diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index c3dde9caa7..3aceb957ab 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -107,7 +107,6 @@ public class CommonsApplication extends MultiDexApplication { /** * Constants begin */ - public static final int OPEN_APPLICATION_DETAIL_SETTINGS = 1001; public static final String DEFAULT_EDIT_SUMMARY = "Uploaded using [[COM:MOA|Commons Mobile App]]"; diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java index 65d0e45a8a..f5ce556c41 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java @@ -9,6 +9,7 @@ import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; @@ -33,6 +34,23 @@ public class BookmarkLocationsFragment extends DaggerFragment { @Inject BookmarkLocationsDao bookmarkLocationDao; @Inject CommonPlaceClickActions commonPlaceClickActions; private PlaceAdapter adapter; + + private final ActivityResultLauncher cameraPickLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> { + contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks); + }); + }); + + private final ActivityResultLauncher galleryPickLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> { + contributionController.onPictureReturnedFromGallery(result, requireActivity(), callbacks); + }); + }); + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { @Override public void onActivityResult(Map result) { @@ -45,7 +63,7 @@ public void onActivityResult(Map result) { contributionController.locationPermissionCallback.onLocationPermissionGranted(); } else { if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher); + contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult); } else { contributionController.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied)); } @@ -83,7 +101,9 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { return Unit.INSTANCE; }, commonPlaceClickActions, - inAppCameraLocationPermissionLauncher + inAppCameraLocationPermissionLauncher, + galleryPickLauncherForResult, + cameraPickLauncherForResult ); binding.listView.setAdapter(adapter); } @@ -109,11 +129,6 @@ private void initList() { } } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - contributionController.handleActivityResult(getActivity(), requestCode, resultCode, data); - } - @Override public void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java index 1251d10273..fcfd329740 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java @@ -7,6 +7,7 @@ import android.content.Context; import android.content.Intent; import android.widget.Toast; +import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; @@ -64,10 +65,11 @@ public ContributionController(@Named("default_preferences") JsonKvStore defaultK * Check for permissions and initiate camera click */ public void initiateCameraPick(Activity activity, - ActivityResultLauncher inAppCameraLocationPermissionLauncher) { + ActivityResultLauncher inAppCameraLocationPermissionLauncher, + ActivityResultLauncher resultLauncher) { boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true); if (!useExtStorage) { - initiateCameraUpload(activity); + initiateCameraUpload(activity, resultLauncher); return; } @@ -75,12 +77,12 @@ public void initiateCameraPick(Activity activity, () -> { if (defaultKvStore.getBoolean("inAppCameraFirstRun")) { defaultKvStore.putBoolean("inAppCameraFirstRun", false); - askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher); + askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher, resultLauncher); } else if (defaultKvStore.getBoolean("inAppCameraLocationPref")) { createDialogsAndHandleLocationPermissions(activity, - inAppCameraLocationPermissionLauncher); + inAppCameraLocationPermissionLauncher, resultLauncher); } else { - initiateCameraUpload(activity); + initiateCameraUpload(activity, resultLauncher); } }, R.string.storage_permission_title, @@ -94,7 +96,8 @@ public void initiateCameraPick(Activity activity, * @param activity */ private void createDialogsAndHandleLocationPermissions(Activity activity, - ActivityResultLauncher inAppCameraLocationPermissionLauncher) { + ActivityResultLauncher inAppCameraLocationPermissionLauncher, + ActivityResultLauncher resultLauncher) { locationPermissionCallback = new LocationPermissionCallback() { @Override public void onLocationPermissionDenied(String toastMessage) { @@ -103,16 +106,16 @@ public void onLocationPermissionDenied(String toastMessage) { toastMessage, Toast.LENGTH_LONG ).show(); - initiateCameraUpload(activity); + initiateCameraUpload(activity, resultLauncher); } @Override public void onLocationPermissionGranted() { if (!locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) { showLocationOffDialog(activity, R.string.in_app_camera_needs_location, - R.string.in_app_camera_location_unavailable); + R.string.in_app_camera_location_unavailable, resultLauncher); } else { - initiateCameraUpload(activity); + initiateCameraUpload(activity, resultLauncher); } } }; @@ -135,9 +138,10 @@ public void onLocationPermissionGranted() { * @param activity Activity reference * @param dialogTextResource Resource id of text to be shown in dialog * @param toastTextResource Resource id of text to be shown in toast + * @param resultLauncher */ private void showLocationOffDialog(Activity activity, int dialogTextResource, - int toastTextResource) { + int toastTextResource, ActivityResultLauncher resultLauncher) { DialogUtil .showAlertDialog(activity, activity.getString(R.string.ask_to_turn_location_on), @@ -148,20 +152,21 @@ private void showLocationOffDialog(Activity activity, int dialogTextResource, () -> { Toast.makeText(activity, activity.getString(toastTextResource), Toast.LENGTH_LONG).show(); - initiateCameraUpload(activity); + initiateCameraUpload(activity, resultLauncher); } ); } public void handleShowRationaleFlowCameraLocation(Activity activity, - ActivityResultLauncher inAppCameraLocationPermissionLauncher) { + ActivityResultLauncher inAppCameraLocationPermissionLauncher, + ActivityResultLauncher resultLauncher) { 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), () -> { createDialogsAndHandleLocationPermissions(activity, - inAppCameraLocationPermissionLauncher); + inAppCameraLocationPermissionLauncher, resultLauncher); }, () -> locationPermissionCallback.onLocationPermissionDenied( activity.getString(R.string.in_app_camera_location_permission_denied)), @@ -181,7 +186,8 @@ public void handleShowRationaleFlowCameraLocation(Activity activity, * @param activity */ private void askUserToAllowLocationAccess(Activity activity, - ActivityResultLauncher inAppCameraLocationPermissionLauncher) { + ActivityResultLauncher inAppCameraLocationPermissionLauncher, + ActivityResultLauncher resultLauncher) { DialogUtil.showAlertDialog(activity, activity.getString(R.string.in_app_camera_location_permission_title), activity.getString(R.string.in_app_camera_location_access_explanation), @@ -190,12 +196,12 @@ private void askUserToAllowLocationAccess(Activity activity, () -> { defaultKvStore.putBoolean("inAppCameraLocationPref", true); createDialogsAndHandleLocationPermissions(activity, - inAppCameraLocationPermissionLauncher); + inAppCameraLocationPermissionLauncher, resultLauncher); }, () -> { ViewUtil.showLongToast(activity, R.string.in_app_camera_location_permission_denied); defaultKvStore.putBoolean("inAppCameraLocationPref", false); - initiateCameraUpload(activity); + initiateCameraUpload(activity, resultLauncher); }, null, true); @@ -204,18 +210,18 @@ private void askUserToAllowLocationAccess(Activity activity, /** * Initiate gallery picker */ - public void initiateGalleryPick(final Activity activity, final boolean allowMultipleUploads) { - initiateGalleryUpload(activity, allowMultipleUploads); + public void initiateGalleryPick(final Activity activity, ActivityResultLauncher resultLauncher, final boolean allowMultipleUploads) { + initiateGalleryUpload(activity, resultLauncher, allowMultipleUploads); } /** * Initiate gallery picker with permission */ - public void initiateCustomGalleryPickWithPermission(final Activity activity) { + public void initiateCustomGalleryPickWithPermission(final Activity activity, ActivityResultLauncher resultLauncher) { setPickerConfiguration(activity, true); PermissionUtils.checkPermissionsAndPerformAction(activity, - () -> FilePicker.openCustomSelector(activity, 0), + () -> FilePicker.openCustomSelector(activity, resultLauncher, 0), R.string.storage_permission_title, R.string.write_storage_permission_rationale, PermissionUtils.PERMISSIONS_STORAGE); @@ -225,12 +231,10 @@ public void initiateCustomGalleryPickWithPermission(final Activity activity) { /** * Open chooser for gallery uploads */ - private void initiateGalleryUpload(final Activity activity, + private void initiateGalleryUpload(final Activity activity, ActivityResultLauncher resultLauncher, final boolean allowMultipleUploads) { setPickerConfiguration(activity, allowMultipleUploads); - boolean openDocumentIntentPreferred = defaultKvStore.getBoolean( - "openDocumentPhotoPickerPref", true); - FilePicker.openGallery(activity, 0, openDocumentIntentPreferred); + FilePicker.openGallery(activity, resultLauncher, 0, isDocumentPhotoPickerPreferred()); } /** @@ -247,22 +251,43 @@ private void setPickerConfiguration(Activity activity, /** * Initiate camera upload by opening camera */ - private void initiateCameraUpload(Activity activity) { + private void initiateCameraUpload(Activity activity, ActivityResultLauncher resultLauncher) { setPickerConfiguration(activity, false); if (defaultKvStore.getBoolean("inAppCameraLocationPref", false)) { locationBeforeImageCapture = locationManager.getLastLocation(); } isInAppCameraUpload = true; - FilePicker.openCameraForImage(activity, 0); + FilePicker.openCameraForImage(activity, resultLauncher, 0); + } + + private boolean isDocumentPhotoPickerPreferred(){ + return defaultKvStore.getBoolean( + "openDocumentPhotoPickerPref", true); + } + + public void onPictureReturnedFromGallery(ActivityResult result, Activity activity, FilePicker.Callbacks callbacks){ + + if(isDocumentPhotoPickerPreferred()){ + FilePicker.onPictureReturnedFromDocuments(result, activity, callbacks); + } else { + FilePicker.onPictureReturnedFromGallery(result, activity, callbacks); + } + } + + public void onPictureReturnedFromCustomSelector(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) { + FilePicker.onPictureReturnedFromCustomSelector(result, activity, callbacks); + } + + public void onPictureReturnedFromCamera(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) { + FilePicker.onPictureReturnedFromCamera(result, activity, callbacks); } /** * Attaches callback for file picker. */ - public void handleActivityResult(Activity activity, int requestCode, int resultCode, - Intent data) { - FilePicker.handleActivityResult(requestCode, resultCode, data, activity, - new DefaultCallback() { + public void handleActivityResultWithCallback(Activity activity, FilePicker.HandleActivityResult handleActivityResult) { + + handleActivityResult.onHandleActivityResult(new DefaultCallback() { @Override public void onCanceled(final ImageSource source, final int type) { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index 53c91534e4..509d1eb95b 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -6,6 +6,7 @@ import android.Manifest.permission; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; @@ -20,6 +21,7 @@ import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; @@ -96,6 +98,30 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl private int contributionsSize; private String userName; + private final ActivityResultLauncher galleryPickLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { + controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks); + }); + }); + + private final ActivityResultLauncher customSelectorLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { + controller.onPictureReturnedFromCustomSelector(result, requireActivity(), callbacks); + }); + }); + + private final ActivityResultLauncher cameraPickLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { + controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks); + }); + }); + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult( new RequestMultiplePermissions(), new ActivityResultCallback>() { @@ -111,7 +137,7 @@ public void onActivityResult(Map result) { } else { if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { controller.handleShowRationaleFlowCameraLocation(getActivity(), - inAppCameraLocationPermissionLauncher); + inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult); } else { controller.locationPermissionCallback.onLocationPermissionDenied( getActivity().getString( @@ -322,7 +348,7 @@ private void initializeAnimations() { private void setListeners() { binding.fabPlus.setOnClickListener(view -> animateFAB(isFabOpen)); binding.fabCamera.setOnClickListener(view -> { - controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher); + controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult); animateFAB(isFabOpen); }); binding.fabCamera.setOnLongClickListener(view -> { @@ -330,7 +356,7 @@ private void setListeners() { return true; }); binding.fabGallery.setOnClickListener(view -> { - controller.initiateGalleryPick(getActivity(), true); + controller.initiateGalleryPick(getActivity(), galleryPickLauncherForResult, true); animateFAB(isFabOpen); }); binding.fabGallery.setOnLongClickListener(view -> { @@ -343,7 +369,7 @@ private void setListeners() { * Launch Custom Selector. */ protected void launchCustomSelector() { - controller.initiateCustomGalleryPickWithPermission(getActivity()); + controller.initiateCustomGalleryPickWithPermission(getActivity(), customSelectorLauncherForResult); animateFAB(isFabOpen); } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java index 54d3e96818..a9e9ee5c62 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java @@ -438,13 +438,6 @@ public void onReady() { }); } - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - Timber.d(data != null ? data.toString() : "onActivityResult data is null"); - super.onActivityResult(requestCode, resultCode, data); - controller.handleActivityResult(this, requestCode, resultCode, data); - } - @Override protected void onResume() { super.onResume(); diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt index 3bba6f05cc..959db52f3b 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt @@ -13,6 +13,8 @@ import android.view.Window import android.widget.Button import android.widget.ImageButton import android.widget.TextView +import androidx.activity.result.ActivityResult +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -146,6 +148,10 @@ class CustomSelectorActivity : private var showPartialAccessIndicator by mutableStateOf(false) + private val startForResult = registerForActivityResult(StartActivityForResult()){ result -> + onFullScreenDataReceived(result) + } + /** * onCreate Activity, sets theme, initialises the view model, setup view. */ @@ -224,17 +230,10 @@ class CustomSelectorActivity : /** * When data will be send from full screen mode, it will be passed to fragment */ - override fun onActivityResult( - requestCode: Int, - resultCode: Int, - data: Intent?, - ) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == Constants.RequestCodes.RECEIVE_DATA_FROM_FULL_SCREEN_MODE && - resultCode == Activity.RESULT_OK - ) { + private fun onFullScreenDataReceived(result: ActivityResult){ + if (result.resultCode == Activity.RESULT_OK) { val selectedImages: ArrayList = - data!! + result.data!! .getParcelableArrayListExtra(CustomSelectorConstants.NEW_SELECTED_IMAGES)!! viewModel?.selectedImages?.value = selectedImages } @@ -509,7 +508,7 @@ class CustomSelectorActivity : selectedImages, ) intent.putExtra(CustomSelectorConstants.BUCKET_ID, bucketId) - startActivityForResult(intent, Constants.RequestCodes.RECEIVE_DATA_FROM_FULL_SCREEN_MODE) + startForResult.launch(intent) } /** diff --git a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt index 0dbdf71ae0..cfd7f36b9a 100644 --- a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt @@ -6,6 +6,8 @@ import android.os.Bundle import android.os.Parcelable import android.speech.RecognizerIntent import android.view.View +import androidx.activity.result.ActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import fr.free.nrw.commons.CommonsApplication @@ -70,10 +72,14 @@ class DescriptionEditActivity : private lateinit var binding: ActivityDescriptionEditBinding - private val requestCodeForVoiceInput = 1213 - private var descriptionAndCaptions: ArrayList? = null + private val voiceInputResultLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result: ActivityResult -> + onVoiceInput(result) + } + @Inject lateinit var descriptionEditHelper: DescriptionEditHelper @Inject lateinit var sessionManager: SessionManager @@ -115,6 +121,7 @@ class DescriptionEditActivity : savedLanguageValue, descriptionAndCaptions, recentLanguagesDao, + voiceInputResultLauncher ) uploadMediaDetailAdapter.setCallback { titleStringID: Int, messageStringId: Int -> showInfoAlert( @@ -149,6 +156,15 @@ class DescriptionEditActivity : override fun onPrimaryCaptionTextChange(isNotEmpty: Boolean) {} + private fun onVoiceInput(result: ActivityResult) { + if (result.resultCode == RESULT_OK && result.data != null) { + val resultData = result.data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) + uploadMediaDetailAdapter.handleSpeechResult(resultData!![0]) + } else { + Timber.e("Error %s", result.resultCode) + } + } + /** * Adds new language item to RecyclerView */ @@ -292,22 +308,6 @@ class DescriptionEditActivity : progressDialog!!.show() } - override fun onActivityResult( - requestCode: Int, - resultCode: Int, - data: Intent?, - ) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == requestCodeForVoiceInput) { - if (resultCode == RESULT_OK && data != null) { - val result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) - uploadMediaDetailAdapter.handleSpeechResult(result!![0]) - } else { - Timber.e("Error %s", resultCode) - } - } - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) diff --git a/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java b/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java index f907f0a014..4a58232522 100644 --- a/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java +++ b/app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java @@ -4,20 +4,11 @@ public interface Constants { String DEFAULT_FOLDER_NAME = "CommonsContributions"; /** - * Provides the request codes utilised by the FilePicker + * Provides the request codes for permission handling */ interface RequestCodes { int LOCATION = 1; int STORAGE = 2; - int FILE_PICKER_IMAGE_IDENTIFICATOR = 0b1101101100; //876 - int SOURCE_CHOOSER = 1 << 15; - - int PICK_PICTURE_FROM_CUSTOM_SELECTOR = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 10); - int PICK_PICTURE_FROM_DOCUMENTS = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 11); - int PICK_PICTURE_FROM_GALLERY = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 12); - int TAKE_PICTURE = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 13); - - int RECEIVE_DATA_FROM_FULL_SCREEN_MODE = 1 << 9; } /** diff --git a/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java b/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java index daa29276a8..b64db24c5f 100644 --- a/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java +++ b/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java @@ -12,6 +12,8 @@ import android.net.Uri; import android.provider.MediaStore; import android.text.TextUtils; +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.PreferenceManager; @@ -107,31 +109,25 @@ private static int restoreType(@NonNull Context context) { * * @param type Custom type of your choice, which will be returned with the images */ - public static void openGallery(Activity activity, int type, boolean openDocumentIntentPreferred) { + public static void openGallery(Activity activity, ActivityResultLauncher resultLauncher, int type, boolean openDocumentIntentPreferred) { Intent intent = createGalleryIntent(activity, type, openDocumentIntentPreferred); - int requestCode = RequestCodes.PICK_PICTURE_FROM_GALLERY; - - if(openDocumentIntentPreferred){ - requestCode = RequestCodes.PICK_PICTURE_FROM_DOCUMENTS; - } - - activity.startActivityForResult(intent, requestCode); + resultLauncher.launch(intent); } /** * Opens Custom Selector */ - public static void openCustomSelector(Activity activity, int type) { + public static void openCustomSelector(Activity activity, ActivityResultLauncher resultLauncher, int type) { Intent intent = createCustomSelectorIntent(activity, type); - activity.startActivityForResult(intent, RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR); + resultLauncher.launch(intent); } /** * Opens the camera app to pick image clicked by user */ - public static void openCameraForImage(Activity activity, int type) { + public static void openCameraForImage(Activity activity, ActivityResultLauncher resultLauncher, int type) { Intent intent = createCameraForImageIntent(activity, type); - activity.startActivityForResult(intent, RequestCodes.TAKE_PICTURE); + resultLauncher.launch(intent); } @Nullable @@ -154,43 +150,6 @@ private static UploadableFile takenCameraVideo(Context context) throws URISyntax } } - /** - * Any activity can use this method to attach their callback to the file picker - */ - public static void handleActivityResult(int requestCode, int resultCode, Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) { - boolean isHandledPickedFile = (requestCode & RequestCodes.FILE_PICKER_IMAGE_IDENTIFICATOR) > 0; - if (isHandledPickedFile) { - requestCode &= ~RequestCodes.SOURCE_CHOOSER; - if (requestCode == RequestCodes.PICK_PICTURE_FROM_GALLERY || - requestCode == RequestCodes.TAKE_PICTURE || - requestCode == RequestCodes.PICK_PICTURE_FROM_DOCUMENTS || - requestCode == RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR) { - if (resultCode == Activity.RESULT_OK) { - if (requestCode == RequestCodes.PICK_PICTURE_FROM_DOCUMENTS && !isPhoto(data)) { - onPictureReturnedFromDocuments(data, activity, callbacks); - } else if (requestCode == RequestCodes.PICK_PICTURE_FROM_GALLERY && !isPhoto(data)) { - onPictureReturnedFromGallery(data, activity, callbacks); - } else if (requestCode == RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR) { - onPictureReturnedFromCustomSelector(data, activity, callbacks); - } else if (requestCode == RequestCodes.TAKE_PICTURE) { - onPictureReturnedFromCamera(activity, callbacks); - } - } else { - if (requestCode == RequestCodes.PICK_PICTURE_FROM_DOCUMENTS) { - callbacks.onCanceled(FilePicker.ImageSource.DOCUMENTS, restoreType(activity)); - } else if (requestCode == RequestCodes.PICK_PICTURE_FROM_GALLERY) { - callbacks.onCanceled(FilePicker.ImageSource.GALLERY, restoreType(activity)); - } else if (requestCode == RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR){ - callbacks.onCanceled(ImageSource.CUSTOM_SELECTOR, restoreType(activity)); - } - else { - callbacks.onCanceled(FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); - } - } - } - } - } - public static List handleExternalImagesPicked(Intent data, Activity activity) { try { return getFilesFromGalleryPictures(data, activity); @@ -243,18 +202,22 @@ private static Intent plainGalleryPickerIntent(boolean openDocumentIntentPreferr return intent; } - private static void onPictureReturnedFromDocuments(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) { - try { - Uri photoPath = data.getData(); - UploadableFile photoFile = PickedFiles.pickedExistingPicture(activity, photoPath); - callbacks.onImagesPicked(singleFileList(photoFile), FilePicker.ImageSource.DOCUMENTS, restoreType(activity)); + public static void onPictureReturnedFromDocuments(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) { + if(result.getResultCode() == Activity.RESULT_OK && !isPhoto(result.getData())){ + try { + Uri photoPath = result.getData().getData(); + UploadableFile photoFile = PickedFiles.pickedExistingPicture(activity, photoPath); + callbacks.onImagesPicked(singleFileList(photoFile), FilePicker.ImageSource.DOCUMENTS, restoreType(activity)); - if (configuration(activity).shouldCopyPickedImagesToPublicGalleryAppFolder()) { - PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile)); + if (configuration(activity).shouldCopyPickedImagesToPublicGalleryAppFolder()) { + PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile)); + } + } catch (Exception e) { + e.printStackTrace(); + callbacks.onImagePickerError(e, FilePicker.ImageSource.DOCUMENTS, restoreType(activity)); } - } catch (Exception e) { - e.printStackTrace(); - callbacks.onImagePickerError(e, FilePicker.ImageSource.DOCUMENTS, restoreType(activity)); + } else { + callbacks.onCanceled(FilePicker.ImageSource.DOCUMENTS, restoreType(activity)); } } @@ -262,14 +225,18 @@ private static void onPictureReturnedFromDocuments(Intent data, Activity activit * onPictureReturnedFromCustomSelector. * Retrieve and forward the images to upload wizard through callback. */ - private static void onPictureReturnedFromCustomSelector(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) { - try { - List files = getFilesFromCustomSelector(data, activity); - callbacks.onImagesPicked(files, ImageSource.CUSTOM_SELECTOR, restoreType(activity)); - } catch (Exception e) { - e.printStackTrace(); - callbacks.onImagePickerError(e, ImageSource.CUSTOM_SELECTOR, restoreType(activity)); - } + public static void onPictureReturnedFromCustomSelector(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) { + if(result.getResultCode() == Activity.RESULT_OK){ + try { + List files = getFilesFromCustomSelector(result.getData(), activity); + callbacks.onImagesPicked(files, ImageSource.CUSTOM_SELECTOR, restoreType(activity)); + } catch (Exception e) { + e.printStackTrace(); + callbacks.onImagePickerError(e, ImageSource.CUSTOM_SELECTOR, restoreType(activity)); + } + } else { + callbacks.onCanceled(ImageSource.CUSTOM_SELECTOR, restoreType(activity)); + } } /** @@ -292,13 +259,17 @@ private static List getFilesFromCustomSelector(Intent data, Acti return files; } - private static void onPictureReturnedFromGallery(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) { - try { - List files = getFilesFromGalleryPictures(data, activity); - callbacks.onImagesPicked(files, FilePicker.ImageSource.GALLERY, restoreType(activity)); - } catch (Exception e) { - e.printStackTrace(); - callbacks.onImagePickerError(e, FilePicker.ImageSource.GALLERY, restoreType(activity)); + public static void onPictureReturnedFromGallery(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) { + if(result.getResultCode() == Activity.RESULT_OK && !isPhoto(result.getData())){ + try { + List files = getFilesFromGalleryPictures(result.getData(), activity); + callbacks.onImagesPicked(files, FilePicker.ImageSource.GALLERY, restoreType(activity)); + } catch (Exception e) { + e.printStackTrace(); + callbacks.onImagePickerError(e, FilePicker.ImageSource.GALLERY, restoreType(activity)); + } + } else{ + callbacks.onCanceled(FilePicker.ImageSource.GALLERY, restoreType(activity)); } } @@ -324,69 +295,40 @@ private static List getFilesFromGalleryPictures(Intent data, Act return files; } - private static void onPictureReturnedFromCamera(Activity activity, @NonNull FilePicker.Callbacks callbacks) { - try { - String lastImageUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_PHOTO_URI, null); - if (!TextUtils.isEmpty(lastImageUri)) { - revokeWritePermission(activity, Uri.parse(lastImageUri)); - } + public static void onPictureReturnedFromCamera(ActivityResult activityResult, Activity activity, @NonNull FilePicker.Callbacks callbacks) { + if(activityResult.getResultCode() == Activity.RESULT_OK){ + try { + String lastImageUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_PHOTO_URI, null); + if (!TextUtils.isEmpty(lastImageUri)) { + revokeWritePermission(activity, Uri.parse(lastImageUri)); + } - UploadableFile photoFile = FilePicker.takenCameraPicture(activity); - List files = new ArrayList<>(); - files.add(photoFile); + UploadableFile photoFile = FilePicker.takenCameraPicture(activity); + List files = new ArrayList<>(); + files.add(photoFile); - if (photoFile == null) { - Exception e = new IllegalStateException("Unable to get the picture returned from camera"); - callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); - } else { - if (configuration(activity).shouldCopyTakenPhotosToPublicGalleryAppFolder()) { - PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile)); - } + if (photoFile == null) { + Exception e = new IllegalStateException("Unable to get the picture returned from camera"); + callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); + } else { + if (configuration(activity).shouldCopyTakenPhotosToPublicGalleryAppFolder()) { + PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile)); + } - callbacks.onImagesPicked(files, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); - } + callbacks.onImagesPicked(files, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); + } - PreferenceManager.getDefaultSharedPreferences(activity) + PreferenceManager.getDefaultSharedPreferences(activity) .edit() .remove(KEY_LAST_CAMERA_PHOTO) .remove(KEY_PHOTO_URI) .apply(); - } catch (Exception e) { - e.printStackTrace(); - callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); - } - } - - private static void onVideoReturnedFromCamera(Activity activity, @NonNull FilePicker.Callbacks callbacks) { - try { - String lastVideoUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_VIDEO_URI, null); - if (!TextUtils.isEmpty(lastVideoUri)) { - revokeWritePermission(activity, Uri.parse(lastVideoUri)); - } - - UploadableFile photoFile = FilePicker.takenCameraVideo(activity); - List files = new ArrayList<>(); - files.add(photoFile); - - if (photoFile == null) { - Exception e = new IllegalStateException("Unable to get the video returned from camera"); - callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_VIDEO, restoreType(activity)); - } else { - if (configuration(activity).shouldCopyTakenPhotosToPublicGalleryAppFolder()) { - PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile)); - } - - callbacks.onImagesPicked(files, FilePicker.ImageSource.CAMERA_VIDEO, restoreType(activity)); + } catch (Exception e) { + e.printStackTrace(); + callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); } - - PreferenceManager.getDefaultSharedPreferences(activity) - .edit() - .remove(KEY_LAST_CAMERA_VIDEO) - .remove(KEY_VIDEO_URI) - .apply(); - } catch (Exception e) { - e.printStackTrace(); - callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_VIDEO, restoreType(activity)); + } else { + callbacks.onCanceled(FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity)); } } @@ -406,4 +348,8 @@ public interface Callbacks { void onCanceled(FilePicker.ImageSource source, int type); } + + public interface HandleActivityResult{ + void onHandleActivityResult(FilePicker.Callbacks callbacks); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 7336c1b407..dd0829a1b5 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -1,13 +1,10 @@ package fr.free.nrw.commons.media; -import static android.app.Activity.RESULT_CANCELED; -import static android.app.Activity.RESULT_OK; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_NEEDING_CATEGORIES; import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_UNCATEGORISED; import static fr.free.nrw.commons.description.EditDescriptionConstants.LIST_OF_DESCRIPTION_AND_CAPTION; -import static fr.free.nrw.commons.description.EditDescriptionConstants.UPDATED_WIKITEXT; import static fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT; import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION; import static fr.free.nrw.commons.utils.LangCodeUtils.getLocalizedResources; @@ -112,8 +109,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements CategoryEditHelper.Callback { - private static final int REQUEST_CODE = 1001; - private static final int REQUEST_CODE_EDIT_DESCRIPTION = 1002; private static final String IMAGE_BACKGROUND_COLOR = "image_background_color"; static final int DEFAULT_IMAGE_BACKGROUND_COLOR = 0; @@ -1065,81 +1060,6 @@ private LinkedHashMap getCaptionsList() { return captionList; } - /** - * Get the result from another activity and act accordingly. - * @param requestCode - * @param resultCode - * @param data - */ - @Override - public void onActivityResult(final int requestCode, final int resultCode, - @Nullable final Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_OK) { - final String updatedWikiText = data.getStringExtra(UPDATED_WIKITEXT); - - try { - compositeDisposable.add(descriptionEditHelper.addDescription(getContext(), media, - updatedWikiText) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(s -> { - Timber.d("Descriptions are added."); - })); - } catch (Exception e) { - if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) { - final String username = sessionManager.getUserName(); - final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener( - getActivity(), - requireActivity().getString(R.string.invalid_login_message), - username - ); - - CommonsApplication.getInstance().clearApplicationData( - requireActivity(), logoutListener); - } - } - - final ArrayList uploadMediaDetails - = data.getParcelableArrayListExtra(LIST_OF_DESCRIPTION_AND_CAPTION); - - LinkedHashMap updatedCaptions = new LinkedHashMap<>(); - for (UploadMediaDetail mediaDetail: - uploadMediaDetails) { - try { - compositeDisposable.add(descriptionEditHelper.addCaption(getContext(), media, - mediaDetail.getLanguageCode(), mediaDetail.getCaptionText()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(s -> { - updateCaptions(mediaDetail, updatedCaptions); - Timber.d("Caption is added."); - })); - - } catch (Exception e) { - if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) { - final String username = sessionManager.getUserName(); - final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener( - getActivity(), - requireActivity().getString(R.string.invalid_login_message), - username - ); - - CommonsApplication.getInstance().clearApplicationData( - requireActivity(), logoutListener); - } - } - } - binding.progressBarEdit.setVisibility(GONE); - binding.descriptionEdit.setVisibility(VISIBLE); - - } else if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_CANCELED) { - binding.progressBarEdit.setVisibility(GONE); - binding.descriptionEdit.setVisibility(VISIBLE); - } - } - /** * Adds caption to the map and updates captions * @param mediaDetail UploadMediaDetail diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt index 5152ac0f79..a4ea3cd5b2 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt @@ -1,5 +1,6 @@ package fr.free.nrw.commons.nearby +import android.content.Intent import android.view.View import android.view.View.GONE import android.view.View.INVISIBLE @@ -17,9 +18,9 @@ import fr.free.nrw.commons.databinding.ItemPlaceBinding fun placeAdapterDelegate( bookmarkLocationDao: BookmarkLocationsDao, onItemClick: ((Place) -> Unit)? = null, - onCameraClicked: (Place, ActivityResultLauncher>) -> Unit, + onCameraClicked: (Place, ActivityResultLauncher>, ActivityResultLauncher) -> Unit, onCameraLongPressed: () -> Boolean, - onGalleryClicked: (Place) -> Unit, + onGalleryClicked: (Place, ActivityResultLauncher) -> Unit, onGalleryLongPressed: () -> Boolean, onBookmarkClicked: (Place, Boolean) -> Unit, onBookmarkLongPressed: () -> Boolean, @@ -28,6 +29,8 @@ fun placeAdapterDelegate( onDirectionsClicked: (Place) -> Unit, onDirectionsLongPressed: () -> Boolean, inAppCameraLocationPermissionLauncher: ActivityResultLauncher>, + cameraPickLauncherForResult: ActivityResultLauncher, + galleryPickLauncherForResult: ActivityResultLauncher ) = adapterDelegateViewBinding({ layoutInflater, parent -> ItemPlaceBinding.inflate(layoutInflater, parent, false) }) { @@ -44,10 +47,10 @@ fun placeAdapterDelegate( onItemClick?.invoke(item) } } - nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher) } + nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult) } nearbyButtonLayout.cameraButton.setOnLongClickListener { onCameraLongPressed() } - nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item) } + nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item, galleryPickLauncherForResult) } nearbyButtonLayout.galleryButton.setOnLongClickListener { onGalleryLongPressed() } bookmarkButtonImage.setOnClickListener { val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt index f3eecf1160..a4d6b14b7d 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt @@ -28,14 +28,14 @@ class CommonPlaceClickActions private val activity: Activity, private val contributionController: ContributionController, ) { - fun onCameraClicked(): (Place, ActivityResultLauncher>) -> Unit = - { place, launcher -> + fun onCameraClicked(): (Place, ActivityResultLauncher>, ActivityResultLauncher) -> Unit = + { place, launcher, resultLauncher -> if (applicationKvStore.getBoolean("login_skipped", false)) { showLoginDialog() } else { Timber.d("Camera button tapped. Image title: ${place.getName()}Image desc: ${place.longDescription}") storeSharedPrefs(place) - contributionController.initiateCameraPick(activity, launcher) + contributionController.initiateCameraPick(activity, launcher, resultLauncher) } } @@ -72,14 +72,14 @@ class CommonPlaceClickActions true } - fun onGalleryClicked(): (Place) -> Unit = - { + fun onGalleryClicked(): (Place, ActivityResultLauncher) -> Unit = + {place, galleryPickLauncherForResult -> if (applicationKvStore.getBoolean("login_skipped", false)) { showLoginDialog() } else { - Timber.d("Gallery button tapped. Image title: ${it.getName()}Image desc: ${it.getLongDescription()}") - storeSharedPrefs(it) - contributionController.initiateGalleryPick(activity, false) + Timber.d("Gallery button tapped. Image title: ${place.getName()}Image desc: ${place.getLongDescription()}") + storeSharedPrefs(place) + contributionController.initiateGalleryPick(activity, galleryPickLauncherForResult, false) } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java index f578afc259..7a7d5cdcba 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java @@ -49,6 +49,7 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions; import androidx.activity.result.contract.ActivityResultContracts.RequestPermission; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -225,6 +226,31 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private GridLayoutManager gridLayoutManager; private List dataList; private BottomSheetAdapter bottomSheetAdapter; + + private final ActivityResultLauncher galleryPickLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { + controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks); + }); + }); + + private final ActivityResultLauncher customSelectorLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { + controller.onPictureReturnedFromCustomSelector(result, requireActivity(), callbacks); + }); + }); + + private final ActivityResultLauncher cameraPickLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { + controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks); + }); + }); + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult( new RequestMultiplePermissions(), new ActivityResultCallback>() { @@ -240,7 +266,7 @@ public void onActivityResult(Map result) { } else { if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { controller.handleShowRationaleFlowCameraLocation(getActivity(), - inAppCameraLocationPermissionLauncher); + inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult); } else { controller.locationPermissionCallback.onLocationPermissionDenied( getActivity().getString( @@ -570,7 +596,9 @@ private void initRvNearbyList() { return Unit.INSTANCE; }, commonPlaceClickActions, - inAppCameraLocationPermissionLauncher + inAppCameraLocationPermissionLauncher, + galleryPickLauncherForResult, + cameraPickLauncherForResult ); binding.bottomSheetNearby.rvNearbyList.setAdapter(adapter); } @@ -2201,7 +2229,7 @@ private void passInfoToSheet(final Place place) { if (binding.fabCamera.isShown()) { Timber.d("Camera button tapped. Place: %s", selectedPlace.toString()); storeSharedPrefs(selectedPlace); - controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher); + controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult); } }); @@ -2210,6 +2238,7 @@ private void passInfoToSheet(final Place place) { Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString()); storeSharedPrefs(selectedPlace); controller.initiateGalleryPick(getActivity(), + galleryPickLauncherForResult, false); } }); @@ -2218,7 +2247,7 @@ private void passInfoToSheet(final Place place) { if (binding.fabCustomGallery.isShown()) { Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString()); storeSharedPrefs(selectedPlace); - controller.initiateCustomGalleryPickWithPermission(getActivity()); + controller.initiateCustomGalleryPickWithPermission(getActivity(), customSelectorLauncherForResult); } }); } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt index 689aa7efca..e5cc926671 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt @@ -1,5 +1,6 @@ package fr.free.nrw.commons.nearby.fragments +import android.content.Intent import androidx.activity.result.ActivityResultLauncher import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao import fr.free.nrw.commons.nearby.Place @@ -12,6 +13,8 @@ class PlaceAdapter( onBookmarkClicked: (Place, Boolean) -> Unit, commonPlaceClickActions: CommonPlaceClickActions, inAppCameraLocationPermissionLauncher: ActivityResultLauncher>, + galleryPickLauncherForResult: ActivityResultLauncher, + cameraPickLauncherForResult: ActivityResultLauncher ) : BaseDelegateAdapter( placeAdapterDelegate( bookmarkLocationsDao, @@ -27,6 +30,8 @@ class PlaceAdapter( commonPlaceClickActions.onDirectionsClicked(), commonPlaceClickActions.onDirectionsLongPressed(), inAppCameraLocationPermissionLauncher, + cameraPickLauncherForResult, + galleryPickLauncherForResult ), areItemsTheSame = { oldItem, newItem -> oldItem.wikiDataEntityId == newItem.wikiDataEntityId }, ) diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index 94e799aa29..5e631425b4 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -21,6 +21,7 @@ import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.preference.ListPreference; import androidx.preference.MultiSelectListPreference; import androidx.preference.Preference; @@ -85,6 +86,15 @@ public class SettingsFragment extends PreferenceFragmentCompat { private View separator; private ListView languageHistoryListView; private static final String GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content"; + + private final ActivityResultLauncher cameraPickLauncherForResult = + registerForActivityResult(new StartActivityForResult(), + result -> { + contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> { + contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks); + }); + }); + private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { @Override public void onActivityResult(Map result) { @@ -93,7 +103,7 @@ public void onActivityResult(Map result) { areAllGranted = areAllGranted && b; } if (!areAllGranted && shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher); + contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult); } } }); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java index 23b1873401..35906c3fb5 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.java @@ -441,14 +441,6 @@ public void onRequestPermissionsResult(final int requestCode, super.onRequestPermissionsResult(requestCode, permissions, grantResults); } - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS) { - //TODO: Confirm if handling manual permission enabled is required - } - } - /** * Sets the flag indicating whether the upload is of a specific place. * diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.java index ecddab43d8..6fc8b3266d 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.java @@ -20,6 +20,7 @@ import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.constraintlayout.widget.ConstraintLayout; @@ -57,27 +58,29 @@ public class UploadMediaDetailAdapter extends private int currentPosition; private Fragment fragment; private Activity activity; + private final ActivityResultLauncher voiceInputResultLauncher; private SelectedVoiceIcon selectedVoiceIcon; - private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213; private RowItemDescriptionBinding binding; public UploadMediaDetailAdapter(Fragment fragment, String savedLanguageValue, - RecentLanguagesDao recentLanguagesDao) { + RecentLanguagesDao recentLanguagesDao, ActivityResultLauncher voiceInputResultLauncher) { uploadMediaDetails = new ArrayList<>(); selectedLanguages = new HashMap<>(); this.savedLanguageValue = savedLanguageValue; this.recentLanguagesDao = recentLanguagesDao; this.fragment = fragment; + this.voiceInputResultLauncher = voiceInputResultLauncher; } public UploadMediaDetailAdapter(Activity activity, final String savedLanguageValue, - List uploadMediaDetails, RecentLanguagesDao recentLanguagesDao) { + List uploadMediaDetails, RecentLanguagesDao recentLanguagesDao, ActivityResultLauncher voiceInputResultLauncher) { this.uploadMediaDetails = uploadMediaDetails; selectedLanguages = new HashMap<>(); this.savedLanguageValue = savedLanguageValue; this.recentLanguagesDao = recentLanguagesDao; this.activity = activity; + this.voiceInputResultLauncher = voiceInputResultLauncher; } public void setCallback(Callback callback) { @@ -150,11 +153,7 @@ private void startSpeechInput(String locale) { ); try { - if (activity == null) { - fragment.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT); - } else { - activity.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT); - } + voiceInputResultLauncher.launch(intent); } catch (Exception e) { Timber.e(e.getMessage()); } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java index 105df1837a..2c4c2ecd3d 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java @@ -18,6 +18,9 @@ import android.widget.CheckBox; import android.widget.ImageView; import android.widget.Toast; +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.exifinterface.media.ExifInterface; @@ -58,9 +61,24 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener { - private static final int REQUEST_CODE = 1211; - private static final int REQUEST_CODE_FOR_EDIT_ACTIVITY = 1212; - private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213; + private UploadMediaDetailAdapter uploadMediaDetailAdapter; + + private final ActivityResultLauncher startForResult = registerForActivityResult( + new StartActivityForResult(), result -> { + onCameraPosition(result); + }); + + private final ActivityResultLauncher startForEditActivityResult = registerForActivityResult( + new StartActivityForResult(), result -> { + onEditActivityResult(result); + } + ); + + private final ActivityResultLauncher voiceInputResultLauncher = registerForActivityResult( + new StartActivityForResult(), result -> { + onVoiceInput(result); + } + ); public static Activity activity ; @@ -84,8 +102,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements private boolean hasUserRemovedLocation; - private UploadMediaDetailAdapter uploadMediaDetailAdapter; - @Inject UploadMediaDetailsContract.UserActionListener presenter; @@ -279,7 +295,7 @@ private void initPresenter() { */ private void initRecyclerView() { uploadMediaDetailAdapter = new UploadMediaDetailAdapter(this, - defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao); + defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao, voiceInputResultLauncher); uploadMediaDetailAdapter.setCallback(this::showInfoAlert); uploadMediaDetailAdapter.setEventListener(this); binding.rvDescriptions.setLayoutManager(new LinearLayoutManager(getContext())); @@ -593,14 +609,14 @@ public void showExternalMap(final UploadItem uploadItem) { * This method is called to start the image editing activity for a specific UploadItem. * It sets the UploadItem as the currently editable item, creates an intent to launch the * EditActivity, and passes the image file path as an extra in the intent. The activity - * is started with a request code, allowing the result to be handled in onActivityResult. + * is started using resultLauncher that handles the result in respective callback. */ @Override public void showEditActivity(UploadItem uploadItem) { editableUploadItem = uploadItem; Intent intent = new Intent(getContext(), EditActivity.class); intent.putExtra("image", uploadableFile.getFilePath().toString()); - startActivityForResult(intent, REQUEST_CODE_FOR_EDIT_ACTIVITY); + startForEditActivityResult.launch(intent); } /** @@ -615,6 +631,8 @@ private void goToLocationPickerActivity(final UploadItem uploadItem) { double defaultLongitude = -122.431297; double defaultZoom = 16.0; + final Intent locationPickerIntent; + /* Retrieve image location from EXIF if present or check if user has provided location while using the in-app camera. Use location of last UploadItem if none of them is available */ @@ -624,10 +642,11 @@ private void goToLocationPickerActivity(final UploadItem uploadItem) { .getDecLatitude(); defaultLongitude = uploadItem.getGpsCoords().getDecLongitude(); defaultZoom = uploadItem.getGpsCoords().getZoomLevel(); - startActivityForResult(new LocationPicker.IntentBuilder() + + locationPickerIntent = new LocationPicker.IntentBuilder() .defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom)) .activityKey("UploadActivity") - .build(getActivity()), REQUEST_CODE); + .build(getActivity()); } else { if (defaultKvStore.getString(LAST_LOCATION) != null) { final String[] locationLatLng @@ -638,27 +657,20 @@ private void goToLocationPickerActivity(final UploadItem uploadItem) { if (defaultKvStore.getString(LAST_ZOOM) != null) { defaultZoom = Double.parseDouble(defaultKvStore.getString(LAST_ZOOM)); } - startActivityForResult(new LocationPicker.IntentBuilder() + + locationPickerIntent = new LocationPicker.IntentBuilder() .defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom)) .activityKey("NoLocationUploadActivity") - .build(getActivity()), REQUEST_CODE); + .build(getActivity()); } + startForResult.launch(locationPickerIntent); } - /** - * Get the coordinates and update the existing coordinates. - * @param requestCode code of request - * @param resultCode code of result - * @param data intent - */ - @Override - public void onActivityResult(final int requestCode, final int resultCode, - @Nullable final Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) { + private void onCameraPosition(ActivityResult result){ + if (result.getResultCode() == RESULT_OK) { - assert data != null; - final CameraPosition cameraPosition = LocationPicker.getCameraPosition(data); + assert result.getData() != null; + final CameraPosition cameraPosition = LocationPicker.getCameraPosition(result.getData()); if (cameraPosition != null) { @@ -678,8 +690,21 @@ public void onActivityResult(final int requestCode, final int resultCode, removeLocation(); } } - if (requestCode == REQUEST_CODE_FOR_EDIT_ACTIVITY && resultCode == RESULT_OK) { - String result = data.getStringExtra("editedImageFilePath"); + } + + private void onVoiceInput(ActivityResult result) { + if (result.getResultCode() == RESULT_OK && result.getData() != null) { + ArrayList resultData = result.getData().getStringArrayListExtra( + RecognizerIntent.EXTRA_RESULTS); + uploadMediaDetailAdapter.handleSpeechResult(resultData.get(0)); + }else { + Timber.e("Error %s", result.getResultCode()); + } + } + + private void onEditActivityResult(ActivityResult result){ + if (result.getResultCode() == RESULT_OK) { + String path = result.getData().getStringExtra("editedImageFilePath"); if (Objects.equals(result, "Error")) { Timber.e("Error in rotating image"); @@ -687,24 +712,15 @@ public void onActivityResult(final int requestCode, final int resultCode, } try { if (binding != null){ - binding.backgroundImage.setImageURI(Uri.fromFile(new File(result))); + binding.backgroundImage.setImageURI(Uri.fromFile(new File(path))); } - editableUploadItem.setContentUri(Uri.fromFile(new File(result))); + editableUploadItem.setContentUri(Uri.fromFile(new File(path))); callback.changeThumbnail(indexOfFragment, - result); + path); } catch (Exception e) { Timber.e(e); } } - else if (requestCode == REQUEST_CODE_FOR_VOICE_INPUT) { - if (resultCode == RESULT_OK && data != null) { - ArrayList result = data.getStringArrayListExtra( - RecognizerIntent.EXTRA_RESULTS); - uploadMediaDetailAdapter.handleSpeechResult(result.get(0)); - }else { - Timber.e("Error %s", resultCode); - } - } } /** diff --git a/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java index 9082c1f0fc..828ef2338b 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java @@ -54,8 +54,7 @@ private static void askUserToManuallyEnablePermissionFromSettings(final Activity final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); final Uri uri = Uri.fromParts("package", activity.getPackageName(), null); intent.setData(uri); - activity.startActivityForResult(intent, - CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS); + activity.startActivity(intent); } /** diff --git a/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt index a2eb41615a..780322603a 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt @@ -340,20 +340,6 @@ class MainActivityUnitTests { method.invoke(activity, null, true) } - @Test - @Throws(Exception::class) - fun testOnActivityResult() { - val method: Method = - MainActivity::class.java.getDeclaredMethod( - "onActivityResult", - Int::class.java, - Int::class.java, - Intent::class.java, - ) - method.isAccessible = true - method.invoke(activity, 0, 0, null) - } - @Test @Throws(Exception::class) fun testOnResume() { diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt index 0274fed7d3..b1d66ee4d3 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt @@ -1,8 +1,10 @@ package fr.free.nrw.commons.customselector.ui.selector +import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.activity.result.ActivityResult import fr.free.nrw.commons.OkHttpConnectionFactory import fr.free.nrw.commons.TestCommonsApplication import fr.free.nrw.commons.contributions.ContributionDao @@ -98,20 +100,20 @@ class CustomSelectorActivityTest { } /** - * Test onActivityResult function. + * Test callback when result received. */ @Test @Throws(Exception::class) - fun testOnActivityResult() { + fun testResultLauncher() { + val intent = Mockito.mock(Intent::class.java) + val activityResult = ActivityResult(Activity.RESULT_OK, intent) val func = activity.javaClass.getDeclaredMethod( - "onActivityResult", - Int::class.java, - Int::class.java, - Intent::class.java, + "onFullScreenDataReceived", + ActivityResult::class.java, ) func.isAccessible = true - func.invoke(activity, 512, -1, Mockito.mock(Intent::class.java)) + func.invoke(activity, activityResult) } /** diff --git a/app/src/test/kotlin/fr/free/nrw/commons/filepicker/FilePickerTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/filepicker/FilePickerTest.kt index 365af27f03..b7ef7878fd 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/filepicker/FilePickerTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/filepicker/FilePickerTest.kt @@ -6,18 +6,19 @@ import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.net.Uri +import android.provider.MediaStore +import androidx.activity.result.ActivityResultLauncher import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider +import com.nhaarman.mockitokotlin2.KArgumentCaptor +import com.nhaarman.mockitokotlin2.argumentCaptor import com.nhaarman.mockitokotlin2.verify import fr.free.nrw.commons.TestCommonsApplication -import fr.free.nrw.commons.filepicker.Constants.RequestCodes +import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorActivity import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers -import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.`when` @@ -48,8 +49,10 @@ class FilePickerTest { @Mock var unit: Unit? = null - @Captor - var requestCodeCaptor: ArgumentCaptor? = null + @Mock + private lateinit var mockResultLauncher: ActivityResultLauncher + + private val intentCaptor: KArgumentCaptor = argumentCaptor() private lateinit var context: Context @@ -65,15 +68,17 @@ class FilePickerTest { `when`(sharedPref.edit()).thenReturn(sharedPreferencesEditor) `when`(sharedPref.edit().putInt("type", 0)).thenReturn(sharedPreferencesEditor) val openDocumentPreferred = nextBoolean() - FilePicker.openGallery(activity, 0, openDocumentPreferred) - verify(activity).startActivityForResult( - ArgumentMatchers.any(), - requestCodeCaptor?.capture()?.toInt()!!, - ) - if(openDocumentPreferred){ - assertEquals(requestCodeCaptor?.value, RequestCodes.PICK_PICTURE_FROM_DOCUMENTS) - }else{ - assertEquals(requestCodeCaptor?.value, RequestCodes.PICK_PICTURE_FROM_GALLERY) + + FilePicker.openGallery(activity, mockResultLauncher, 0, openDocumentPreferred) + + verify(mockResultLauncher).launch(intentCaptor.capture()) + + val capturedIntent = intentCaptor.firstValue + + if (openDocumentPreferred) { + assertEquals(Intent.ACTION_OPEN_DOCUMENT, capturedIntent.action) + } else { + assertEquals(Intent.ACTION_GET_CONTENT, capturedIntent.action) } } @@ -84,12 +89,13 @@ class FilePickerTest { `when`(sharedPref.edit().putInt("type", 0)).thenReturn(sharedPreferencesEditor) val mockApplication = mock(Application::class.java) `when`(activity.applicationContext).thenReturn(mockApplication) - FilePicker.openCameraForImage(activity, 0) - verify(activity).startActivityForResult( - ArgumentMatchers.any(), - requestCodeCaptor?.capture()?.toInt()!!, - ) - assertEquals(requestCodeCaptor?.value, RequestCodes.TAKE_PICTURE) + FilePicker.openCameraForImage(activity, mockResultLauncher, 0) + + verify(mockResultLauncher).launch(intentCaptor.capture()) + + val capturedIntent = intentCaptor.firstValue + + assertEquals(MediaStore.ACTION_IMAGE_CAPTURE, capturedIntent.action) } @Test @@ -183,46 +189,20 @@ class FilePickerTest { method.invoke(mockFilePicker, mockIntent) } - @Test - fun testHandleActivityResultCaseOne() { - val mockIntent = mock(Intent::class.java) - FilePicker.handleActivityResult( - RequestCodes.FILE_PICKER_IMAGE_IDENTIFICATOR, - Activity.RESULT_OK, - mockIntent, - activity, - object : DefaultCallback() { - override fun onCanceled( - source: FilePicker.ImageSource, - type: Int, - ) { - super.onCanceled(source, type) - } - - override fun onImagePickerError( - e: Exception, - source: FilePicker.ImageSource, - type: Int, - ) { - } - - override fun onImagesPicked( - imagesFiles: List, - source: FilePicker.ImageSource, - type: Int, - ) { - } - }, - ) - } - @Test fun testOpenCustomSelectorRequestCode() { `when`(PreferenceManager.getDefaultSharedPreferences(activity)).thenReturn(sharedPref) `when`(sharedPref.edit()).thenReturn(sharedPreferencesEditor) `when`(sharedPref.edit().putInt("type", 0)).thenReturn(sharedPreferencesEditor) - FilePicker.openCustomSelector(activity, 0) - verify(activity).startActivityForResult(ArgumentMatchers.any(), requestCodeCaptor?.capture()?.toInt()!!) - assertEquals(requestCodeCaptor?.value, RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR) + FilePicker.openCustomSelector(activity, mockResultLauncher, 0) + + verify(mockResultLauncher).launch(intentCaptor.capture()) + + val capturedIntent = intentCaptor.firstValue + + assertEquals( + CustomSelectorActivity.Companion::class.java.declaringClass.name, + capturedIntent.component?.className + ) } } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/media/MediaDetailFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/media/MediaDetailFragmentUnitTests.kt index 7f9e3d5763..ea1d3402d3 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/media/MediaDetailFragmentUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/media/MediaDetailFragmentUnitTests.kt @@ -19,6 +19,7 @@ import android.widget.ProgressBar import android.widget.ScrollView import android.widget.Spinner import android.widget.TextView +import androidx.activity.result.ActivityResult import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentTransaction import androidx.test.core.app.ApplicationProvider @@ -76,7 +77,6 @@ import java.util.Locale @Config(sdk = [21], application = TestCommonsApplication::class) @LooperMode(LooperMode.Mode.PAUSED) class MediaDetailFragmentUnitTests { - private val requestCode = 1001 private val lastLocation = "last_location_while_uploading" private lateinit var fragment: MediaDetailFragment private lateinit var fragmentManager: FragmentManager @@ -231,24 +231,6 @@ class MediaDetailFragmentUnitTests { fragment.onCreateView(layoutInflater, null, savedInstanceState) } - @Test - @Throws(Exception::class) - fun testOnActivityResultLocationPickerActivity() { - fragment.onActivityResult(requestCode, Activity.RESULT_CANCELED, intent) - } - - @Test - @Throws(Exception::class) - fun `test OnActivity Result Cancelled LocationPickerActivity`() { - fragment.onActivityResult(requestCode, Activity.RESULT_CANCELED, intent) - } - - @Test - @Throws(Exception::class) - fun `test OnActivity Result Cancelled DescriptionEditActivity`() { - fragment.onActivityResult(requestCode, Activity.RESULT_OK, intent) - } - @Test @Throws(Exception::class) fun testOnSaveInstanceState() { diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt index d15fe06e5f..938e595af6 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt @@ -167,20 +167,6 @@ class UploadActivityUnitTests { activity.makeUploadRequest() } - @Test - @Throws(Exception::class) - fun testOnActivityResult() { - val method: Method = - UploadActivity::class.java.getDeclaredMethod( - "onActivityResult", - Int::class.java, - Int::class.java, - Intent::class.java, - ) - method.isAccessible = true - method.invoke(activity, CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS, 0, Intent()) - } - @Test @Throws(Exception::class) fun testReceiveSharedItems() { diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt index db5b20f7e6..794b6e64ee 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt @@ -2,11 +2,13 @@ package fr.free.nrw.commons.upload import android.app.Dialog import android.content.Context +import android.content.Intent import android.view.View import android.widget.AdapterView import android.widget.GridLayout import android.widget.ListView import android.widget.TextView +import androidx.activity.result.ActivityResultLauncher import androidx.test.core.app.ApplicationProvider import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.times @@ -67,13 +69,16 @@ class UploadMediaDetailAdapterUnitTest { @Mock private lateinit var adapterView: AdapterView + @Mock + private lateinit var mockResultLauncher: ActivityResultLauncher + @Before fun setUp() { MockitoAnnotations.openMocks(this) uploadMediaDetails = mutableListOf(uploadMediaDetail, uploadMediaDetail) activity = Robolectric.buildActivity(UploadActivity::class.java).get() fragment = mock(UploadMediaDetailFragment::class.java) - adapter = UploadMediaDetailAdapter(fragment, "", recentLanguagesDao) + adapter = UploadMediaDetailAdapter(fragment, "", recentLanguagesDao, mockResultLauncher) context = ApplicationProvider.getApplicationContext() Whitebox.setInternalState(adapter, "uploadMediaDetails", uploadMediaDetails) Whitebox.setInternalState(adapter, "eventListener", eventListener) diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragmentUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragmentUnitTest.kt index ed76b4519f..169bcd5c01 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragmentUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragmentUnitTest.kt @@ -11,6 +11,7 @@ import android.view.View import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView +import androidx.activity.result.ActivityResult import androidx.appcompat.widget.AppCompatButton import androidx.appcompat.widget.AppCompatImageButton import androidx.fragment.app.FragmentManager @@ -348,7 +349,7 @@ class UploadMediaDetailFragmentUnitTest { @Test @Throws(Exception::class) - fun testOnActivityResultOnMapIconClicked() { + fun testOnCameraPositionCallbackOnMapIconClicked() { shadowOf(Looper.getMainLooper()).idle() Mockito.mock(LocationPicker::class.java) val intent = Mockito.mock(Intent::class.java) @@ -363,13 +364,18 @@ class UploadMediaDetailFragmentUnitTest { `when`(latLng.latitude).thenReturn(0.0) `when`(latLng.longitude).thenReturn(0.0) `when`(uploadItem.gpsCoords).thenReturn(imageCoordinates) - fragment.onActivityResult(1211, Activity.RESULT_OK, intent) + val activityResult = ActivityResult(Activity.RESULT_OK, intent) + + val handleResultMethod = UploadMediaDetailFragment::class.java.getDeclaredMethod("onCameraPosition", ActivityResult::class.java) + handleResultMethod.isAccessible = true + + handleResultMethod.invoke(fragment, activityResult) Mockito.verify(presenter, Mockito.times(0)).getImageQuality(0, location, activity) } @Test @Throws(Exception::class) - fun testOnActivityResultAddLocationDialog() { + fun testOnCameraPositionCallbackAddLocationDialog() { shadowOf(Looper.getMainLooper()).idle() Mockito.mock(LocationPicker::class.java) val intent = Mockito.mock(Intent::class.java) @@ -387,7 +393,13 @@ class UploadMediaDetailFragmentUnitTest { `when`(latLng.latitude).thenReturn(0.0) `when`(latLng.longitude).thenReturn(0.0) `when`(uploadItem.gpsCoords).thenReturn(imageCoordinates) - fragment.onActivityResult(1211, Activity.RESULT_OK, intent) + + val activityResult = ActivityResult(Activity.RESULT_OK,intent) + + val handleResultMethod = UploadMediaDetailFragment::class.java.getDeclaredMethod("onCameraPosition", ActivityResult::class.java) + handleResultMethod.isAccessible = true + + handleResultMethod.invoke(fragment, activityResult) Mockito.verify(presenter, Mockito.times(1)).displayLocDialog(0, null, false) }