2

We are selecting image/video files with this code

//Pick an image from storage
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.setType(type); //Can be image/* or video/*
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        activityResultLauncher.launch(Intent.createChooser(intent, "Select Item"));

Then obtain the file Uri(s) on new ActivityResult API

protected final ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                Log.wtf("WTF", result.toString());
                if (result.getResultCode() == Activity.RESULT_OK) {
                    // There are no request codes
                    Intent data = result.getData();

                    if (data == null) {
                        Toast.makeText(getContext(), R.string.unknown_error, Toast.LENGTH_SHORT).show();
                        return;
                    }

                    activityResult(true, data);
                }
                else
                    activityResult(false, null);
            });

Unfortunately after updating to Android 11 all we got is RESULT_CANCELED.

E/WTF: ActivityResult{resultCode=RESULT_CANCELED, data=null}
Bitwise DEVS
  • 2,858
  • 4
  • 24
  • 67
  • If you use `ActivityResultContracts.OpenDocument`, does it work? If so, perhaps you could see what is different about your implementation (besides adding the extra). For example, perhaps you should not be using `Intent.createChooser()`. – CommonsWare Sep 16 '21 at 18:52
  • @CommonsWare I am trying to use `ActivityResultContracts.OpenMultipleDocuments()` but how can I launch the intent with this? – Bitwise DEVS Sep 16 '21 at 19:08
  • You don't have an `Intent` with `ActivityResultContracts.OpenMultipleDocuments`. It replaces `ActivityResultContracts.StartActivityForResult`. – CommonsWare Sep 16 '21 at 19:09
  • @CommonsWare yes so how can I launch the intent where user can select multiple files? Can you provide a sample? Thanks – Bitwise DEVS Sep 16 '21 at 19:11
  • "so how can I launch the intent where user can select multiple files?" -- if you use `ActivityResultContracts.OpenMultipleDocuments`, you do not need an `Intent`. "Can you provide a sample?" -- see the code in [this question](https://stackoverflow.com/q/61666538/115145). – CommonsWare Sep 16 '21 at 19:52
  • 1
    You were never supposed to use `Intent.createChooser` with `ACTION_OPEN_DOCUMENT`. What exactly were you trying to do with that code? – ianhanniballake Sep 16 '21 at 20:42
  • @ianhanniballake I guess you were right, but so far there is no issue with doing it prior to Android 11. – Bitwise DEVS Sep 17 '21 at 01:13
  • @ianhanniballake perhaps you could help this [library](https://github.com/CanHub/Android-Image-Cropper/issues/253) as well where it also use `Intent.createChooser` when selecting source of image either from camera, gallery or file manager in one of its [class](https://github.com/CanHub/Android-Image-Cropper/blob/main/cropper/src/main/java/com/canhub/cropper/CropImage.kt) which also experiencing `RESULT_CANCELED` – Bitwise DEVS Oct 28 '21 at 19:17
  • @BitwiseDEVS On which device(s) did this issue occur? Did you test it with Android 10 using the same device(s)? – yasirkula Oct 28 '21 at 22:14
  • It is with the Xiaomi in Android 11 that it does not work with the `Intent.createChooser`, I proposed a solution here : https://stackoverflow.com/a/73624845/2389197 – Joris Sep 06 '22 at 16:04

2 Answers2

0

As what Ian said, you were not supposed to user Intent.createChooser with ACTION_OPEN_DOCUMENT though it works prior to Android 11.

Bitwise DEVS
  • 2,858
  • 4
  • 24
  • 67
0

Here is a helper class you use as a contract to select image/video/pdf using Activity Result API that will return you a list of Uri's. It can be configured for single or multiple selection of files.

Tested in android 10 and 11.

class SelectFileContract : ActivityResultContract<Pair<SELECTION_TYPE, Boolean>, List<Uri>?>() {
    var TAG = this.javaClass.simpleName
    override fun createIntent(context: Context, input: Pair<SELECTION_TYPE, Boolean>): Intent {

        var intent: Intent? = null
        intent = when (input.first) {
            SELECTION_TYPE.IMAGE -> Intent(
                Intent.ACTION_PICK,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            )
            SELECTION_TYPE.VIDEO -> Intent(
                Intent.ACTION_PICK,
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI
            )
            SELECTION_TYPE.PDF -> {
                Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
                    type = "application/pdf"
                    addCategory(Intent.CATEGORY_OPENABLE)
                }
            }
        }
        if (input.second == true) {
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
        }

        return intent!!
    }

    override fun parseResult(resultCode: Int, intent: Intent?): List<Uri>? = when (resultCode) {

        Activity.RESULT_OK -> {
            val uriList = mutableListOf<Uri>()
            /**
             * in case of single selection the Uri will be inside [intent.data]
             */
            intent?.data?.let { uriList.add(it) }


            /**
             * in case of multiple selection the Uri will be inside [intent.clipData]
             */
            intent?.clipData?.let { clipData: ClipData ->
                for (i in 0 until clipData.itemCount) {
                    uriList.add(clipData.getItemAt(i).uri)
                }
            }

            Log.d(TAG, uriList.toString())
            uriList
        }
        else -> null


    }
}

enum class SELECTION_TYPE {
    IMAGE,
    VIDEO,
    PDF
}

Then in activity specific the contract:

 private val simpleContractRegistration =
        registerForActivityResult(SelectFileContract()) { result: List<Uri>? ->
            result?.let {
                Log.d(TAG, result.toString())
            }
        }

Then launch the registration:

binding.button.setOnClickListener {
            simpleContractRegistration.launch(
                Pair(
                    SELECTION_TYPE.IMAGE,
                    false
                )
            )
        }
Chinmay
  • 354
  • 4
  • 10