diff --git a/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java b/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java index abe2eefd5..7454c77ef 100644 --- a/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java @@ -10,6 +10,7 @@ import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment. import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_ZOOM; import android.content.Intent; +import android.content.pm.PackageManager; import android.graphics.BitmapFactory; import android.location.Location; import android.os.Bundle; @@ -21,7 +22,6 @@ import android.view.animation.OvershootInterpolator; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; @@ -56,6 +56,7 @@ import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import fr.free.nrw.commons.MapStyle; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.filepicker.Constants; import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.location.LocationPermissionsHelper; import fr.free.nrw.commons.location.LocationPermissionsHelper.Dialog; @@ -72,7 +73,7 @@ import timber.log.Timber; * Helps to pick location and return the result with an intent */ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCallback, - OnCameraMoveStartedListener, OnCameraIdleListener, Observer { + OnCameraMoveStartedListener, OnCameraIdleListener, Observer, LocationPermissionCallback { /** * DROPPED_MARKER_LAYER_ID : id for layer @@ -474,30 +475,21 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa R.string.upload_map_location_access ); LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper( - this, locationManager, new LocationPermissionCallback() { - @Override - public void onLocationPermissionDenied(String toastMessage) { - // Do nothing - } - - @Override - public void onLocationPermissionGranted() { - fr.free.nrw.commons.location.LatLng currLocation = locationManager.getLastLocation(); - if (currLocation != null) { - final CameraPosition position; - position = new CameraPosition.Builder() - .target(new com.mapbox.mapboxsdk.geometry.LatLng(currLocation.getLatitude(), - currLocation.getLongitude(), 0)) // Sets the new camera position - .zoom(mapboxMap.getCameraPosition().zoom) // Same zoom level - .build(); - - mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1000); - } - } - }); + this, locationManager, this); locationPermissionsHelper.handleLocationPermissions(locationAccessDialog, locationOffDialog); } + @Override + public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, + @NonNull final int[] grantResults) { + if (requestCode == Constants.RequestCodes.LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + onLocationPermissionGranted(); + } else { + onLocationPermissionDenied(""); + } + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + @Override protected void onStart() { super.onStart(); @@ -539,4 +531,24 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa super.onLowMemory(); mapView.onLowMemory(); } + + @Override + public void onLocationPermissionDenied(String toastMessage) { + //do nothing + } + + @Override + public void onLocationPermissionGranted() { + fr.free.nrw.commons.location.LatLng currLocation = locationManager.getLastLocation(); + if (currLocation != null) { + final CameraPosition position; + position = new CameraPosition.Builder() + .target(new com.mapbox.mapboxsdk.geometry.LatLng(currLocation.getLatitude(), + currLocation.getLongitude(), 0)) // Sets the new camera position + .zoom(mapboxMap.getCameraPosition().zoom) // Same zoom level + .build(); + + mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1000); + } + } } diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java index 21d4d7460..361bd20b6 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java @@ -1,5 +1,6 @@ package fr.free.nrw.commons.bookmarks.locations; +import android.Manifest.permission; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; @@ -8,6 +9,9 @@ import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; @@ -21,6 +25,7 @@ import fr.free.nrw.commons.nearby.Place; import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions; import fr.free.nrw.commons.nearby.fragments.PlaceAdapter; import java.util.List; +import java.util.Map; import javax.inject.Inject; import kotlin.Unit; @@ -36,6 +41,25 @@ public class BookmarkLocationsFragment extends DaggerFragment { @Inject BookmarkLocationsDao bookmarkLocationDao; @Inject CommonPlaceClickActions commonPlaceClickActions; private PlaceAdapter adapter; + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { + @Override + public void onActivityResult(Map result) { + boolean areAllGranted = true; + for(final boolean b : result.values()) { + areAllGranted = areAllGranted && b; + } + + if (areAllGranted) { + contributionController.locationPermissionCallback.onLocationPermissionGranted(); + } else { + if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { + contributionController.handleShowRationaleFlowCameraLocation(getActivity()); + } else { + contributionController.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied)); + } + } + } + }); /** * Create an instance of the fragment with the right bundle parameters @@ -67,7 +91,8 @@ public class BookmarkLocationsFragment extends DaggerFragment { adapter.remove(place); return Unit.INSTANCE; }, - commonPlaceClickActions + commonPlaceClickActions, + inAppCameraLocationPermissionLauncher ); recyclerView.setAdapter(adapter); } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java index 567293b81..66aff1325 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java @@ -3,10 +3,12 @@ package fr.free.nrw.commons.contributions; import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; import android.Manifest; +import android.Manifest.permission; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.widget.Toast; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import fr.free.nrw.commons.R; import fr.free.nrw.commons.filepicker.DefaultCallback; @@ -37,9 +39,12 @@ public class ContributionController { private final JsonKvStore defaultKvStore; private LatLng locationBeforeImageCapture; private boolean isInAppCameraUpload; + public LocationPermissionCallback locationPermissionCallback; + private LocationPermissionsHelper locationPermissionsHelper; @Inject LocationServiceManager locationManager; + @Inject public ContributionController(@Named("default_preferences") JsonKvStore defaultKvStore) { this.defaultKvStore = defaultKvStore; @@ -48,7 +53,8 @@ public class ContributionController { /** * Check for permissions and initiate camera click */ - public void initiateCameraPick(Activity activity) { + public void initiateCameraPick(Activity activity, + ActivityResultLauncher inAppCameraLocationPermissionLauncher) { boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true); if (!useExtStorage) { initiateCameraUpload(activity); @@ -56,19 +62,20 @@ public class ContributionController { } PermissionUtils.checkPermissionsAndPerformAction(activity, - PermissionUtils.PERMISSIONS_STORAGE, - () -> { - if (defaultKvStore.getBoolean("inAppCameraFirstRun")) { - defaultKvStore.putBoolean("inAppCameraFirstRun", false); - askUserToAllowLocationAccess(activity); - } else if(defaultKvStore.getBoolean("inAppCameraLocationPref")) { - createDialogsAndHandleLocationPermissions(activity); - } else { - initiateCameraUpload(activity); - } - }, - R.string.storage_permission_title, - R.string.write_storage_permission_rationale); + () -> { + if (defaultKvStore.getBoolean("inAppCameraFirstRun")) { + defaultKvStore.putBoolean("inAppCameraFirstRun", false); + askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher); + } else if (defaultKvStore.getBoolean("inAppCameraLocationPref")) { + createDialogsAndHandleLocationPermissions(activity, + inAppCameraLocationPermissionLauncher); + } else { + initiateCameraUpload(activity); + } + }, + R.string.storage_permission_title, + R.string.write_storage_permission_rationale, + PermissionUtils.PERMISSIONS_STORAGE); } /** @@ -76,7 +83,8 @@ public class ContributionController { * * @param activity */ - private void createDialogsAndHandleLocationPermissions(Activity activity) { + private void createDialogsAndHandleLocationPermissions(Activity activity, + ActivityResultLauncher inAppCameraLocationPermissionLauncher) { LocationPermissionsHelper.Dialog locationAccessDialog = new Dialog( R.string.location_permission_title, R.string.in_app_camera_location_permission_rationale @@ -86,52 +94,73 @@ public class ContributionController { R.string.ask_to_turn_location_on, R.string.in_app_camera_needs_location ); - LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper( - activity, locationManager, - new LocationPermissionCallback() { - @Override - public void onLocationPermissionDenied(String toastMessage) { - Toast.makeText( - activity, - toastMessage, - Toast.LENGTH_LONG - ).show(); - initiateCameraUpload(activity); - } - - @Override - public void onLocationPermissionGranted() { - initiateCameraUpload(activity); - } + locationPermissionCallback = new LocationPermissionCallback() { + @Override + public void onLocationPermissionDenied(String toastMessage) { + Toast.makeText( + activity, + toastMessage, + Toast.LENGTH_LONG + ).show(); + initiateCameraUpload(activity); } - ); - locationPermissionsHelper.handleLocationPermissions( - locationAccessDialog, - locationOffDialog - ); + + @Override + public void onLocationPermissionGranted() { + initiateCameraUpload(activity); + } + }; + + locationPermissionsHelper = new LocationPermissionsHelper( + activity, locationManager, locationPermissionCallback); + if (inAppCameraLocationPermissionLauncher != null) { + inAppCameraLocationPermissionLauncher.launch( + new String[]{permission.ACCESS_FINE_LOCATION}); + } else { + locationPermissionsHelper.handleLocationPermissions(locationAccessDialog, + locationOffDialog); + } + + } + + public void handleShowRationaleFlowCameraLocation(Activity activity) { + DialogUtil.showAlertDialog(activity, activity.getString(R.string.location_permission_title), + activity.getString(R.string.in_app_camera_location_permission_rationale), + activity.getString(android.R.string.ok), + activity.getString(android.R.string.cancel), + () -> { + if (!locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) { + locationPermissionsHelper.showLocationOffDialog(activity); + } + }, + () -> locationPermissionCallback.onLocationPermissionDenied( + activity.getString(R.string.in_app_camera_location_permission_denied)), + null, + false); } /** - * Suggest user to attach location information with pictures. - * If the user selects "Yes", then: - * - * Location is taken from the EXIF if the default camera application - * does not redact location tags. - * - * Otherwise, if the EXIF metadata does not have location information, - * then location captured by the app is used + * Suggest user to attach location information with pictures. If the user selects "Yes", then: + *

+ * Location is taken from the EXIF if the default camera application does not redact location + * tags. + *

+ * Otherwise, if the EXIF metadata does not have location information, then location captured by + * the app is used * * @param activity */ - private void askUserToAllowLocationAccess(Activity activity) { + private void askUserToAllowLocationAccess(Activity activity, + ActivityResultLauncher inAppCameraLocationPermissionLauncher) { DialogUtil.showAlertDialog(activity, activity.getString(R.string.in_app_camera_location_permission_title), activity.getString(R.string.in_app_camera_location_access_explanation), activity.getString(R.string.option_allow), activity.getString(R.string.option_dismiss), - ()-> { + () -> { defaultKvStore.putBoolean("inAppCameraLocationPref", true); - createDialogsAndHandleLocationPermissions(activity); + createDialogsAndHandleLocationPermissions(activity, + inAppCameraLocationPermissionLauncher); }, () -> { defaultKvStore.putBoolean("inAppCameraLocationPref", false); @@ -141,15 +170,6 @@ public class ContributionController { true); } - /** - * Check if apps have access to location even after having individual access - * - * @return - */ - private boolean isLocationAccessToAppsTurnedOn() { - return (locationManager.isNetworkProviderEnabled() || locationManager.isGPSProviderEnabled()); - } - /** * Initiate gallery picker */ @@ -161,22 +181,24 @@ public class ContributionController { * Initiate gallery picker with permission */ public void initiateCustomGalleryPickWithPermission(final Activity activity) { - setPickerConfiguration(activity,true); + setPickerConfiguration(activity, true); PermissionUtils.checkPermissionsAndPerformAction(activity, - PermissionUtils.PERMISSIONS_STORAGE, () -> FilePicker.openCustomSelector(activity, 0), R.string.storage_permission_title, - R.string.write_storage_permission_rationale); + R.string.write_storage_permission_rationale, + PermissionUtils.PERMISSIONS_STORAGE); } /** * Open chooser for gallery uploads */ - private void initiateGalleryUpload(final Activity activity, final boolean allowMultipleUploads) { + private void initiateGalleryUpload(final Activity activity, + final boolean allowMultipleUploads) { setPickerConfiguration(activity, allowMultipleUploads); - boolean openDocumentIntentPreferred = defaultKvStore.getBoolean("openDocumentPhotoPickerPref", true); + boolean openDocumentIntentPreferred = defaultKvStore.getBoolean( + "openDocumentPhotoPickerPref", true); FilePicker.openGallery(activity, 0, openDocumentIntentPreferred); } @@ -184,11 +206,11 @@ public class ContributionController { * Sets configuration for file picker */ private void setPickerConfiguration(Activity activity, - boolean allowMultipleUploads) { + boolean allowMultipleUploads) { boolean copyToExternalStorage = defaultKvStore.getBoolean("useExternalStorage", true); FilePicker.configuration(activity) - .setCopyTakenPhotosToPublicGalleryAppFolder(copyToExternalStorage) - .setAllowMultiplePickInGallery(allowMultipleUploads); + .setCopyTakenPhotosToPublicGalleryAppFolder(copyToExternalStorage) + .setAllowMultiplePickInGallery(allowMultipleUploads); } /** @@ -206,36 +228,39 @@ public class ContributionController { /** * Attaches callback for file picker. */ - public void handleActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { - FilePicker.handleActivityResult(requestCode, resultCode, data, activity, new DefaultCallback() { + public void handleActivityResult(Activity activity, int requestCode, int resultCode, + Intent data) { + FilePicker.handleActivityResult(requestCode, resultCode, data, activity, + new DefaultCallback() { - @Override - public void onCanceled(final ImageSource source, final int type) { - super.onCanceled(source, type); - defaultKvStore.remove(PLACE_OBJECT); - } + @Override + public void onCanceled(final ImageSource source, final int type) { + super.onCanceled(source, type); + defaultKvStore.remove(PLACE_OBJECT); + } - @Override - public void onImagePickerError(Exception e, FilePicker.ImageSource source, int type) { - ViewUtil.showShortToast(activity, R.string.error_occurred_in_picking_images); - } + @Override + public void onImagePickerError(Exception e, FilePicker.ImageSource source, + int type) { + ViewUtil.showShortToast(activity, R.string.error_occurred_in_picking_images); + } - @Override - public void onImagesPicked(@NonNull List imagesFiles, FilePicker.ImageSource source, int type) { - Intent intent = handleImagesPicked(activity, imagesFiles); - activity.startActivity(intent); - } - }); + @Override + public void onImagesPicked(@NonNull List imagesFiles, + FilePicker.ImageSource source, int type) { + Intent intent = handleImagesPicked(activity, imagesFiles); + activity.startActivity(intent); + } + }); } public List handleExternalImagesPicked(Activity activity, - Intent data) { + Intent data) { return FilePicker.handleExternalImagesPicked(data, activity); } /** - * Returns intent to be passed to upload activity - * Attaches place object for nearby uploads and + * Returns intent to be passed to upload activity Attaches place object for nearby uploads and * location before image capture if in-app camera is used */ private Intent handleImagesPicked(Context context, @@ -263,5 +288,4 @@ public class ContributionController { isInAppCameraUpload = false; // reset the flag for next use return shareIntent; } - } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index 7d8058568..b9cbf83f9 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -7,6 +7,7 @@ import static fr.free.nrw.commons.profile.ProfileActivity.KEY_USERNAME; import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; import android.Manifest; +import android.Manifest.permission; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; @@ -21,6 +22,9 @@ import android.widget.CheckBox; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; @@ -35,6 +39,7 @@ import fr.free.nrw.commons.profile.ProfileActivity; import fr.free.nrw.commons.theme.BaseActivity; import java.util.Date; import java.util.List; +import java.util.Map; import javax.inject.Inject; import javax.inject.Named; import androidx.work.WorkManager; @@ -117,6 +122,29 @@ public class ContributionsFragment String userName; private boolean isUserProfile; + private ActivityResultLauncher nearbyLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { + @Override + public void onActivityResult(Map result) { + boolean areAllGranted = true; + for (final boolean b : result.values()) { + areAllGranted = areAllGranted && b; + } + + if (areAllGranted) { + onLocationPermissionGranted(); + } else { + if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) + && store.getBoolean("displayLocationPermissionForCardView", true) + && !store.getBoolean("doNotAskForLocationPermission", false) + && (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) { + nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION; + showNearbyCardPermissionRationale(); + } else { + displayYouWontSeeNearbyMessage(); + } + } + } + }); @NonNull public static ContributionsFragment newInstance() { @@ -451,12 +479,7 @@ public class ContributionsFragment } private void requestLocationPermission() { - PermissionUtils.checkPermissionsAndPerformAction(getActivity(), - new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, - this::onLocationPermissionGranted, - this::displayYouWontSeeNearbyMessage, - -1, - -1); + nearbyLocationPermissionLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION}); } private void onLocationPermissionGranted() { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index 13155f37b..aa12816cc 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -4,6 +4,7 @@ import static android.view.View.GONE; import static android.view.View.VISIBLE; import static fr.free.nrw.commons.di.NetworkingModule.NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE; +import android.Manifest.permission; import android.content.Context; import android.content.res.Configuration; import android.net.Uri; @@ -18,6 +19,9 @@ import android.view.animation.AnimationUtils; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; @@ -42,6 +46,7 @@ import fr.free.nrw.commons.media.MediaClient; import fr.free.nrw.commons.utils.SystemThemeUtils; import fr.free.nrw.commons.utils.ViewUtil; import java.util.Locale; +import java.util.Map; import java.util.Objects; import javax.inject.Inject; import javax.inject.Named; @@ -114,6 +119,27 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl private int contributionsSize; String userName; + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { + @Override + public void onActivityResult(Map result) { + boolean areAllGranted = true; + for (final boolean b : result.values()) { + areAllGranted = areAllGranted && b; + } + + if (areAllGranted) { + controller.locationPermissionCallback.onLocationPermissionGranted(); + } else { + if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { + controller.handleShowRationaleFlowCameraLocation(getActivity()); + } else { + controller.locationPermissionCallback.onLocationPermissionDenied( + getActivity().getString(R.string.in_app_camera_location_permission_denied)); + } + } + } + }); + @Override public void onCreate(@Nullable @org.jetbrains.annotations.Nullable final Bundle savedInstanceState) { @@ -297,7 +323,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl private void setListeners() { fabPlus.setOnClickListener(view -> animateFAB(isFabOpen)); fabCamera.setOnClickListener(view -> { - controller.initiateCameraPick(getActivity()); + controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher); animateFAB(isFabOpen); }); fabGallery.setOnClickListener(view -> { @@ -393,10 +419,10 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl @Override public void deleteUpload(final Contribution contribution) { DialogUtil.showAlertDialog(getActivity(), - String.format(getString(R.string.cancelling_upload), - Locale.getDefault().getDisplayLanguage()), - String.format(getString(R.string.cancel_upload_dialog), - Locale.getDefault().getDisplayLanguage()), + String.format(Locale.getDefault().getDisplayLanguage(), + getString(R.string.cancelling_upload)), + String.format(Locale.getDefault().getDisplayLanguage(), + getString(R.string.cancel_upload_dialog)), "YES", "NO", () -> { ViewUtil.showShortToast(getContext(), R.string.cancelling_upload); @@ -422,8 +448,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl public void addImageToWikipedia(Contribution contribution) { DialogUtil.showAlertDialog(getActivity(), getString(R.string.add_picture_to_wikipedia_article_title), - String.format(getString(R.string.add_picture_to_wikipedia_article_desc), - Locale.getDefault().getDisplayLanguage()), + getString(R.string.add_picture_to_wikipedia_article_desc), () -> { showAddImageToWikipediaInstructions(contribution); }, () -> { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java index 6a14f8ec6..7ba087494 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java @@ -165,11 +165,10 @@ public class MainActivity extends BaseActivity if (VERSION.SDK_INT >= VERSION_CODES.Q) { PermissionUtils.checkPermissionsAndPerformAction( this, - new String[]{permission.ACCESS_MEDIA_LOCATION}, () -> {}, R.string.media_location_permission_denied, - R.string.add_location_manually - ); + R.string.add_location_manually, + permission.ACCESS_MEDIA_LOCATION); } } } diff --git a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java index a916c20cb..b51e74af9 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java @@ -7,6 +7,7 @@ import static fr.free.nrw.commons.utils.MapUtils.CAMERA_TARGET_SHIFT_FACTOR_PORT import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL; import android.Manifest; +import android.Manifest.permission; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; @@ -29,6 +30,9 @@ import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; @@ -84,6 +88,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import java.util.Arrays; import java.util.List; +import java.util.Map; import javax.inject.Inject; import javax.inject.Named; import timber.log.Timber; @@ -144,6 +149,38 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment @BindView(R.id.title) TextView title; @BindView(R.id.category) TextView distance; + private ActivityResultLauncher activityResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { + @Override + public void onActivityResult(Map result) { + boolean areAllGranted = true; + for(final boolean b : result.values()) { + areAllGranted = areAllGranted && b; + } + + if (areAllGranted) { + locationPermissionGranted(); + } else { + if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { + DialogUtil.showAlertDialog(getActivity(), getActivity().getString(R.string.location_permission_title), + getActivity().getString(R.string.location_permission_rationale_nearby), + getActivity().getString(android.R.string.ok), + getActivity().getString(android.R.string.cancel), + () -> { + if (!(locationManager.isNetworkProviderEnabled() || locationManager.isGPSProviderEnabled())) { + showLocationOffDialog(); + } + }, + () -> isPermissionDenied = true, + null, + false); + } else { + isPermissionDenied = true; + } + + } + } + }); + @NonNull public static ExploreMapFragment newInstance() { @@ -403,12 +440,7 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment @Override public void checkPermissionsAndPerformAction() { Timber.d("Checking permission and perfoming action"); - PermissionUtils.checkPermissionsAndPerformAction(getActivity(), - new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, - this::locationPermissionGranted, - () -> isPermissionDenied = true, - R.string.location_permission_title, - R.string.location_permission_rationale_nearby); + activityResultLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION}); } private void locationPermissionGranted() { diff --git a/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java b/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java index c25461740..cc04e3956 100644 --- a/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java +++ b/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java @@ -7,6 +7,7 @@ public interface Constants { * Provides the request codes utilised by the FilePicker */ interface RequestCodes { + int LOCATION = 1; int FILE_PICKER_IMAGE_IDENTIFICATOR = 0b1101101100; //876 int SOURCE_CHOOSER = 1 << 15; diff --git a/app/src/main/java/fr/free/nrw/commons/location/LocationPermissionsHelper.java b/app/src/main/java/fr/free/nrw/commons/location/LocationPermissionsHelper.java index 9760f5d41..f2be79c67 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LocationPermissionsHelper.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LocationPermissionsHelper.java @@ -5,8 +5,10 @@ import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.provider.Settings; -import android.widget.Toast; +import androidx.core.app.ActivityCompat; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.filepicker.Constants; +import fr.free.nrw.commons.filepicker.Constants.RequestCodes; import fr.free.nrw.commons.utils.DialogUtil; import fr.free.nrw.commons.utils.PermissionUtils; @@ -55,27 +57,62 @@ public class LocationPermissionsHelper { Dialog locationAccessDialog, Dialog locationOffDialog ) { - PermissionUtils.checkPermissionsAndPerformAction(activity, - new String[]{permission.ACCESS_FINE_LOCATION}, - () -> { - if(!isLocationAccessToAppsTurnedOn()) { - showLocationOffDialog(locationOffDialog); - } else { - if (callback != null) { - callback.onLocationPermissionGranted(); - } + if (PermissionUtils.hasPermission(activity, new String[]{permission.ACCESS_FINE_LOCATION})) { + callback.onLocationPermissionGranted(); + } else { + if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission.ACCESS_FINE_LOCATION)) { + if (locationAccessDialog != null && locationOffDialog != null) { + DialogUtil.showAlertDialog(activity, activity.getString(locationAccessDialog.dialogTitleResource), + activity.getString(locationAccessDialog.dialogTextResource), + activity.getString(android.R.string.ok), + activity.getString(android.R.string.cancel), + () -> { + if (!isLocationAccessToAppsTurnedOn()) { + showLocationOffDialog(activity); + } else { + ActivityCompat.requestPermissions(activity, + new String[]{permission.ACCESS_FINE_LOCATION}, 1); + } + }, + () -> callback.onLocationPermissionDenied(activity.getString(R.string.in_app_camera_location_permission_denied)), + null, + false); } - }, - () -> { - if (callback != null) { - callback.onLocationPermissionDenied(activity.getString( - R.string.in_app_camera_location_permission_denied)); - } - }, - locationAccessDialog.dialogTitleResource, - locationAccessDialog.dialogTextResource); + } else { + ActivityCompat.requestPermissions(activity, new String[]{permission.ACCESS_FINE_LOCATION}, + RequestCodes.LOCATION); + } + } } + public void showLocationOffDialog(Activity activity) { + DialogUtil + .showAlertDialog(activity, + activity.getString(R.string.ask_to_turn_location_on), + activity.getString(R.string.in_app_camera_needs_location), + activity.getString(R.string.title_app_shortcut_setting), + activity.getString(R.string.cancel), + () -> openLocationSettings(activity), + () -> callback.onLocationPermissionDenied(activity.getString( + R.string.in_app_camera_location_unavailable))); + } + + /** + * Open location source settings so that apps with location access can access it + * + * TODO: modify it to fix https://github.com/commons-app/apps-android-commons/issues/5255 + */ + + public void openLocationSettings(Activity activity) { + final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + final PackageManager packageManager = activity.getPackageManager(); + + if (intent.resolveActivity(packageManager)!= null) { + activity.startActivity(intent); + } + } + + /** * Check if apps have access to location even after having individual access * @@ -85,38 +122,6 @@ public class LocationPermissionsHelper { return (locationManager.isNetworkProviderEnabled() || locationManager.isGPSProviderEnabled()); } - /** - * Ask user to grant location access to apps - * - */ - - private void showLocationOffDialog(Dialog locationOffDialog) { - DialogUtil - .showAlertDialog(activity, - activity.getString(locationOffDialog.dialogTitleResource), - activity.getString(locationOffDialog.dialogTextResource), - activity.getString(R.string.title_app_shortcut_setting), - activity.getString(R.string.cancel), - () -> openLocationSettings(), - () -> callback.onLocationPermissionDenied(activity.getString( - R.string.in_app_camera_location_unavailable))); - } - - /** - * Open location source settings so that apps with location access can access it - * - * TODO: modify it to fix https://github.com/commons-app/apps-android-commons/issues/5255 - */ - - private void openLocationSettings() { - final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); - final PackageManager packageManager = activity.getPackageManager(); - - if (intent.resolveActivity(packageManager)!= null) { - activity.startActivity(intent); - } - } - /** * Handle onPermissionDenied within individual classes based on the requirements */ diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 8b7cf26c3..0cc4bf91f 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -367,13 +367,13 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements launchZoomActivityAfterPermissionCheck(view); } else { PermissionUtils.checkPermissionsAndPerformAction(getActivity(), - PermissionUtils.PERMISSIONS_STORAGE, () -> { launchZoomActivityAfterPermissionCheck(view); }, R.string.storage_permission_title, - R.string.read_storage_permission_rationale - ); + R.string.read_storage_permission_rationale, + PermissionUtils.PERMISSIONS_STORAGE + ); } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt index 63873de58..5498176cd 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt @@ -2,6 +2,7 @@ package fr.free.nrw.commons.nearby import android.view.View import android.view.View.* +import androidx.activity.result.ActivityResultLauncher import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.transition.TransitionManager @@ -15,11 +16,12 @@ import fr.free.nrw.commons.databinding.ItemPlaceBinding fun placeAdapterDelegate( bookmarkLocationDao: BookmarkLocationsDao, onItemClick: ((Place) -> Unit)? = null, - onCameraClicked: (Place) -> Unit, + onCameraClicked: (Place, ActivityResultLauncher>) -> Unit, onGalleryClicked: (Place) -> Unit, onBookmarkClicked: (Place, Boolean) -> Unit, onOverflowIconClicked: (Place, View) -> Unit, - onDirectionsClicked: (Place) -> Unit + onDirectionsClicked: (Place) -> Unit, + inAppCameraLocationPermissionLauncher: ActivityResultLauncher> ) = adapterDelegateViewBinding({ layoutInflater, parent -> ItemPlaceBinding.inflate(layoutInflater, parent, false) }) { @@ -36,7 +38,7 @@ fun placeAdapterDelegate( onItemClick?.invoke(item) } } - nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item) } + nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher) } nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item) } bookmarkButtonImage.setOnClickListener { val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt index a06af32da..1b1f87737 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.net.Uri import android.view.MenuItem import android.view.View +import androidx.activity.result.ActivityResultLauncher import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import fr.free.nrw.commons.R @@ -26,13 +27,13 @@ class CommonPlaceClickActions @Inject constructor( private val contributionController: ContributionController ) { - fun onCameraClicked(): (Place) -> Unit = { + fun onCameraClicked(): (Place, ActivityResultLauncher>) -> Unit = { place, launcher -> if (applicationKvStore.getBoolean("login_skipped", false)) { showLoginDialog() } else { - Timber.d("Camera button tapped. Image title: ${it.getName()}Image desc: ${it.longDescription}") - storeSharedPrefs(it) - contributionController.initiateCameraPick(activity) + Timber.d("Camera button tapped. Image title: ${place.getName()}Image desc: ${place.longDescription}") + storeSharedPrefs(place) + contributionController.initiateCameraPick(activity, launcher) } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java index ba78d041c..275fcddb6 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java @@ -8,6 +8,7 @@ import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; import android.Manifest; +import android.Manifest.permission; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; @@ -22,7 +23,6 @@ import android.os.Bundle; import android.provider.Settings; import android.text.Html; import android.text.method.LinkMovementMethod; -import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; @@ -42,6 +42,9 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -76,7 +79,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.maps.UiSettings; import com.mapbox.pluginscalebar.ScaleBarOptions; import com.mapbox.pluginscalebar.ScaleBarPlugin; @@ -126,6 +128,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; @@ -242,6 +245,56 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private PlaceAdapter adapter; private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback; private boolean isAdvancedQueryFragmentVisible = false; + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { + @Override + public void onActivityResult(Map result) { + boolean areAllGranted = true; + for (final boolean b : result.values()) { + areAllGranted = areAllGranted && b; + } + + if (areAllGranted) { + controller.locationPermissionCallback.onLocationPermissionGranted(); + } else { + if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { + controller.handleShowRationaleFlowCameraLocation(getActivity()); + } else { + controller.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied)); + } + } + } + }); + + private ActivityResultLauncher locationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { + @Override + public void onActivityResult(Map result) { + boolean areAllGranted = true; + for (final boolean b : result.values()) { + areAllGranted = areAllGranted && b; + } + + if (areAllGranted) { + locationPermissionGranted(); + } else { + if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { + DialogUtil.showAlertDialog(getActivity(), getActivity().getString(R.string.location_permission_title), + getActivity().getString(R.string.location_permission_rationale_nearby), + getActivity().getString(android.R.string.ok), + getActivity().getString(android.R.string.cancel), + () -> { + if (!(locationManager.isNetworkProviderEnabled() || locationManager.isGPSProviderEnabled())) { + showLocationOffDialog(); + } + }, + () -> isPermissionDenied = true, + null, + false); + } else { + isPermissionDenied = true; + } + } + } + }); /** * Holds filtered markers that are to be shown @@ -429,7 +482,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment updateMarker(isBookmarked, place, null); return Unit.INSTANCE; }, - commonPlaceClickActions + commonPlaceClickActions, + inAppCameraLocationPermissionLauncher ); rvNearbyList.setAdapter(adapter); } @@ -1214,12 +1268,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Override public void checkPermissionsAndPerformAction() { Timber.d("Checking permission and perfoming action"); - PermissionUtils.checkPermissionsAndPerformAction(getActivity(), - new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, - this::locationPermissionGranted, - () -> isPermissionDenied = true, - R.string.location_permission_title, - R.string.location_permission_rationale_nearby); + locationPermissionLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION}); } /** @@ -1815,7 +1864,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment if (fabCamera.isShown()) { Timber.d("Camera button tapped. Place: %s", selectedPlace.toString()); storeSharedPrefs(selectedPlace); - controller.initiateCameraPick(getActivity()); + controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher); } }); diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt index 528c30c6a..c61721bd3 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt @@ -1,5 +1,6 @@ package fr.free.nrw.commons.nearby.fragments +import androidx.activity.result.ActivityResultLauncher import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.nearby.placeAdapterDelegate @@ -9,7 +10,8 @@ class PlaceAdapter( bookmarkLocationsDao: BookmarkLocationsDao, onPlaceClicked: ((Place) -> Unit)? = null, onBookmarkClicked: (Place, Boolean) -> Unit, - commonPlaceClickActions: CommonPlaceClickActions + commonPlaceClickActions: CommonPlaceClickActions, + inAppCameraLocationPermissionLauncher: ActivityResultLauncher> ) : BaseDelegateAdapter( placeAdapterDelegate( @@ -19,7 +21,8 @@ class PlaceAdapter( commonPlaceClickActions.onGalleryClicked(), onBookmarkClicked, commonPlaceClickActions.onOverflowClicked(), - commonPlaceClickActions.onDirectionsClicked() + commonPlaceClickActions.onDirectionsClicked(), + inAppCameraLocationPermissionLauncher ), areItemsTheSame = {oldItem, newItem -> oldItem.wikiDataEntityId == newItem.wikiDataEntityId } ) diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index a67054541..51074bd57 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -2,7 +2,7 @@ package fr.free.nrw.commons.settings; import static android.content.Context.MODE_PRIVATE; -import android.Manifest; +import android.Manifest.permission; import android.app.Activity; import android.app.Dialog; import android.content.Intent; @@ -18,7 +18,9 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; -import android.widget.Toast; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.preference.ListPreference; import androidx.preference.MultiSelectListPreference; import androidx.preference.Preference; @@ -31,18 +33,15 @@ import androidx.recyclerview.widget.RecyclerView.Adapter; 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.PermissionRequest; import com.karumi.dexter.listener.multi.MultiplePermissionsListener; -import com.karumi.dexter.listener.single.BasePermissionListener; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.campaigns.CampaignView; +import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.kvstore.JsonKvStore; -import fr.free.nrw.commons.location.LocationPermissionsHelper; -import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermissionCallback; import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.logging.CommonsLogSender; import fr.free.nrw.commons.recentlanguages.Language; @@ -56,7 +55,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Objects; +import java.util.Map; import javax.inject.Inject; import javax.inject.Named; @@ -72,6 +71,9 @@ public class SettingsFragment extends PreferenceFragmentCompat { @Inject RecentLanguagesDao recentLanguagesDao; + @Inject + ContributionController contributionController; + @Inject LocationServiceManager locationManager; @@ -83,6 +85,18 @@ public class SettingsFragment extends PreferenceFragmentCompat { private View separator; private ListView languageHistoryListView; private static final String GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content"; + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { + @Override + public void onActivityResult(Map result) { + boolean areAllGranted = true; + for (final boolean b : result.values()) { + areAllGranted = areAllGranted && b; + } + if (!areAllGranted && shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { + contributionController.handleShowRationaleFlowCameraLocation(getActivity()); + } + } + }); @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { @@ -205,32 +219,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { * @param activity */ private void createDialogsAndHandleLocationPermissions(Activity activity) { - LocationPermissionsHelper.Dialog locationAccessDialog = new LocationPermissionsHelper.Dialog( - R.string.location_permission_title, - R.string.in_app_camera_location_permission_rationale - ); - - LocationPermissionsHelper.Dialog locationOffDialog = new LocationPermissionsHelper.Dialog( - R.string.ask_to_turn_location_on, - R.string.in_app_camera_needs_location - ); - - LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper( - activity, locationManager, new LocationPermissionCallback() { - @Override - public void onLocationPermissionDenied(String toastMessage) { - // dismiss the dialog - } - - @Override - public void onLocationPermissionGranted() { - // dismiss the dialog - } - }); - locationPermissionsHelper.handleLocationPermissions( - locationAccessDialog, - locationOffDialog - ); + inAppCameraLocationPermissionLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION}); } /** 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 ab6fa7035..5b86bbb58 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 @@ -149,10 +149,10 @@ public class UploadActivity extends BaseActivity implements UploadContract.View, init(); nearbyPopupAnswers = new HashMap<>(); PermissionUtils.checkPermissionsAndPerformAction(this, - PERMISSIONS_STORAGE, this::receiveSharedItems, R.string.storage_permission_title, - R.string.write_storage_permission_rationale_for_image_share); + R.string.write_storage_permission_rationale_for_image_share, + PERMISSIONS_STORAGE); //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(); @@ -255,12 +255,12 @@ public class UploadActivity extends BaseActivity implements UploadContract.View, 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); + R.string.write_storage_permission_rationale_for_image_share, + PERMISSIONS_STORAGE); } } 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 480823d1f..757dbc6cd 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,6 @@ object DownloadUtils { } PermissionUtils.checkPermissionsAndPerformAction( activity, - PermissionUtils.PERMISSIONS_STORAGE, { enqueueRequest(activity, req) }, { Toast.makeText( @@ -48,8 +47,9 @@ object DownloadUtils { ).show() }, R.string.storage_permission, - R.string.write_storage_permission_rationale - ) + R.string.write_storage_permission_rationale, + *PermissionUtils.PERMISSIONS_STORAGE + ) } private fun enqueueRequest(activity: Activity, req: DownloadManager.Request) { 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 d98bb6c86..9cacf7461 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 @@ -100,11 +100,11 @@ 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, String[] permissions, + public static void checkPermissionsAndPerformAction(Activity activity, Runnable onPermissionGranted, @StringRes int rationaleTitle, - @StringRes int rationaleMessage) { - checkPermissionsAndPerformAction(activity, permissions, onPermissionGranted, null, - rationaleTitle, rationaleMessage); + @StringRes int rationaleMessage, String... permissions) { + checkPermissionsAndPerformAction(activity, onPermissionGranted, null, + rationaleTitle, rationaleMessage, permissions); } /** @@ -125,9 +125,9 @@ 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, String[] permissions, + public static void checkPermissionsAndPerformAction(Activity activity, Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle, - @StringRes int rationaleMessage) { + @StringRes int rationaleMessage, String... permissions) { Dexter.withActivity(activity) .withPermissions(permissions) .withListener(new MultiplePermissionsListener() { @@ -135,6 +135,7 @@ public class PermissionUtils { public void onPermissionsChecked(MultiplePermissionsReport report) { if (report.areAllPermissionsGranted()) { onPermissionGranted.run(); + return; } if (report.isAnyPermissionPermanentlyDenied()) { // permission is denied permanently, we will show user a dialog message.