26

In Android 10 apps that need to access storage need to ask permission to access a concrete path. But apps like file explorer can ask permission for access to the root storage and gain permission to read/write to all storage. That is what I am trying to do.

According to Android we must use ACTION_OPEN_DOCUMENT_TREE for this. The problem I have is that everything seems correct, but the permission is not granted to the app.

  private void askAndroid10Perm()
    {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        intent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                        | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
                        | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
        startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT_TREE);
    }

Here the user can see Android file tree and, with main storage selected, click to grant permission. "It will allow - app name - to have full access to all files currently store under this location, and any future content stored here" -> Allow

Then:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case REQUEST_CODE_OPEN_DOCUMENT_TREE:
            if (resultCode == Activity.RESULT_OK) {
                Uri treeUri = data.getData();
                int takeFlags = data.getFlags();
                takeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION |
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

                    Log.i("TAG", "takePersistableUriPermission: " + treeUri);
                    this.getContentResolver().takePersistableUriPermission(treeUri, takeFlags);

                }

            }
    }
}

Log:

takePersistableUriPermission: content://com.android.externalstorage.documents/tree/primary%3A

Then the app will still not have permission to access to root.

open failed: EACCES (Permission denied)

Of course I have:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Granted by the user.

Milk
  • 2,469
  • 5
  • 31
  • 54
user2983041
  • 1,761
  • 4
  • 19
  • 31
  • I don't think you can have root access in Android Q – Gaurav Mall Aug 11 '19 at 10:38
  • Some apps that I tested have this access with scoped storage. For example "Solid explorer" app. – user2983041 Aug 11 '19 at 10:40
  • 1
    Yes, I know. I had asked a similar question and CommonWare said to me that that is because of the engineers those companies have. I know, his answer wasn't that useful. – Gaurav Mall Aug 11 '19 at 10:41
  • what do you mean with root access? – greywolf82 Aug 11 '19 at 11:18
  • Access to device storage files. Same files that show default file explorer preinstalled app. I am not talking about system root files. Root dir of mounted devices, external sd card and internal storage. – user2983041 Aug 11 '19 at 12:52
  • You can do it but you didn't show in the question how you are trying to "open" the root. You can use DocumentFile class and then use list files. – greywolf82 Aug 14 '19 at 12:32

5 Answers5

42

Add line in Manifest

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:requestLegacyExternalStorage="true" //Add this Line
    android:label="@string/app_name">

---------<Activity, Sevices or Recivers>----------

</application>
D_K
  • 419
  • 5
  • 7
12

you must add this line in your AndroidManifest.xml

android:requestLegacyExternalStorage="true"
tohid hajimorad
  • 187
  • 1
  • 9
8

The problem was that I use File object to access files, but permission only work if we use DocumentFile object to manipulate files.

Solved using DocumentFile instead of File.

It has multiple negative points to use DocumentFile, such as performance and that you don't have access to apache commons libraries for example, but there is no other option.

user2983041
  • 1,761
  • 4
  • 19
  • 31
  • does File(path), file.delete(), mkdirs() not work on android Q? What does scoped storage change? – Aswin P Ashok Aug 14 '19 at 18:03
  • 3
    There are libs for java that you can copy, cut or zip directories in "File" objects for example. This libs not exist for DocumentFile. – user2983041 Aug 15 '19 at 18:08
  • File API is not available in android 10 for files in shared storage that your app does not own. https://developer.android.com/training/data-storage/shared/media#direct-file-paths – M. Reza Nasirloo Jun 16 '21 at 06:23
1

It could be simpler with Simple Storage. You can request the storage full access to the user:

class MainActivity : AppCompatActivity() {

    private val storageHelper = SimpleStorageHelper(this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btnRequestStorageAccess.setOnClickListener {
            storageHelper.requestStorageAccess()
        }

        storageHelper.onStorageAccessGranted = { requestCode, root ->
            // do stuff
        }
    }
}

It works on Android 10 and higher. No need to add android:requestLegacyExternalStorage="true" to the manifest file.

Anggrayudi H
  • 14,977
  • 11
  • 54
  • 87
0

(NOT WORKING ON ANDROID 11)add this in your manifest file in the application so your application will be as follow :

<application
    android:requestLegacyExternalStorage="true"

for android 11 I did like this

        ContextWrapper cw = new ContextWrapper(mContext);
String fullPath =cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC).toString();
File directory = cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC);

check it here https://www.programmersought.com/article/50766505696/