diff --git a/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java index b0a72eae1..5fb444192 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java @@ -1,6 +1,7 @@ package fr.free.nrw.commons.utils; import android.Manifest; +import android.Manifest.permission; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; @@ -20,24 +21,23 @@ import fr.free.nrw.commons.R; import fr.free.nrw.commons.upload.UploadActivity; import java.util.List; - public class PermissionUtils { + public static String[] PERMISSIONS_STORAGE = getPermissionsStorage(); - public static String[] PERMISSIONS_STORAGE = isSDKVersionScopedStorageCompatible() ? - isSDKVersionTiramisu() ? new String[]{ - Manifest.permission.READ_MEDIA_IMAGES} : - new String[]{Manifest.permission.READ_EXTERNAL_STORAGE} - : isSDKVersionTiramisu() ? new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_MEDIA_IMAGES} - : new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; - - private static boolean isSDKVersionScopedStorageCompatible() { - return Build.VERSION.SDK_INT > Build.VERSION_CODES.P; - } - - public static boolean isSDKVersionTiramisu() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU; + static String[] getPermissionsStorage() { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + return new String[]{ Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED, + Manifest.permission.READ_MEDIA_IMAGES }; + } + if(Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU) { + return new String[]{ Manifest.permission.READ_MEDIA_IMAGES }; + } + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE }; + } + return new String[]{ + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE }; } /** @@ -45,11 +45,11 @@ public class PermissionUtils { * blocked(marked never ask again by the user) It open the app settings from where the user can * manually give us the required permission. * - * @param activity + * @param activity The Activity which requires a permission which has been blocked */ - private static void askUserToManuallyEnablePermissionFromSettings(Activity activity) { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - Uri uri = Uri.fromParts("package", activity.getPackageName(), null); + private static void askUserToManuallyEnablePermissionFromSettings(final Activity activity) { + final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + final Uri uri = Uri.fromParts("package", activity.getPackageName(), null); intent.setData(uri); activity.startActivityForResult(intent, CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS); @@ -58,14 +58,13 @@ public class PermissionUtils { /** * Checks whether the app already has a particular permission * - * @param activity - * @param permissions permissions to be checked - * @return + * @param activity The Activity context to check permissions against + * @param permissions An array of permission strings to check + * @return `true if the app has all the specified permissions, `false` otherwise */ - public static boolean hasPermission(Activity activity, String permissions[]) { + public static boolean hasPermission(final Activity activity, final String[] permissions) { boolean hasPermission = true; - for (String permission : permissions - ) { + for(final String permission : permissions) { hasPermission = hasPermission && ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED; @@ -73,6 +72,15 @@ public class PermissionUtils { return hasPermission; } + public static boolean hasPartialAccess(final Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + return ContextCompat.checkSelfPermission(activity, + permission.READ_MEDIA_VISUAL_USER_SELECTED + ) == PackageManager.PERMISSION_GRANTED; + } + return false; + } + /** * Checks for a particular permission and runs the runnable to perform an action when the * permission is granted Also, it shows a rationale if needed @@ -99,9 +107,17 @@ public class PermissionUtils { * @param rationaleMessage rationale message to be displayed when permission was denied. It * can be an invalid @StringRes */ - public static void checkPermissionsAndPerformAction(Activity activity, - Runnable onPermissionGranted, @StringRes int rationaleTitle, - @StringRes int rationaleMessage, String... permissions) { + public static void checkPermissionsAndPerformAction( + final Activity activity, + final Runnable onPermissionGranted, + final @StringRes int rationaleTitle, + final @StringRes int rationaleMessage, + final String... permissions + ) { + if (hasPartialAccess(activity)) { + onPermissionGranted.run(); + return; + } checkPermissionsAndPerformAction(activity, onPermissionGranted, null, rationaleTitle, rationaleMessage, permissions); } @@ -125,25 +141,30 @@ public class PermissionUtils { * @param rationaleTitle rationale title to be displayed when permission was denied * @param rationaleMessage rationale message to be displayed when permission was denied */ - public static void checkPermissionsAndPerformAction(Activity activity, - Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle, - @StringRes int rationaleMessage, String... permissions) { + public static void checkPermissionsAndPerformAction( + final Activity activity, + final Runnable onPermissionGranted, + final Runnable onPermissionDenied, + final @StringRes int rationaleTitle, + final @StringRes int rationaleMessage, + final String... permissions + ) { Dexter.withActivity(activity) .withPermissions(permissions) .withListener(new MultiplePermissionsListener() { @Override - public void onPermissionsChecked(MultiplePermissionsReport report) { - if (report.areAllPermissionsGranted()) { + public void onPermissionsChecked(final MultiplePermissionsReport report) { + if (report.areAllPermissionsGranted() || hasPartialAccess(activity)) { onPermissionGranted.run(); return; } if (report.isAnyPermissionPermanentlyDenied()) { // permission is denied permanently, we will show user a dialog message. - DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle), + DialogUtil.showAlertDialog( + activity, activity.getString(rationaleTitle), activity.getString(rationaleMessage), activity.getString(R.string.navigation_item_settings), - null, - () -> { + null, () -> { askUserToManuallyEnablePermissionFromSettings(activity); if (activity instanceof UploadActivity) { ((UploadActivity) activity).setShowPermissionsDialog(true); @@ -158,13 +179,16 @@ public class PermissionUtils { } @Override - public void onPermissionRationaleShouldBeShown(List permissions, - PermissionToken token) { + public void onPermissionRationaleShouldBeShown( + final List permissions, + final PermissionToken token + ) { if (rationaleTitle == -1 && rationaleMessage == -1) { token.continuePermissionRequest(); return; } - DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle), + DialogUtil.showAlertDialog( + activity, activity.getString(rationaleTitle), activity.getString(rationaleMessage), activity.getString(android.R.string.ok), activity.getString(android.R.string.cancel), @@ -173,24 +197,19 @@ public class PermissionUtils { ((UploadActivity) activity).setShowPermissionsDialog(true); } token.continuePermissionRequest(); - } - , + }, () -> { Toast.makeText(activity.getApplicationContext(), - R.string.permissions_are_required_for_functionality, - Toast.LENGTH_LONG) - .show(); + R.string.permissions_are_required_for_functionality, + Toast.LENGTH_LONG + ).show(); token.cancelPermissionRequest(); if (activity instanceof UploadActivity) { activity.finish(); } - } - , - null, - false); + }, null, false + ); } - }) - .onSameThread() - .check(); + }).onSameThread().check(); } }