Android 13 permission related fixes (#5299)

* Android 13 permission related fixes

* removes audio and video as permissions
This commit is contained in:
Srishti Rohatgi 2023-09-22 06:09:28 +05:30 committed by GitHub
parent f5770539a5
commit 6881158743
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 162 additions and 125 deletions

View file

@ -14,6 +14,8 @@
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS" /> <uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS" />
<uses-permission android:name="android.permission.SET_WALLPAPER"/> <uses-permission android:name="android.permission.SET_WALLPAPER"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

View file

@ -56,7 +56,7 @@ public class ContributionController {
} }
PermissionUtils.checkPermissionsAndPerformAction(activity, PermissionUtils.checkPermissionsAndPerformAction(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE, PermissionUtils.PERMISSIONS_STORAGE,
() -> { () -> {
if (defaultKvStore.getBoolean("inAppCameraFirstRun")) { if (defaultKvStore.getBoolean("inAppCameraFirstRun")) {
defaultKvStore.putBoolean("inAppCameraFirstRun", false); defaultKvStore.putBoolean("inAppCameraFirstRun", false);
@ -159,7 +159,7 @@ public class ContributionController {
setPickerConfiguration(activity,true); setPickerConfiguration(activity,true);
PermissionUtils.checkPermissionsAndPerformAction(activity, PermissionUtils.checkPermissionsAndPerformAction(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE, PermissionUtils.PERMISSIONS_STORAGE,
() -> FilePicker.openCustomSelector(activity, 0), () -> FilePicker.openCustomSelector(activity, 0),
R.string.storage_permission_title, R.string.storage_permission_title,
R.string.write_storage_permission_rationale); R.string.write_storage_permission_rationale);

View file

@ -439,7 +439,7 @@ public class ContributionsFragment
} }
private void checkPermissionsAndShowNearbyCardView() { private void checkPermissionsAndShowNearbyCardView() {
if (PermissionUtils.hasPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) { if (PermissionUtils.hasPermission(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) {
onLocationPermissionGranted(); onLocationPermissionGranted();
} else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) } else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
&& store.getBoolean("displayLocationPermissionForCardView", true) && store.getBoolean("displayLocationPermissionForCardView", true)
@ -452,7 +452,7 @@ public class ContributionsFragment
private void requestLocationPermission() { private void requestLocationPermission() {
PermissionUtils.checkPermissionsAndPerformAction(getActivity(), PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
this::onLocationPermissionGranted, this::onLocationPermissionGranted,
this::displayYouWontSeeNearbyMessage, this::displayYouWontSeeNearbyMessage,
-1, -1,

View file

@ -165,7 +165,7 @@ public class MainActivity extends BaseActivity
if (VERSION.SDK_INT >= VERSION_CODES.Q) { if (VERSION.SDK_INT >= VERSION_CODES.Q) {
PermissionUtils.checkPermissionsAndPerformAction( PermissionUtils.checkPermissionsAndPerformAction(
this, this,
permission.ACCESS_MEDIA_LOCATION, new String[]{permission.ACCESS_MEDIA_LOCATION},
() -> {}, () -> {},
R.string.media_location_permission_denied, R.string.media_location_permission_denied,
R.string.add_location_manually R.string.add_location_manually

View file

@ -263,7 +263,7 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
private void performMapReadyActions() { private void performMapReadyActions() {
if (isMapBoxReady) { if (isMapBoxReady) {
if(!applicationKvStore.getBoolean("doNotAskForLocationPermission", false) || if(!applicationKvStore.getBoolean("doNotAskForLocationPermission", false) ||
PermissionUtils.hasPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)){ PermissionUtils.hasPermission(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION})){
checkPermissionsAndPerformAction(); checkPermissionsAndPerformAction();
}else{ }else{
isPermissionDenied = true; isPermissionDenied = true;
@ -404,8 +404,8 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
public void checkPermissionsAndPerformAction() { public void checkPermissionsAndPerformAction() {
Timber.d("Checking permission and perfoming action"); Timber.d("Checking permission and perfoming action");
PermissionUtils.checkPermissionsAndPerformAction(getActivity(), PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
() -> locationPermissionGranted(), this::locationPermissionGranted,
() -> isPermissionDenied = true, () -> isPermissionDenied = true,
R.string.location_permission_title, R.string.location_permission_title,
R.string.location_permission_rationale_nearby); R.string.location_permission_rationale_nearby);

View file

@ -56,7 +56,7 @@ public class LocationPermissionsHelper {
Dialog locationOffDialog Dialog locationOffDialog
) { ) {
PermissionUtils.checkPermissionsAndPerformAction(activity, PermissionUtils.checkPermissionsAndPerformAction(activity,
permission.ACCESS_FINE_LOCATION, new String[]{permission.ACCESS_FINE_LOCATION},
() -> { () -> {
if(!isLocationAccessToAppsTurnedOn()) { if(!isLocationAccessToAppsTurnedOn()) {
showLocationOffDialog(locationOffDialog); showLocationOffDialog(locationOffDialog);

View file

@ -362,15 +362,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
@OnClick(R.id.mediaDetailImageViewSpacer) @OnClick(R.id.mediaDetailImageViewSpacer)
public void launchZoomActivity(final View view) { public void launchZoomActivity(final View view) {
final boolean permission = PermissionUtils. final boolean hasPermission = PermissionUtils.hasPermission(getActivity(), PermissionUtils.PERMISSIONS_STORAGE);
hasPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE); if (hasPermission) {
if (permission) {
launchZoomActivityAfterPermissionCheck(view); launchZoomActivityAfterPermissionCheck(view);
} } else {
else {
PermissionUtils.checkPermissionsAndPerformAction(getActivity(), PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
Manifest.permission.READ_EXTERNAL_STORAGE, PermissionUtils.PERMISSIONS_STORAGE,
() -> { () -> {
launchZoomActivityAfterPermissionCheck(view); launchZoomActivityAfterPermissionCheck(view);
}, },
@ -1076,7 +1073,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
} else if (requestCode == REQUEST_CODE && resultCode == RESULT_CANCELED) { } else if (requestCode == REQUEST_CODE && resultCode == RESULT_CANCELED) {
viewUtil.showShortToast(getContext(), viewUtil.showShortToast(getContext(),
Objects.requireNonNull(getContext()) requireContext()
.getString(R.string.coordinates_picking_unsuccessful)); .getString(R.string.coordinates_picking_unsuccessful));
} else if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_CANCELED) { } else if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_CANCELED) {

View file

@ -441,7 +441,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
private void performMapReadyActions() { private void performMapReadyActions() {
if (((MainActivity)getActivity()).activeFragment == ActiveFragment.NEARBY && isMapBoxReady) { if (((MainActivity)getActivity()).activeFragment == ActiveFragment.NEARBY && isMapBoxReady) {
if(!applicationKvStore.getBoolean("doNotAskForLocationPermission", false) || if(!applicationKvStore.getBoolean("doNotAskForLocationPermission", false) ||
PermissionUtils.hasPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)){ PermissionUtils.hasPermission(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION})){
checkPermissionsAndPerformAction(); checkPermissionsAndPerformAction();
}else{ }else{
isPermissionDenied = true; isPermissionDenied = true;
@ -1215,8 +1215,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
public void checkPermissionsAndPerformAction() { public void checkPermissionsAndPerformAction() {
Timber.d("Checking permission and perfoming action"); Timber.d("Checking permission and perfoming action");
PermissionUtils.checkPermissionsAndPerformAction(getActivity(), PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
() -> locationPermissionGranted(), this::locationPermissionGranted,
() -> isPermissionDenied = true, () -> isPermissionDenied = true,
R.string.location_permission_title, R.string.location_permission_title,
R.string.location_permission_rationale_nearby); R.string.location_permission_rationale_nearby);

View file

@ -29,7 +29,11 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder; import androidx.preference.PreferenceViewHolder;
import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.Adapter;
import com.karumi.dexter.Dexter; import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionGrantedResponse; import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import com.karumi.dexter.listener.single.BasePermissionListener; import com.karumi.dexter.listener.single.BasePermissionListener;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.Utils;
@ -371,7 +375,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
Locale defLocale = new Locale(languageCode); Locale defLocale = new Locale(languageCode);
if(keyListPreference.equals("appUiDefaultLanguagePref")) { if(keyListPreference.equals("appUiDefaultLanguagePref")) {
appUiLanguageListPreference.setSummary(defLocale.getDisplayLanguage(defLocale)); appUiLanguageListPreference.setSummary(defLocale.getDisplayLanguage(defLocale));
setLocale(Objects.requireNonNull(getActivity()), languageCode); setLocale(requireActivity(), languageCode);
getActivity().recreate(); getActivity().recreate();
final Intent intent = new Intent(getActivity(), MainActivity.class); final Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent); startActivity(intent);
@ -436,7 +440,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
final Locale defLocale = new Locale(recentLanguageCode); final Locale defLocale = new Locale(recentLanguageCode);
if (keyListPreference.equals("appUiDefaultLanguagePref")) { if (keyListPreference.equals("appUiDefaultLanguagePref")) {
appUiLanguageListPreference.setSummary(defLocale.getDisplayLanguage(defLocale)); appUiLanguageListPreference.setSummary(defLocale.getDisplayLanguage(defLocale));
setLocale(Objects.requireNonNull(getActivity()), recentLanguageCode); setLocale(requireActivity(), recentLanguageCode);
getActivity().recreate(); getActivity().recreate();
final Intent intent = new Intent(getActivity(), MainActivity.class); final Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent); startActivity(intent);
@ -506,7 +510,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
* First checks for external storage permissions and then sends logs via email * First checks for external storage permissions and then sends logs via email
*/ */
private void checkPermissionsAndSendLogs() { private void checkPermissionsAndSendLogs() {
if (PermissionUtils.hasPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) { if (PermissionUtils.hasPermission(getActivity(), PermissionUtils.PERMISSIONS_STORAGE)) {
commonsLogSender.send(getActivity(), null); commonsLogSender.send(getActivity(), null);
} else { } else {
requestExternalStoragePermissions(); requestExternalStoragePermissions();
@ -514,16 +518,26 @@ public class SettingsFragment extends PreferenceFragmentCompat {
} }
/** /**
* Requests external storage permissions and shows a toast stating that log collection has started * Requests external storage permissions and shows a toast stating that log collection has
* started
*/ */
private void requestExternalStoragePermissions() { private void requestExternalStoragePermissions() {
Dexter.withActivity(getActivity()) Dexter.withActivity(getActivity())
.withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) .withPermissions(PermissionUtils.PERMISSIONS_STORAGE)
.withListener(new BasePermissionListener() { .withListener(new MultiplePermissionsListener() {
@Override @Override
public void onPermissionGranted(PermissionGrantedResponse response) { public void onPermissionsChecked(MultiplePermissionsReport report) {
ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.log_collection_started)); ViewUtil.showLongToast(getActivity(),
getResources().getString(R.string.log_collection_started));
} }
}).check();
@Override
public void onPermissionRationaleShouldBeShown(
List<PermissionRequest> permissions, PermissionToken token) {
}
})
.onSameThread()
.check();
} }
} }

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.upload; package fr.free.nrw.commons.upload;
import static fr.free.nrw.commons.contributions.ContributionController.ACTION_INTERNAL_UPLOADS; import static fr.free.nrw.commons.contributions.ContributionController.ACTION_INTERNAL_UPLOADS;
import static fr.free.nrw.commons.utils.PermissionUtils.PERMISSIONS_STORAGE;
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
import android.Manifest; import android.Manifest;
@ -56,6 +57,7 @@ import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import java.security.Permission;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -146,9 +148,8 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
compositeDisposable = new CompositeDisposable(); compositeDisposable = new CompositeDisposable();
init(); init();
nearbyPopupAnswers = new HashMap<>(); nearbyPopupAnswers = new HashMap<>();
PermissionUtils.checkPermissionsAndPerformAction(this, PermissionUtils.checkPermissionsAndPerformAction(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSIONS_STORAGE,
this::receiveSharedItems, this::receiveSharedItems,
R.string.storage_permission_title, R.string.storage_permission_title,
R.string.write_storage_permission_rationale_for_image_share); R.string.write_storage_permission_rationale_for_image_share);
@ -159,7 +160,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
if (dpi<=321) { if (dpi<=321) {
onRlContainerTitleClicked(); onRlContainerTitleClicked();
} }
if (PermissionUtils.hasPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) { if (PermissionUtils.hasPermission(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) {
locationManager.registerLocationManager(); locationManager.registerLocationManager();
} }
locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
@ -251,15 +252,17 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
} }
private void checkStoragePermissions() { private void checkStoragePermissions() {
final boolean hasAllPermissions = PermissionUtils.hasPermission(this, PERMISSIONS_STORAGE);
if (!hasAllPermissions) {
PermissionUtils.checkPermissionsAndPerformAction(this, PermissionUtils.checkPermissionsAndPerformAction(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSIONS_STORAGE,
() -> { () -> {
//TODO handle this //TODO handle this
}, },
R.string.storage_permission_title, R.string.storage_permission_title,
R.string.write_storage_permission_rationale_for_image_share); R.string.write_storage_permission_rationale_for_image_share);
} }
}
@Override @Override
protected void onStop() { protected void onStop() {
@ -670,5 +673,4 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
this::finish this::finish
); );
} }
} }

View file

@ -38,7 +38,7 @@ object DownloadUtils {
} }
PermissionUtils.checkPermissionsAndPerformAction( PermissionUtils.checkPermissionsAndPerformAction(
activity, activity,
permission.WRITE_EXTERNAL_STORAGE, PermissionUtils.PERMISSIONS_STORAGE,
{ enqueueRequest(activity, req) }, { enqueueRequest(activity, req) },
{ {
Toast.makeText( Toast.makeText(

View file

@ -1,121 +1,143 @@
package fr.free.nrw.commons.utils; package fr.free.nrw.commons.utils;
import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.karumi.dexter.Dexter; import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken; import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest; import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.single.BasePermissionListener; import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import java.util.List;
public class PermissionUtils { public class PermissionUtils {
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;
}
/** /**
* This method can be used by any activity which requires a permission which has been blocked(marked never ask again by the user) * This method can be used by any activity which requires a permission which has been
It open the app settings from where the user can manually give us the required permission. * 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
*/ */
private static void askUserToManuallyEnablePermissionFromSettings(Activity activity) { private static void askUserToManuallyEnablePermissionFromSettings(Activity activity) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", activity.getPackageName(), null); Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri); intent.setData(uri);
activity.startActivityForResult(intent,CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS); activity.startActivityForResult(intent,
CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS);
} }
/** /**
* Checks whether the app already has a particular permission * Checks whether the app already has a particular permission
* *
* @param activity * @param activity
* @param permission permission to be checked * @param permissions permissions to be checked
* @return * @return
*/ */
public static boolean hasPermission(Activity activity, String permission) { public static boolean hasPermission(Activity activity, String permissions[]) {
return ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED; boolean hasPermission = true;
for (String permission : permissions
) {
hasPermission = hasPermission &&
ContextCompat.checkSelfPermission(activity, permission)
== PackageManager.PERMISSION_GRANTED;
}
return hasPermission;
} }
/** /**
* Checks for a particular permission and runs the runnable to perform an action when the permission is granted * Checks for a particular permission and runs the runnable to perform an action when the
* Also, it shows a rationale if needed * permission is granted Also, it shows a rationale if needed
* * <p>
* rationaleTitle and rationaleMessage can be invalid @StringRes. If the value is -1 then no permission rationale * rationaleTitle and rationaleMessage can be invalid @StringRes. If the value is -1 then no
* will be displayed and permission would be requested * permission rationale will be displayed and permission would be requested
* * <p>
* Sample usage: * Sample usage:
* * <p>
* PermissionUtils.checkPermissionsAndPerformAction(activity, * PermissionUtils.checkPermissionsAndPerformAction(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
* Manifest.permission.WRITE_EXTERNAL_STORAGE, * () -> initiateCameraUpload(activity), R.string.storage_permission_title,
* () -> initiateCameraUpload(activity),
* R.string.storage_permission_title,
* R.string.write_storage_permission_rationale); * R.string.write_storage_permission_rationale);
* * <p>
* If you don't want the permission rationale to be shown then use: * If you don't want the permission rationale to be shown then use:
* * <p>
* PermissionUtils.checkPermissionsAndPerformAction(activity, * PermissionUtils.checkPermissionsAndPerformAction(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
* Manifest.permission.WRITE_EXTERNAL_STORAGE, * () -> initiateCameraUpload(activity), - 1, -1);
* () -> initiateCameraUpload(activity),
* - 1, -1);
*
*
* *
* @param activity activity requesting permissions * @param activity activity requesting permissions
* @param permission the permission being requests * @param permissions the permissions array being requests
* @param onPermissionGranted the runnable to be executed when the permission is granted * @param onPermissionGranted the runnable to be executed when the permission is granted
* @param rationaleTitle rationale title to be displayed when permission was denied. It can be an invalid @StringRes * @param rationaleTitle rationale title to be displayed when permission was denied. It can
* @param rationaleMessage rationale message to be displayed when permission was denied. It can be an invalid @StringRes * be an invalid @StringRes
* @param rationaleMessage rationale message to be displayed when permission was denied. It
* can be an invalid @StringRes
*/ */
public static void checkPermissionsAndPerformAction(Activity activity, String permission, public static void checkPermissionsAndPerformAction(Activity activity, String[] permissions,
Runnable onPermissionGranted, @StringRes int rationaleTitle, Runnable onPermissionGranted, @StringRes int rationaleTitle,
@StringRes int rationaleMessage) { @StringRes int rationaleMessage) {
checkPermissionsAndPerformAction(activity, permission, onPermissionGranted, null, checkPermissionsAndPerformAction(activity, permissions, onPermissionGranted, null,
rationaleTitle, rationaleMessage); rationaleTitle, rationaleMessage);
} }
/** /**
* Checks for a particular permission and runs the corresponding runnables to perform an action when the permission is granted/denied * Checks for a particular permission and runs the corresponding runnables to perform an action
* Also, it shows a rationale if needed * when the permission is granted/denied Also, it shows a rationale if needed
* * <p>
* Sample usage: * Sample usage:
* * <p>
* PermissionUtils.checkPermissionsAndPerformAction(activity, * PermissionUtils.checkPermissionsAndPerformAction(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
* Manifest.permission.WRITE_EXTERNAL_STORAGE, * () -> initiateCameraUpload(activity), () -> showMessage(), R.string.storage_permission_title,
* () -> initiateCameraUpload(activity),
* () -> showMessage(),
* R.string.storage_permission_title,
* R.string.write_storage_permission_rationale); * R.string.write_storage_permission_rationale);
* *
*
* @param activity activity requesting permissions * @param activity activity requesting permissions
* @param permission the permission being requests * @param permissions the permissions array being requested
* @param onPermissionGranted the runnable to be executed when the permission is granted * @param onPermissionGranted the runnable to be executed when the permission is granted
* @param onPermissionDenied the runnable to be executed when the permission is denied(but not permanently) * @param onPermissionDenied the runnable to be executed when the permission is denied(but not
* permanently)
* @param rationaleTitle rationale title to be displayed when permission was denied * @param rationaleTitle rationale title to be displayed when permission was denied
* @param rationaleMessage rationale message to be displayed when permission was denied * @param rationaleMessage rationale message to be displayed when permission was denied
*/ */
public static void checkPermissionsAndPerformAction(Activity activity, String permission, public static void checkPermissionsAndPerformAction(Activity activity, String[] permissions,
Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle, Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle,
@StringRes int rationaleMessage) { @StringRes int rationaleMessage) {
Dexter.withActivity(activity) Dexter.withActivity(activity)
.withPermission(permission) .withPermissions(permissions)
.withListener(new BasePermissionListener() { .withListener(new MultiplePermissionsListener() {
@Override public void onPermissionGranted(PermissionGrantedResponse response) { @Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
onPermissionGranted.run(); onPermissionGranted.run();
} }
if (report.isAnyPermissionPermanentlyDenied()) {
@Override public void onPermissionDenied(PermissionDeniedResponse response) { // permission is denied permanently, we will show user a dialog message.
if (response.isPermanentlyDenied()) {
DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle), DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle),
activity.getString(rationaleMessage), activity.getString(rationaleMessage),
activity.getString(R.string.navigation_item_settings), null, activity.getString(R.string.navigation_item_settings), null,
@ -128,7 +150,7 @@ public class PermissionUtils {
} }
@Override @Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions,
PermissionToken token) { PermissionToken token) {
if (rationaleTitle == -1 && rationaleMessage == -1) { if (rationaleTitle == -1 && rationaleMessage == -1) {
token.continuePermissionRequest(); token.continuePermissionRequest();
@ -144,7 +166,7 @@ public class PermissionUtils {
false); false);
} }
}) })
.onSameThread()
.check(); .check();
} }
} }