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 9a1c5c935..035f542b3 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 @@ -4,12 +4,14 @@ import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment. import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_ZOOM; import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL; +import android.Manifest.permission; import android.annotation.SuppressLint; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Drawable; +import android.location.LocationManager; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.Html; @@ -21,12 +23,14 @@ 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; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.AppCompatTextView; import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.google.android.material.floatingactionbutton.FloatingActionButton; import fr.free.nrw.commons.CameraPosition; @@ -39,9 +43,9 @@ import fr.free.nrw.commons.auth.csrf.CsrfTokenClient; import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException; import fr.free.nrw.commons.coordinates.CoordinateEditHelper; import fr.free.nrw.commons.filepicker.Constants; +import fr.free.nrw.commons.kvstore.BasicKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.location.LocationPermissionsHelper; -import fr.free.nrw.commons.location.LocationPermissionsHelper.Dialog; import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermissionCallback; import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.theme.BaseActivity; @@ -135,6 +139,7 @@ public class LocationPickerActivity extends BaseActivity implements @Named("default_preferences") public JsonKvStore applicationKvStore; + BasicKvStore store; /** * isDarkTheme: for keeping a track of the device theme and modifying the map theme accordingly */ @@ -145,6 +150,8 @@ public class LocationPickerActivity extends BaseActivity implements @Inject LocationServiceManager locationManager; + LocationPermissionsHelper locationPermissionsHelper; + @Inject SessionManager sessionManager; @@ -163,6 +170,7 @@ public class LocationPickerActivity extends BaseActivity implements isDarkTheme = systemThemeUtils.isDeviceInNightMode(); moveToCurrentLocation = false; + store = new BasicKvStore(this, "LocationPermissions"); getWindow().requestFeature(Window.FEATURE_ACTION_BAR); final ActionBar actionBar = getSupportActionBar(); @@ -482,19 +490,10 @@ public class LocationPickerActivity extends BaseActivity implements * Center the map at user's current location */ private void requestLocationPermissions() { - LocationPermissionsHelper.Dialog locationAccessDialog = new Dialog( - R.string.location_permission_title, - R.string.upload_map_location_access - ); - - LocationPermissionsHelper.Dialog locationOffDialog = new Dialog( - R.string.ask_to_turn_location_on, - R.string.upload_map_location_access - ); - LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper( + locationPermissionsHelper = new LocationPermissionsHelper( this, locationManager, this); - locationPermissionsHelper.handleLocationPermissions(locationAccessDialog, - locationOffDialog); + locationPermissionsHelper.requestForLocationAccess(R.string.location_permission_title, + R.string.upload_map_location_access); } @Override @@ -505,7 +504,7 @@ public class LocationPickerActivity extends BaseActivity implements && grantResults[0] == PackageManager.PERMISSION_GRANTED) { onLocationPermissionGranted(); } else { - onLocationPermissionDenied(""); + onLocationPermissionDenied(getString(R.string.upload_map_location_access)); } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } @@ -524,21 +523,50 @@ public class LocationPickerActivity extends BaseActivity implements @Override public void onLocationPermissionDenied(String toastMessage) { - //do nothing + if (!ActivityCompat.shouldShowRequestPermissionRationale(this, + permission.ACCESS_FINE_LOCATION)) { + if (!locationPermissionsHelper.checkLocationPermission(this)) { + if (store.getBoolean("isPermissionDenied", false)) { + // means user has denied location permission twice or checked the "Don't show again" + locationPermissionsHelper.showAppSettingsDialog(this, + R.string.upload_map_location_access); + } else { + Toast.makeText(getBaseContext(), toastMessage, Toast.LENGTH_LONG).show(); + } + store.putBoolean("isPermissionDenied", true); + } + } else { + Toast.makeText(getBaseContext(), toastMessage, Toast.LENGTH_LONG).show(); + } } @Override public void onLocationPermissionGranted() { + if (moveToCurrentLocation || !(activity.equals("MediaActivity"))) { + if (locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) { + locationManager.requestLocationUpdatesFromProvider( + LocationManager.NETWORK_PROVIDER); + locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); + getLocation(); + } else { + getLocation(); + locationPermissionsHelper.showLocationOffDialog(this, + R.string.ask_to_turn_location_on_text); + } + } + } + + /** + * Gets new location if locations services are on, else gets last location + */ + private void getLocation() { fr.free.nrw.commons.location.LatLng currLocation = locationManager.getLastLocation(); if (currLocation != null) { GeoPoint currLocationGeopoint = new GeoPoint(currLocation.getLatitude(), currLocation.getLongitude()); addLocationMarker(currLocationGeopoint); - if (moveToCurrentLocation) { - mapView.getController().setCenter(currLocationGeopoint); - mapView.getController().animateTo(currLocationGeopoint); - moveToCurrentLocation = false; - } + mapView.getController().setCenter(currLocationGeopoint); + mapView.getController().animateTo(currLocationGeopoint); markerImage.setTranslationY(0); } } 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 216b56712..65d0e45a8 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 @@ -45,7 +45,7 @@ public class BookmarkLocationsFragment extends DaggerFragment { contributionController.locationPermissionCallback.onLocationPermissionGranted(); } else { if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - contributionController.handleShowRationaleFlowCameraLocation(getActivity()); + contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher); } else { contributionController.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied)); } 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 140c7d67d..7c48bb2b0 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 @@ -17,7 +17,6 @@ import fr.free.nrw.commons.filepicker.UploadableFile; import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LocationPermissionsHelper; -import fr.free.nrw.commons.location.LocationPermissionsHelper.Dialog; import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermissionCallback; import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.nearby.Place; @@ -84,15 +83,6 @@ public class ContributionController { */ 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 - ); - - LocationPermissionsHelper.Dialog locationOffDialog = new Dialog( - R.string.ask_to_turn_location_on, - R.string.in_app_camera_needs_location - ); locationPermissionCallback = new LocationPermissionCallback() { @Override public void onLocationPermissionDenied(String toastMessage) { @@ -106,7 +96,12 @@ public class ContributionController { @Override public void onLocationPermissionGranted() { - initiateCameraUpload(activity); + if (!locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) { + showLocationOffDialog(activity, R.string.in_app_camera_needs_location, + R.string.in_app_camera_location_unavailable); + } else { + initiateCameraUpload(activity); + } } }; @@ -115,22 +110,46 @@ public class ContributionController { if (inAppCameraLocationPermissionLauncher != null) { inAppCameraLocationPermissionLauncher.launch( new String[]{permission.ACCESS_FINE_LOCATION}); - } else { - locationPermissionsHelper.handleLocationPermissions(locationAccessDialog, - locationOffDialog); } } - public void handleShowRationaleFlowCameraLocation(Activity activity) { + /** + * Shows a dialog alerting the user about location services being off + * and asking them to turn it on + * TODO: Add a seperate callback in LocationPermissionsHelper for this. + * Ref: https://github.com/commons-app/apps-android-commons/pull/5494/files#r1510553114 + * + * @param activity Activity reference + * @param dialogTextResource Resource id of text to be shown in dialog + * @param toastTextResource Resource id of text to be shown in toast + */ + private void showLocationOffDialog(Activity activity, int dialogTextResource, + int toastTextResource) { + DialogUtil + .showAlertDialog(activity, + activity.getString(R.string.ask_to_turn_location_on), + activity.getString(dialogTextResource), + activity.getString(R.string.title_app_shortcut_setting), + activity.getString(R.string.cancel), + () -> locationPermissionsHelper.openLocationSettings(activity), + () -> { + Toast.makeText(activity, activity.getString(toastTextResource), + Toast.LENGTH_LONG).show(); + initiateCameraUpload(activity); + } + ); + } + + public void handleShowRationaleFlowCameraLocation(Activity activity, + ActivityResultLauncher inAppCameraLocationPermissionLauncher) { 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); - } + createDialogsAndHandleLocationPermissions(activity, + inAppCameraLocationPermissionLauncher); }, () -> locationPermissionCallback.onLocationPermissionDenied( activity.getString(R.string.in_app_camera_location_permission_denied)), @@ -162,6 +181,7 @@ public class ContributionController { inAppCameraLocationPermissionLauncher); }, () -> { + ViewUtil.showLongToast(activity, R.string.in_app_camera_location_permission_denied); defaultKvStore.putBoolean("inAppCameraLocationPref", false); initiateCameraUpload(activity); }, 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 9186b62fc..189b2665f 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 @@ -147,21 +147,20 @@ public class ContributionsFragment areAllGranted = areAllGranted && b; } - if (areAllGranted) { - onLocationPermissionGranted(); + if (areAllGranted) { + onLocationPermissionGranted(); + } else { + if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) + && store.getBoolean("displayLocationPermissionForCardView", true) + && !store.getBoolean("doNotAskForLocationPermission", false) + && (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) { + binding.cardViewNearby.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION; } else { - if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) - && store.getBoolean("displayLocationPermissionForCardView", true) - && !store.getBoolean("doNotAskForLocationPermission", false) - && (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) { - binding.cardViewNearby.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION; - showNearbyCardPermissionRationale(); - } else { - displayYouWontSeeNearbyMessage(); - } + displayYouWontSeeNearbyMessage(); } } - }); + } + }); @NonNull public static ContributionsFragment newInstance() { @@ -537,6 +536,7 @@ public class ContributionsFragment private void displayYouWontSeeNearbyMessage() { ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.unable_to_display_nearest_place)); + // Set to true as the user doesn't want the app to ask for location permission anymore store.putBoolean("doNotAskForLocationPermission", true); } 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 fb48c3c65..2dbe8aff0 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 @@ -98,26 +98,30 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl private int contributionsSize; private 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; - } + 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()); + if (areAllGranted) { + controller.locationPermissionCallback.onLocationPermissionGranted(); } else { - controller.locationPermissionCallback.onLocationPermissionDenied( - getActivity().getString(R.string.in_app_camera_location_permission_denied)); + if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { + controller.handleShowRationaleFlowCameraLocation(getActivity(), + inAppCameraLocationPermissionLauncher); + } else { + controller.locationPermissionCallback.onLocationPermissionDenied( + getActivity().getString( + R.string.in_app_camera_location_permission_denied)); + } } } - } - }); + }); @Override diff --git a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapContract.java b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapContract.java index 935c1ed5b..feb66bf55 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapContract.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapContract.java @@ -11,11 +11,9 @@ public class ExploreMapContract { interface View { boolean isNetworkConnectionEstablished(); - void populatePlaces(LatLng currentLatLng); - void checkPermissionsAndPerformAction(); - void recenterMap(LatLng currentLatLng); - void showLocationOffDialog(); - void openLocationSettings(); + void populatePlaces(LatLng curlatLng); + void askForLocationPermission(); + void recenterMap(LatLng curLatLng); void hideBottomDetailsSheet(); LatLng getMapCenter(); LatLng getMapFocus(); 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 b4c2c32d6..52a5571e9 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 @@ -48,8 +48,11 @@ import fr.free.nrw.commons.databinding.FragmentExploreMapBinding; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.explore.ExploreMapRootFragment; import fr.free.nrw.commons.explore.paging.LiveDataConverter; +import fr.free.nrw.commons.filepicker.Constants; import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.location.LatLng; +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.location.LocationUpdateListener; import fr.free.nrw.commons.media.MediaClient; @@ -65,7 +68,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import java.util.ArrayList; import java.util.List; -import java.util.Map; import javax.inject.Inject; import javax.inject.Named; import org.osmdroid.events.MapEventsReceiver; @@ -87,7 +89,7 @@ import org.osmdroid.views.overlay.TilesOverlay; import timber.log.Timber; public class ExploreMapFragment extends CommonsDaggerSupportFragment - implements ExploreMapContract.View, LocationUpdateListener { + implements ExploreMapContract.View, LocationUpdateListener, LocationPermissionCallback { private BottomSheetBehavior bottomSheetDetailsBehavior; private BroadcastReceiver broadcastReceiver; @@ -119,48 +121,40 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment BookmarkLocationsDao bookmarkLocationDao; // May be needed in future if we want to integrate bookmarking explore places @Inject SystemThemeUtils systemThemeUtils; + LocationPermissionsHelper locationPermissionsHelper; private ExploreMapPresenter presenter; public FragmentExploreMapBinding binding; - 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(); + private ActivityResultLauncher activityResultLauncher = registerForActivityResult( + new ActivityResultContracts.RequestPermission(), isGranted -> { + if (isGranted) { + 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_explore), + getActivity().getString(android.R.string.ok), + getActivity().getString(android.R.string.cancel), + () -> { + askForLocationPermission(); + }, + null, + null, + false); } 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; + if (isPermissionDenied) { + locationPermissionsHelper.showAppSettingsDialog(getActivity(), + R.string.explore_map_needs_location); } - + Timber.d("The user checked 'Don't ask again' or denied the permission twice"); + isPermissionDenied = true; } } }); - @NonNull public static ExploreMapFragment newInstance() { ExploreMapFragment fragment = new ExploreMapFragment(); @@ -184,7 +178,7 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment setSearchThisAreaButtonVisibility(false); binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution))); initNetworkBroadCastReceiver(); - + locationPermissionsHelper = new LocationPermissionsHelper(getActivity(),locationManager,this); if (presenter == null) { presenter = new ExploreMapPresenter(bookmarkLocationDao); } @@ -278,7 +272,9 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment } }); - + if (!locationPermissionsHelper.checkLocationPermission(getActivity())) { + askForLocationPermission(); + } } @Override @@ -288,8 +284,7 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment presenter.attachView(this); registerNetworkReceiver(); if (isResumed()) { - if (!isPermissionDenied && !applicationKvStore - .getBoolean("doNotAskForLocationPermission", false)) { + if (locationPermissionsHelper.checkLocationPermission(getActivity())) { performMapReadyActions(); } else { startMapWithoutPermission(); @@ -297,8 +292,24 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment } } + @Override + public void onPause() { + super.onPause(); + // unregistering the broadcastReceiver, as it was causing an exception and a potential crash + unregisterNetworkReceiver(); + } + + + /** + * Unregisters the networkReceiver + */ + private void unregisterNetworkReceiver() { + if (getActivity() != null) { + getActivity().unregisterReceiver(broadcastReceiver); + } + } + private void startMapWithoutPermission() { - applicationKvStore.putBoolean("doNotAskForLocationPermission", true); lastKnownLocation = MapUtils.defaultLatLng; moveCameraToPosition( new GeoPoint(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude())); @@ -316,13 +327,14 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment binding.mapView.getOverlayManager().getTilesOverlay() .setColorFilter(TilesOverlay.INVERT_COLORS); } - if (!applicationKvStore.getBoolean("doNotAskForLocationPermission", false) || - PermissionUtils.hasPermission(getActivity(), - new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) { - checkPermissionsAndPerformAction(); - } else { + if (applicationKvStore.getBoolean("doNotAskForLocationPermission", false) && + !locationPermissionsHelper.checkLocationPermission(getActivity())) { isPermissionDenied = true; } + lastKnownLocation = MapUtils.defaultLatLng; + moveCameraToPosition( + new GeoPoint(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude())); + presenter.onMapReady(exploreMapController); } private void initViews() { @@ -394,7 +406,6 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment public void populatePlaces(LatLng currentLatLng) { final Observable nearbyPlacesInfoObservable; if (currentLatLng == null) { - checkPermissionsAndPerformAction(); return; } if (currentLatLng.equals(getLastMapFocus())) { // Means we are checking around current location @@ -417,8 +428,9 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment }, throwable -> { Timber.d(throwable); - showErrorMessage(getString(R.string.error_fetching_nearby_places) - + throwable.getLocalizedMessage()); + // Not showing the user, throwable localizedErrorMessage + showErrorMessage(getString(R.string.error_fetching_nearby_places)); + setProgressBarVisibility(false); presenter.lockUnlockNearby(false); })); @@ -445,9 +457,9 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment } @Override - public void checkPermissionsAndPerformAction() { - Timber.d("Checking permission and perfoming action"); - activityResultLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION}); + public void askForLocationPermission() { + Timber.d("Asking for location permission"); + activityResultLauncher.launch(permission.ACCESS_FINE_LOCATION); } private void locationPermissionGranted() { @@ -466,9 +478,9 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment locationManager.requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER); locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); setProgressBarVisibility(true); - } else { - Toast.makeText(getContext(), getString(R.string.nearby_location_not_available), - Toast.LENGTH_LONG).show(); + } + else { + locationPermissionsHelper.showLocationOffDialog(getActivity(), R.string.ask_to_turn_location_on_text); } presenter.onMapReady(exploreMapController); registerUnregisterLocationListener(false); @@ -480,13 +492,24 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment @Override public void recenterMap(LatLng currentLatLng) { - if (isPermissionDenied || currentLatLng == null) { - recenterToUserLocation = true; - checkPermissionsAndPerformAction(); - if (!isPermissionDenied && !(locationManager.isNetworkProviderEnabled() - || locationManager.isGPSProviderEnabled())) { - showLocationOffDialog(); + // if user has denied permission twice, then show dialog + if (isPermissionDenied) { + if (locationPermissionsHelper.checkLocationPermission(getActivity())) { + // this will run when user has given permission by opening app's settings + isPermissionDenied = false; + recenterMap(currentLatLng); + } else { + askForLocationPermission(); } + } else { + if (!locationPermissionsHelper.checkLocationPermission(getActivity())) { + askForLocationPermission(); + } else { + locationPermissionGranted(); + } + } + if (currentLatLng == null) { + recenterToUserLocation = true; return; } recenterMarkerToPosition(new GeoPoint(currentLatLng.getLatitude(), currentLatLng.getLongitude())); @@ -514,31 +537,6 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment } } - @Override - public void showLocationOffDialog() { - // This creates a dialog box that prompts the user to enable location - DialogUtil - .showAlertDialog(getActivity(), getString(R.string.ask_to_turn_location_on), - getString(R.string.nearby_needs_location), - getString(R.string.yes), getString(R.string.no), this::openLocationSettings, null); - } - - @Override - public void openLocationSettings() { - // This method opens the location settings of the device along with a followup toast. - final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); - final PackageManager packageManager = getActivity().getPackageManager(); - - if (intent.resolveActivity(packageManager) != null) { - startActivity(intent); - Toast.makeText(getContext(), R.string.recommend_high_accuracy_mode, Toast.LENGTH_LONG) - .show(); - } else { - Toast.makeText(getContext(), R.string.cannot_open_location_settings, Toast.LENGTH_LONG) - .show(); - } - } - @Override public void hideBottomDetailsSheet() { bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); @@ -843,7 +841,20 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment if (mapCenter != null) { latLnge = new fr.free.nrw.commons.location.LatLng( mapCenter.getLatitude(), mapCenter.getLongitude(), 100); + } else { + if (applicationKvStore.getString("LastLocation") != null) { + final String[] locationLatLng + = applicationKvStore.getString("LastLocation").split(","); + lastKnownLocation + = new fr.free.nrw.commons.location.LatLng(Double.parseDouble(locationLatLng[0]), + Double.parseDouble(locationLatLng[1]), 1f); + latLnge = lastKnownLocation; + } else { + latLnge = new fr.free.nrw.commons.location.LatLng(51.506255446947776, + -0.07483536015053005, 1f); + } } + moveCameraToPosition(new GeoPoint(latLnge.getLatitude(),latLnge.getLongitude())); return latLnge; } @@ -902,4 +913,10 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment } }; } + + @Override + public void onLocationPermissionDenied(String toastMessage) {} + + @Override + public void onLocationPermissionGranted() {} } diff --git a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapPresenter.java b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapPresenter.java index c07aae24c..94b9cf5ad 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapPresenter.java @@ -131,7 +131,6 @@ public class ExploreMapPresenter public void onMapReady(ExploreMapController exploreMapController) { this.exploreMapController = exploreMapController; - exploreMapFragmentView.addSearchThisAreaButtonAction(); if (null != exploreMapFragmentView) { exploreMapFragmentView.addSearchThisAreaButtonAction(); initializeMapOperations(); @@ -141,7 +140,6 @@ public class ExploreMapPresenter public void initializeMapOperations() { lockUnlockNearby(false); updateMap(LOCATION_SIGNIFICANTLY_CHANGED); - exploreMapFragmentView.addSearchThisAreaButtonAction(); } public Observable loadAttractionsFromLocation(LatLng currentLatLng, 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 d72cb0832..77e089c9c 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 @@ -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(); } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java b/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java index 8763926bc..df999dbf0 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java @@ -24,7 +24,7 @@ public interface NearbyParentFragmentContract { boolean isListBottomSheetExpanded(); - void checkPermissionsAndPerformAction(); + void askForLocationPermission(); void displayLoginSkippedWarning(); @@ -36,8 +36,6 @@ public interface NearbyParentFragmentContract { void recenterMap(LatLng currentLatLng); - void showLocationOffDialog(); - void openLocationSettings(); void hideBottomSheet(); 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 4b5b78d5d..e4bc8ad7b 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 @@ -6,7 +6,6 @@ import static fr.free.nrw.commons.location.LocationServiceManager.LocationChange import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; -import android.Manifest; import android.Manifest.permission; import android.annotation.SuppressLint; import android.app.ProgressDialog; @@ -67,6 +66,8 @@ import fr.free.nrw.commons.contributions.MainActivity.ActiveFragment; import fr.free.nrw.commons.databinding.FragmentNearbyParentBinding; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; 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.LatLng; import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationUpdateListener; @@ -84,9 +85,9 @@ import fr.free.nrw.commons.upload.FileUtils; import fr.free.nrw.commons.utils.DialogUtil; import fr.free.nrw.commons.utils.ExecutorUtils; import fr.free.nrw.commons.utils.LayoutUtils; +import fr.free.nrw.commons.utils.MapUtils; import fr.free.nrw.commons.utils.NearbyFABUtils; import fr.free.nrw.commons.utils.NetworkUtils; -import fr.free.nrw.commons.utils.PermissionUtils; import fr.free.nrw.commons.utils.SystemThemeUtils; import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.wikidata.WikidataEditListener; @@ -130,7 +131,8 @@ import timber.log.Timber; public class NearbyParentFragment extends CommonsDaggerSupportFragment implements NearbyParentFragmentContract.View, - WikidataEditListener.WikidataP18EditListener, LocationUpdateListener { + WikidataEditListener.WikidataP18EditListener, LocationUpdateListener, + LocationPermissionCallback { FragmentNearbyParentBinding binding; @@ -152,6 +154,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment SystemThemeUtils systemThemeUtils; @Inject CommonPlaceClickActions commonPlaceClickActions; + private LocationPermissionsHelper locationPermissionsHelper; private NearbyFilterSearchRecyclerViewAdapter nearbyFilterSearchRecyclerViewAdapter; private BottomSheetBehavior bottomSheetListBehavior; private BottomSheetBehavior bottomSheetDetailsBehavior; @@ -201,7 +204,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment controller.locationPermissionCallback.onLocationPermissionGranted(); } else { if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - controller.handleShowRationaleFlowCameraLocation(getActivity()); + controller.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher); } else { controller.locationPermissionCallback.onLocationPermissionDenied( getActivity().getString( @@ -223,15 +226,17 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment getActivity().getString(android.R.string.ok), getActivity().getString(android.R.string.cancel), () -> { - if (!(locationManager.isNetworkProviderEnabled() - || locationManager.isGPSProviderEnabled())) { - showLocationOffDialog(); - } + askForLocationPermission(); }, - () -> isPermissionDenied = true, + null, null, false); } else { + if (isPermissionDenied) { + locationPermissionsHelper.showAppSettingsDialog(getActivity(), + R.string.nearby_needs_location); + } + Timber.d("The user checked 'Don't ask again' or denied the permission twice"); isPermissionDenied = true; } } @@ -323,7 +328,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } else { binding.rlContainerWlmMonthMessage.setVisibility(View.GONE); } - + locationPermissionsHelper = new LocationPermissionsHelper(getActivity(), locationManager, + this); presenter.attachView(this); isPermissionDenied = false; recenterToUserLocation = false; @@ -426,7 +432,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } initNearbyFilter(); addCheckBoxCallback(); - performMapReadyActions(); moveCameraToPosition(lastMapFocus); initRvNearbyList(); onResume(); @@ -471,6 +476,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment binding.tvLearnMore.setOnClickListener(v ->onLearnMoreClicked()); binding.nearbyFilter.ivToggleChips.setOnClickListener(v -> onToggleChipsClicked()); + + if (!locationPermissionsHelper.checkLocationPermission(getActivity())) { + askForLocationPermission(); + } } /** @@ -527,14 +536,18 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private void performMapReadyActions() { if (((MainActivity) getActivity()).activeFragment == ActiveFragment.NEARBY) { - if (!applicationKvStore.getBoolean("doNotAskForLocationPermission", false) || - PermissionUtils.hasPermission(getActivity(), - new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) { - checkPermissionsAndPerformAction(); - } else { + if (applicationKvStore.getBoolean("doNotAskForLocationPermission", false) && + !locationPermissionsHelper.checkLocationPermission(getActivity())) { isPermissionDenied = true; } } + presenter.onMapReady(); + } + + @Override + public void askForLocationPermission() { + Timber.d("Asking for location permission"); + locationPermissionLauncher.launch(permission.ACCESS_FINE_LOCATION); } private void locationPermissionGranted() { @@ -554,8 +567,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); setProgressBarVisibility(true); } else { - Toast.makeText(getContext(), getString(R.string.nearby_location_not_available), - Toast.LENGTH_LONG).show(); + locationPermissionsHelper.showLocationOffDialog(getActivity(), R.string.ask_to_turn_location_on_text); } presenter.onMapReady(); registerUnregisterLocationListener(false); @@ -568,15 +580,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment presenter.attachView(this); registerNetworkReceiver(); if (isResumed() && ((MainActivity) getActivity()).activeFragment == ActiveFragment.NEARBY) { - if (!isPermissionDenied && !applicationKvStore.getBoolean( - "doNotAskForLocationPermission", false)) { - if (!locationManager.isGPSProviderEnabled()) { - startMapWithCondition("Without GPS"); - } else { - startTheMap(); - } + if (locationPermissionsHelper.checkLocationPermission(getActivity())) { + locationPermissionGranted(); } else { - startMapWithCondition("Without Permission"); + startMapWithoutPermission(); } } } @@ -586,12 +593,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment * coordinates, other than that it points to the last known location which can be get by the key * "LastLocation" from applicationKvStore * - * @param condition : for which condition the map should start */ - private void startMapWithCondition(final String condition) { - if (condition.equals("Without Permission")) { - applicationKvStore.putBoolean("doNotAskForLocationPermission", true); - } + private void startMapWithoutPermission() { if (applicationKvStore.getString("LastLocation") != null) { final String[] locationLatLng = applicationKvStore.getString("LastLocation").split(","); @@ -599,12 +602,13 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment = new fr.free.nrw.commons.location.LatLng(Double.parseDouble(locationLatLng[0]), Double.parseDouble(locationLatLng[1]), 1f); } else { - lastKnownLocation = new fr.free.nrw.commons.location.LatLng(51.50550, - -0.07520, 1f); + lastKnownLocation = MapUtils.defaultLatLng; } if (binding.map != null) { - recenterMap(lastKnownLocation); + moveCameraToPosition( + new GeoPoint(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude())); } + presenter.onMapReady(); } private void registerNetworkReceiver() { @@ -1426,12 +1430,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment // TODO } - @Override - public void checkPermissionsAndPerformAction() { - Timber.d("Checking permission and perfoming action"); - locationPermissionLauncher.launch(permission.ACCESS_FINE_LOCATION); - } - /** * Starts animation of fab plus (turning on opening) and other FABs */ @@ -1559,6 +1557,14 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment return presenter.backButtonClicked(); } + @Override + public void onLocationPermissionDenied(String toastMessage) { + } + + @Override + public void onLocationPermissionGranted() { + } + /** * onLogoutComplete is called after shared preferences and data stored in local database are * cleared. @@ -1856,18 +1862,37 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Override public void recenterMap(fr.free.nrw.commons.location.LatLng currentLatLng) { - if (isPermissionDenied || currentLatLng == null) { - recenterToUserLocation = true; - checkPermissionsAndPerformAction(); - if (!isPermissionDenied && !(locationManager.isNetworkProviderEnabled() - || locationManager.isGPSProviderEnabled())) { - showLocationOffDialog(); + // if user has denied permission twice, then show dialog + if (isPermissionDenied) { + if (locationPermissionsHelper.checkLocationPermission(getActivity())) { + // this will run when user has given permission by opening app's settings + isPermissionDenied = false; + locationPermissionGranted(); + return; + } else { + askForLocationPermission(); } + } else { + if (!locationPermissionsHelper.checkLocationPermission(getActivity())) { + askForLocationPermission(); + } else { + locationPermissionGranted(); + } + } + if (currentLatLng == null) { + recenterToUserLocation = true; return; } - addCurrentLocationMarker(currentLatLng); - binding.map.getController() - .animateTo(new GeoPoint(currentLatLng.getLatitude(), currentLatLng.getLongitude())); + + /* + * FIXME: With the revamp of the location permission helper in the MR + * #5494[1], there is a doubt that the following code is redundant. + * If we could confirm the same, the following code can be removed. If it + * turns out to be necessary, we could replace this with a comment + * clarifying why it is necessary. + * + * Ref: https://github.com/commons-app/apps-android-commons/pull/5494#discussion_r1560404794 + */ if (lastMapFocus != null) { Location mylocation = new Location(""); Location dest_location = new Location(""); @@ -1890,15 +1915,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } } - @Override - public void showLocationOffDialog() { - // This creates a dialog box that prompts the user to enable location - DialogUtil - .showAlertDialog(getActivity(), getString(R.string.ask_to_turn_location_on), - getString(R.string.nearby_needs_location), - getString(R.string.yes), getString(R.string.no), this::openLocationSettings, null); - } - @Override public void openLocationSettings() { // This method opens the location settings of the device along with a followup toast. @@ -2103,7 +2119,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment super.setUserVisibleHint(isVisibleToUser); this.isVisibleToUser = isVisibleToUser; if (isResumed() && isVisibleToUser) { - startTheMap(); + performMapReadyActions(); } else { if (null != bottomSheetListBehavior) { bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); @@ -2115,10 +2131,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } } - private void startTheMap() { - performMapReadyActions(); - } - /** * Clears all markers from the map and resets certain map overlays and gestures. After clearing * markers, it re-adds a scale bar overlay and rotation gesture overlay to the map. diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/presenter/NearbyParentFragmentPresenter.java b/app/src/main/java/fr/free/nrw/commons/nearby/presenter/NearbyParentFragmentPresenter.java index 06608d6b9..440cb5638 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/presenter/NearbyParentFragmentPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/presenter/NearbyParentFragmentPresenter.java @@ -92,7 +92,6 @@ public class NearbyParentFragmentPresenter public void initializeMapOperations() { lockUnlockNearby(false); updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED); - this.nearbyParentFragmentView.addSearchThisAreaButtonAction(); nearbyParentFragmentView.setCheckBoxAction(); } 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 253f3cd55..94e799aa2 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 @@ -93,7 +93,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { areAllGranted = areAllGranted && b; } if (!areAllGranted && shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - contributionController.handleShowRationaleFlowCameraLocation(getActivity()); + contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher); } } }); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f05b8b2b7..04aa6af9b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -282,6 +282,8 @@ Nearby might not work properly, Location not available. Location access denied. Please set your location manually to use this feature. Permission required to display a list of nearby places + Permission required to display a list of nearby images + Directions Wikidata @@ -355,7 +357,7 @@ Share App Rotate - Error fetching nearby places. + Could not load nearby places No pictures in this area No nearby places around Error fetching nearby monuments. @@ -586,7 +588,7 @@ Upload your first media by tapping on the add button. Could not add coordinates. Could not add descriptions. Could not add caption. - Unable to get coordinates. + Image\'s coordinates not updated Unable to get descriptions. Edit descriptions and captions @@ -623,8 +625,10 @@ Upload your first media by tapping on the add button. Failed to open location settings. Please turn on location manually For best results, choose the High Accuracy mode. Turn on location? + Kindly turn on location services for the app show your current location Nearby needs location enabled to work properly - You need to give access to your current location to set location automatically. + Explore map needs location permission to display nearby images + You need to give location permission to set location automatically. Did you shoot these two pictures at the same place? Do you want to use the latitude/longitude of the picture on the right? Load More No places found, try changing your search criteria. diff --git a/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentPresenterTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentPresenterTest.kt index e4bc42d88..f3f0863f5 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentPresenterTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentPresenterTest.kt @@ -71,7 +71,6 @@ class NearbyParentFragmentPresenterTest { verify(nearbyParentFragmentView).`setProgressBarVisibility`(true) assertTrue(null == nearbyParentFragmentView.mapCenter) verify(nearbyParentFragmentView).populatePlaces(null) - verify(nearbyParentFragmentView).addSearchThisAreaButtonAction() verify(nearbyParentFragmentView).setCheckBoxAction() } @@ -121,7 +120,7 @@ class NearbyParentFragmentPresenterTest { /** * Test updateMapAndList method returns with zero interactions when last location is null */ - @Test @Ignore + @Test fun testUpdateMapAndListWhenLastLocationIsNull() { whenever(nearbyParentFragmentView.isNetworkConnectionEstablished()).thenReturn(true) whenever(nearbyParentFragmentView.getLastLocation()).thenReturn(null) diff --git a/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentUnitTest.kt index 018cc50ae..9c812ad28 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/nearby/NearbyParentFragmentUnitTest.kt @@ -379,12 +379,4 @@ class NearbyParentFragmentUnitTest { Assert.assertEquals(shadowActivity.nextStartedActivityForResult, null) } - @Test @Ignore - @Throws(Exception::class) - fun testShowLocationOffDialog() { - fragment.showLocationOffDialog() - val dialog: AlertDialog = ShadowAlertDialog.getLatestDialog() as AlertDialog - Assert.assertEquals(dialog.isShowing, true) - } - -} \ No newline at end of file +}