Merge branch 'master' of https://github.com/siva-subramaniam-v/apps-android-commons into gradle-version-upgrade

This commit is contained in:
Siva Subramaniam 2023-06-26 12:15:38 +05:30
commit c4d4cbeae2
73 changed files with 801 additions and 186 deletions

View file

@ -147,7 +147,11 @@ public class LoginActivity extends AccountAuthenticatorActivity {
loginCredentials.setVisibility(View.GONE);
}
}
/**
* Hides the keyboard if the user's focus is not on the password (hasFocus is false).
* @param view The keyboard
* @param hasFocus Set to true if the keyboard has focus
*/
@OnFocusChange(R.id.login_password)
void onPasswordFocusChanged(View view, boolean hasFocus) {
if (!hasFocus) {

View file

@ -3,12 +3,9 @@ package fr.free.nrw.commons.contributions;
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
import android.Manifest;
import android.Manifest.permission;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import androidx.annotation.NonNull;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.filepicker.DefaultCallback;
@ -70,15 +67,6 @@ public class ContributionController {
PermissionUtils.checkPermissionsAndPerformAction(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
() -> {
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
PermissionUtils.checkPermissionsAndPerformAction(
activity,
permission.ACCESS_MEDIA_LOCATION,
() -> {},
R.string.media_location_permission_denied,
R.string.add_location_manually
);
}
FilePicker.openCustomSelector(activity, 0);
},
R.string.storage_permission_title,
@ -91,7 +79,8 @@ public class ContributionController {
*/
private void initiateGalleryUpload(final Activity activity, final boolean allowMultipleUploads) {
setPickerConfiguration(activity, allowMultipleUploads);
FilePicker.openGallery(activity, 0);
boolean isGetContentPickerPreferred = defaultKvStore.getBoolean("getContentPhotoPickerPref");
FilePicker.openGallery(activity, 0, isGetContentPickerPreferred);
}
/**

View file

@ -5,7 +5,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@ -152,6 +151,20 @@ public class MainActivity extends BaseActivity
}
}
setUpPager();
/**
* Ask the user for media location access just after login
* so that location in the EXIF metadata of the images shared by the user
* is retained on devices running Android 10 or above
*/
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
PermissionUtils.checkPermissionsAndPerformAction(
this,
permission.ACCESS_MEDIA_LOCATION,
() -> {},
R.string.media_location_permission_denied,
R.string.add_location_manually
);
}
}
}

View file

@ -44,10 +44,11 @@ public class FilePicker implements Constants {
return uri;
}
private static Intent createGalleryIntent(@NonNull Context context, int type) {
private static Intent createGalleryIntent(@NonNull Context context, int type,
boolean isGetContentPickerPreferred) {
// storing picked image type to shared preferences
storeType(context, type);
return plainGalleryPickerIntent()
return plainGalleryPickerIntent(isGetContentPickerPreferred)
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, configuration(context).allowsMultiplePickingInGallery());
}
@ -103,8 +104,8 @@ public class FilePicker implements Constants {
*
* @param type Custom type of your choice, which will be returned with the images
*/
public static void openGallery(Activity activity, int type) {
Intent intent = createGalleryIntent(activity, type);
public static void openGallery(Activity activity, int type, boolean isGetContentPickerPreferred) {
Intent intent = createGalleryIntent(activity, type, isGetContentPickerPreferred);
activity.startActivityForResult(intent, RequestCodes.PICK_PICTURE_FROM_GALLERY);
}
@ -198,8 +199,40 @@ public class FilePicker implements Constants {
return data == null || (data.getData() == null && data.getClipData() == null);
}
private static Intent plainGalleryPickerIntent() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
private static Intent plainGalleryPickerIntent(boolean isGetContentPickerPreferred) {
/**
* Asking for ACCESS_MEDIA_LOCATION at runtime solved the location-loss issue
* in the custom selector in Contributions fragment.
* Detailed discussion: https://github.com/commons-app/apps-android-commons/issues/5015
*
* This permission check, however, was insufficient to fix location-loss in
* the regular selector in Contributions fragment and Nearby fragment,
* especially on some devices running Android 13 that use the new Photo Picker by default.
*
* New Photo Picker: https://developer.android.com/training/data-storage/shared/photopicker
*
* The new Photo Picker introduced by Android redacts location tags from EXIF metadata.
* Reported on the Google Issue Tracker: https://issuetracker.google.com/issues/243294058
* Status: Won't fix (Intended behaviour)
*
* Switched intent from ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT
* (based on user's preference) as:
*
* ACTION_GET_CONTENT opens the 'best application' for choosing that kind of data
* The best application is the new Photo Picker that redacts the location tags
*
* ACTION_OPEN_DOCUMENT, however, displays the various DocumentsProvider instances
* installed on the device, letting the user interactively navigate through them.
*
* So, this allows us to use the traditional file picker that does not redact location tags from EXIF.
*
*/
Intent intent;
if (isGetContentPickerPreferred) {
intent = new Intent(Intent.ACTION_GET_CONTENT);
} else {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
}
intent.setType("image/*");
return intent;
}

View file

@ -38,7 +38,10 @@ public class LatLng implements Parcelable {
this.latitude = Math.max(-90.0D, Math.min(90.0D, latitude));
this.accuracy = accuracy;
}
/**
* An alternate constructor for this class.
* @param in A parcelable which contains the latitude, longitude, and accuracy
*/
public LatLng(Parcel in) {
latitude = in.readDouble();
longitude = in.readDouble();

View file

@ -57,6 +57,7 @@ import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.request.ImageRequest;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.LocationPicker.LocationPicker;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.MediaDataExtractor;
@ -1232,6 +1233,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
if (media == null || media.getUser() == null) {
return;
}
if (sessionManager.getUserName() == null) {
String userProfileLink = BuildConfig.COMMONS_URL + "/wiki/User:" + media.getUser();
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(userProfileLink));
startActivity(browserIntent);
return;
}
ProfileActivity.startYourself(getActivity(), media.getUser(), !Objects
.equals(sessionManager.getUserName(), media.getUser()));
}

View file

@ -259,7 +259,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
/**
* Saves response of list of places for the first time
*/
private List<Place> places;
private List<Place> places = new ArrayList<>();
@NonNull
public static NearbyParentFragment newInstance() {

View file

@ -129,6 +129,10 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
if (getReviewActivity().reviewController.firstRevision != null) {
user = getReviewActivity().reviewController.firstRevision.getUser();
} else {
if(savedInstanceState != null) {
user = savedInstanceState.getString(SAVED_USER);
}
}
//if the user is null because of whatsoever reason, review will not be sent anyways

View file

@ -42,6 +42,7 @@ import fr.free.nrw.commons.recentlanguages.Language;
import fr.free.nrw.commons.recentlanguages.RecentLanguagesAdapter;
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao;
import fr.free.nrw.commons.upload.LanguagesAdapter;
import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.utils.PermissionUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import java.util.HashMap;
@ -71,6 +72,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
private TextView recentLanguagesTextView;
private View separator;
private ListView languageHistoryListView;
private static final String GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content";
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@ -150,6 +152,17 @@ public class SettingsFragment extends PreferenceFragmentCompat {
checkPermissionsAndSendLogs();
return true;
});
Preference getContentPickerPreference = findPreference("getContentPhotoPickerPref");
getContentPickerPreference.setOnPreferenceChangeListener(
(preference, newValue) -> {
boolean isGetContentPickerTurnedOn = (boolean) newValue;
if (isGetContentPickerTurnedOn) {
showLocationLossWarning();
}
return true;
}
);
// Disable some settings when not logged in.
if (defaultKvStore.getBoolean("login_skipped", false)) {
findPreference("useExternalStorage").setEnabled(false);
@ -162,6 +175,26 @@ public class SettingsFragment extends PreferenceFragmentCompat {
}
}
/**
* On some devices, the new Photo Picker with GET_CONTENT takeover
* redacts location tags from EXIF metadata
*
* Show warning to the user when ACTION_GET_CONTENT intent is enabled
*/
private void showLocationLossWarning() {
DialogUtil.showAlertDialog(
getActivity(),
null,
getString(R.string.location_loss_warning),
getString(R.string.ok),
getString(R.string.read_help_link),
() -> {},
() -> Utils.handleWebUrl(requireContext(), Uri.parse(GET_CONTENT_PICKER_HELP_URL)),
null,
true
);
}
@Override
protected Adapter onCreateAdapter(final PreferenceScreen preferenceScreen) {
return new PreferenceGroupAdapter(preferenceScreen) {

View file

@ -3,12 +3,7 @@ package fr.free.nrw.commons.upload.mediaDetails;
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
import static fr.free.nrw.commons.utils.ImageUtils.EMPTY_CAPTION;
import static fr.free.nrw.commons.utils.ImageUtils.FILE_FBMD;
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NO_EXIF;
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_BLURRY;
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_DARK;
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_GEOLOCATION_DIFFERENT;
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_KEEP;
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
@ -331,11 +326,8 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
view.showDuplicatePicturePopup(uploadItem);
}
// If image has some problems check if the bits are set in errorCode and
// show popup accordingly
if (((errorCode & FILE_NO_EXIF) != 0) || ((errorCode & IMAGE_DARK) != 0) ||
((errorCode & FILE_FBMD) != 0) || ((errorCode & IMAGE_GEOLOCATION_DIFFERENT) != 0) ||
((errorCode & IMAGE_BLURRY) != 0)) {
// If image has some other problems, show popup accordingly
if (errorCode != EMPTY_CAPTION && errorCode != FILE_NAME_EXISTS) {
view.showBadImagePopup(errorCode, uploadItem);
}