Repository: commons-app/apps-android-commons (language: kotlin)

Issue:
[Tech Debt] Remove usage of deprecated `startActivityForResult` & `onActivityResult` APIs  in favour of decoupled result APIs
Remove usage of deprecated `startActivityForResult` & `onActivityResult` APIs  in favour of decoupled result APIs. 

> While the underlying [startActivityForResult()](https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int)) and [onActivityResult()](https://developer.android.com/reference/android/app/Activity#onActivityResult(int,%20int,%20android.content.Intent)) APIs are available on the Activity class on all API levels, Google strongly recommends using the Activity Result APIs introduced in AndroidX [Activity](https://developer.android.com/jetpack/androidx/releases/activity) and [Fragment](https://developer.android.com/jetpack/androidx/releases/fragment) classes.

For more on what benefits it offers refer here https://developer.android.com/training/basics/intents/result#custom

P.S: We already have newer code using this API. Only some place that needs refactor.


Discussion hints:
nan

Pull request: Use new result API
Fixes #5849

What changes did you make and why?

- Migrate Activities that are launched with expectancy of getting result back, to new result api.

#### For ease of review, these are the  functionalities that are affected and have been tested. 

- File picking -> Camera, Gallery, Custom; from every place one or more of these options can be used have been refactored.
- getting result back from `ImageFragment` launched from `CustomSelectorActivity` 
- getting result of  voice input.
-  result from image editing from `EditActivity`

**Tests performed (required)**
`betaDebug` & `prodDebug` tested on Oneplust 9RT 5G , Android 14




Test command: ./gradlew :app:testBetaDebugUnitTest --tests "fr.free.nrw.commons.upload.UploadActivityUnitTests" --tests "fr.free.nrw.commons.media.MediaDetailFragmentUnitTests" --tests "fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragmentUnitTest" --tests "fr.free.nrw.commons.contributions.MainActivityUnitTests" --tests "fr.free.nrw.commons.filepicker.FilePickerTest" --tests "fr.free.nrw.commons.upload.UploadMediaDetailAdapterUnitTest" --tests "fr.free.nrw.commons.customselector.ui.selector.CustomSelectorActivityTest"

Fix patch:
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<Intent> cameraPickLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
+            });
+        });
+
+      private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
+          registerForActivityResult(new StartActivityForResult(),
+        result -> {
+              contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                contributionController.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
+            });
+        });
+
     private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
         @Override
         public void onActivityResult(Map<String, Boolean> result) {
@@ -45,7 +63,7 @@ public void onActivityResult(Map<String, Boolean> 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<String[]> inAppCameraLocationPermissionLauncher) {
+        ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
+        ActivityResultLauncher<Intent> 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<String[]> inAppCameraLocationPermissionLauncher) {
+        ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
+        ActivityResultLauncher<Intent> 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<Intent> 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<String[]> inAppCameraLocationPermissionLauncher) {
+        ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
+        ActivityResultLauncher<Intent> 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<String[]> inAppCameraLocationPermissionLauncher) {
+        ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
+        ActivityResultLauncher<Intent> 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<Intent> 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<Intent> 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<Intent> 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<Intent> 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<Intent> galleryPickLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
+            });
+        });
+
+    private final ActivityResultLauncher<Intent> customSelectorLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                controller.onPictureReturnedFromCustomSelector(result, requireActivity(), callbacks);
+            });
+        });
+
+    private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
+            });
+        });
+
     private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(
         new RequestMultiplePermissions(),
         new ActivityResultCallback<Map<String, Boolean>>() {
@@ -111,7 +137,7 @@ public void onActivityResult(Map<String, Boolean> 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<Image> =
-                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<UploadMediaDetail>? = 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<Intent> 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<Intent> 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<Intent> 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<UploadableFile> 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<UploadableFile> 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<UploadableFile> 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<UploadableFile> getFilesFromCustomSelector(Intent data, Acti
         return files;
     }
 
-    private static void onPictureReturnedFromGallery(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
-        try {
-            List<UploadableFile> 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<UploadableFile> 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<UploadableFile> 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<UploadableFile> files = new ArrayList<>();
-            files.add(photoFile);
+                UploadableFile photoFile = FilePicker.takenCameraPicture(activity);
+                List<UploadableFile> 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<UploadableFile> 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<String,String> 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<UploadMediaDetail> uploadMediaDetails
-                = data.getParcelableArrayListExtra(LIST_OF_DESCRIPTION_AND_CAPTION);
-
-            LinkedHashMap<String, String> 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<Array<String>>) -> Unit,
+    onCameraClicked: (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit,
     onCameraLongPressed: () -> Boolean,
-    onGalleryClicked: (Place) -> Unit,
+    onGalleryClicked: (Place, ActivityResultLauncher<Intent>) -> Unit,
     onGalleryLongPressed: () -> Boolean,
     onBookmarkClicked: (Place, Boolean) -> Unit,
     onBookmarkLongPressed: () -> Boolean,
@@ -28,6 +29,8 @@ fun placeAdapterDelegate(
     onDirectionsClicked: (Place) -> Unit,
     onDirectionsLongPressed: () -> Boolean,
     inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>,
+    cameraPickLauncherForResult: ActivityResultLauncher<Intent>,
+    galleryPickLauncherForResult: ActivityResultLauncher<Intent>
 ) = adapterDelegateViewBinding<Place, Place, ItemPlaceBinding>({ 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<Array<String>>) -> Unit =
-            { place, launcher ->
+        fun onCameraClicked(): (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> 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<Intent>) -> 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<BottomSheetItem> dataList;
     private BottomSheetAdapter bottomSheetAdapter;
+
+    private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
+            });
+        });
+
+    private final ActivityResultLauncher<Intent> customSelectorLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                controller.onPictureReturnedFromCustomSelector(result, requireActivity(), callbacks);
+            });
+        });
+
+    private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
+            });
+        });
+
     private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(
         new RequestMultiplePermissions(),
         new ActivityResultCallback<Map<String, Boolean>>() {
@@ -240,7 +266,7 @@ public void onActivityResult(Map<String, Boolean> 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<Array<String>>,
+    galleryPickLauncherForResult: ActivityResultLauncher<Intent>,
+    cameraPickLauncherForResult: ActivityResultLauncher<Intent>
 ) : BaseDelegateAdapter<Place>(
         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<Intent> cameraPickLauncherForResult =
+        registerForActivityResult(new StartActivityForResult(),
+        result -> {
+            contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
+                contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
+            });
+        });
+
     private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
         @Override
         public void onActivityResult(Map<String, Boolean> result) {
@@ -93,7 +103,7 @@ public void onActivityResult(Map<String, Boolean> 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<Intent> 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<Intent> 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<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao) {
+        List<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao, ActivityResultLauncher<Intent> 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<Intent> startForResult = registerForActivityResult(
+        new StartActivityForResult(), result -> {
+                onCameraPosition(result);
+        });
+
+    private final ActivityResultLauncher<Intent> startForEditActivityResult = registerForActivityResult(
+        new StartActivityForResult(), result -> {
+            onEditActivityResult(result);
+        }
+    );
+
+    private final ActivityResultLauncher<Intent> 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<String> 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<String> 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);
     }
 
     /**


Test patch:
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<Integer>? = null
+    @Mock
+    private lateinit var mockResultLauncher: ActivityResultLauncher<Intent>
+
+    private val intentCaptor: KArgumentCaptor<Intent> = 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<UploadableFile>,
-                    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<RecentLanguagesAdapter>
 
+    @Mock
+    private lateinit var mockResultLauncher: ActivityResultLauncher<Intent>
+
     @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)
     }