Skip to content
This repository has been archived by the owner on Jul 2, 2021. It is now read-only.

Commit

Permalink
Merge pull request #17 from Karumi/add-rotate-screen-support
Browse files Browse the repository at this point in the history
Add rotate screen support. #14 and #15
  • Loading branch information
Serchinastico committed Nov 30, 2015
2 parents adcd407 + 828c62e commit 6041d1a
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 14 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ Dexter.checkPermissions(new CompositePermissionListener(snackbarMultiplePermissi

**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) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_activity);
Dexter.continuePendingRequestsIfPossible(permissionsListener);
}
```

Add it to your project
----------------------

Expand Down
1 change: 1 addition & 0 deletions dexter/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<activity
android:name=".DexterActivity"
android:theme="@style/Theme.Transparent"
android:launchMode="singleTask"
/>
</application>

Expand Down
25 changes: 22 additions & 3 deletions dexter/src/main/java/com/karumi/dexter/Dexter.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,29 @@ 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.
*/
static void onActivityCreated(Activity activity) {
instance.onActivityCreated(activity);
public static void continuePendingRequestsIfPossible(MultiplePermissionsListener listener) {
instance.continuePendingRequestsIfPossible(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 continuePendingRequestIfPossible(PermissionListener listener) {
instance.continuePendingRequestIfPossible(listener);
}

/**
* Method called whenever the DexterActivity has been created or recreated and is ready to be
* used.
*/
static void onActivityReady(Activity activity) {
instance.onActivityReady(activity);
}

/**
Expand Down
8 changes: 7 additions & 1 deletion dexter/src/main/java/com/karumi/dexter/DexterActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String> grantedPermissions = new LinkedList<>();
Expand Down
45 changes: 38 additions & 7 deletions dexter/src/main/java/com/karumi/dexter/DexterInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -38,15 +39,18 @@
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;
private final IntentProvider intentProvider;
private final Collection<String> pendingPermissions;
private final MultiplePermissionsReport multiplePermissionsReport;
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) {
Expand All @@ -56,6 +60,7 @@ final class DexterInstance {
this.pendingPermissions = new TreeSet<>();
this.multiplePermissionsReport = new MultiplePermissionsReport();
this.isRequestingPermission = new AtomicBoolean();
this.rationaleAccepted = new AtomicBoolean();
}

/**
Expand Down Expand Up @@ -86,15 +91,37 @@ void checkPermissions(MultiplePermissionsListener listener, Collection<String> p
multiplePermissionsReport.clear();
this.listener = listener;

startTransparentActivity();
startTransparentActivityIfNeeded();
}

/**
* Method called whenever the inner activity has been created and is ready to be used
* Check if there is a permission pending to be confirmed by the user and restarts the
* request for permission process.
*/
void onActivityCreated(Activity activity) {
this.activity = activity;
void continuePendingRequestIfPossible(PermissionListener listener) {
MultiplePermissionsListenerToPermissionListenerAdapter adapter =
new MultiplePermissionsListenerToPermissionListenerAdapter(listener);
continuePendingRequestsIfPossible(adapter);
}

/**
* Check if there are some permissions pending to be confirmed by the user and restarts the
* request for permission process.
*/
void continuePendingRequestsIfPossible(MultiplePermissionsListener listener) {
boolean isShowingRationale = !pendingPermissions.isEmpty() && !rationaleAccepted.get();
this.listener = listener;
if (isShowingRationale) {
onActivityReady(activity);
}
}

/**
* Method called whenever the inner activity has been created or restarted and is ready to be
* used.
*/
void onActivityReady(Activity activity) {
this.activity = activity;
Collection<String> deniedRequests = new LinkedList<>();
Collection<String> grantedRequests = new LinkedList<>();

Expand Down Expand Up @@ -134,6 +161,7 @@ void onPermissionRequestDenied(Collection<String> permissions) {
* with the permission request process
*/
void onContinuePermissionRequest() {
rationaleAccepted.set(true);
requestPermissionsToSystem(pendingPermissions);
}

Expand All @@ -142,6 +170,7 @@ void onContinuePermissionRequest() {
* the permission request process
*/
void onCancelPermissionRequest() {
rationaleAccepted.set(false);
updatePermissionsAsDenied(pendingPermissions);
}

Expand All @@ -162,7 +191,7 @@ void requestPermissionsToSystem(Collection<String> permissions) {
permissions.toArray(new String[permissions.size()]), PERMISSIONS_REQUEST_CODE);
}

private void startTransparentActivity() {
private void startTransparentActivityIfNeeded() {
Intent intent = intentProvider.get(context, DexterActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Expand All @@ -183,7 +212,7 @@ private void handleDeniedPermissions(Collection<String> permissions) {

if (shouldShowRequestRationalePermissions.isEmpty()) {
requestPermissionsToSystem(permissions);
} else {
} else if (!rationaleAccepted.get()) {
PermissionRationaleToken permissionToken = new PermissionRationaleToken(this);
listener.onPermissionRationaleShouldBeShown(shouldShowRequestRationalePermissions,
permissionToken);
Expand Down Expand Up @@ -216,7 +245,9 @@ private void onPermissionsChecked(Collection<String> permissions) {
if (pendingPermissions.isEmpty()) {
activity.finish();
isRequestingPermission.set(false);
rationaleAccepted.set(false);
listener.onPermissionsChecked(multiplePermissionsReport);
listener = EMPTY_LISTENER;
}
}

Expand Down
22 changes: 21 additions & 1 deletion dexter/src/test/java/com/karumi/dexter/DexterInstanceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(permissionListener);

thenPermissionRationaleIsShown(2);
}

private void givenPermissionIsAlreadyDenied(String permission) {
givenPermissionIsChecked(permission, PackageManager.PERMISSION_DENIED);
}
Expand All @@ -129,7 +140,11 @@ 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(PermissionListener permissionListener) {
dexter.continuePendingRequestIfPossible(permissionListener);
}

private void thenPermissionIsGranted(String permission) {
Expand All @@ -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<PermissionGrantedResponse> getPermissionGrantedResponseMatcher(
final String permission) {
return new ArgumentMatcher<PermissionGrantedResponse>() {
Expand Down
2 changes: 0 additions & 2 deletions sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@

<activity
android:name=".SampleActivity"
android:configChanges="orientation"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.continuePendingRequestsIfPossible(allPermissionsListener);
}

@OnClick(R.id.all_permissions_button) public void onAllPermissionsButtonClicked() {
Expand Down

0 comments on commit 6041d1a

Please sign in to comment.