diff --git a/app/src/main/java/pub/devrel/easypermissions/sample/MainActivity.java b/app/src/main/java/pub/devrel/easypermissions/sample/MainActivity.java index e9e0e02..9a76aab 100644 --- a/app/src/main/java/pub/devrel/easypermissions/sample/MainActivity.java +++ b/app/src/main/java/pub/devrel/easypermissions/sample/MainActivity.java @@ -30,8 +30,7 @@ import pub.devrel.easypermissions.AppSettingsDialog; import pub.devrel.easypermissions.EasyPermissions; -public class MainActivity extends AppCompatActivity implements - EasyPermissions.PermissionCallbacks { +public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { private static final String TAG = "MainActivity"; diff --git a/app/src/main/java/pub/devrel/easypermissions/sample/MainFragment.java b/app/src/main/java/pub/devrel/easypermissions/sample/MainFragment.java index 0b5379c..2f33300 100644 --- a/app/src/main/java/pub/devrel/easypermissions/sample/MainFragment.java +++ b/app/src/main/java/pub/devrel/easypermissions/sample/MainFragment.java @@ -15,11 +15,13 @@ import pub.devrel.easypermissions.AfterPermissionGranted; import pub.devrel.easypermissions.EasyPermissions; +/** + * Created in {@link R.layout#activity_main} + */ public class MainFragment extends Fragment implements EasyPermissions.PermissionCallbacks { private static final String TAG = "MainFragment"; private static final int RC_SMS_PERM = 122; - private static final int RC_SETTINGS = 123; @Override public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java b/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java index b550f81..db31bb0 100644 --- a/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java +++ b/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java @@ -1,15 +1,16 @@ package pub.devrel.easypermissions; -import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; import android.support.v4.app.Fragment; import android.text.TextUtils; @@ -65,6 +66,7 @@ public void onClick(DialogInterface dialog, int which) { intent.setData(uri); // Start for result + //noinspection NewApi The Builder constructor prevents this startForResult(activityOrFragment, intent, settingsRequestCode); } }); @@ -76,7 +78,7 @@ public void onClick(DialogInterface dialog, int which) { mAlertDialog = dialogBuilder.create(); } - @TargetApi(11) + @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) private void startForResult(Object object, Intent intent, int requestCode) { if (object instanceof Activity) { ((Activity) object).startActivityForResult(intent, requestCode); @@ -135,7 +137,7 @@ public Builder(@NonNull android.support.v4.app.Fragment fragment, @NonNull Strin * @param fragment the Fragment in which to display the dialog. * @param rationale text explaining why the user should launch the app settings screen. */ - @TargetApi(11) + @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) public Builder(@NonNull android.app.Fragment fragment, @NonNull String rationale) { mActivityOrFragment = fragment; mContext = fragment.getActivity(); diff --git a/easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java b/easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java index 56327fc..7a3671f 100644 --- a/easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java +++ b/easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java @@ -15,28 +15,23 @@ */ package pub.devrel.easypermissions; -import android.annotation.SuppressLint; -import android.annotation.TargetApi; +import android.Manifest; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.pm.PackageManager; import android.os.Build; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.support.annotation.StringRes; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.content.ContextCompat; -import android.support.v7.app.AlertDialog; import android.util.Log; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -44,12 +39,7 @@ */ public class EasyPermissions { - private static final String TAG = "EasyPermissions"; - private static final String DIALOG_TAG = "RationaleDialogFragmentCompat"; - - - public interface PermissionCallbacks extends - ActivityCompat.OnRequestPermissionsResultCallback { + public interface PermissionCallbacks extends ActivityCompat.OnRequestPermissionsResultCallback { void onPermissionsGranted(int requestCode, List perms); @@ -57,19 +47,24 @@ public interface PermissionCallbacks extends } + private static final String TAG = "EasyPermissions"; + private static final String DIALOG_TAG = "RationaleDialogFragmentCompat"; + /** * Check if the calling context has a set of permissions. * - * @param context - * the calling context. - * @param perms - * one ore more permissions, such as {@code android.Manifest.permission.CAMERA}. - * @return true if all permissions are already granted, false if at least one permission is not yet granted. + * @param context the calling context. + * @param perms one ore more permissions, such as {@link Manifest.permission#CAMERA}. + * @return true if all permissions are already granted, false if at least one permission is not + * yet granted. + * @see Manifest.permission */ public static boolean hasPermissions(@NonNull Context context, @NonNull String... perms) { // Always return true for SDK < M, let the system deal with the permissions if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { Log.w(TAG, "hasPermissions: API version < M, returning true by default"); + + // DANGER ZONE!!! Changing this will break the library. return true; } @@ -85,205 +80,183 @@ public static boolean hasPermissions(@NonNull Context context, @NonNull String.. } /** - * Request a set of permissions, showing rationale if the system requests it. + * Request a set of permissions, showing a rationale if the system requests it. * - * @param object - * Activity or Fragment requesting permissions. Should implement - * {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback} - * or {@code android.support.v13.app.FragmentCompat.OnRequestPermissionsResultCallback} - * @param rationale - * a message explaining why the application needs this set of permissions, will be displayed if the user rejects the request the first - * time. - * @param requestCode - * request code to track this request, must be < 256. - * @param perms - * a set of permissions to be requested. + * @see #requestPermissions(Activity, String, int, int, int, String...) */ - public static void requestPermissions(@NonNull final Object object, @NonNull String rationale, - final int requestCode, @NonNull final String... perms) { - requestPermissions(object, rationale, + public static void requestPermissions(@NonNull Activity activity, + @NonNull String rationale, + int requestCode, + @NonNull String... perms) { + requestPermissions( + activity, + rationale, android.R.string.ok, android.R.string.cancel, - requestCode, perms); + requestCode, + perms); } /** * Request a set of permissions, showing rationale if the system requests it. * - * @param object - * Activity or Fragment requesting permissions. Should implement - * {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback} - * or {@code android.support.v13.app.FragmentCompat.OnRequestPermissionsResultCallback} - * @param rationale - * a message explaining why the application needs this set of permissions, will be displayed if the user rejects the request the first - * time. - * @param positiveButton - * custom text for positive button - * @param negativeButton - * custom text for negative button - * @param requestCode - * request code to track this request, must be < 256. - * @param perms - * a set of permissions to be requested. + * @param activity {@link Activity} requesting permissions. Should implement {@link + * ActivityCompat.OnRequestPermissionsResultCallback} or override {@link + * FragmentActivity#onRequestPermissionsResult(int, String[], int[])} if + * it extends from {@link FragmentActivity}. + * @param rationale a message explaining why the application needs this set of permissions, + * will be displayed if the user rejects the request the first time. + * @param positiveButton custom text for positive button + * @param negativeButton custom text for negative button + * @param requestCode request code to track this request, must be < 256. + * @param perms a set of permissions to be requested. + * @see Manifest.permission */ - @SuppressLint("NewApi") - public static void requestPermissions(@NonNull final Object object, @NonNull String rationale, - @StringRes int positiveButton, @StringRes int negativeButton, - final int requestCode, @NonNull final String... perms) { - - checkCallingObjectSuitability(object); - - // Determine if rationale should be shown (generally when the user has previously - // denied the request); - boolean shouldShowRationale = false; - for (String perm : perms) { - shouldShowRationale = - shouldShowRationale || shouldShowRequestPermissionRationale(object, perm); + @SuppressWarnings("NewApi") + public static void requestPermissions(@NonNull Activity activity, + @NonNull String rationale, + @StringRes int positiveButton, + @StringRes int negativeButton, + int requestCode, + @NonNull String... perms) { + if (hasPermissions(activity, perms)) { + notifyAlreadyHasPermissions(activity, requestCode, perms); + return; } - if (shouldShowRationale) { - // If we can get a FragmentManager, show a RationaleDialogFragmentCompat. Otherwise, show - // an AlertDialog. The Fragment has the advantage of surviving rotations. - if (getSupportFragmentManager(object) != null) { - // Show AppCompatDialogFragment - showRationaleDialogFragmentCompat(getSupportFragmentManager(object), - rationale, positiveButton, negativeButton, requestCode, perms); - } else if (getFragmentManager(object) != null) { - // Show DialogFragment - showRationaleDialogFragment(getFragmentManager(object), - rationale, positiveButton, negativeButton, requestCode, perms); - } else { - // Revert to AlertDialog - showRationaleAlertDialog(object, rationale, positiveButton, negativeButton, - requestCode, perms); - } + if (shouldShowRationale(activity, perms)) { + showRationaleDialogFragment( + activity.getFragmentManager(), + rationale, + positiveButton, + negativeButton, + requestCode, + perms); } else { - executePermissionsRequest(object, perms, requestCode); + ActivityCompat.requestPermissions(activity, perms, requestCode); } } /** - * Show a {@link RationaleDialogFragmentCompat} explaining permission request rationale. - */ - @RequiresApi(Build.VERSION_CODES.HONEYCOMB) - private static void showRationaleDialogFragmentCompat( - @NonNull final android.support.v4.app.FragmentManager fragmentManager, - @NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, - final int requestCode, @NonNull final String... perms) { - - RationaleDialogFragmentCompat fragment = RationaleDialogFragmentCompat - .newInstance(positiveButton, negativeButton, rationale, requestCode, perms); - fragment.show(fragmentManager, DIALOG_TAG); - } - - /** - * Show a {@link RationaleDialogFragment} explaining permission request rationale. + * Request a set of permissions, showing rationale if the system requests it. + * + * @see #requestPermissions(Fragment, String, int, int, int, String...) */ - @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) - private static void showRationaleDialogFragment( - @NonNull final android.app.FragmentManager fragmentManager, - @NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, - final int requestCode, @NonNull final String... perms) { - - RationaleDialogFragment fragment = RationaleDialogFragment - .newInstance(positiveButton, negativeButton, rationale, requestCode, perms); - fragment.show(fragmentManager, DIALOG_TAG); + public static void requestPermissions(@NonNull Fragment fragment, + @NonNull String rationale, + int requestCode, + @NonNull String... perms) { + requestPermissions( + fragment, + rationale, + android.R.string.ok, + android.R.string.cancel, + requestCode, + perms); } /** - * Show an {@link AlertDialog} explaining permission request rationale. + * Request a set of permissions, showing rationale if the system requests it. + * + * @param fragment {@link Fragment} requesting permissions. Should override {@link + * Fragment#onRequestPermissionsResult(int, String[], int[])}. + * @see #requestPermissions(Activity, String, int, int, int, String...) */ - private static void showRationaleAlertDialog( - @NonNull final Object object, @NonNull String rationale, - @StringRes int positiveButton, @StringRes int negativeButton, - final int requestCode, @NonNull final String... perms) { - - Activity activity = getActivity(object); - if (activity == null) { - throw new IllegalStateException("Can't show rationale dialog for null Activity"); + @SuppressWarnings("NewApi") + public static void requestPermissions(@NonNull Fragment fragment, + @NonNull String rationale, + @StringRes int positiveButton, + @StringRes int negativeButton, + int requestCode, + @NonNull String... perms) { + if (hasPermissions(fragment.getContext(), perms)) { + notifyAlreadyHasPermissions(fragment, requestCode, perms); + return; } - new AlertDialog.Builder(activity) - .setCancelable(false) - .setMessage(rationale) - .setPositiveButton(positiveButton, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - executePermissionsRequest(object, perms, requestCode); - } - }) - .setNegativeButton(negativeButton, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // act as if the permissions were denied - if (object instanceof PermissionCallbacks) { - ((PermissionCallbacks) object).onPermissionsDenied(requestCode, Arrays.asList(perms)); - } - } - }) - .create() - .show(); + if (shouldShowRationale(fragment, perms)) { + RationaleDialogFragmentCompat + .newInstance(positiveButton, negativeButton, rationale, requestCode, perms) + .show(fragment.getChildFragmentManager(), DIALOG_TAG); + } else { + fragment.requestPermissions(perms, requestCode); + } } /** - * Check if at least one permission in the list of denied permissions has been permanently denied (user clicked "Never ask again"). + * Request a set of permissions, showing rationale if the system requests it. * - * @param object - * Activity or Fragment requesting permissions. - * @param deniedPermissions - * list of denied permissions, usually from {@link PermissionCallbacks#onPermissionsDenied(int, List)} - * @return {@code true} if at least one permission in the list was permanently denied. + * @see #requestPermissions(android.app.Fragment, String, int, int, int, String...) */ - public static boolean somePermissionPermanentlyDenied(@NonNull Object object, - @NonNull List deniedPermissions) { - for (String deniedPermission : deniedPermissions) { - if (permissionPermanentlyDenied(object, deniedPermission)) { - return true; - } - } - - return false; + @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) + public static void requestPermissions(@NonNull android.app.Fragment fragment, + @NonNull String rationale, + int requestCode, + @NonNull String... perms) { + requestPermissions( + fragment, + rationale, + android.R.string.ok, + android.R.string.cancel, + requestCode, + perms); } - /** - * Check if a permission has been permanently denied (user clicked "Never ask again"). + * Request a set of permissions, showing rationale if the system requests it. * - * @param object - * Activity or Fragment requesting permissions. - * @param deniedPermission - * denied permission. - * @return {@code true} if the permissions has been permanently denied. + * @param fragment {@link android.app.Fragment} requesting permissions. Should override {@link + * android.app.Fragment#onRequestPermissionsResult(int, String[], int[])}. + * @see #requestPermissions(Activity, String, int, int, int, String...) */ - public static boolean permissionPermanentlyDenied(@NonNull Object object, - @NonNull String deniedPermission) { - return !shouldShowRequestPermissionRationale(object, deniedPermission); - } + @SuppressWarnings("NewApi") + @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) + public static void requestPermissions(@NonNull android.app.Fragment fragment, + @NonNull String rationale, + @StringRes int positiveButton, + @StringRes int negativeButton, + int requestCode, + @NonNull String... perms) { + if (hasPermissions(fragment.getActivity(), perms)) { + notifyAlreadyHasPermissions(fragment, requestCode, perms); + return; + } + if (shouldShowRationale(fragment, perms)) { + showRationaleDialogFragment( + fragment.getChildFragmentManager(), + rationale, + positiveButton, + negativeButton, + requestCode, + perms); + } else { + fragment.requestPermissions(perms, requestCode); + } + } /** - * Handle the result of a permission request, should be called from the calling Activity's {@link android.support.v4.app.ActivityCompat - * .OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])} method. + * Handle the result of a permission request, should be called from the calling {@link + * Activity}'s {@link ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, + * String[], int[])} method. *

- * If any permissions were granted or denied, the {@code object} will receive the appropriate callbacks through {@link PermissionCallbacks} and - * methods annotated with {@link AfterPermissionGranted} will be run if appropriate. + * If any permissions were granted or denied, the {@code object} will receive the appropriate + * callbacks through {@link PermissionCallbacks} and methods annotated with {@link + * AfterPermissionGranted} will be run if appropriate. * - * @param requestCode - * requestCode argument to permission result callback. - * @param permissions - * permissions argument to permission result callback. - * @param grantResults - * grantResults argument to permission result callback. - * @param receivers - * an array of objects that have a method annotated with {@link AfterPermissionGranted} or implement {@link PermissionCallbacks}. + * @param requestCode requestCode argument to permission result callback. + * @param permissions permissions argument to permission result callback. + * @param grantResults grantResults argument to permission result callback. + * @param receivers an array of objects that have a method annotated with {@link + * AfterPermissionGranted} or implement {@link PermissionCallbacks}. */ - public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + public static void onRequestPermissionsResult(int requestCode, + @NonNull String[] permissions, @NonNull int[] grantResults, @NonNull Object... receivers) { - // Make a collection of granted and denied permissions from the request. - ArrayList granted = new ArrayList<>(); - ArrayList denied = new ArrayList<>(); + List granted = new ArrayList<>(); + List denied = new ArrayList<>(); for (int i = 0; i < permissions.length; i++) { String perm = permissions[i]; if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { @@ -314,85 +287,152 @@ public static void onRequestPermissionsResult(int requestCode, @NonNull String[] runAnnotatedMethods(object, requestCode); } } - } - @TargetApi(23) - private static boolean shouldShowRequestPermissionRationale(@NonNull Object object, - @NonNull String perm) { - if (object instanceof Activity) { - return ActivityCompat.shouldShowRequestPermissionRationale((Activity) object, perm); - } else if (object instanceof Fragment) { - return ((Fragment) object).shouldShowRequestPermissionRationale(perm); - } else if (object instanceof android.app.Fragment) { - return ((android.app.Fragment) object).shouldShowRequestPermissionRationale(perm); - } else { - return false; + /** + * Check if at least one permission in the list of denied permissions has been permanently + * denied (user clicked "Never ask again"). + * + * @param activity {@link Activity} requesting permissions. + * @param deniedPermissions list of denied permissions, usually from {@link + * PermissionCallbacks#onPermissionsDenied(int, List)} + * @return {@code true} if at least one permission in the list was permanently denied. + */ + public static boolean somePermissionPermanentlyDenied(@NonNull Activity activity, + @NonNull List deniedPermissions) { + for (String deniedPermission : deniedPermissions) { + if (permissionPermanentlyDenied(activity, deniedPermission)) { + return true; + } } + + return false; } - @TargetApi(23) - static void executePermissionsRequest(@NonNull Object object, @NonNull String[] perms, int requestCode) { - checkCallingObjectSuitability(object); - if (object instanceof android.app.Activity) { - ActivityCompat.requestPermissions((Activity) object, perms, requestCode); - } else if (object instanceof android.support.v4.app.Fragment) { - ((android.support.v4.app.Fragment) object).requestPermissions(perms, requestCode); - } else if (object instanceof android.app.Fragment) { - ((android.app.Fragment) object).requestPermissions(perms, requestCode); + /** + * Check if at least one permission in the list of denied permissions has been permanently + * denied (user clicked "Never ask again"). + * + * @see #somePermissionPermanentlyDenied(Activity, List) + */ + public static boolean somePermissionPermanentlyDenied(@NonNull Fragment fragment, + @NonNull List deniedPermissions) { + for (String deniedPermission : deniedPermissions) { + if (permissionPermanentlyDenied(fragment, deniedPermission)) { + return true; + } } + + return false; } - @TargetApi(11) - private static Activity getActivity(@NonNull Object object) { - if (object instanceof Activity) { - return ((Activity) object); - } else if (object instanceof android.support.v4.app.Fragment) { - return ((android.support.v4.app.Fragment) object).getActivity(); - } else if (object instanceof android.app.Fragment) { - return ((android.app.Fragment) object).getActivity(); - } else { - return null; + /** + * Check if at least one permission in the list of denied permissions has been permanently + * denied (user clicked "Never ask again"). + * + * @see #somePermissionPermanentlyDenied(Activity, List) + */ + @RequiresApi(api = Build.VERSION_CODES.M) + public static boolean somePermissionPermanentlyDenied(@NonNull android.app.Fragment fragment, + @NonNull List deniedPermissions) { + for (String deniedPermission : deniedPermissions) { + if (permissionPermanentlyDenied(fragment, deniedPermission)) { + return true; + } } + + return false; + } + + /** + * Check if a permission has been permanently denied (user clicked "Never ask again"). + * + * @param activity {@link Activity} requesting permissions. + * @param deniedPermission denied permission. + * @return {@code true} if the permissions has been permanently denied. + */ + public static boolean permissionPermanentlyDenied(@NonNull Activity activity, + @NonNull String deniedPermission) { + return !shouldShowRequestPermissionRationale(activity, deniedPermission); } - @Nullable - @SuppressLint("NewApi") - private static android.support.v4.app.FragmentManager getSupportFragmentManager( - @NonNull Object object) { - - if (object instanceof android.support.v4.app.FragmentActivity) { - // Support library FragmentActivity - return ((FragmentActivity) object).getSupportFragmentManager(); - } else if (object instanceof android.support.v4.app.Fragment) { - // Support library Fragment - return ((Fragment) object).getChildFragmentManager(); + /** + * Check if a permission has been permanently denied (user clicked "Never ask again"). + * + * @see #permissionPermanentlyDenied(Activity, String) + */ + public static boolean permissionPermanentlyDenied(@NonNull Fragment fragment, + @NonNull String deniedPermission) { + return !shouldShowRequestPermissionRationale(fragment, deniedPermission); + } + + /** + * Check if a permission has been permanently denied (user clicked "Never ask again"). + * + * @see #permissionPermanentlyDenied(Activity, String) + */ + @RequiresApi(api = Build.VERSION_CODES.M) + public static boolean permissionPermanentlyDenied(@NonNull android.app.Fragment fragment, + @NonNull String deniedPermission) { + return !shouldShowRequestPermissionRationale(fragment, deniedPermission); + } + + private static void notifyAlreadyHasPermissions(Object object, + int requestCode, + @NonNull String[] perms) { + int[] grantResults = new int[perms.length]; + for (int i = 0; i < perms.length; i++) { + grantResults[i] = PackageManager.PERMISSION_GRANTED; } - return null; + onRequestPermissionsResult(requestCode, perms, grantResults, object); } - @Nullable - private static android.app.FragmentManager getFragmentManager(@NonNull Object object) { + /** + * @param object Activity or Fragment + * @return true if the user has previously denied any of the {@code perms} and we should show a + * rationale, false otherwise. + */ + private static boolean shouldShowRationale(@NonNull Object object, @NonNull String[] perms) { + boolean shouldShowRationale = false; + for (String perm : perms) { + shouldShowRationale = + shouldShowRationale || shouldShowRequestPermissionRationale(object, perm); + } + return shouldShowRationale; + } + + private static boolean shouldShowRequestPermissionRationale(@NonNull Object object, + @NonNull String perm) { if (object instanceof Activity) { - // Framework Activity - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - // Above SDK 11, we can get Fragment manager - return ((Activity) object).getFragmentManager(); - } + return ActivityCompat.shouldShowRequestPermissionRationale((Activity) object, perm); + } else if (object instanceof Fragment) { + return ((Fragment) object).shouldShowRequestPermissionRationale(perm); } else if (object instanceof android.app.Fragment) { - // Framework Fragment - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - // Above SDK 17, we can get a child Fragment manager - return ((android.app.Fragment) object).getChildFragmentManager(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return ((android.app.Fragment) object).shouldShowRequestPermissionRationale(perm); } else { - // Otherwise, we just return the standard Fragment manager - return ((android.app.Fragment) object).getFragmentManager(); + throw new IllegalArgumentException( + "Target SDK needs to be greater than 23 if caller is android.app.Fragment"); } + } else { + throw new IllegalArgumentException("Object was neither an Activity nor a Fragment."); } + } - return null; - + /** + * Show a {@link RationaleDialogFragment} explaining permission request rationale. + */ + @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) + private static void showRationaleDialogFragment(@NonNull android.app.FragmentManager fragmentManager, + @NonNull String rationale, + @StringRes int positiveButton, + @StringRes int negativeButton, + int requestCode, + @NonNull String... perms) { + RationaleDialogFragment + .newInstance(positiveButton, negativeButton, rationale, requestCode, perms) + .show(fragmentManager, DIALOG_TAG); } private static void runAnnotatedMethods(@NonNull Object object, int requestCode) { @@ -400,6 +440,7 @@ private static void runAnnotatedMethods(@NonNull Object object, int requestCode) if (isUsingAndroidAnnotations(object)) { clazz = clazz.getSuperclass(); } + for (Method method : clazz.getDeclaredMethods()) { if (method.isAnnotationPresent(AfterPermissionGranted.class)) { // Check for annotated methods with matching request code. @@ -427,25 +468,6 @@ private static void runAnnotatedMethods(@NonNull Object object, int requestCode) } } - private static void checkCallingObjectSuitability(@Nullable Object object) { - if (object == null) { - throw new NullPointerException("Activity or Fragment should not be null"); - } - // Make sure Object is an Activity or Fragment - boolean isActivity = object instanceof android.app.Activity; - boolean isSupportFragment = object instanceof android.support.v4.app.Fragment; - boolean isAppFragment = object instanceof android.app.Fragment; - boolean isMinSdkM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; - if (!(isSupportFragment || isActivity || (isAppFragment && isMinSdkM))) { - if (isAppFragment) { - throw new IllegalArgumentException( - "Target SDK needs to be greater than 23 if caller is android.app.Fragment"); - } else { - throw new IllegalArgumentException("Caller must be an Activity or a Fragment."); - } - } - } - private static boolean isUsingAndroidAnnotations(@NonNull Object object) { if (!object.getClass().getSimpleName().endsWith("_")) { return false; diff --git a/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java b/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java index 15b16b2..9025faf 100644 --- a/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java +++ b/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java @@ -4,6 +4,9 @@ import android.content.DialogInterface; import android.os.Build; import android.support.annotation.RequiresApi; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; import java.util.Arrays; @@ -48,8 +51,12 @@ class RationaleDialogClickListener implements Dialog.OnClickListener { @Override public void onClick(DialogInterface dialog, int which) { if (which == Dialog.BUTTON_POSITIVE) { - EasyPermissions.executePermissionsRequest(mHost, - mConfig.permissions, mConfig.requestCode); + if (mHost instanceof Fragment) { + ((Fragment) mHost).requestPermissions(mConfig.permissions, mConfig.requestCode); + } else { // mHost instance of FragmentActivity + ActivityCompat.requestPermissions( + (FragmentActivity) mHost, mConfig.permissions, mConfig.requestCode); + } } else { notifyPermissionDenied(); } diff --git a/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java b/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java index 20bf037..0ca76d6 100644 --- a/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java +++ b/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java @@ -17,9 +17,7 @@ @RequiresApi(Build.VERSION_CODES.HONEYCOMB) public class RationaleDialogFragment extends DialogFragment { - private EasyPermissions.PermissionCallbacks permissionCallbacks; - private RationaleDialogConfig config; - private RationaleDialogClickListener clickListener; + private EasyPermissions.PermissionCallbacks mPermissionCallbacks; static RationaleDialogFragment newInstance( @StringRes int positiveButton, @StringRes int negativeButton, @@ -47,16 +45,16 @@ public void onAttach(Context context) { if (isAtLeastJellyBeanMR1 && getParentFragment() != null && getParentFragment() instanceof EasyPermissions.PermissionCallbacks) { - permissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment(); + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment(); } else if (context instanceof EasyPermissions.PermissionCallbacks) { - permissionCallbacks = (EasyPermissions.PermissionCallbacks) context; + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) context; } } @Override public void onDetach() { super.onDetach(); - permissionCallbacks = null; + mPermissionCallbacks = null; } @NonNull @@ -66,8 +64,9 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { setCancelable(false); // Get config from arguments, create click listener - config = new RationaleDialogConfig(getArguments()); - clickListener = new RationaleDialogClickListener(this, config, permissionCallbacks); + RationaleDialogConfig config = new RationaleDialogConfig(getArguments()); + RationaleDialogClickListener clickListener = + new RationaleDialogClickListener(this, config, mPermissionCallbacks); // Create an AlertDialog return config.createDialog(getActivity(), clickListener); diff --git a/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java b/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java index af665b5..5f0a82f 100644 --- a/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java +++ b/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java @@ -1,24 +1,22 @@ package pub.devrel.easypermissions; -import android.annotation.TargetApi; import android.app.Dialog; import android.content.Context; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.RequiresApi; import android.support.annotation.StringRes; import android.support.v7.app.AppCompatDialogFragment; /** - * {@link AppCompatDialogFragment} to display rationale for permission requests when the request comes from - * a Fragment or Activity that can host a Fragment. + * {@link AppCompatDialogFragment} to display rationale for permission requests when the request + * comes from a Fragment or Activity that can host a Fragment. */ -@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) +@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public class RationaleDialogFragmentCompat extends AppCompatDialogFragment { - - private EasyPermissions.PermissionCallbacks permissionCallbacks; - private RationaleDialogConfig config; - private RationaleDialogClickListener clickListener; + + private EasyPermissions.PermissionCallbacks mPermissionCallbacks; static RationaleDialogFragmentCompat newInstance( @StringRes int positiveButton, @StringRes int negativeButton, @@ -39,16 +37,16 @@ static RationaleDialogFragmentCompat newInstance( public void onAttach(Context context) { super.onAttach(context); if (getParentFragment() != null && getParentFragment() instanceof EasyPermissions.PermissionCallbacks) { - permissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment(); + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment(); } else if (context instanceof EasyPermissions.PermissionCallbacks) { - permissionCallbacks = (EasyPermissions.PermissionCallbacks) context; + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) context; } } @Override public void onDetach() { super.onDetach(); - permissionCallbacks = null; + mPermissionCallbacks = null; } @NonNull @@ -58,8 +56,9 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { setCancelable(false); // Get config from arguments, create click listener - config = new RationaleDialogConfig(getArguments()); - clickListener = new RationaleDialogClickListener(this, config, permissionCallbacks); + RationaleDialogConfig config = new RationaleDialogConfig(getArguments()); + RationaleDialogClickListener clickListener = + new RationaleDialogClickListener(this, config, mPermissionCallbacks); // Create an AlertDialog return config.createDialog(getContext(), clickListener);