Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - ask write to SD card permission dialog

I am having trouble gaining write access to device SD card root directory. I can write to device internal storage and app package folder in an SD card without problems. I found that gaining access to an SD card is possible using Storage Access Framework, so I looked at other apps to see how they gain access to an SD card, and found Total Commander with its neat permission dialog.

write to SD card permission dialog

How to show such a dialog because I cannot find any examples? My goal is to store large files on the SD card that stay after uninstalling the app.

Similar questions:

Android (Write on external SD-Card): java.io.IOException: Permission denied

Android M write to SD Card - Permission Denied

Android SD Card Write Permission using SAF (Storage Access Framework)

like image 861
Anurban Avatar asked Mar 01 '19 13:03

Anurban


People also ask

How do I set custom permissions in Android dialog?

requestPermissions(thisActivity, new String[]{Manifest. permission. READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); Android system creates a popup dialog to request permission.

How do I request permission in Android 11?

Starting in Android 11, whenever your app requests a permission related to location, microphone, or camera, the user-facing permissions dialog contains an option called Only this time. If the user selects this option in the dialog, your app is granted a temporary one-time permission.


Video Answer


2 Answers

I found open source file manager. Looked at the code and finally found the solution.

Only works on Android N (7.0.0) (api 24) and above.

First get root path of SD card and show user permission dialog.

public void takeCardUriPermission(String sdCardRootPath) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            File sdCard = new File(sdCardRootPath);
            StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
            StorageVolume storageVolume = storageManager.getStorageVolume(sdCard);
            Intent intent = storageVolume.createAccessIntent(null);
            try {
                startActivityForResult(intent, 4010);
            } catch (ActivityNotFoundException e) {
            }
        }
    }

When user accepts the request, onActivityResult() gets triggered and we can save uri from intent data

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 4010) {

            Uri uri = data.getData();

            grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);

            final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);

            getContentResolver().takePersistableUriPermission(uri, takeFlags);
        }
    }

Now we can retrieve uri of SD card root and use it with Storage Access Framework

public Uri getUri() {
        List<UriPermission> persistedUriPermissions = getContentResolver().getPersistedUriPermissions();
        if (persistedUriPermissions.size() > 0) {
            UriPermission uriPermission = persistedUriPermissions.get(0);
            return uriPermission.getUri();
        }
        return null;
    }
like image 118
Anurban Avatar answered Oct 21 '22 20:10

Anurban


Unfortunately, using createAccessIntent is now deprecated in Android Q, and the documentation states that if you use it in Android Q, it will immediately return RESULT_CANCELED.

They recommend you use an intent with ACTION_OPEN_DOCUMENT_TREE.You can specify the directory it opens initially (which is only supported on Android O and above), making it easier for the user, but this still is not a very user friendly approach.

I'm wondering if there are any other user friendly solutions that anyone knows of? I don't understand why Android removed createAccessIntent, as it seems to be the most user friendly way.

like image 25
Shawney Avatar answered Oct 21 '22 22:10

Shawney