13

I just started off with android M and I am unable to access the external storage. I get the following error

Caused by: java.lang.SecurityException: Permission Denial: reading 
com.android.providers.media.MediaProvider uri 
content://media/external/images/media from pid=15355, uid=10053 requires 
android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission() 

I am adding user-permission in manifest like

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

and my build file is with following settings :

compileSdkVersion 23
buildToolsVersion "22.0.1"

minSdkVersion 16
targetSdkVersion 23

How to read and write from external storage in android M?

Kushal Sharma
  • 5,978
  • 5
  • 25
  • 41
  • 1
    Wow you asked a question and immediately answered it yourself within miliseconds. You're a true genius. – Sharp Edge Aug 24 '15 at 06:34
  • 3
    Hi @SharpEdge i think its a good practice to do so. http://stackoverflow.com/help/self-answer I spent an hour finding the solution and hope it saves someone else time in future. :) – Kushal Sharma Aug 24 '15 at 06:37
  • I didn't knew that.. this statement existed **"If you have a question that you already know the answer to, and you would like to document that knowledge in public so that others (including yourself) can find it later"** Sorry for being sarcastic. – Sharp Edge Aug 24 '15 at 06:44
  • 1
    Its okay, i don't mind it :) have a nice day! – Kushal Sharma Aug 24 '15 at 06:51

5 Answers5

22

Reading from the documentation. I have to ask user for permission at runtime. Code example :

Add permission to android manifest like we used to do earlier :

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

Check if the user has already granted the permission. If yes, skip asking for permission and continue with your work flow else ask user for permission :

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (!Settings.System.canWrite(this)) {
        requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE}, 2909);
    } else {
        // continue with your code
    }
} else {
    // continue with your code
}

Now to check if the user granted the permission or denied it @Override OnRequestPermissionResult to get a callback :

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case 2909: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.e("Permission", "Granted");
            } else {
                Log.e("Permission", "Denied");
            }
            return;
        }
    }
}

I was not able to READ external storage only by asking WRITE permission, so i had to request for Manifest.permission.READ_EXTERNAL_STORAGE as well.


Also if you want to target versions below api 23, check the Build VERSION at runtime with IF statement and ask for permissions only if VERSION is equal or above Android M.

RmK
  • 1,408
  • 15
  • 28
Kushal Sharma
  • 5,978
  • 5
  • 25
  • 41
  • Hi @ajit you are correct, its valid only on min API 23! However with a simple version check by `if` statement at runtime.. You can support previous version as well.. I will edit the ans with pre M support as soon as I get back on my computer.. – Kushal Sharma Nov 03 '15 at 12:16
  • Today I post one question but wondering for finding proper solution can you help me – Ajit Kumar Dubey Nov 03 '15 at 12:21
  • One thing is very important can you add code for both (min level 23 or below), so that it will helpful for other developer. Thanks – Ajit Kumar Dubey Nov 03 '15 at 12:23
  • @Ajit I have updated the ans with your suggestions! Thanks for pointing out :) – Kushal Sharma Nov 03 '15 at 13:00
  • Why is `onRequestPermissionsResult()` necessary? What kind of code runs in there. – IgorGanapolsky Dec 11 '15 at 05:07
  • `onRequestPermissionResult()` is the callback for `requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 2909);` so that you can check if user granted the permission or not. Just like callback for `startActivtyForResult` – Kushal Sharma Dec 11 '15 at 05:37
  • @KushalSharma I already added parmission in manifest but I couldn't find the Manifest.permission.WRITE_EXTERNAL_STORAGE in my Project – KDOSHI Dec 17 '15 at 11:34
  • 1
    `Settings.System.canWrite(this)` and `WRITE_EXTERNAL_STORAGE` are two very different things! Should be (comment code is hideous, posted answer with correction). – Anthony Jan 28 '16 at 17:04
6

In case you are looking for a way to handle in any android version (you are compiling for M, but some devices can be using other versions) there is a compatibility version.

if (ContextCompat.checkSelfPermission(CreatePlayerActivity.this,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {

        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(CreatePlayerActivity.this,
                Manifest.permission.READ_EXTERNAL_STORAGE)) {

            // Show an expanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.

        } else {

            // No explanation needed, we can request the permission.

            ActivityCompat.requestPermissions(CreatePlayerActivity.this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

            // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    }
Goofyahead
  • 5,874
  • 6
  • 29
  • 33
2

In regards to the selected answer:

Settings.System.canWrite(this) and WRITE_EXTERNAL_STORAGE are two very different things! Should be:

    boolean needsRead = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED;

    boolean needsWrite = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED;

    if (needsRead || needsWrite)
        requestStoragePermission()
Anthony
  • 7,638
  • 3
  • 38
  • 71
1

I was struggling with WRITE_EXTERNAL_STORAGE permission: after I requested it, the dialog didn't show up and immediately returned DENIED.

The problem was in one of the included libraries. It contained the same permission declaration in its AndroidManifest.xml, but with maxSdkVersion="22". The declaration in application's manifest file was overridden by the library.

To override permission from the library I used the following:

  <uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    tools:node="remove"
    tools:selector="com.example.lib" />

I hope this might be helpful.

ntoskrnl
  • 1,545
  • 1
  • 15
  • 25
-1

I used this utility on github. It works with with both API 22 and 23. Adding runtime permissions is not hard but having to seperate your code and move the methods around to capture callbacks is a little pain. This library provides a chained api to do all you need to do for supporting runtime permissions.

https://github.com/kayvannj/PermissionUtil

moberme
  • 669
  • 7
  • 13