66import android .app .Activity ;
77import android .content .Context ;
88import android .content .Intent ;
9+ import android .widget .Toast ;
910import androidx .annotation .NonNull ;
1011import fr .free .nrw .commons .R ;
1112import fr .free .nrw .commons .filepicker .DefaultCallback ;
1213import fr .free .nrw .commons .filepicker .FilePicker ;
1314import fr .free .nrw .commons .filepicker .FilePicker .ImageSource ;
1415import fr .free .nrw .commons .filepicker .UploadableFile ;
1516import fr .free .nrw .commons .kvstore .JsonKvStore ;
17+ import fr .free .nrw .commons .location .LatLng ;
18+ import fr .free .nrw .commons .location .LocationPermissionsHelper ;
19+ import fr .free .nrw .commons .location .LocationPermissionsHelper .Dialog ;
20+ import fr .free .nrw .commons .location .LocationPermissionsHelper .LocationPermissionCallback ;
21+ import fr .free .nrw .commons .location .LocationServiceManager ;
1622import fr .free .nrw .commons .nearby .Place ;
1723import fr .free .nrw .commons .upload .UploadActivity ;
24+ import fr .free .nrw .commons .utils .DialogUtil ;
1825import fr .free .nrw .commons .utils .PermissionUtils ;
1926import fr .free .nrw .commons .utils .ViewUtil ;
2027import java .util .ArrayList ;
@@ -28,7 +35,11 @@ public class ContributionController {
2835
2936 public static final String ACTION_INTERNAL_UPLOADS = "internalImageUploads" ;
3037 private final JsonKvStore defaultKvStore ;
38+ private LatLng locationBeforeImageCapture ;
39+ private boolean isInAppCameraUpload ;
3140
41+ @ Inject
42+ LocationServiceManager locationManager ;
3243 @ Inject
3344 public ContributionController (@ Named ("default_preferences" ) JsonKvStore defaultKvStore ) {
3445 this .defaultKvStore = defaultKvStore ;
@@ -46,11 +57,94 @@ public void initiateCameraPick(Activity activity) {
4657
4758 PermissionUtils .checkPermissionsAndPerformAction (activity ,
4859 Manifest .permission .WRITE_EXTERNAL_STORAGE ,
49- () -> initiateCameraUpload (activity ),
60+ () -> {
61+ if (defaultKvStore .getBoolean ("inAppCameraFirstRun" )) {
62+ defaultKvStore .putBoolean ("inAppCameraFirstRun" , false );
63+ askUserToAllowLocationAccess (activity );
64+ } else if (defaultKvStore .getBoolean ("inAppCameraLocationPref" )) {
65+ createDialogsAndHandleLocationPermissions (activity );
66+ } else {
67+ initiateCameraUpload (activity );
68+ }
69+ },
5070 R .string .storage_permission_title ,
5171 R .string .write_storage_permission_rationale );
5272 }
5373
74+ /**
75+ * Asks users to provide location access
76+ *
77+ * @param activity
78+ */
79+ private void createDialogsAndHandleLocationPermissions (Activity activity ) {
80+ LocationPermissionsHelper .Dialog locationAccessDialog = new Dialog (
81+ R .string .location_permission_title ,
82+ R .string .in_app_camera_location_permission_rationale
83+ );
84+
85+ LocationPermissionsHelper .Dialog locationOffDialog = new Dialog (
86+ R .string .ask_to_turn_location_on ,
87+ R .string .in_app_camera_needs_location
88+ );
89+ LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper (
90+ activity , locationManager ,
91+ new LocationPermissionCallback () {
92+ @ Override
93+ public void onLocationPermissionDenied () {
94+ initiateCameraUpload (activity );
95+ }
96+
97+ @ Override
98+ public void onLocationPermissionGranted () {
99+ initiateCameraUpload (activity );
100+ }
101+ }
102+ );
103+ locationPermissionsHelper .handleLocationPermissions (
104+ locationAccessDialog ,
105+ locationOffDialog
106+ );
107+ }
108+
109+ /**
110+ * Suggest user to attach location information with pictures.
111+ * If the user selects "Yes", then:
112+ *
113+ * Location is taken from the EXIF if the default camera application
114+ * does not redact location tags.
115+ *
116+ * Otherwise, if the EXIF metadata does not have location information,
117+ * then location captured by the app is used
118+ *
119+ * @param activity
120+ */
121+ private void askUserToAllowLocationAccess (Activity activity ) {
122+ DialogUtil .showAlertDialog (activity ,
123+ activity .getString (R .string .in_app_camera_location_permission_title ),
124+ activity .getString (R .string .in_app_camera_location_access_explanation ),
125+ activity .getString (R .string .option_allow ),
126+ activity .getString (R .string .option_dismiss ),
127+ ()-> {
128+ defaultKvStore .putBoolean ("inAppCameraLocationPref" , true );
129+ createDialogsAndHandleLocationPermissions (activity );
130+ },
131+ () -> {
132+ defaultKvStore .putBoolean ("inAppCameraLocationPref" , false );
133+ initiateCameraUpload (activity );
134+ },
135+ null ,
136+ true );
137+ }
138+
139+ /**
140+ * Check if apps have access to location even after having individual access
141+ *
142+ * @return
143+ */
144+ private boolean isLocationAccessToAppsTurnedOn () {
145+ return (locationManager .isNetworkProviderEnabled () || locationManager .isGPSProviderEnabled ());
146+ }
147+
54148 /**
55149 * Initiate gallery picker
56150 */
@@ -66,9 +160,7 @@ public void initiateCustomGalleryPickWithPermission(final Activity activity) {
66160
67161 PermissionUtils .checkPermissionsAndPerformAction (activity ,
68162 Manifest .permission .WRITE_EXTERNAL_STORAGE ,
69- () -> {
70- FilePicker .openCustomSelector (activity , 0 );
71- },
163+ () -> FilePicker .openCustomSelector (activity , 0 ),
72164 R .string .storage_permission_title ,
73165 R .string .write_storage_permission_rationale );
74166 }
@@ -99,6 +191,10 @@ private void setPickerConfiguration(Activity activity,
99191 */
100192 private void initiateCameraUpload (Activity activity ) {
101193 setPickerConfiguration (activity , false );
194+ if (defaultKvStore .getBoolean ("inAppCameraLocationPref" , false )) {
195+ locationBeforeImageCapture = locationManager .getLastLocation ();
196+ }
197+ isInAppCameraUpload = true ;
102198 FilePicker .openCameraForImage (activity , 0 );
103199 }
104200
@@ -134,7 +230,8 @@ public List<UploadableFile> handleExternalImagesPicked(Activity activity,
134230
135231 /**
136232 * Returns intent to be passed to upload activity
137- * Attaches place object for nearby uploads
233+ * Attaches place object for nearby uploads and
234+ * location before image capture if in-app camera is used
138235 */
139236 private Intent handleImagesPicked (Context context ,
140237 List <UploadableFile > imagesFiles ) {
@@ -148,6 +245,17 @@ private Intent handleImagesPicked(Context context,
148245 shareIntent .putExtra (PLACE_OBJECT , place );
149246 }
150247
248+ if (locationBeforeImageCapture != null ) {
249+ shareIntent .putExtra (
250+ UploadActivity .LOCATION_BEFORE_IMAGE_CAPTURE ,
251+ locationBeforeImageCapture );
252+ }
253+
254+ shareIntent .putExtra (
255+ UploadActivity .IN_APP_CAMERA_UPLOAD ,
256+ isInAppCameraUpload
257+ );
258+ isInAppCameraUpload = false ; // reset the flag for next use
151259 return shareIntent ;
152260 }
153261
0 commit comments