Slide 1

Slide 1 text

Shintaro  Katafuchi PermissionsDispatcher

Slide 2

Slide 2 text

I  am… • Shintaro  Katafuchi   • GitHub:  hotchemi   • Recruit  Technologies  Co.,Ltd.   • Scrum  Engineering  Group   • kyobashi.dex  ←  Now!!!

Slide 3

Slide 3 text

Runtime  Permissions

Slide 4

Slide 4 text

Before

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

After

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Runtime  Permissions • From  Marshmallow   • User  can  manage  permissions  at  runtime   • User  can  revoke  permissions  from  setting   • Showing  dialog  →  targeted  M  app   • From  setting  →  even  not  targeted  M  app

Slide 9

Slide 9 text

Other  stuff… • Permission  groups   • ex)  android.permission-­‐group.CALENDAR   • android.permission.READ_CALENDAR   • android.permission.WRITE_CALENDAR   • shouldShowRequestPermissionRationale…?   • A  ton  of  support  library  methods…   • Activity,  ActivityCompat,  PermissionChcker,  ContextCompat,  Fragment,  FragmentCompat…

Slide 10

Slide 10 text

Code

Slide 11

Slide 11 text

public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);   
        showCamera();                  
    
     }   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   }

Slide 12

Slide 12 text

public  class  MainActivity  extends  AppCompatActivity  {   private  static  final  int  REQUEST_SHOWCAMERA  =  0;   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);          showCamera();   
 
    
     }   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   }

Slide 13

Slide 13 text

public  class  MainActivity  extends  AppCompatActivity  {   private  static  final  int  REQUEST_SHOWCAMERA  =  0;   private  static  final  String[]  PERMISSION_SHOWCAMERA  =  new  String[]{"android.permission.CAMERA"};   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);          showCamera();   
 
    
     }   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   }

Slide 14

Slide 14 text

public  class  MainActivity  extends  AppCompatActivity  {   private  static  final  int  REQUEST_SHOWCAMERA  =  0;   private  static  final  String[]  PERMISSION_SHOWCAMERA  =  new  String[]{"android.permission.CAMERA"};   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);          if  (PermissionUtils.hasSelfPermissions(target,  PERMISSION_SHOWCAMERA))  {
            showCamera();          }  else  {
            if  (PermissionUtils.shouldShowRequestPermissionRationale(target,  PERMISSION_SHOWCAMERA))  {
                Toast.makeText(this,  R.string.permission_camera_rationale,  Toast.LENGTH_SHORT).show();
            }
            ActivityCompat.requestPermissions(target,  PERMISSION_SHOWCAMERA,  REQUEST_SHOWCAMERA);          }     }   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   }

Slide 15

Slide 15 text

public  class  MainActivity  extends  AppCompatActivity  {   private  static  final  int  REQUEST_SHOWCAMERA  =  0;   private  static  final  String[]  PERMISSION_SHOWCAMERA  =  new  String[]{"android.permission.CAMERA"};   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);          if  (PermissionUtils.hasSelfPermissions(target,  PERMISSION_SHOWCAMERA))  {
            showCamera();          }  else  {
            if  (PermissionUtils.shouldShowRequestPermissionRationale(target,  PERMISSION_SHOWCAMERA))  {
                Toast.makeText(this,  R.string.permission_camera_rationale,  Toast.LENGTH_SHORT).show();
            }
            ActivityCompat.requestPermissions(target,  PERMISSION_SHOWCAMERA,  REQUEST_SHOWCAMERA);          }     }   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   } @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
 switch  (requestCode)  {
        case  REQUEST_SHOWCAMERA:
        if  (PermissionUtils.verifyPermissions(grantResults))  {
            target.showCamera();
        }  else  {              Toast.makeText(this,  R.string.permission_camera_denied,  Toast.LENGTH_SHORT).show();          }
        break;
 }

Slide 16

Slide 16 text

PermissionsDispatcher

Slide 17

Slide 17 text

PermissionsDispatcher • Generate  codes  with  annotation  processing   • Support  over  api  level  4   • Simple  annotation  based  API   • @RuntimePermissions   • @NeedsPermission(s)   • @ShowRationale(s)  ※Option   • @DeniedPermission(s)  ※Option https://github.com/hotchemi/PermissionsDispatcher

Slide 18

Slide 18 text

public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showCamera();   }   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
  
 }   }

Slide 19

Slide 19 text

@RuntimePermissions   public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showCamera();   }   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
  
 }   }

Slide 20

Slide 20 text

@RuntimePermissions   public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showCamera();   }          @NeedsPermission(Manifest.permission.CAMERA)   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
  
 }   }

Slide 21

Slide 21 text

@RuntimePermissions   public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showCamera();   }          @NeedsPermission(Manifest.permission.CAMERA)   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   @ShowsRationale(Manifest.permission.CAMERA)
 void  showRationaleForCamera()  {
        Toast.makeText(this,  R.string.permission_camera_rationale,  Toast.LENGTH_SHORT).show();
 }   @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
  
 }   }

Slide 22

Slide 22 text

@RuntimePermissions   public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showCamera();   }          @NeedsPermission(Manifest.permission.CAMERA)   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   @ShowsRationale(Manifest.permission.CAMERA)
 void  showRationaleForCamera()  {
        Toast.makeText(this,  R.string.permission_camera_rationale,  Toast.LENGTH_SHORT).show();
 }   @DeniedPermission(Manifest.permission.CAMERA)
 void  deniedPermissionForCamera()  {
        Toast.makeText(this,  R.string.permission_camera_denied,  Toast.LENGTH_SHORT).show();
 }   @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
  
 }   }

Slide 23

Slide 23 text

@RuntimePermissions   public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showCamera();   }          @NeedsPermission(Manifest.permission.CAMERA)   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   @ShowsRationale(Manifest.permission.CAMERA)
 void  showRationaleForCamera()  {
        Toast.makeText(this,  R.string.permission_camera_rationale,  Toast.LENGTH_SHORT).show();
 }   @DeniedPermission(Manifest.permission.CAMERA)
 void  deniedPermissionForCamera()  {
        Toast.makeText(this,  R.string.permission_camera_denied,  Toast.LENGTH_SHORT).show();
 }   @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
    MainActivityPermissionsDispatcher.onRequestPermissionsResult(this,  requestCode,  grantResults);
 }   }

Slide 24

Slide 24 text

@RuntimePermissions   public  class  MainActivity  extends  AppCompatActivity  {   
 @Override
 protected  void  onCreate(Bundle  savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
           }          @NeedsPermission(Manifest.permission.CAMERA)   void  showCamera()  {
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.sample_content_fragment,  CameraPreviewFragment.newInstance())
                        .addToBackStack("camera")
                        .commitAllowingStateLoss();
 }   @ShowsRationale(Manifest.permission.CAMERA)
 void  showRationaleForCamera()  {
        Toast.makeText(this,  R.string.permission_camera_rationale,  Toast.LENGTH_SHORT).show();
 }   @DeniedPermission(Manifest.permission.CAMERA)
 void  deniedPermissionForCamera()  {
        Toast.makeText(this,  R.string.permission_camera_denied,  Toast.LENGTH_SHORT).show();
 }   @Override
 public  void  onRequestPermissionsResult(int  requestCode,  String[]  permissions,  int[]  grantResults)  {
    MainActivityPermissionsDispatcher.onRequestPermissionsResult(this,  requestCode,  grantResults);
 }   } MainActivityPermissionsDispatcher.showCameraWithCheck(this);

Slide 25

Slide 25 text

package  permissions.dispatcher.sample;
 
 import  android.support.v4.app.ActivityCompat;
 import  java.lang.String;
 import  permissions.dispatcher.PermissionUtils;
 
 public  final  class  MainActivityPermissionsDispatcher  {
    private  static  final  int  REQUEST_SHOWCAMERA  =  0;
 
    private  static  final  String[]  PERMISSION_SHOWCAMERA  =  new  String[]{"android.permission.CAMERA"};
 
    private  MainActivityPermissionsDispatcher()  {
    }
 
    public  static  void  showCameraWithCheck(MainActivity  target)  {
        if  (PermissionUtils.hasSelfPermissions(target,  PERMISSION_SHOWCAMERA))  {
            target.showCamera();
        }  else  {
            if  (PermissionUtils.shouldShowRequestPermissionRationale(target,  PERMISSION_SHOWCAMERA))  {
                target.showRationaleForCamera();
            }
            ActivityCompat.requestPermissions(target,  PERMISSION_SHOWCAMERA,  REQUEST_SHOWCAMERA);
        }
    }
 
    public  static  void  onRequestPermissionsResult(MainActivity  target,  int  requestCode,  int[]  grantResults)  {
        switch  (requestCode)  {
            case  REQUEST_SHOWCAMERA:
            if  (PermissionUtils.verifyPermissions(grantResults))  {
                target.showCamera();
            }
            break;
            case  REQUEST_SHOWCONTACTS:
            if  (PermissionUtils.verifyPermissions(grantResults))  {
                target.showContacts();
            }
            break;
            default:
            break;
        }
    }
 } Generated  code

Slide 26

Slide 26 text

Milestone • 1.2.1…  existing  bug  fix   • 2.0.0…  Rewriting  processor  in  Kotlin   • Thanks  @aurae!

Slide 27

Slide 27 text

Practice • 1.Finding   • https://github.com/hotchemi/m-­‐permissions-­‐checker   • 2.Handling   • https://github.com/hotchemi/permissionsdispatcher   • That’s  it!

Slide 28

Slide 28 text

Thanks.   Any  questions?