Android Java - set EXTRA_INITIAL_URI in ActivityResultLauncher<String> .... new ActivityResultCallback<Uri>()

69 Views Asked by At

I want to let the user of my app choose a file, then the app open this file. For opening the file, I need its uri. In the official documentation https://developer.android.com/training/basics/intents/result#launch I see this simple example :

ActivityResultLauncher<String> mGetContent = registerForActivityResult(new GetContent(),
    new ActivityResultCallback<Uri>() {
        @Override
        public void onActivityResult(Uri uri) {
            // Handle the returned Uri
        }
});

Called with : mGetContent.launch("image/*");

That allows to open the selected file. Exactly what I need.

But I'd like to define an initial directory, called EXTRA_INITIAL_URI, but this can be set with a putExtra like this : intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI,uri);

The problem is that there is no intent in this kind of implementation. So my question is : is it possible to define a EXTRA_INITIAL_URI , if yes how ?

Thanks a lot.

1

There are 1 best solutions below

2
On BEST ANSWER

GetContent, and the ACTION_GET_CONTENT that it is named after doesn't support EXTRA_INITIAL_URI at all: the list of intents it does support include:

  • ACTION_OPEN_DOCUMENT
  • ACTION_CREATE_DOCUMENT
  • ACTION_OPEN_DOCUMENT_TREE

which is why it isn't a parameter on that particular Activity Result Contract.

You'll note that OpenDocumentTree specifically states:

The input is an optional Uri of the initial starting location.

Which maps to setting the EXTRA_INITIAL_URI for that Activity Result contract, so you can use that contract directly if you are trying to select a folder.

For the other two, CreateDocument and OpenDocument, both specifically state:

This can be extended to override createIntent if you wish to pass additional extras to the Intent created by super.createIntent().

Which means you'd extend that contract to set the initial Uri.

For example, if you wanted to pass in the initial Uri as a constructor parameter to the contract, you'd write the class as

public class OpenDocumentAtFolder extends ActivityResultContracts.OpenDocument {
    private final Uri initialUri;

    public CustomContract(@NonNull Uri initialUri) {
        this.initialUri = initialUri;
    }

    @NonNull
    @Override
    public Intent createIntent(@NonNull Context context, @NonNull String[] input) {
        return super.createIntent(context, input)
                .putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri);
    }
}

Which you'd then use in place of GetContent:

ActivityResultLauncher<String> mOpenDocumentAtFolder = registerForActivityResult(
    new OpenDocumentAtFolder(yourDefaultUriHere),
    new ActivityResultCallback<Uri>() {
        @Override
        public void onActivityResult(Uri uri) {
            // Handle the returned Uri
        }
});

The guide to creating custom contracts talks more about writing type safe contracts if, for example, you wanted to instead have to pass the Uri and a mime type to launch, you could write your own custom contract that doesn't extend OpenDocument at all, but instead just uses the same underlying Intent extras that you want.