mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
fixes issues related to location permission denial even when allowed inside in-app camera flow (#5313)
* fixes issues related to location permission denial even when allowed inside in-app camera flow * fixes related to in app camera location permissions
This commit is contained in:
parent
8d604a25fa
commit
9525409b9b
18 changed files with 442 additions and 251 deletions
|
|
@ -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 static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_ZOOM;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
@ -21,7 +22,6 @@ import android.view.animation.OvershootInterpolator;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
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.MapStyle;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.Utils;
|
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.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.location.LocationPermissionsHelper;
|
import fr.free.nrw.commons.location.LocationPermissionsHelper;
|
||||||
import fr.free.nrw.commons.location.LocationPermissionsHelper.Dialog;
|
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
|
* Helps to pick location and return the result with an intent
|
||||||
*/
|
*/
|
||||||
public class LocationPickerActivity extends BaseActivity implements OnMapReadyCallback,
|
public class LocationPickerActivity extends BaseActivity implements OnMapReadyCallback,
|
||||||
OnCameraMoveStartedListener, OnCameraIdleListener, Observer<CameraPosition> {
|
OnCameraMoveStartedListener, OnCameraIdleListener, Observer<CameraPosition>, LocationPermissionCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DROPPED_MARKER_LAYER_ID : id for layer
|
* DROPPED_MARKER_LAYER_ID : id for layer
|
||||||
|
|
@ -474,30 +475,21 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa
|
||||||
R.string.upload_map_location_access
|
R.string.upload_map_location_access
|
||||||
);
|
);
|
||||||
LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper(
|
LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper(
|
||||||
this, locationManager, new LocationPermissionCallback() {
|
this, locationManager, this);
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
locationPermissionsHelper.handleLocationPermissions(locationAccessDialog, locationOffDialog);
|
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
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
@ -539,4 +531,24 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa
|
||||||
super.onLowMemory();
|
super.onLowMemory();
|
||||||
mapView.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.bookmarks.locations;
|
package fr.free.nrw.commons.bookmarks.locations;
|
||||||
|
|
||||||
|
import android.Manifest.permission;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
@ -8,6 +9,9 @@ import android.view.ViewGroup;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
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.CommonPlaceClickActions;
|
||||||
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter;
|
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
|
|
||||||
|
|
@ -36,6 +41,25 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
@Inject BookmarkLocationsDao bookmarkLocationDao;
|
@Inject BookmarkLocationsDao bookmarkLocationDao;
|
||||||
@Inject CommonPlaceClickActions commonPlaceClickActions;
|
@Inject CommonPlaceClickActions commonPlaceClickActions;
|
||||||
private PlaceAdapter adapter;
|
private PlaceAdapter adapter;
|
||||||
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Map<String, Boolean> 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
|
* Create an instance of the fragment with the right bundle parameters
|
||||||
|
|
@ -67,7 +91,8 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
adapter.remove(place);
|
adapter.remove(place);
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
},
|
},
|
||||||
commonPlaceClickActions
|
commonPlaceClickActions,
|
||||||
|
inAppCameraLocationPermissionLauncher
|
||||||
);
|
);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,12 @@ package fr.free.nrw.commons.contributions;
|
||||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.Manifest.permission;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.filepicker.DefaultCallback;
|
import fr.free.nrw.commons.filepicker.DefaultCallback;
|
||||||
|
|
@ -37,9 +39,12 @@ public class ContributionController {
|
||||||
private final JsonKvStore defaultKvStore;
|
private final JsonKvStore defaultKvStore;
|
||||||
private LatLng locationBeforeImageCapture;
|
private LatLng locationBeforeImageCapture;
|
||||||
private boolean isInAppCameraUpload;
|
private boolean isInAppCameraUpload;
|
||||||
|
public LocationPermissionCallback locationPermissionCallback;
|
||||||
|
private LocationPermissionsHelper locationPermissionsHelper;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LocationServiceManager locationManager;
|
LocationServiceManager locationManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ContributionController(@Named("default_preferences") JsonKvStore defaultKvStore) {
|
public ContributionController(@Named("default_preferences") JsonKvStore defaultKvStore) {
|
||||||
this.defaultKvStore = defaultKvStore;
|
this.defaultKvStore = defaultKvStore;
|
||||||
|
|
@ -48,7 +53,8 @@ public class ContributionController {
|
||||||
/**
|
/**
|
||||||
* Check for permissions and initiate camera click
|
* Check for permissions and initiate camera click
|
||||||
*/
|
*/
|
||||||
public void initiateCameraPick(Activity activity) {
|
public void initiateCameraPick(Activity activity,
|
||||||
|
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
||||||
boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
||||||
if (!useExtStorage) {
|
if (!useExtStorage) {
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity);
|
||||||
|
|
@ -56,19 +62,20 @@ public class ContributionController {
|
||||||
}
|
}
|
||||||
|
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
||||||
PermissionUtils.PERMISSIONS_STORAGE,
|
() -> {
|
||||||
() -> {
|
if (defaultKvStore.getBoolean("inAppCameraFirstRun")) {
|
||||||
if (defaultKvStore.getBoolean("inAppCameraFirstRun")) {
|
defaultKvStore.putBoolean("inAppCameraFirstRun", false);
|
||||||
defaultKvStore.putBoolean("inAppCameraFirstRun", false);
|
askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher);
|
||||||
askUserToAllowLocationAccess(activity);
|
} else if (defaultKvStore.getBoolean("inAppCameraLocationPref")) {
|
||||||
} else if(defaultKvStore.getBoolean("inAppCameraLocationPref")) {
|
createDialogsAndHandleLocationPermissions(activity,
|
||||||
createDialogsAndHandleLocationPermissions(activity);
|
inAppCameraLocationPermissionLauncher);
|
||||||
} else {
|
} else {
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
R.string.storage_permission_title,
|
R.string.storage_permission_title,
|
||||||
R.string.write_storage_permission_rationale);
|
R.string.write_storage_permission_rationale,
|
||||||
|
PermissionUtils.PERMISSIONS_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,7 +83,8 @@ public class ContributionController {
|
||||||
*
|
*
|
||||||
* @param activity
|
* @param activity
|
||||||
*/
|
*/
|
||||||
private void createDialogsAndHandleLocationPermissions(Activity activity) {
|
private void createDialogsAndHandleLocationPermissions(Activity activity,
|
||||||
|
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
||||||
LocationPermissionsHelper.Dialog locationAccessDialog = new Dialog(
|
LocationPermissionsHelper.Dialog locationAccessDialog = new Dialog(
|
||||||
R.string.location_permission_title,
|
R.string.location_permission_title,
|
||||||
R.string.in_app_camera_location_permission_rationale
|
R.string.in_app_camera_location_permission_rationale
|
||||||
|
|
@ -86,52 +94,73 @@ public class ContributionController {
|
||||||
R.string.ask_to_turn_location_on,
|
R.string.ask_to_turn_location_on,
|
||||||
R.string.in_app_camera_needs_location
|
R.string.in_app_camera_needs_location
|
||||||
);
|
);
|
||||||
LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper(
|
locationPermissionCallback = new LocationPermissionCallback() {
|
||||||
activity, locationManager,
|
@Override
|
||||||
new LocationPermissionCallback() {
|
public void onLocationPermissionDenied(String toastMessage) {
|
||||||
@Override
|
Toast.makeText(
|
||||||
public void onLocationPermissionDenied(String toastMessage) {
|
activity,
|
||||||
Toast.makeText(
|
toastMessage,
|
||||||
activity,
|
Toast.LENGTH_LONG
|
||||||
toastMessage,
|
).show();
|
||||||
Toast.LENGTH_LONG
|
initiateCameraUpload(activity);
|
||||||
).show();
|
|
||||||
initiateCameraUpload(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLocationPermissionGranted() {
|
|
||||||
initiateCameraUpload(activity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
locationPermissionsHelper.handleLocationPermissions(
|
@Override
|
||||||
locationAccessDialog,
|
public void onLocationPermissionGranted() {
|
||||||
locationOffDialog
|
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.
|
* Suggest user to attach location information with pictures. If the user selects "Yes", then:
|
||||||
* If the user selects "Yes", then:
|
* <p>
|
||||||
*
|
* Location is taken from the EXIF if the default camera application does not redact location
|
||||||
* Location is taken from the EXIF if the default camera application
|
* tags.
|
||||||
* does not redact location tags.
|
* <p>
|
||||||
*
|
* Otherwise, if the EXIF metadata does not have location information, then location captured by
|
||||||
* Otherwise, if the EXIF metadata does not have location information,
|
* the app is used
|
||||||
* then location captured by the app is used
|
|
||||||
*
|
*
|
||||||
* @param activity
|
* @param activity
|
||||||
*/
|
*/
|
||||||
private void askUserToAllowLocationAccess(Activity activity) {
|
private void askUserToAllowLocationAccess(Activity activity,
|
||||||
|
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
||||||
DialogUtil.showAlertDialog(activity,
|
DialogUtil.showAlertDialog(activity,
|
||||||
activity.getString(R.string.in_app_camera_location_permission_title),
|
activity.getString(R.string.in_app_camera_location_permission_title),
|
||||||
activity.getString(R.string.in_app_camera_location_access_explanation),
|
activity.getString(R.string.in_app_camera_location_access_explanation),
|
||||||
activity.getString(R.string.option_allow),
|
activity.getString(R.string.option_allow),
|
||||||
activity.getString(R.string.option_dismiss),
|
activity.getString(R.string.option_dismiss),
|
||||||
()-> {
|
() -> {
|
||||||
defaultKvStore.putBoolean("inAppCameraLocationPref", true);
|
defaultKvStore.putBoolean("inAppCameraLocationPref", true);
|
||||||
createDialogsAndHandleLocationPermissions(activity);
|
createDialogsAndHandleLocationPermissions(activity,
|
||||||
|
inAppCameraLocationPermissionLauncher);
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
defaultKvStore.putBoolean("inAppCameraLocationPref", false);
|
defaultKvStore.putBoolean("inAppCameraLocationPref", false);
|
||||||
|
|
@ -141,15 +170,6 @@ public class ContributionController {
|
||||||
true);
|
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
|
* Initiate gallery picker
|
||||||
*/
|
*/
|
||||||
|
|
@ -161,22 +181,24 @@ public class ContributionController {
|
||||||
* Initiate gallery picker with permission
|
* Initiate gallery picker with permission
|
||||||
*/
|
*/
|
||||||
public void initiateCustomGalleryPickWithPermission(final Activity activity) {
|
public void initiateCustomGalleryPickWithPermission(final Activity activity) {
|
||||||
setPickerConfiguration(activity,true);
|
setPickerConfiguration(activity, true);
|
||||||
|
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
||||||
PermissionUtils.PERMISSIONS_STORAGE,
|
|
||||||
() -> FilePicker.openCustomSelector(activity, 0),
|
() -> FilePicker.openCustomSelector(activity, 0),
|
||||||
R.string.storage_permission_title,
|
R.string.storage_permission_title,
|
||||||
R.string.write_storage_permission_rationale);
|
R.string.write_storage_permission_rationale,
|
||||||
|
PermissionUtils.PERMISSIONS_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open chooser for gallery uploads
|
* 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);
|
setPickerConfiguration(activity, allowMultipleUploads);
|
||||||
boolean openDocumentIntentPreferred = defaultKvStore.getBoolean("openDocumentPhotoPickerPref", true);
|
boolean openDocumentIntentPreferred = defaultKvStore.getBoolean(
|
||||||
|
"openDocumentPhotoPickerPref", true);
|
||||||
FilePicker.openGallery(activity, 0, openDocumentIntentPreferred);
|
FilePicker.openGallery(activity, 0, openDocumentIntentPreferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,11 +206,11 @@ public class ContributionController {
|
||||||
* Sets configuration for file picker
|
* Sets configuration for file picker
|
||||||
*/
|
*/
|
||||||
private void setPickerConfiguration(Activity activity,
|
private void setPickerConfiguration(Activity activity,
|
||||||
boolean allowMultipleUploads) {
|
boolean allowMultipleUploads) {
|
||||||
boolean copyToExternalStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
boolean copyToExternalStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
||||||
FilePicker.configuration(activity)
|
FilePicker.configuration(activity)
|
||||||
.setCopyTakenPhotosToPublicGalleryAppFolder(copyToExternalStorage)
|
.setCopyTakenPhotosToPublicGalleryAppFolder(copyToExternalStorage)
|
||||||
.setAllowMultiplePickInGallery(allowMultipleUploads);
|
.setAllowMultiplePickInGallery(allowMultipleUploads);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -206,36 +228,39 @@ public class ContributionController {
|
||||||
/**
|
/**
|
||||||
* Attaches callback for file picker.
|
* Attaches callback for file picker.
|
||||||
*/
|
*/
|
||||||
public void handleActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
public void handleActivityResult(Activity activity, int requestCode, int resultCode,
|
||||||
FilePicker.handleActivityResult(requestCode, resultCode, data, activity, new DefaultCallback() {
|
Intent data) {
|
||||||
|
FilePicker.handleActivityResult(requestCode, resultCode, data, activity,
|
||||||
|
new DefaultCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCanceled(final ImageSource source, final int type) {
|
public void onCanceled(final ImageSource source, final int type) {
|
||||||
super.onCanceled(source, type);
|
super.onCanceled(source, type);
|
||||||
defaultKvStore.remove(PLACE_OBJECT);
|
defaultKvStore.remove(PLACE_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onImagePickerError(Exception e, FilePicker.ImageSource source, int type) {
|
public void onImagePickerError(Exception e, FilePicker.ImageSource source,
|
||||||
ViewUtil.showShortToast(activity, R.string.error_occurred_in_picking_images);
|
int type) {
|
||||||
}
|
ViewUtil.showShortToast(activity, R.string.error_occurred_in_picking_images);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onImagesPicked(@NonNull List<UploadableFile> imagesFiles, FilePicker.ImageSource source, int type) {
|
public void onImagesPicked(@NonNull List<UploadableFile> imagesFiles,
|
||||||
Intent intent = handleImagesPicked(activity, imagesFiles);
|
FilePicker.ImageSource source, int type) {
|
||||||
activity.startActivity(intent);
|
Intent intent = handleImagesPicked(activity, imagesFiles);
|
||||||
}
|
activity.startActivity(intent);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UploadableFile> handleExternalImagesPicked(Activity activity,
|
public List<UploadableFile> handleExternalImagesPicked(Activity activity,
|
||||||
Intent data) {
|
Intent data) {
|
||||||
return FilePicker.handleExternalImagesPicked(data, activity);
|
return FilePicker.handleExternalImagesPicked(data, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns intent to be passed to upload activity
|
* Returns intent to be passed to upload activity Attaches place object for nearby uploads and
|
||||||
* Attaches place object for nearby uploads and
|
|
||||||
* location before image capture if in-app camera is used
|
* location before image capture if in-app camera is used
|
||||||
*/
|
*/
|
||||||
private Intent handleImagesPicked(Context context,
|
private Intent handleImagesPicked(Context context,
|
||||||
|
|
@ -263,5 +288,4 @@ public class ContributionController {
|
||||||
isInAppCameraUpload = false; // reset the flag for next use
|
isInAppCameraUpload = false; // reset the flag for next use
|
||||||
return shareIntent;
|
return shareIntent;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import static fr.free.nrw.commons.profile.ProfileActivity.KEY_USERNAME;
|
||||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.Manifest.permission;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
@ -21,6 +22,9 @@ import android.widget.CheckBox;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
@ -35,6 +39,7 @@ import fr.free.nrw.commons.profile.ProfileActivity;
|
||||||
import fr.free.nrw.commons.theme.BaseActivity;
|
import fr.free.nrw.commons.theme.BaseActivity;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import androidx.work.WorkManager;
|
import androidx.work.WorkManager;
|
||||||
|
|
@ -117,6 +122,29 @@ public class ContributionsFragment
|
||||||
|
|
||||||
String userName;
|
String userName;
|
||||||
private boolean isUserProfile;
|
private boolean isUserProfile;
|
||||||
|
private ActivityResultLauncher<String[]> nearbyLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Map<String, Boolean> 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
|
@NonNull
|
||||||
public static ContributionsFragment newInstance() {
|
public static ContributionsFragment newInstance() {
|
||||||
|
|
@ -451,12 +479,7 @@ public class ContributionsFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestLocationPermission() {
|
private void requestLocationPermission() {
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
|
nearbyLocationPermissionLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION});
|
||||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
|
||||||
this::onLocationPermissionGranted,
|
|
||||||
this::displayYouWontSeeNearbyMessage,
|
|
||||||
-1,
|
|
||||||
-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLocationPermissionGranted() {
|
private void onLocationPermissionGranted() {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE;
|
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.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
@ -18,6 +19,9 @@ import android.view.animation.AnimationUtils;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.AppCompatTextView;
|
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.SystemThemeUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
@ -114,6 +119,27 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
|
|
||||||
private int contributionsSize;
|
private int contributionsSize;
|
||||||
String userName;
|
String userName;
|
||||||
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Map<String, Boolean> 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
|
@Override
|
||||||
public void onCreate(@Nullable @org.jetbrains.annotations.Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable @org.jetbrains.annotations.Nullable final Bundle savedInstanceState) {
|
||||||
|
|
@ -297,7 +323,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
private void setListeners() {
|
private void setListeners() {
|
||||||
fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
|
fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
|
||||||
fabCamera.setOnClickListener(view -> {
|
fabCamera.setOnClickListener(view -> {
|
||||||
controller.initiateCameraPick(getActivity());
|
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher);
|
||||||
animateFAB(isFabOpen);
|
animateFAB(isFabOpen);
|
||||||
});
|
});
|
||||||
fabGallery.setOnClickListener(view -> {
|
fabGallery.setOnClickListener(view -> {
|
||||||
|
|
@ -393,10 +419,10 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
@Override
|
@Override
|
||||||
public void deleteUpload(final Contribution contribution) {
|
public void deleteUpload(final Contribution contribution) {
|
||||||
DialogUtil.showAlertDialog(getActivity(),
|
DialogUtil.showAlertDialog(getActivity(),
|
||||||
String.format(getString(R.string.cancelling_upload),
|
String.format(Locale.getDefault().getDisplayLanguage(),
|
||||||
Locale.getDefault().getDisplayLanguage()),
|
getString(R.string.cancelling_upload)),
|
||||||
String.format(getString(R.string.cancel_upload_dialog),
|
String.format(Locale.getDefault().getDisplayLanguage(),
|
||||||
Locale.getDefault().getDisplayLanguage()),
|
getString(R.string.cancel_upload_dialog)),
|
||||||
"YES", "NO",
|
"YES", "NO",
|
||||||
() -> {
|
() -> {
|
||||||
ViewUtil.showShortToast(getContext(), R.string.cancelling_upload);
|
ViewUtil.showShortToast(getContext(), R.string.cancelling_upload);
|
||||||
|
|
@ -422,8 +448,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
public void addImageToWikipedia(Contribution contribution) {
|
public void addImageToWikipedia(Contribution contribution) {
|
||||||
DialogUtil.showAlertDialog(getActivity(),
|
DialogUtil.showAlertDialog(getActivity(),
|
||||||
getString(R.string.add_picture_to_wikipedia_article_title),
|
getString(R.string.add_picture_to_wikipedia_article_title),
|
||||||
String.format(getString(R.string.add_picture_to_wikipedia_article_desc),
|
getString(R.string.add_picture_to_wikipedia_article_desc),
|
||||||
Locale.getDefault().getDisplayLanguage()),
|
|
||||||
() -> {
|
() -> {
|
||||||
showAddImageToWikipediaInstructions(contribution);
|
showAddImageToWikipediaInstructions(contribution);
|
||||||
}, () -> {
|
}, () -> {
|
||||||
|
|
|
||||||
|
|
@ -165,11 +165,10 @@ public class MainActivity extends BaseActivity
|
||||||
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
|
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(
|
PermissionUtils.checkPermissionsAndPerformAction(
|
||||||
this,
|
this,
|
||||||
new String[]{permission.ACCESS_MEDIA_LOCATION},
|
|
||||||
() -> {},
|
() -> {},
|
||||||
R.string.media_location_permission_denied,
|
R.string.media_location_permission_denied,
|
||||||
R.string.add_location_manually
|
R.string.add_location_manually,
|
||||||
);
|
permission.ACCESS_MEDIA_LOCATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.Manifest.permission;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -29,6 +30,9 @@ import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.AppCompatTextView;
|
import androidx.appcompat.widget.AppCompatTextView;
|
||||||
|
|
@ -84,6 +88,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
@ -144,6 +149,38 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
|
||||||
@BindView(R.id.title) TextView title;
|
@BindView(R.id.title) TextView title;
|
||||||
@BindView(R.id.category) TextView distance;
|
@BindView(R.id.category) TextView distance;
|
||||||
|
|
||||||
|
private ActivityResultLauncher<String[]> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Map<String, Boolean> 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
|
@NonNull
|
||||||
public static ExploreMapFragment newInstance() {
|
public static ExploreMapFragment newInstance() {
|
||||||
|
|
@ -403,12 +440,7 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
|
||||||
@Override
|
@Override
|
||||||
public void checkPermissionsAndPerformAction() {
|
public void checkPermissionsAndPerformAction() {
|
||||||
Timber.d("Checking permission and perfoming action");
|
Timber.d("Checking permission and perfoming action");
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
|
activityResultLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION});
|
||||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
|
||||||
this::locationPermissionGranted,
|
|
||||||
() -> isPermissionDenied = true,
|
|
||||||
R.string.location_permission_title,
|
|
||||||
R.string.location_permission_rationale_nearby);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void locationPermissionGranted() {
|
private void locationPermissionGranted() {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ public interface Constants {
|
||||||
* Provides the request codes utilised by the FilePicker
|
* Provides the request codes utilised by the FilePicker
|
||||||
*/
|
*/
|
||||||
interface RequestCodes {
|
interface RequestCodes {
|
||||||
|
int LOCATION = 1;
|
||||||
int FILE_PICKER_IMAGE_IDENTIFICATOR = 0b1101101100; //876
|
int FILE_PICKER_IMAGE_IDENTIFICATOR = 0b1101101100; //876
|
||||||
int SOURCE_CHOOSER = 1 << 15;
|
int SOURCE_CHOOSER = 1 << 15;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,10 @@ import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.widget.Toast;
|
import androidx.core.app.ActivityCompat;
|
||||||
import fr.free.nrw.commons.R;
|
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.DialogUtil;
|
||||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||||
|
|
||||||
|
|
@ -55,27 +57,62 @@ public class LocationPermissionsHelper {
|
||||||
Dialog locationAccessDialog,
|
Dialog locationAccessDialog,
|
||||||
Dialog locationOffDialog
|
Dialog locationOffDialog
|
||||||
) {
|
) {
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
if (PermissionUtils.hasPermission(activity, new String[]{permission.ACCESS_FINE_LOCATION})) {
|
||||||
new String[]{permission.ACCESS_FINE_LOCATION},
|
callback.onLocationPermissionGranted();
|
||||||
() -> {
|
} else {
|
||||||
if(!isLocationAccessToAppsTurnedOn()) {
|
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission.ACCESS_FINE_LOCATION)) {
|
||||||
showLocationOffDialog(locationOffDialog);
|
if (locationAccessDialog != null && locationOffDialog != null) {
|
||||||
} else {
|
DialogUtil.showAlertDialog(activity, activity.getString(locationAccessDialog.dialogTitleResource),
|
||||||
if (callback != null) {
|
activity.getString(locationAccessDialog.dialogTextResource),
|
||||||
callback.onLocationPermissionGranted();
|
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);
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
() -> {
|
ActivityCompat.requestPermissions(activity, new String[]{permission.ACCESS_FINE_LOCATION},
|
||||||
if (callback != null) {
|
RequestCodes.LOCATION);
|
||||||
callback.onLocationPermissionDenied(activity.getString(
|
}
|
||||||
R.string.in_app_camera_location_permission_denied));
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
locationAccessDialog.dialogTitleResource,
|
|
||||||
locationAccessDialog.dialogTextResource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
* Check if apps have access to location even after having individual access
|
||||||
*
|
*
|
||||||
|
|
@ -85,38 +122,6 @@ public class LocationPermissionsHelper {
|
||||||
return (locationManager.isNetworkProviderEnabled() || locationManager.isGPSProviderEnabled());
|
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
|
* Handle onPermissionDenied within individual classes based on the requirements
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -367,13 +367,13 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||||
launchZoomActivityAfterPermissionCheck(view);
|
launchZoomActivityAfterPermissionCheck(view);
|
||||||
} else {
|
} else {
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
|
PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
|
||||||
PermissionUtils.PERMISSIONS_STORAGE,
|
|
||||||
() -> {
|
() -> {
|
||||||
launchZoomActivityAfterPermissionCheck(view);
|
launchZoomActivityAfterPermissionCheck(view);
|
||||||
},
|
},
|
||||||
R.string.storage_permission_title,
|
R.string.storage_permission_title,
|
||||||
R.string.read_storage_permission_rationale
|
R.string.read_storage_permission_rationale,
|
||||||
);
|
PermissionUtils.PERMISSIONS_STORAGE
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.nearby
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.*
|
import android.view.View.*
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
|
|
@ -15,11 +16,12 @@ import fr.free.nrw.commons.databinding.ItemPlaceBinding
|
||||||
fun placeAdapterDelegate(
|
fun placeAdapterDelegate(
|
||||||
bookmarkLocationDao: BookmarkLocationsDao,
|
bookmarkLocationDao: BookmarkLocationsDao,
|
||||||
onItemClick: ((Place) -> Unit)? = null,
|
onItemClick: ((Place) -> Unit)? = null,
|
||||||
onCameraClicked: (Place) -> Unit,
|
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>) -> Unit,
|
||||||
onGalleryClicked: (Place) -> Unit,
|
onGalleryClicked: (Place) -> Unit,
|
||||||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||||
onOverflowIconClicked: (Place, View) -> Unit,
|
onOverflowIconClicked: (Place, View) -> Unit,
|
||||||
onDirectionsClicked: (Place) -> Unit
|
onDirectionsClicked: (Place) -> Unit,
|
||||||
|
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>
|
||||||
) = adapterDelegateViewBinding<Place, Place, ItemPlaceBinding>({ layoutInflater, parent ->
|
) = adapterDelegateViewBinding<Place, Place, ItemPlaceBinding>({ layoutInflater, parent ->
|
||||||
ItemPlaceBinding.inflate(layoutInflater, parent, false)
|
ItemPlaceBinding.inflate(layoutInflater, parent, false)
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -36,7 +38,7 @@ fun placeAdapterDelegate(
|
||||||
onItemClick?.invoke(item)
|
onItemClick?.invoke(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item) }
|
nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher) }
|
||||||
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item) }
|
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item) }
|
||||||
bookmarkButtonImage.setOnClickListener {
|
bookmarkButtonImage.setOnClickListener {
|
||||||
val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
|
|
@ -26,13 +27,13 @@ class CommonPlaceClickActions @Inject constructor(
|
||||||
private val contributionController: ContributionController
|
private val contributionController: ContributionController
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun onCameraClicked(): (Place) -> Unit = {
|
fun onCameraClicked(): (Place, ActivityResultLauncher<Array<String>>) -> Unit = { place, launcher ->
|
||||||
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
||||||
showLoginDialog()
|
showLoginDialog()
|
||||||
} else {
|
} else {
|
||||||
Timber.d("Camera button tapped. Image title: ${it.getName()}Image desc: ${it.longDescription}")
|
Timber.d("Camera button tapped. Image title: ${place.getName()}Image desc: ${place.longDescription}")
|
||||||
storeSharedPrefs(it)
|
storeSharedPrefs(place)
|
||||||
contributionController.initiateCameraPick(activity)
|
contributionController.initiateCameraPick(activity, launcher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.Manifest.permission;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -22,7 +23,6 @@ import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
|
@ -42,6 +42,9 @@ import android.widget.ProgressBar;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
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.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
@ -76,7 +79,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||||
import com.mapbox.mapboxsdk.maps.MapView;
|
import com.mapbox.mapboxsdk.maps.MapView;
|
||||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||||
import com.mapbox.mapboxsdk.maps.Style;
|
|
||||||
import com.mapbox.mapboxsdk.maps.UiSettings;
|
import com.mapbox.mapboxsdk.maps.UiSettings;
|
||||||
import com.mapbox.pluginscalebar.ScaleBarOptions;
|
import com.mapbox.pluginscalebar.ScaleBarOptions;
|
||||||
import com.mapbox.pluginscalebar.ScaleBarPlugin;
|
import com.mapbox.pluginscalebar.ScaleBarPlugin;
|
||||||
|
|
@ -126,6 +128,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
@ -242,6 +245,56 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
private PlaceAdapter adapter;
|
private PlaceAdapter adapter;
|
||||||
private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback;
|
private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback;
|
||||||
private boolean isAdvancedQueryFragmentVisible = false;
|
private boolean isAdvancedQueryFragmentVisible = false;
|
||||||
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Map<String, Boolean> 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<String[]> locationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Map<String, Boolean> 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
|
* Holds filtered markers that are to be shown
|
||||||
|
|
@ -429,7 +482,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
updateMarker(isBookmarked, place, null);
|
updateMarker(isBookmarked, place, null);
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
},
|
},
|
||||||
commonPlaceClickActions
|
commonPlaceClickActions,
|
||||||
|
inAppCameraLocationPermissionLauncher
|
||||||
);
|
);
|
||||||
rvNearbyList.setAdapter(adapter);
|
rvNearbyList.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
@ -1214,12 +1268,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
@Override
|
@Override
|
||||||
public void checkPermissionsAndPerformAction() {
|
public void checkPermissionsAndPerformAction() {
|
||||||
Timber.d("Checking permission and perfoming action");
|
Timber.d("Checking permission and perfoming action");
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(getActivity(),
|
locationPermissionLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION});
|
||||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
|
||||||
this::locationPermissionGranted,
|
|
||||||
() -> isPermissionDenied = true,
|
|
||||||
R.string.location_permission_title,
|
|
||||||
R.string.location_permission_rationale_nearby);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1815,7 +1864,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
if (fabCamera.isShown()) {
|
if (fabCamera.isShown()) {
|
||||||
Timber.d("Camera button tapped. Place: %s", selectedPlace.toString());
|
Timber.d("Camera button tapped. Place: %s", selectedPlace.toString());
|
||||||
storeSharedPrefs(selectedPlace);
|
storeSharedPrefs(selectedPlace);
|
||||||
controller.initiateCameraPick(getActivity());
|
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.nearby.fragments
|
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.bookmarks.locations.BookmarkLocationsDao
|
||||||
import fr.free.nrw.commons.nearby.Place
|
import fr.free.nrw.commons.nearby.Place
|
||||||
import fr.free.nrw.commons.nearby.placeAdapterDelegate
|
import fr.free.nrw.commons.nearby.placeAdapterDelegate
|
||||||
|
|
@ -9,7 +10,8 @@ class PlaceAdapter(
|
||||||
bookmarkLocationsDao: BookmarkLocationsDao,
|
bookmarkLocationsDao: BookmarkLocationsDao,
|
||||||
onPlaceClicked: ((Place) -> Unit)? = null,
|
onPlaceClicked: ((Place) -> Unit)? = null,
|
||||||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||||
commonPlaceClickActions: CommonPlaceClickActions
|
commonPlaceClickActions: CommonPlaceClickActions,
|
||||||
|
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>
|
||||||
) :
|
) :
|
||||||
BaseDelegateAdapter<Place>(
|
BaseDelegateAdapter<Place>(
|
||||||
placeAdapterDelegate(
|
placeAdapterDelegate(
|
||||||
|
|
@ -19,7 +21,8 @@ class PlaceAdapter(
|
||||||
commonPlaceClickActions.onGalleryClicked(),
|
commonPlaceClickActions.onGalleryClicked(),
|
||||||
onBookmarkClicked,
|
onBookmarkClicked,
|
||||||
commonPlaceClickActions.onOverflowClicked(),
|
commonPlaceClickActions.onOverflowClicked(),
|
||||||
commonPlaceClickActions.onDirectionsClicked()
|
commonPlaceClickActions.onDirectionsClicked(),
|
||||||
|
inAppCameraLocationPermissionLauncher
|
||||||
),
|
),
|
||||||
areItemsTheSame = {oldItem, newItem -> oldItem.wikiDataEntityId == newItem.wikiDataEntityId }
|
areItemsTheSame = {oldItem, newItem -> oldItem.wikiDataEntityId == newItem.wikiDataEntityId }
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package fr.free.nrw.commons.settings;
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest.permission;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
@ -18,7 +18,9 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
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.ListPreference;
|
||||||
import androidx.preference.MultiSelectListPreference;
|
import androidx.preference.MultiSelectListPreference;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
|
@ -31,18 +33,15 @@ import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||||
import com.karumi.dexter.Dexter;
|
import com.karumi.dexter.Dexter;
|
||||||
import com.karumi.dexter.MultiplePermissionsReport;
|
import com.karumi.dexter.MultiplePermissionsReport;
|
||||||
import com.karumi.dexter.PermissionToken;
|
import com.karumi.dexter.PermissionToken;
|
||||||
import com.karumi.dexter.listener.PermissionGrantedResponse;
|
|
||||||
import com.karumi.dexter.listener.PermissionRequest;
|
import com.karumi.dexter.listener.PermissionRequest;
|
||||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
|
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.R;
|
||||||
import fr.free.nrw.commons.Utils;
|
import fr.free.nrw.commons.Utils;
|
||||||
import fr.free.nrw.commons.campaigns.CampaignView;
|
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.contributions.MainActivity;
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
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.location.LocationServiceManager;
|
||||||
import fr.free.nrw.commons.logging.CommonsLogSender;
|
import fr.free.nrw.commons.logging.CommonsLogSender;
|
||||||
import fr.free.nrw.commons.recentlanguages.Language;
|
import fr.free.nrw.commons.recentlanguages.Language;
|
||||||
|
|
@ -56,7 +55,7 @@ import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Map;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
|
@ -72,6 +71,9 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
@Inject
|
@Inject
|
||||||
RecentLanguagesDao recentLanguagesDao;
|
RecentLanguagesDao recentLanguagesDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ContributionController contributionController;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LocationServiceManager locationManager;
|
LocationServiceManager locationManager;
|
||||||
|
|
||||||
|
|
@ -83,6 +85,18 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
private View separator;
|
private View separator;
|
||||||
private ListView languageHistoryListView;
|
private ListView languageHistoryListView;
|
||||||
private static final String GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content";
|
private static final String GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content";
|
||||||
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Map<String, Boolean> result) {
|
||||||
|
boolean areAllGranted = true;
|
||||||
|
for (final boolean b : result.values()) {
|
||||||
|
areAllGranted = areAllGranted && b;
|
||||||
|
}
|
||||||
|
if (!areAllGranted && shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||||
|
contributionController.handleShowRationaleFlowCameraLocation(getActivity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
|
@ -205,32 +219,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
* @param activity
|
* @param activity
|
||||||
*/
|
*/
|
||||||
private void createDialogsAndHandleLocationPermissions(Activity activity) {
|
private void createDialogsAndHandleLocationPermissions(Activity activity) {
|
||||||
LocationPermissionsHelper.Dialog locationAccessDialog = new LocationPermissionsHelper.Dialog(
|
inAppCameraLocationPermissionLauncher.launch(new String[]{permission.ACCESS_FINE_LOCATION});
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -149,10 +149,10 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
init();
|
init();
|
||||||
nearbyPopupAnswers = new HashMap<>();
|
nearbyPopupAnswers = new HashMap<>();
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(this,
|
PermissionUtils.checkPermissionsAndPerformAction(this,
|
||||||
PERMISSIONS_STORAGE,
|
|
||||||
this::receiveSharedItems,
|
this::receiveSharedItems,
|
||||||
R.string.storage_permission_title,
|
R.string.storage_permission_title,
|
||||||
R.string.write_storage_permission_rationale_for_image_share);
|
R.string.write_storage_permission_rationale_for_image_share,
|
||||||
|
PERMISSIONS_STORAGE);
|
||||||
//getting the current dpi of the device and if it is less than 320dp i.e. overlapping
|
//getting the current dpi of the device and if it is less than 320dp i.e. overlapping
|
||||||
//threshold, thumbnails automatically minimizes
|
//threshold, thumbnails automatically minimizes
|
||||||
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||||
|
|
@ -255,12 +255,12 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
final boolean hasAllPermissions = PermissionUtils.hasPermission(this, PERMISSIONS_STORAGE);
|
final boolean hasAllPermissions = PermissionUtils.hasPermission(this, PERMISSIONS_STORAGE);
|
||||||
if (!hasAllPermissions) {
|
if (!hasAllPermissions) {
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(this,
|
PermissionUtils.checkPermissionsAndPerformAction(this,
|
||||||
PERMISSIONS_STORAGE,
|
|
||||||
() -> {
|
() -> {
|
||||||
//TODO handle this
|
//TODO handle this
|
||||||
},
|
},
|
||||||
R.string.storage_permission_title,
|
R.string.storage_permission_title,
|
||||||
R.string.write_storage_permission_rationale_for_image_share);
|
R.string.write_storage_permission_rationale_for_image_share,
|
||||||
|
PERMISSIONS_STORAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ object DownloadUtils {
|
||||||
}
|
}
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(
|
PermissionUtils.checkPermissionsAndPerformAction(
|
||||||
activity,
|
activity,
|
||||||
PermissionUtils.PERMISSIONS_STORAGE,
|
|
||||||
{ enqueueRequest(activity, req) },
|
{ enqueueRequest(activity, req) },
|
||||||
{
|
{
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
|
|
@ -48,8 +47,9 @@ object DownloadUtils {
|
||||||
).show()
|
).show()
|
||||||
},
|
},
|
||||||
R.string.storage_permission,
|
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) {
|
private fun enqueueRequest(activity: Activity, req: DownloadManager.Request) {
|
||||||
|
|
|
||||||
|
|
@ -100,11 +100,11 @@ public class PermissionUtils {
|
||||||
* @param rationaleMessage rationale message to be displayed when permission was denied. It
|
* @param rationaleMessage rationale message to be displayed when permission was denied. It
|
||||||
* can be an invalid @StringRes
|
* can be an invalid @StringRes
|
||||||
*/
|
*/
|
||||||
public static void checkPermissionsAndPerformAction(Activity activity, String[] permissions,
|
public static void checkPermissionsAndPerformAction(Activity activity,
|
||||||
Runnable onPermissionGranted, @StringRes int rationaleTitle,
|
Runnable onPermissionGranted, @StringRes int rationaleTitle,
|
||||||
@StringRes int rationaleMessage) {
|
@StringRes int rationaleMessage, String... permissions) {
|
||||||
checkPermissionsAndPerformAction(activity, permissions, onPermissionGranted, null,
|
checkPermissionsAndPerformAction(activity, onPermissionGranted, null,
|
||||||
rationaleTitle, rationaleMessage);
|
rationaleTitle, rationaleMessage, permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -125,9 +125,9 @@ public class PermissionUtils {
|
||||||
* @param rationaleTitle rationale title to be displayed when permission was denied
|
* @param rationaleTitle rationale title to be displayed when permission was denied
|
||||||
* @param rationaleMessage rationale message to be displayed when permission was denied
|
* @param rationaleMessage rationale message to be displayed when permission was denied
|
||||||
*/
|
*/
|
||||||
public static void checkPermissionsAndPerformAction(Activity activity, String[] permissions,
|
public static void checkPermissionsAndPerformAction(Activity activity,
|
||||||
Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle,
|
Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle,
|
||||||
@StringRes int rationaleMessage) {
|
@StringRes int rationaleMessage, String... permissions) {
|
||||||
Dexter.withActivity(activity)
|
Dexter.withActivity(activity)
|
||||||
.withPermissions(permissions)
|
.withPermissions(permissions)
|
||||||
.withListener(new MultiplePermissionsListener() {
|
.withListener(new MultiplePermissionsListener() {
|
||||||
|
|
@ -135,6 +135,7 @@ public class PermissionUtils {
|
||||||
public void onPermissionsChecked(MultiplePermissionsReport report) {
|
public void onPermissionsChecked(MultiplePermissionsReport report) {
|
||||||
if (report.areAllPermissionsGranted()) {
|
if (report.areAllPermissionsGranted()) {
|
||||||
onPermissionGranted.run();
|
onPermissionGranted.run();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (report.isAnyPermissionPermanentlyDenied()) {
|
if (report.isAnyPermissionPermanentlyDenied()) {
|
||||||
// permission is denied permanently, we will show user a dialog message.
|
// permission is denied permanently, we will show user a dialog message.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue