Fixes Location related flow of the app #5256 , #5461, #5490 (#5494)

* Resolved merged conflicts

* Resolved merge conflicts and updated workflow

* Updated Location Flow and merged conflicts

* Update flow and merge conflicts

* Fixed LocationPicker's location flow

* Removed redundant code from  LocationPermissionsHelper

* Fixed Explore fragment crashing and incorrect behaviour

* Updated LocationPicker Flow

* Fixed Nearby not working as intended

* Final update to location flow of all maps

* Added the reqested changes and fixed bugs

* Resolved requested change in in-app camera location flow

* Fixed In-app camera location flow

* Resolved conflicts in ContributionsListFragment

* Updated java doc as requested

* Resolved nearby card dialog not being shown

* Optimised LocationPermissionsHelper javadoc

* Made requested changes for preference check

* Added javadoc and requested comment for later reference

* Implemented requested code changes

* Fixed failing test due to changes made during PR

* Added string resource for ExploreMapFragment

* Changed string resource for rationale dialog

* Added standard location flow information in LocationPermissionsHelper

* Added javadoc for doNotAskForLocationPermission

* Removed unused import

* Updated javadoc

* Removed values-yue-hant

* Fix some merge conflict errors

* Fix minor errors due to mergre conflicts

* Fix some refactor errors

* Fixed minor bug due to merging conflicts

* Delete app/src/main/res/values-yue-hant directory

* Final changes to NearbyParentFragment

* Fixes #5686 map coordinates set to image coords

* Removed some redundant code from recenterMap

* Removed one test whose method no longer exists

* Removed unused method from contract of nearby

* Removed redundant method from NearbyParentFragment

* nearby: add a FIXME about the possibly redudant code

---------

Co-authored-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com>
This commit is contained in:
Shashwat Kedia 2024-04-17 09:18:34 +05:30 committed by GitHub
parent 1f2e31d45b
commit 04f9ef4819
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 421 additions and 297 deletions

View file

@ -1,10 +1,13 @@
package fr.free.nrw.commons.location;
import android.Manifest;
import android.Manifest.permission;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
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.RequestCodes;
@ -12,120 +15,172 @@ import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.utils.PermissionUtils;
/**
* Helper class to handle location permissions
* Helper class to handle location permissions.
*
* Location flow for fragments containing a map is as follows:
* Case 1: When location permission has never been asked for or denied before
* Check if permission is already granted or not.
* If not already granted, ask for it (if it isn't denied twice before).
* If now user grants permission, go to Case 3/4, else go to Case 2.
*
* Case 2: When location permission is just asked but has been denied
* Shows a toast to tell the user why location permission is needed.
* Also shows a rationale to the user, on agreeing to which, we go back to Case 1.
* Show current location / nearby pins / nearby images according to the default location.
*
* Case 3: When location permission are already granted, but location services are off
* Asks the user to turn on the location service, using a dialog.
* If the user rejects, checks for the last known location and shows stuff using that location.
* Also displays a toast telling the user why location should be turned on.
*
* Case 4: When location permission has been granted and location services are also on
* Do whatever is required by that particular activity / fragment using current location.
*
*/
public class LocationPermissionsHelper {
Activity activity;
LocationServiceManager locationManager;
LocationPermissionCallback callback;
public LocationPermissionsHelper(Activity activity, LocationServiceManager locationManager,
LocationPermissionCallback callback) {
this.activity = activity;
this.locationManager = locationManager;
this.callback = callback;
}
public static class Dialog {
int dialogTitleResource;
int dialogTextResource;
public Dialog(int dialogTitle, int dialogText) {
dialogTitleResource = dialogTitle;
dialogTextResource = dialogText;
}
}
/**
* Handles the entire location permissions flow
* Ask for location permission if the user agrees on attaching location with pictures and the
* app does not have the access to location
*
* @param locationAccessDialog
* @param locationOffDialog
* @param dialogTitleResource Resource id of the title of the dialog
* @param dialogTextResource Resource id of the text of the dialog
*/
public void handleLocationPermissions(Dialog locationAccessDialog,
Dialog locationOffDialog) {
requestForLocationAccess(locationAccessDialog, locationOffDialog);
}
/**
* Ask for location permission if the user agrees on attaching location with pictures
* and the app does not have the access to location
*
* @param locationAccessDialog
* @param locationOffDialog
*/
private void requestForLocationAccess(
Dialog locationAccessDialog,
Dialog locationOffDialog
public void requestForLocationAccess(
int dialogTitleResource,
int dialogTextResource
) {
if (PermissionUtils.hasPermission(activity, new String[]{permission.ACCESS_FINE_LOCATION})) {
if (checkLocationPermission(activity)) {
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 (ActivityCompat.shouldShowRequestPermissionRationale(activity,
permission.ACCESS_FINE_LOCATION)) {
DialogUtil.showAlertDialog(activity, activity.getString(dialogTitleResource),
activity.getString(dialogTextResource),
activity.getString(android.R.string.ok),
activity.getString(android.R.string.cancel),
() -> {
ActivityCompat.requestPermissions(activity,
new String[]{permission.ACCESS_FINE_LOCATION}, 1);
},
() -> callback.onLocationPermissionDenied(
activity.getString(R.string.upload_map_location_access)),
null,
false);
} else {
ActivityCompat.requestPermissions(activity, new String[]{permission.ACCESS_FINE_LOCATION},
ActivityCompat.requestPermissions(activity,
new String[]{permission.ACCESS_FINE_LOCATION},
RequestCodes.LOCATION);
}
}
}
public void showLocationOffDialog(Activity activity) {
/**
* Shows a dialog for user to open the settings page and turn on location services
*
* @param activity Activity object
* @param dialogTextResource int id of the required string resource
*/
public void showLocationOffDialog(Activity activity, int dialogTextResource) {
DialogUtil
.showAlertDialog(activity,
activity.getString(R.string.ask_to_turn_location_on),
activity.getString(R.string.in_app_camera_needs_location),
activity.getString(dialogTextResource),
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)));
() -> Toast.makeText(activity, activity.getString(dialogTextResource),
Toast.LENGTH_LONG).show()
);
}
/**
* Open location source settings so that apps with location access can access it
* Opens the location access page in settings, for user to turn on location services
*
* TODO: modify it to fix https://github.com/commons-app/apps-android-commons/issues/5255
* @param activity Activtiy object
*/
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) {
if (intent.resolveActivity(packageManager) != null) {
activity.startActivity(intent);
} else {
Toast.makeText(activity, R.string.cannot_open_location_settings, Toast.LENGTH_LONG)
.show();
}
}
/**
* Shows a dialog for user to open the app's settings page and give location permission
*
* @param activity Activity object
* @param dialogTextResource int id of the required string resource
*/
public void showAppSettingsDialog(Activity activity, int dialogTextResource) {
DialogUtil
.showAlertDialog(activity, activity.getString(R.string.location_permission_title),
activity.getString(dialogTextResource),
activity.getString(R.string.title_app_shortcut_setting),
activity.getString(R.string.cancel),
() -> openAppSettings(activity),
() -> Toast.makeText(activity, activity.getString(dialogTextResource),
Toast.LENGTH_LONG).show()
);
}
/**
* Opens detailed settings page of the app for the user to turn on location services
*
* @param activity Activity object
*/
public void openAppSettings(Activity activity) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri);
activity.startActivity(intent);
}
/**
* Check if apps have access to location even after having individual access
*
* @return
* @return Returns true if location services are on and false otherwise
*/
public boolean isLocationAccessToAppsTurnedOn() {
return (locationManager.isNetworkProviderEnabled() || locationManager.isGPSProviderEnabled());
return (locationManager.isNetworkProviderEnabled()
|| locationManager.isGPSProviderEnabled());
}
/**
* Checks if location permission is already granted or not
*
* @param activity Activity object
* @return Returns true if location permission is granted and false otherwise
*/
public boolean checkLocationPermission(Activity activity) {
return PermissionUtils.hasPermission(activity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
}
/**
* Handle onPermissionDenied within individual classes based on the requirements
*/
public interface LocationPermissionCallback {
void onLocationPermissionDenied(String toastMessage);
void onLocationPermissionGranted();
}
}