Slide 1

Slide 1 text

PermissionsDispatcher +ShintaroKatafuchi

Slide 2

Slide 2 text

• +ShintaroKatafuchi • @hotchemi • Android dev at Quipper • Member of DroidKaigi

Slide 3

Slide 3 text

• From Marshmallow • Grant permissions at runtime • User can revoke permissions
 from settings screen

Slide 4

Slide 4 text

• Never ask again • Once user check and denied,
 checkSelfPermission always 
 return PERMISSION_DENIED • targetSdkVersion >= 23 • Lead user to settings screen

Slide 5

Slide 5 text

public class MainActivity extends AppCompatActivity { 
 @Override protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main); 
 showCamera(); 
 
 } }

Slide 6

Slide 6 text

public class MainActivity extends AppCompatActivity { 
 @Override protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main); showCamera(); 
 
 
 } } private static final int REQUEST_SHOWCAMERA = 0;

Slide 7

Slide 7 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(); 
 
 
 } } private static final String[] PERMISSION_SHOWCAMERA = new String[]{"android.permission.CAMERA"};

Slide 8

Slide 8 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 (PermissionChecker.checkSelfPermissions(this, PERMISSION_SHOWCAMERA) == PERMISSION_GRANTED) {
 showCamera(); } else {
 if (ActivityCompat.shouldShowRequestPermissionRationale(this, PERMISSION_SHOWCAMERA)) {
 // show rationale
 }
 ActivityCompat.requestPermissions(this, PERMISSION_SHOWCAMERA, REQUEST_SHOWCAMERA); }

Slide 9

Slide 9 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 (PermissionChecker.checkSelfPermissions(this, PERMISSION_SHOWCAMERA) == PERMISSION_GRANTED) {
 showCamera(); } else {
 if (ActivityCompat.shouldShowRequestPermissionRationale(this, PERMISSION_SHOWCAMERA)) {
 // show rationale
 }
 ActivityCompat.requestPermissions(this, PERMISSION_SHOWCAMERA, REQUEST_SHOWCAMERA); } } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
 switch (requestCode) {
 case REQUEST_SHOWCAMERA:
 if (PermissionUtils.verifyPermissions(grantResults)) { // check all permissions are granted
 showCamera();
 } else { if (ActivityCompat.shouldShowRequestPermissionRationale(this, PERMISSION_SHOWCAMERA)) { // show denied action } else { // never ask again } }
 break;
 }

Slide 10

Slide 10 text

No worries

Slide 11

Slide 11 text

• PermissionsDispatcher • Generate codes with annotation processing • supported on API levels 4 and up • Processor module is written with Kotlin • https://github.com/hotchemi/PermissionsDispatcher

Slide 12

Slide 12 text

• Simple annotation based API • @RuntimePermissions ✔ • @NeedsPermission ✔ • @OnDeniedPermission • @OnShowRationale • @NeverAskAgain

Slide 13

Slide 13 text

apply plugin: 'android-apt' dependencies {
 compile “com.github.hotchemi:permissionsdispatcher:2.1.3” apt “com.github.hotchemi:permissionsdispatcher-processor:2.1.3”
 }

Slide 14

Slide 14 text

• @RuntimePermissions • Activity • Fragment • Fragment(support v4) public class MainActivity extends AppCompatActivity{ }

Slide 15

Slide 15 text

• @RuntimePermissions • Activity • Fragment • Fragment(support v4) public class MainActivity extends AppCompatActivity{ } @RuntimePermissions

Slide 16

Slide 16 text

• @NeedsPermission • Single permission • Multiple permissions void showCamera() {
 getSupportFragmentManager().beginTransaction()
 .replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
 .addToBackStack("camera")
 .commitAllowingStateLoss();
 }

Slide 17

Slide 17 text

• @NeedsPermission • Single permission • Multiple permissions void showCamera() {
 getSupportFragmentManager().beginTransaction()
 .replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
 .addToBackStack("camera")
 .commitAllowingStateLoss();
 } @NeedsPermission(Manifest.permission.CAMERA)

Slide 18

Slide 18 text

• @OnPermissionDenied • Single permission • Multiple permissions 
 void onCameraDenied() {
 Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_LONG).show();
 }

Slide 19

Slide 19 text

• @OnPermissionDenied • Single permission • Multiple permissions 
 void onCameraDenied() {
 Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_LONG).show();
 } @OnPermissionDenied(Manifest.permission.CAMERA)

Slide 20

Slide 20 text

• @OnShowRationale • Asynchronous support 
 
 void showRationaleForCamera(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();
 } })
 .setMessage(R.string.permission_camera_rationale)
 .show();
 }

Slide 21

Slide 21 text

• @OnShowRationale • Asynchronous support 
 @OnShowRationale(Manifest.permission.CAMERA) 
 
 void showRationaleForCamera(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();
 } })
 .setMessage(R.string.permission_camera_rationale)
 .show();
 }

Slide 22

Slide 22 text

• @NeverAskAgain • Single permission • Multiple permissions 
 void onNeverAskAgain() {
 Toast.makeText(this, R.string.permission_camera_neveraskagain, Toast.LENGTH_LONG).show();
 }

Slide 23

Slide 23 text

• @NeverAskAgain • Single permission • Multiple permissions 
 void onNeverAskAgain() {
 Toast.makeText(this, R.string.permission_camera_neveraskagain, Toast.LENGTH_LONG).show();
 } @NeverAskAgain(Manifest.permission.CAMERA)

Slide 24

Slide 24 text

package permissions.dispatcher.sample;
 
 @RuntimePermissions
 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 findViewById(R.id.button_camera).setOnClickListener(this);
 }
 
 @Override
 public void onClick(@NonNull View v) {
 switch (v.getId()) {
 case R.id.button_camera:
 MainActivityPermissionsDispatcher.showCameraWithCheck(this);
 break;
 }
 }
 
 @Override
 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
 } 
 } 
 
 
 
 MainActivityPermissionsDispatcher.showCameraWithCheck(this); 
 
 
 MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);

Slide 25

Slide 25 text

package permissions.dispatcher.sample;
 
 final class MainActivityPermissionsDispatcher {
 private static final int REQUEST_SHOWCAMERA = 0;
 
 private static final String[] PERMISSION_SHOWCAMERA = new String[] {"android.permission.CAMERA"};
 
 private MainActivityPermissionsDispatcher() {
 }
 
 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);
 }
 }
 }
 
 static void onRequestPermissionsResult(MainActivity target, int requestCode, int[] grantResults) {
 switch (requestCode) {
 case REQUEST_SHOWCAMERA:
 if (PermissionUtils.verifyPermissions(grantResults)) {
 target.showCamera();
 } else {
 target.onCameraDenied();
 }
 break;
 default:
 break;
 }
 }
 
 private static final class ShowCameraPermissionRequest implements PermissionRequest {
 private final WeakReference weakTarget;
 
 private ShowCameraPermissionRequest(MainActivity target) {
 this.weakTarget = new WeakReference<>(target);
 }
 
 @Override
 public void proceed() {
 MainActivity target = weakTarget.get();
 if (target == null) return;
 ActivityCompat.requestPermissions(target, PERMISSION_SHOWCAMERA, REQUEST_SHOWCAMERA);
 }
 
 @Override
 public void cancel() {
 MainActivity target = weakTarget.get();
 if (target == null) return;
 target.onCameraDenied();
 }
 }
 } Generated code

Slide 26

Slide 26 text

permissions-dispatcher-plugin

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Thanks, any questions?