permissions, PermissionToken token) {
+
+ }
+ })
+ .onSameThread()
+ .check();
}
}
diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java
index 91ab805f3..ab6fa7035 100644
--- a/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java
+++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java
@@ -1,6 +1,7 @@
package fr.free.nrw.commons.upload;
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 android.Manifest;
@@ -56,6 +57,7 @@ import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
+import java.security.Permission;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -146,12 +148,11 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
compositeDisposable = new CompositeDisposable();
init();
nearbyPopupAnswers = new HashMap<>();
-
PermissionUtils.checkPermissionsAndPerformAction(this,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- this::receiveSharedItems,
- R.string.storage_permission_title,
- R.string.write_storage_permission_rationale_for_image_share);
+ PERMISSIONS_STORAGE,
+ this::receiveSharedItems,
+ R.string.storage_permission_title,
+ R.string.write_storage_permission_rationale_for_image_share);
//getting the current dpi of the device and if it is less than 320dp i.e. overlapping
//threshold, thumbnails automatically minimizes
DisplayMetrics metrics = getResources().getDisplayMetrics();
@@ -159,7 +160,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
if (dpi<=321) {
onRlContainerTitleClicked();
}
- if (PermissionUtils.hasPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
+ if (PermissionUtils.hasPermission(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) {
locationManager.registerLocationManager();
}
locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
@@ -181,7 +182,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
private void initThumbnailsRecyclerView() {
rvThumbnails.setLayoutManager(new LinearLayoutManager(this,
- LinearLayoutManager.HORIZONTAL, false));
+ LinearLayoutManager.HORIZONTAL, false));
thumbnailsAdapter = new ThumbnailsAdapter(() -> currentSelectedPosition);
rvThumbnails.setAdapter(thumbnailsAdapter);
@@ -193,7 +194,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
vpUpload.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
+ int positionOffsetPixels) {
}
@@ -238,29 +239,31 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
*/
protected void checkBlockStatus() {
compositeDisposable.add(userClient.isUserBlockedFromCommons()
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .filter(result -> result)
- .subscribe(result -> DialogUtil.showAlertDialog(
- this,
- getString(R.string.block_notification_title),
- getString(R.string.block_notification),
- getString(R.string.ok),
- this::finish,
- true)));
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .filter(result -> result)
+ .subscribe(result -> DialogUtil.showAlertDialog(
+ this,
+ getString(R.string.block_notification_title),
+ getString(R.string.block_notification),
+ getString(R.string.ok),
+ this::finish,
+ true)));
}
private void checkStoragePermissions() {
- PermissionUtils.checkPermissionsAndPerformAction(this,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ final boolean hasAllPermissions = PermissionUtils.hasPermission(this, PERMISSIONS_STORAGE);
+ if (!hasAllPermissions) {
+ PermissionUtils.checkPermissionsAndPerformAction(this,
+ PERMISSIONS_STORAGE,
() -> {
//TODO handle this
},
R.string.storage_permission_title,
R.string.write_storage_permission_rationale_for_image_share);
+ }
}
-
@Override
protected void onStop() {
super.onStop();
@@ -328,7 +331,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
@Override
public void updateTopCardTitle() {
tvTopCardTitle.setText(getResources()
- .getQuantityString(R.plurals.upload_count_title, uploadableFiles.size(), uploadableFiles.size()));
+ .getQuantityString(R.plurals.upload_count_title, uploadableFiles.size(), uploadableFiles.size()));
}
@Override
@@ -370,13 +373,13 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
} else {
//Show thumbnails
if (uploadableFiles.size()
- > 1) {//If there is only file, no need to show the image thumbnails
+ > 1) {//If there is only file, no need to show the image thumbnails
thumbnailsAdapter.setUploadableFiles(uploadableFiles);
} else {
llContainerTopCard.setVisibility(View.GONE);
}
tvTopCardTitle.setText(getResources()
- .getQuantityString(R.plurals.upload_count_title, uploadableFiles.size(), uploadableFiles.size()));
+ .getQuantityString(R.plurals.upload_count_title, uploadableFiles.size(), uploadableFiles.size()));
fragments = new ArrayList<>();
/* Suggest users to turn battery optimisation off when uploading more than a few files.
@@ -419,7 +422,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
UploadMediaDetailFragment uploadMediaDetailFragment = new UploadMediaDetailFragment();
LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper(
- this, locationManager, null);
+ this, locationManager, null);
if (locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) {
currLocation = locationManager.getLastLocation();
}
@@ -525,8 +528,8 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
}
float[] distance = new float[2];
Location.distanceBetween(
- currLocation.getLatitude(), currLocation.getLongitude(),
- prevLocation.getLatitude(), prevLocation.getLongitude(), distance);
+ currLocation.getLatitude(), currLocation.getLongitude(),
+ prevLocation.getLatitude(), prevLocation.getLongitude(), distance);
return distance[0];
}
@@ -670,5 +673,4 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
this::finish
);
}
-
}
diff --git a/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt b/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt
index d7d5ae3aa..480823d1f 100644
--- a/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt
+++ b/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt
@@ -38,7 +38,7 @@ object DownloadUtils {
}
PermissionUtils.checkPermissionsAndPerformAction(
activity,
- permission.WRITE_EXTERNAL_STORAGE,
+ PermissionUtils.PERMISSIONS_STORAGE,
{ enqueueRequest(activity, req) },
{
Toast.makeText(
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 1b22fcfc0..d98bb6c86 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,121 +1,143 @@
package fr.free.nrw.commons.utils;
+import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Build;
import android.provider.Settings;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import com.karumi.dexter.Dexter;
+import com.karumi.dexter.MultiplePermissionsReport;
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.single.BasePermissionListener;
+import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
+import java.util.List;
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)
- It open the app settings from where the user can manually give us the required permission.
+ * This method can be used by any activity which requires a permission which has been
+ * 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
*/
private static void askUserToManuallyEnablePermissionFromSettings(Activity activity) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
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
*
* @param activity
- * @param permission permission to be checked
+ * @param permissions permissions to be checked
* @return
*/
- public static boolean hasPermission(Activity activity, String permission) {
- return ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED;
-
+ public static boolean hasPermission(Activity activity, String permissions[]) {
+ 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
- * Also, it shows a rationale if needed
- *
- * rationaleTitle and rationaleMessage can be invalid @StringRes. If the value is -1 then no permission rationale
- * will be displayed and permission would be requested
- *
+ * 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
+ *
+ * rationaleTitle and rationaleMessage can be invalid @StringRes. If the value is -1 then no
+ * permission rationale will be displayed and permission would be requested
+ *
* Sample usage:
- *
- * PermissionUtils.checkPermissionsAndPerformAction(activity,
- * Manifest.permission.WRITE_EXTERNAL_STORAGE,
- * () -> initiateCameraUpload(activity),
- * R.string.storage_permission_title,
- * R.string.write_storage_permission_rationale);
- *
+ *
+ * PermissionUtils.checkPermissionsAndPerformAction(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ * () -> initiateCameraUpload(activity), R.string.storage_permission_title,
+ * R.string.write_storage_permission_rationale);
+ *
* If you don't want the permission rationale to be shown then use:
+ *
+ * PermissionUtils.checkPermissionsAndPerformAction(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ * () -> initiateCameraUpload(activity), - 1, -1);
*
- * PermissionUtils.checkPermissionsAndPerformAction(activity,
- * Manifest.permission.WRITE_EXTERNAL_STORAGE,
- * () -> initiateCameraUpload(activity),
- * - 1, -1);
- *
- *
- *
- * @param activity activity requesting permissions
- * @param permission the permission being requests
+ * @param activity activity requesting permissions
+ * @param permissions the permissions array being requests
* @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 rationaleMessage rationale message 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
+ * 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,
@StringRes int rationaleMessage) {
- checkPermissionsAndPerformAction(activity, permission, onPermissionGranted, null,
+ checkPermissionsAndPerformAction(activity, permissions, onPermissionGranted, null,
rationaleTitle, rationaleMessage);
}
/**
- * Checks for a particular permission and runs the corresponding runnables to perform an action when the permission is granted/denied
- * Also, it shows a rationale if needed
- *
+ * Checks for a particular permission and runs the corresponding runnables to perform an action
+ * when the permission is granted/denied Also, it shows a rationale if needed
+ *
* Sample usage:
+ *
+ * PermissionUtils.checkPermissionsAndPerformAction(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ * () -> initiateCameraUpload(activity), () -> showMessage(), R.string.storage_permission_title,
+ * R.string.write_storage_permission_rationale);
*
- * PermissionUtils.checkPermissionsAndPerformAction(activity,
- * Manifest.permission.WRITE_EXTERNAL_STORAGE,
- * () -> initiateCameraUpload(activity),
- * () -> showMessage(),
- * R.string.storage_permission_title,
- * R.string.write_storage_permission_rationale);
- *
- *
- * @param activity activity requesting permissions
- * @param permission the permission being requests
+ * @param activity activity requesting permissions
+ * @param permissions the permissions array being requested
* @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 rationaleTitle rationale title to be displayed when permission was denied
- * @param rationaleMessage rationale message to be displayed when permission was denied
+ * @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 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,
@StringRes int rationaleMessage) {
Dexter.withActivity(activity)
- .withPermission(permission)
- .withListener(new BasePermissionListener() {
- @Override public void onPermissionGranted(PermissionGrantedResponse response) {
- onPermissionGranted.run();
- }
-
- @Override public void onPermissionDenied(PermissionDeniedResponse response) {
- if (response.isPermanentlyDenied()) {
+ .withPermissions(permissions)
+ .withListener(new MultiplePermissionsListener() {
+ @Override
+ public void onPermissionsChecked(MultiplePermissionsReport report) {
+ if (report.areAllPermissionsGranted()) {
+ onPermissionGranted.run();
+ }
+ if (report.isAnyPermissionPermanentlyDenied()) {
+ // permission is denied permanently, we will show user a dialog message.
DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle),
activity.getString(rationaleMessage),
activity.getString(R.string.navigation_item_settings), null,
@@ -128,7 +150,7 @@ public class PermissionUtils {
}
@Override
- public void onPermissionRationaleShouldBeShown(PermissionRequest permission,
+ public void onPermissionRationaleShouldBeShown(List permissions,
PermissionToken token) {
if (rationaleTitle == -1 && rationaleMessage == -1) {
token.continuePermissionRequest();
@@ -144,7 +166,7 @@ public class PermissionUtils {
false);
}
})
+ .onSameThread()
.check();
}
-
}