From 6d4f4364842b8aa56a3666fb3b2d964ebf3931dd Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 11:31:13 +0100 Subject: [PATCH 01/14] Remove portrait restriction in the SampleActivity declaration --- sample/src/main/AndroidManifest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 7d05c906..89814434 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -34,7 +34,6 @@ From 0269a9adae496cf93b0be96b6f891607638ace84 Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 11:32:20 +0100 Subject: [PATCH 02/14] Check inside DexterInstance if the rationale has been shown or not and create a method to continue with the request permission process if needed --- .../com/karumi/dexter/DexterInstance.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java index 8d7cb7fd..eb2730e5 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java @@ -47,6 +47,7 @@ final class DexterInstance { private Activity activity; private MultiplePermissionsListener listener; private AtomicBoolean isRequestingPermission = new AtomicBoolean(false); + private AtomicBoolean rationaleShown = new AtomicBoolean(false); DexterInstance(Context context, AndroidPermissionService androidPermissionService, IntentProvider intentProvider) { @@ -88,12 +89,23 @@ void checkPermissions(MultiplePermissionsListener listener, Collection p startTransparentActivity(); } + /** + * Check if there is some permission pending to be confirmed by the user and restarts the request + * for permission process. + */ + void checkPendingPermissions() { + boolean shouldContinueRequestingPendingPermissions = + !pendingPermissions.isEmpty() && !rationaleShown.get(); + if (shouldContinueRequestingPendingPermissions) { + startTransparentActivity(); + } + } + /** * Method called whenever the inner activity has been created and is ready to be used */ void onActivityCreated(Activity activity) { this.activity = activity; - Collection deniedRequests = new LinkedList<>(); Collection grantedRequests = new LinkedList<>(); @@ -133,6 +145,7 @@ void onPermissionRequestDenied(Collection permissions) { * with the permission request process */ void onContinuePermissionRequest() { + rationaleShown.set(true); requestPermissionsToSystem(pendingPermissions); } @@ -141,6 +154,7 @@ void onContinuePermissionRequest() { * the permission request process */ void onCancelPermissionRequest() { + rationaleShown.set(false); updatePermissionsAsDenied(pendingPermissions); } @@ -173,7 +187,7 @@ private void handleDeniedPermissions(Collection permissions) { if (shouldShowRequestRationalePermissions.isEmpty()) { requestPermissionsToSystem(permissions); - } else { + } else if (!rationaleShown.get()) { PermissionRationaleToken permissionToken = new PermissionRationaleToken(this); listener.onPermissionRationaleShouldBeShown(shouldShowRequestRationalePermissions, permissionToken); @@ -206,6 +220,7 @@ private void onPermissionsChecked(Collection permissions) { if (pendingPermissions.isEmpty()) { activity.finish(); isRequestingPermission.set(false); + rationaleShown.set(false); listener.onPermissionsChecked(multiplePermissionsReport); } } From 52f83df2cf84c787272f7ca9398c0c68dc8d29d0 Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 11:34:10 +0100 Subject: [PATCH 03/14] Add a method to the public Dexter interface to be able to continue with the dexter permission request process after the rotate screen event --- dexter/src/main/java/com/karumi/dexter/Dexter.java | 8 ++++++++ .../java/com/karumi/dexter/sample/SampleActivity.java | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/dexter/src/main/java/com/karumi/dexter/Dexter.java b/dexter/src/main/java/com/karumi/dexter/Dexter.java index fc9113b0..c5c441ad 100644 --- a/dexter/src/main/java/com/karumi/dexter/Dexter.java +++ b/dexter/src/main/java/com/karumi/dexter/Dexter.java @@ -80,6 +80,14 @@ public static void checkPermissions(MultiplePermissionsListener listener, instance.checkPermissions(listener, permissions); } + /** + * Requests pending permissions if there was some permissions lost during the rotate screen + * process. + */ + public static void checkPendingPermissions() { + instance.checkPendingPermissions(); + } + /** * Method called whenever the DexterActivity has been created and is ready to be used */ diff --git a/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java b/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java index df4ced46..288b34e3 100644 --- a/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java +++ b/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java @@ -59,6 +59,12 @@ public class SampleActivity extends Activity { setContentView(R.layout.sample_activity); ButterKnife.bind(this); createPermissionListeners(); + /* + * If during the rotate screen process the activity has been restarted you can call this method + * to start with the check permission process without keep in an Android Bundle the state of + * the request permission process. + */ + Dexter.checkPendingPermissions(); } @OnClick(R.id.all_permissions_button) public void onAllPermissionsButtonClicked() { From 7d7afb08d17ab699d3aa2de32c537caa8fe023c0 Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 11:52:50 +0100 Subject: [PATCH 04/14] Add test to cover the rotate screen feature --- .../com/karumi/dexter/DexterInstanceTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java index 1293324c..4f714e21 100644 --- a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java +++ b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java @@ -35,6 +35,7 @@ import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -104,6 +105,16 @@ public void onCheckPermissionMoreThanOnceThenThrowException() { thenPermissionIsPermanentlyDenied(ANY_PERMISSION); } + @Test public void onPermissionsPendingThenShouldNotShowPermissionRationaleTwice() { + givenPermissionIsAlreadyDenied(ANY_PERMISSION); + givenShouldShowRationaleForPermission(ANY_PERMISSION); + + whenCheckPermission(permissionListener, ANY_PERMISSION); + whenContinueWithTheCheckPermissionProcess(); + + thenPermissionRationaleIsShown(1); + } + private void givenPermissionIsAlreadyDenied(String permission) { givenPermissionIsChecked(permission, PackageManager.PERMISSION_DENIED); } @@ -132,6 +143,10 @@ private void whenCheckPermission(PermissionListener permissionListener, String p dexter.onActivityCreated(activity); } + private void whenContinueWithTheCheckPermissionProcess() { + dexter.checkPendingPermissions(); + } + private void thenPermissionIsGranted(String permission) { verify(permissionListener).onPermissionGranted( argThat(getPermissionGrantedResponseMatcher(permission))); @@ -153,6 +168,11 @@ private void thenShouldShowRationaleForPermission(String permission) { isA(PermissionToken.class)); } + private void thenPermissionRationaleIsShown(int times) { + verify(permissionListener, times(times)).onPermissionRationaleShouldBeShown( + isA(PermissionRequest.class), isA(PermissionToken.class)); + } + private static ArgumentMatcher getPermissionGrantedResponseMatcher( final String permission) { return new ArgumentMatcher() { From f8a7c70cc899b420668e9083e59d82511d856af0 Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 12:00:17 +0100 Subject: [PATCH 05/14] Update README.md with the new feature documentation --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index dc1a0df8..c9c1c032 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,16 @@ MultiplePermissionsListener dialogMultiplePermissionsListener = /*...*/; Dexter.checkPermissions(new CompositePermissionListener(snackbarMultiplePermissionsListener, dialogMultiplePermissionsListener, /*...*/), Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO); ``` +** If your application has to support configuration changes based on screen rotation remember to add a call to ``Dexter`` in your Activity ``onCreate`` method as follows:** + +```java + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.sample_activity); + Dexter.checkPendingPermissions(); + } +``` + **IMPORTANT**: Remember to follow the [Google design guidelines] [2] to make your application as user-friendly as possible. Add it to your project From 5631b949a2985e946031b5391b1bfc496db49761 Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 12:05:32 +0100 Subject: [PATCH 06/14] Update javadoc --- dexter/src/main/java/com/karumi/dexter/Dexter.java | 4 ++-- dexter/src/main/java/com/karumi/dexter/DexterInstance.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dexter/src/main/java/com/karumi/dexter/Dexter.java b/dexter/src/main/java/com/karumi/dexter/Dexter.java index c5c441ad..f9924af7 100644 --- a/dexter/src/main/java/com/karumi/dexter/Dexter.java +++ b/dexter/src/main/java/com/karumi/dexter/Dexter.java @@ -81,8 +81,8 @@ public static void checkPermissions(MultiplePermissionsListener listener, } /** - * Requests pending permissions if there was some permissions lost during the rotate screen - * process. + * Requests pending permissions if there were some permissions lost. This method can be used to + * recover the Dexter state during a configuration change, for example when the device is rotated. */ public static void checkPendingPermissions() { instance.checkPendingPermissions(); diff --git a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java index eb2730e5..d8f9639e 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java @@ -90,7 +90,7 @@ void checkPermissions(MultiplePermissionsListener listener, Collection p } /** - * Check if there is some permission pending to be confirmed by the user and restarts the request + * Check if there are some permissions pending to be confirmed by the user and restarts the request * for permission process. */ void checkPendingPermissions() { From aacfba2ad7058cf44445f5dd5826bbf42611fb68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Vicente=20G=C3=B3mez=20S=C3=A1nchez?= Date: Wed, 25 Nov 2015 18:14:59 +0100 Subject: [PATCH 07/14] Update README.md to move the screen rotation support to another place as Sergio has requested. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c9c1c032..771aa88a 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,9 @@ MultiplePermissionsListener dialogMultiplePermissionsListener = /*...*/; Dexter.checkPermissions(new CompositePermissionListener(snackbarMultiplePermissionsListener, dialogMultiplePermissionsListener, /*...*/), Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO); ``` -** If your application has to support configuration changes based on screen rotation remember to add a call to ``Dexter`` in your Activity ``onCreate`` method as follows:** +**IMPORTANT**: Remember to follow the [Google design guidelines] [2] to make your application as user-friendly as possible. + +**If your application has to support configuration changes based on screen rotation remember to add a call to ``Dexter`` in your Activity ``onCreate`` method as follows:** ```java @Override protected void onCreate(Bundle savedInstanceState) { @@ -137,8 +139,6 @@ Dexter.checkPermissions(new CompositePermissionListener(snackbarMultiplePermissi } ``` -**IMPORTANT**: Remember to follow the [Google design guidelines] [2] to make your application as user-friendly as possible. - Add it to your project ---------------------- From 4983057fe025b3392d742d9f29f2ed18a8e759ce Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 18:55:48 +0100 Subject: [PATCH 08/14] First approach finished to fix the memory leak problems discovered by Sergio --- .../main/java/com/karumi/dexter/Dexter.java | 12 ++++- .../com/karumi/dexter/DexterInstance.java | 48 ++++++++++++------- sample/src/main/AndroidManifest.xml | 1 - .../karumi/dexter/sample/SampleActivity.java | 2 +- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/dexter/src/main/java/com/karumi/dexter/Dexter.java b/dexter/src/main/java/com/karumi/dexter/Dexter.java index f9924af7..5c190679 100644 --- a/dexter/src/main/java/com/karumi/dexter/Dexter.java +++ b/dexter/src/main/java/com/karumi/dexter/Dexter.java @@ -84,8 +84,16 @@ public static void checkPermissions(MultiplePermissionsListener listener, * Requests pending permissions if there were some permissions lost. This method can be used to * recover the Dexter state during a configuration change, for example when the device is rotated. */ - public static void checkPendingPermissions() { - instance.checkPendingPermissions(); + public static void checkPendingPermissions(MultiplePermissionsListener listener) { + instance.checkPendingPermissions(listener); + } + + /** + * Requests pending permission if there was a permissions lost. This method can be used to + * recover the Dexter state during a configuration change, for example when the device is rotated. + */ + public static void checkPendingPermission(PermissionListener listener) { + instance.checkPendingPermission(listener); } /** diff --git a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java index d8f9639e..9fe7ece0 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java @@ -44,10 +44,10 @@ final class DexterInstance { private final IntentProvider intentProvider; private final Collection pendingPermissions; private final MultiplePermissionsReport multiplePermissionsReport; - private Activity activity; + private static Activity activity; private MultiplePermissionsListener listener; private AtomicBoolean isRequestingPermission = new AtomicBoolean(false); - private AtomicBoolean rationaleShown = new AtomicBoolean(false); + private AtomicBoolean rationaleAccepted = new AtomicBoolean(false); DexterInstance(Context context, AndroidPermissionService androidPermissionService, IntentProvider intentProvider) { @@ -86,21 +86,32 @@ void checkPermissions(MultiplePermissionsListener listener, Collection p multiplePermissionsReport.clear(); this.listener = listener; - startTransparentActivity(); + startTransparentActivityIfNeeded(); } /** - * Check if there are some permissions pending to be confirmed by the user and restarts the request - * for permission process. + * Check if there are some permissions pending to be confirmed by the user and restarts the + * request for permission process. */ - void checkPendingPermissions() { + void checkPendingPermissions(MultiplePermissionsListener listener) { boolean shouldContinueRequestingPendingPermissions = - !pendingPermissions.isEmpty() && !rationaleShown.get(); + !pendingPermissions.isEmpty() && !rationaleAccepted.get(); + this.listener = listener; if (shouldContinueRequestingPendingPermissions) { - startTransparentActivity(); + onActivityCreated(activity); } } + /** + * Check if there is a permission pending to be confirmed by the user and restarts the + * request for permission process. + */ + void checkPendingPermission(PermissionListener listener) { + MultiplePermissionsListenerToPermissionListenerAdapter adapter = + new MultiplePermissionsListenerToPermissionListenerAdapter(listener); + checkPendingPermissions(adapter); + } + /** * Method called whenever the inner activity has been created and is ready to be used */ @@ -145,7 +156,7 @@ void onPermissionRequestDenied(Collection permissions) { * with the permission request process */ void onContinuePermissionRequest() { - rationaleShown.set(true); + rationaleAccepted.set(true); requestPermissionsToSystem(pendingPermissions); } @@ -154,7 +165,7 @@ void onContinuePermissionRequest() { * the permission request process */ void onCancelPermissionRequest() { - rationaleShown.set(false); + rationaleAccepted.set(false); updatePermissionsAsDenied(pendingPermissions); } @@ -166,10 +177,14 @@ void requestPermissionsToSystem(Collection permissions) { permissions.toArray(new String[permissions.size()]), PERMISSIONS_REQUEST_CODE); } - private void startTransparentActivity() { - Intent intent = intentProvider.get(context, DexterActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + private void startTransparentActivityIfNeeded() { + if (activity == null) { + Intent intent = intentProvider.get(context, DexterActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } else { + onActivityCreated(activity); + } } private void handleDeniedPermissions(Collection permissions) { @@ -187,7 +202,7 @@ private void handleDeniedPermissions(Collection permissions) { if (shouldShowRequestRationalePermissions.isEmpty()) { requestPermissionsToSystem(permissions); - } else if (!rationaleShown.get()) { + } else if (!rationaleAccepted.get()) { PermissionRationaleToken permissionToken = new PermissionRationaleToken(this); listener.onPermissionRationaleShouldBeShown(shouldShowRequestRationalePermissions, permissionToken); @@ -218,9 +233,8 @@ private void onPermissionsChecked(Collection permissions) { pendingPermissions.removeAll(permissions); if (pendingPermissions.isEmpty()) { - activity.finish(); isRequestingPermission.set(false); - rationaleShown.set(false); + rationaleAccepted.set(false); listener.onPermissionsChecked(multiplePermissionsReport); } } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 89814434..f39b4725 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -33,7 +33,6 @@ diff --git a/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java b/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java index 288b34e3..f6524c39 100644 --- a/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java +++ b/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java @@ -64,7 +64,7 @@ public class SampleActivity extends Activity { * to start with the check permission process without keep in an Android Bundle the state of * the request permission process. */ - Dexter.checkPendingPermissions(); + Dexter.checkPendingPermissions(allPermissionsListener); } @OnClick(R.id.all_permissions_button) public void onAllPermissionsButtonClicked() { From 2902ed1a0d794bfd40f0a48f90c6b931822a13ba Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 19:11:39 +0100 Subject: [PATCH 09/14] Change the previous implementation to avoid the usage of a static activity and use a single task activity to avoid memory leaks --- dexter/src/main/AndroidManifest.xml | 1 + .../main/java/com/karumi/dexter/Dexter.java | 13 +++--- .../com/karumi/dexter/DexterActivity.java | 8 +++- .../com/karumi/dexter/DexterInstance.java | 40 +++++++++---------- .../com/karumi/dexter/DexterInstanceTest.java | 2 +- 5 files changed, 36 insertions(+), 28 deletions(-) diff --git a/dexter/src/main/AndroidManifest.xml b/dexter/src/main/AndroidManifest.xml index 30baf825..5ce10cb3 100644 --- a/dexter/src/main/AndroidManifest.xml +++ b/dexter/src/main/AndroidManifest.xml @@ -22,6 +22,7 @@ diff --git a/dexter/src/main/java/com/karumi/dexter/Dexter.java b/dexter/src/main/java/com/karumi/dexter/Dexter.java index 5c190679..48877728 100644 --- a/dexter/src/main/java/com/karumi/dexter/Dexter.java +++ b/dexter/src/main/java/com/karumi/dexter/Dexter.java @@ -82,7 +82,8 @@ public static void checkPermissions(MultiplePermissionsListener listener, /** * Requests pending permissions if there were some permissions lost. This method can be used to - * recover the Dexter state during a configuration change, for example when the device is rotated. + * recover the Dexter state during a configuration change, for example when the device is + * rotated. */ public static void checkPendingPermissions(MultiplePermissionsListener listener) { instance.checkPendingPermissions(listener); @@ -90,17 +91,19 @@ public static void checkPendingPermissions(MultiplePermissionsListener listener) /** * Requests pending permission if there was a permissions lost. This method can be used to - * recover the Dexter state during a configuration change, for example when the device is rotated. + * recover the Dexter state during a configuration change, for example when the device is + * rotated. */ public static void checkPendingPermission(PermissionListener listener) { instance.checkPendingPermission(listener); } /** - * Method called whenever the DexterActivity has been created and is ready to be used + * Method called whenever the DexterActivity has been created or recreated and is ready to be + * used. */ - static void onActivityCreated(Activity activity) { - instance.onActivityCreated(activity); + static void onActivityReady(Activity activity) { + instance.onActivityReady(activity); } /** diff --git a/dexter/src/main/java/com/karumi/dexter/DexterActivity.java b/dexter/src/main/java/com/karumi/dexter/DexterActivity.java index c8288322..07bef390 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterActivity.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterActivity.java @@ -17,6 +17,7 @@ package com.karumi.dexter; import android.app.Activity; +import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.view.WindowManager; @@ -27,10 +28,15 @@ public final class DexterActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Dexter.onActivityCreated(this); + Dexter.onActivityReady(this); getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); } + @Override protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Dexter.onActivityReady(this); + } + @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { Collection grantedPermissions = new LinkedList<>(); diff --git a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java index 9fe7ece0..b5ce47df 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java @@ -44,7 +44,7 @@ final class DexterInstance { private final IntentProvider intentProvider; private final Collection pendingPermissions; private final MultiplePermissionsReport multiplePermissionsReport; - private static Activity activity; + private Activity activity; private MultiplePermissionsListener listener; private AtomicBoolean isRequestingPermission = new AtomicBoolean(false); private AtomicBoolean rationaleAccepted = new AtomicBoolean(false); @@ -89,6 +89,16 @@ void checkPermissions(MultiplePermissionsListener listener, Collection p startTransparentActivityIfNeeded(); } + /** + * Check if there is a permission pending to be confirmed by the user and restarts the + * request for permission process. + */ + void checkPendingPermission(PermissionListener listener) { + MultiplePermissionsListenerToPermissionListenerAdapter adapter = + new MultiplePermissionsListenerToPermissionListenerAdapter(listener); + checkPendingPermissions(adapter); + } + /** * Check if there are some permissions pending to be confirmed by the user and restarts the * request for permission process. @@ -98,24 +108,15 @@ void checkPendingPermissions(MultiplePermissionsListener listener) { !pendingPermissions.isEmpty() && !rationaleAccepted.get(); this.listener = listener; if (shouldContinueRequestingPendingPermissions) { - onActivityCreated(activity); + onActivityReady(activity); } } /** - * Check if there is a permission pending to be confirmed by the user and restarts the - * request for permission process. - */ - void checkPendingPermission(PermissionListener listener) { - MultiplePermissionsListenerToPermissionListenerAdapter adapter = - new MultiplePermissionsListenerToPermissionListenerAdapter(listener); - checkPendingPermissions(adapter); - } - - /** - * Method called whenever the inner activity has been created and is ready to be used + * Method called whenever the inner activity has been created or restarted and is ready to be + * used. */ - void onActivityCreated(Activity activity) { + void onActivityReady(Activity activity) { this.activity = activity; Collection deniedRequests = new LinkedList<>(); Collection grantedRequests = new LinkedList<>(); @@ -178,13 +179,9 @@ void requestPermissionsToSystem(Collection permissions) { } private void startTransparentActivityIfNeeded() { - if (activity == null) { - Intent intent = intentProvider.get(context, DexterActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } else { - onActivityCreated(activity); - } + Intent intent = intentProvider.get(context, DexterActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); } private void handleDeniedPermissions(Collection permissions) { @@ -233,6 +230,7 @@ private void onPermissionsChecked(Collection permissions) { pendingPermissions.removeAll(permissions); if (pendingPermissions.isEmpty()) { + activity.finish(); isRequestingPermission.set(false); rationaleAccepted.set(false); listener.onPermissionsChecked(multiplePermissionsReport); diff --git a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java index 4f714e21..b6d675fb 100644 --- a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java +++ b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java @@ -140,7 +140,7 @@ private void givenShouldShowNotRationaleForPermission(String permission) { private void whenCheckPermission(PermissionListener permissionListener, String permission) { dexter.checkPermission(permissionListener, permission); - dexter.onActivityCreated(activity); + dexter.onActivityReady(activity); } private void whenContinueWithTheCheckPermissionProcess() { From bdd9e5b9234949f805402232499e19208b8aff97 Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 19:20:43 +0100 Subject: [PATCH 10/14] Fix broken test --- .../test/java/com/karumi/dexter/DexterInstanceTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java index b6d675fb..501d79d8 100644 --- a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java +++ b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java @@ -110,9 +110,9 @@ public void onCheckPermissionMoreThanOnceThenThrowException() { givenShouldShowRationaleForPermission(ANY_PERMISSION); whenCheckPermission(permissionListener, ANY_PERMISSION); - whenContinueWithTheCheckPermissionProcess(); + whenContinueWithTheCheckPermissionProcess(permissionListener); - thenPermissionRationaleIsShown(1); + thenPermissionRationaleIsShown(2); } private void givenPermissionIsAlreadyDenied(String permission) { @@ -143,8 +143,8 @@ private void whenCheckPermission(PermissionListener permissionListener, String p dexter.onActivityReady(activity); } - private void whenContinueWithTheCheckPermissionProcess() { - dexter.checkPendingPermissions(); + private void whenContinueWithTheCheckPermissionProcess(PermissionListener permissionListener) { + dexter.checkPendingPermission(permissionListener); } private void thenPermissionIsGranted(String permission) { From 463c24a409ace8e96dd256586006972e5c226aa1 Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Wed, 25 Nov 2015 19:28:26 +0100 Subject: [PATCH 11/14] Fix checkstyle issues --- dexter/src/main/java/com/karumi/dexter/DexterInstance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java index 5ce76435..74df27dc 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java @@ -48,7 +48,7 @@ final class DexterInstance { private final AtomicBoolean rationaleAccepted; private Activity activity; private MultiplePermissionsListener listener; - + DexterInstance(Context context, AndroidPermissionService androidPermissionService, IntentProvider intentProvider) { this.context = context; From b697132ff23dca48c638aa70b1a257cd7f037ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Vicente=20G=C3=B3mez=20S=C3=A1nchez?= Date: Wed, 25 Nov 2015 22:40:35 +0100 Subject: [PATCH 12/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f0f3466..2c77b42d 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ Dexter.checkPermissions(new CompositePermissionListener(snackbarMultiplePermissi @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sample_activity); - Dexter.checkPendingPermissions(); + Dexter.checkPendingPermissions(permissionsListener); } ``` From d105db9d582f2ecf7ded1bcedcd19a8f65e9aa7f Mon Sep 17 00:00:00 2001 From: Pedro Vicente Gomez Date: Mon, 30 Nov 2015 08:56:25 +0100 Subject: [PATCH 13/14] Replace dexter listener with an empty implementation to avoid memory leaks --- dexter/src/main/java/com/karumi/dexter/DexterInstance.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java index bb24b98a..298bdf30 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java @@ -23,6 +23,7 @@ import com.karumi.dexter.listener.PermissionDeniedResponse; import com.karumi.dexter.listener.PermissionGrantedResponse; import com.karumi.dexter.listener.PermissionRequest; +import com.karumi.dexter.listener.multi.EmptyMultiplePermissionsListener; import com.karumi.dexter.listener.multi.MultiplePermissionsListener; import com.karumi.dexter.listener.single.PermissionListener; import java.util.Collection; @@ -38,6 +39,8 @@ final class DexterInstance { private static final int PERMISSIONS_REQUEST_CODE = 42; + private static final MultiplePermissionsListener EMPTY_LISTENER = + new EmptyMultiplePermissionsListener(); private final Context context; private final AndroidPermissionService androidPermissionService; @@ -47,7 +50,7 @@ final class DexterInstance { private final AtomicBoolean isRequestingPermission; private final AtomicBoolean rationaleAccepted; private Activity activity; - private MultiplePermissionsListener listener; + private MultiplePermissionsListener listener = EMPTY_LISTENER; DexterInstance(Context context, AndroidPermissionService androidPermissionService, IntentProvider intentProvider) { @@ -245,6 +248,7 @@ private void onPermissionsChecked(Collection permissions) { isRequestingPermission.set(false); rationaleAccepted.set(false); listener.onPermissionsChecked(multiplePermissionsReport); + listener = EMPTY_LISTENER; } } From 828c62e829ceadbcc95df36e7623b912b368eeba Mon Sep 17 00:00:00 2001 From: Sergio Gutierrez Date: Mon, 30 Nov 2015 11:26:41 +0100 Subject: [PATCH 14/14] Rename method to continue pending requests --- README.md | 2 +- dexter/src/main/java/com/karumi/dexter/Dexter.java | 12 +++++++----- .../main/java/com/karumi/dexter/DexterInstance.java | 11 +++++------ .../java/com/karumi/dexter/DexterInstanceTest.java | 2 +- .../com/karumi/dexter/sample/SampleActivity.java | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 2c77b42d..67b5c8f0 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ Dexter.checkPermissions(new CompositePermissionListener(snackbarMultiplePermissi @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sample_activity); - Dexter.checkPendingPermissions(permissionsListener); + Dexter.continuePendingRequestsIfPossible(permissionsListener); } ``` diff --git a/dexter/src/main/java/com/karumi/dexter/Dexter.java b/dexter/src/main/java/com/karumi/dexter/Dexter.java index 808113ee..8d7e8f58 100644 --- a/dexter/src/main/java/com/karumi/dexter/Dexter.java +++ b/dexter/src/main/java/com/karumi/dexter/Dexter.java @@ -92,10 +92,12 @@ public static boolean isRequestOngoing() { } /** - * Method called whenever the DexterActivity has been created and is ready to be used + * Requests pending permissions if there were permissions lost. This method can be used to + * recover the Dexter state during a configuration change, for example when the device is + * rotated. */ - public static void checkPendingPermissions(MultiplePermissionsListener listener) { - instance.checkPendingPermissions(listener); + public static void continuePendingRequestsIfPossible(MultiplePermissionsListener listener) { + instance.continuePendingRequestsIfPossible(listener); } /** @@ -103,8 +105,8 @@ public static void checkPendingPermissions(MultiplePermissionsListener listener) * recover the Dexter state during a configuration change, for example when the device is * rotated. */ - public static void checkPendingPermission(PermissionListener listener) { - instance.checkPendingPermission(listener); + public static void continuePendingRequestIfPossible(PermissionListener listener) { + instance.continuePendingRequestIfPossible(listener); } /** diff --git a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java index 298bdf30..d3b2881b 100644 --- a/dexter/src/main/java/com/karumi/dexter/DexterInstance.java +++ b/dexter/src/main/java/com/karumi/dexter/DexterInstance.java @@ -98,21 +98,20 @@ void checkPermissions(MultiplePermissionsListener listener, Collection p * Check if there is a permission pending to be confirmed by the user and restarts the * request for permission process. */ - void checkPendingPermission(PermissionListener listener) { + void continuePendingRequestIfPossible(PermissionListener listener) { MultiplePermissionsListenerToPermissionListenerAdapter adapter = new MultiplePermissionsListenerToPermissionListenerAdapter(listener); - checkPendingPermissions(adapter); + continuePendingRequestsIfPossible(adapter); } /** * Check if there are some permissions pending to be confirmed by the user and restarts the * request for permission process. */ - void checkPendingPermissions(MultiplePermissionsListener listener) { - boolean shouldContinueRequestingPendingPermissions = - !pendingPermissions.isEmpty() && !rationaleAccepted.get(); + void continuePendingRequestsIfPossible(MultiplePermissionsListener listener) { + boolean isShowingRationale = !pendingPermissions.isEmpty() && !rationaleAccepted.get(); this.listener = listener; - if (shouldContinueRequestingPendingPermissions) { + if (isShowingRationale) { onActivityReady(activity); } } diff --git a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java index 501d79d8..c1025e6f 100644 --- a/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java +++ b/dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java @@ -144,7 +144,7 @@ private void whenCheckPermission(PermissionListener permissionListener, String p } private void whenContinueWithTheCheckPermissionProcess(PermissionListener permissionListener) { - dexter.checkPendingPermission(permissionListener); + dexter.continuePendingRequestIfPossible(permissionListener); } private void thenPermissionIsGranted(String permission) { diff --git a/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java b/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java index 0b751a2b..42220ff4 100644 --- a/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java +++ b/sample/src/main/java/com/karumi/dexter/sample/SampleActivity.java @@ -64,7 +64,7 @@ public class SampleActivity extends Activity { * to start with the check permission process without keep in an Android Bundle the state of * the request permission process. */ - Dexter.checkPendingPermissions(allPermissionsListener); + Dexter.continuePendingRequestsIfPossible(allPermissionsListener); } @OnClick(R.id.all_permissions_button) public void onAllPermissionsButtonClicked() {