title: Android PermissionsDispatcher with API < 23
body: <p>I use hotchemi PermissionsDispatcher to check permissions. It works perfectly for API >= 23. But I'm getting a FATAL EXCEPTION java.lang.StackOverflowError when I try to use the same code on a device with API 16. 
  The error raise when I call <code>showCameraWithCheck()</code> in the generated class <code>MainActivityPermissionsDispatcher</code></p>
  
  <p>I went deeply into the class <code>MainActivityPermissionsDispatcher</code> generated by the PermissionsDispatcher library and found why the Stack Overflow happen. When I call <code>MainActivityPermissionsDispatcher.showCameraWithCheck(this);</code> it goes to this method in the generated <code>MainActivityPermissionsDispatcher</code> :</p>
  
  <pre><code>static void showCameraWithCheck(MainActivity target) {
  if (PermissionUtils.hasSelfPermissions(target, PERMISSION_SHOWCAMERA)) {
    target.showCamera();
  } else {
    if (PermissionUtils.shouldShowRequestPermissionRationale(target, PERMISSION_SHOWCAMERA)) {
      target.showRationaleForCamera(new ShowCameraPermissionRequest(target));
    } else {
      ActivityCompat.requestPermissions(target, PERMISSION_SHOWCAMERA, REQUEST_SHOWCAMERA);
    }
  }
  </code></pre>
  
  <p>}</p>
  
  <p>The thing is <code>PermissionUtils.hasSelfPermissions(target, PERMISSION_SHOWCAMERA)</code> is always true so it called <code>target.showCamera()</code> which is my method who called <code>MainActivityPermissionsDispatcher.showCameraWithCheck(this);</code> so it enter in a no end loop.... I guess the <code>hasSelfPermissions()</code> method check if it's runtime permissions (API >= 23) or old style permissions (&lt; API 23).</p>
  
  <blockquote>
    <p>E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                                java.lang.StackOverflowError
                                                                                                    at android.os.Parcel.readException(Parcel.java:1376)
                                                                                                    at
    android.app.ActivityManagerProxy.checkPermission(ActivityManagerNative.java:2874)
                                                                                                    at android.app.ContextImpl.checkPermission(ContextImpl.java:1285)
                                                                                                    at
    android.content.ContextWrapper.checkPermission(ContextWrapper.java:421)
                                                                                                    at
    android.support.v4.content.PermissionChecker.checkPermission(PermissionChecker.java:89)
                                                                                                    at
    android.support.v4.content.PermissionChecker.checkSelfPermission(PermissionChecker.java:125)
                                                                                                    at
    permissions.dispatcher.PermissionUtils.hasSelfPermissions(PermissionUtils.java:73)
                                                                                                    at
    com.example.android.permissionsdispatcherapp.MainActivityPermissionsDispatcher.showCameraWithCheck(MainActivityPermissionsDispatcher.java:20)
                                                                                                    at
    com.example.android.permissionsdispatcherapp.MainActivity.showCamera(MainActivity.java:52)
    ......................</p>
  </blockquote>
  
  <pre><code>@RuntimePermissions
  public class MainActivity extends AppCompatActivity {
  private static String LOG_TAG = MainActivity.class.getSimpleName();
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
  
      try {
  
          Button btnShowCamera = (Button) findViewById(R.id.btn_show_camera);
          btnShowCamera.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  Log.i(LOG_TAG, "Show camera button pressed.");
                  showCamera();
              }
  
          });
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
  
  @NeedsPermission(Manifest.permission.CAMERA)
  void showCamera() {
      // NOTE: delegate the permission handling to generated method
      // ERROR
      MainActivityPermissionsDispatcher.showCameraWithCheck(this);
  }
  
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
      super.onRequestPermissionsResult(requestCode, permissions, grantResults);
      // NOTE: delegate the permission handling to generated method
      MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
  }
  
  @OnPermissionDenied(Manifest.permission.CAMERA)
  void onCameraDenied() {
      // NOTE: Deal with a denied permission, e.g. by showing specific UI
      // or disabling certain functionality
      Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_LONG).show();
  }
  
  @OnNeverAskAgain(Manifest.permission.CAMERA)
  void onCameraNeverAskAgain() {
      Toast.makeText(this, R.string.permission_camera_never_askagain, Toast.LENGTH_LONG).show();
  }
  
  @OnShowRationale(Manifest.permission.CAMERA)
  void showRationaleForCamera(PermissionRequest request) {
      // NOTE: Show a rationale to explain why the permission is needed, e.g. with a dialog.
      // Call proceed() or cancel() on the provided PermissionRequest to continue or abort
      showRationaleDialog(R.string.permission_camera_rationale, request);
  }
  
  private void showRationaleDialog(@StringRes int messageResId, final PermissionRequest request) {
      new AlertDialog.Builder(this)
              .setPositiveButton(R.string.button_allow, new DialogInterface.OnClickListener() {
                  @Override
                  public void onClick(@NonNull DialogInterface dialog, int which) {
                      request.proceed();
                  }
              })
              .setNegativeButton(R.string.button_deny, new DialogInterface.OnClickListener() {
                  @Override
                  public void onClick(@NonNull DialogInterface dialog, int which) {
                      request.cancel();
                  }
              })
              .setCancelable(false)
              .setMessage(messageResId)
              .show();
  }
  }
  
  enter code here
  </code></pre>