58

I have added uses-permission including WRITE_EXTERNAL_STORAGEMOUNT_UNMOUNT_FILESYSTEMSREAD_EXTERNAL_STORAGE to AndroidManifest.xml.

When I tried to run my application in Nexus5 (Android 6.0),it threw a exception as below:

java.io.IOException: open failed: EACCES (Permission denied)

And I tried another Android phone(Android 5.1),everything was OK.Here's the code:

private File createImageFile() throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(imageFileName, ".jpg", storageDir);
    currentPhotoPath = image.getAbsolutePath();
    return image;
}

Does Android 6.0 have difference about permission?

HelloSilence
  • 935
  • 2
  • 7
  • 19
  • 1
    I think you should check new permission features added on Android 6.0 and change your code according to it..!! – AndiGeeky Oct 09 '15 at 06:03
  • I have read the page [Manifest.permission](http://developer.android.com/reference/android/Manifest.permission.html),and found nothing special. – HelloSilence Oct 09 '15 at 06:06
  • @ samuel40 : I think you do not know about new model. This is old one so please check this -> http://android-developers.blogspot.in/2015/08/building-better-apps-with-runtime.html – AndiGeeky Oct 09 '15 at 06:08
  • Check below answer and refer link to implement new model..!! – AndiGeeky Oct 09 '15 at 06:13
  • 1
    For me, after search Google and try many ways without success. I open **Settings** and find out that Android 6.0 blocks my application permissions in section `Settings > Privacy and safety > App permissions > Storage`. After I enable in the **Storage Permissions** section, it works. Hope that help other people – Xuân-Lợi Vũ Nov 03 '16 at 04:59

9 Answers9

52

Android added new permission model for Android 6.0 (Marshmallow).

http://www.captechconsulting.com/blogs/runtime-permissions-best-practices-and-how-to-gracefully-handle-permission-removal

So you have to check Runtime Permission :

What Are Runtime Permissions?

With Android 6.0 Marshmallow, Google introduced a new permission model that allows users to better understand why an application may be requesting specific permissions. Rather than the user blindly accepting all permissions at install time, the user is now prompted to accept permissions as they become necessary during application use.

When to Implement the New Model?

it doesn’t require full support until you choose to target version 23 in your application. If you are targeting version 22 or below, your application will request all permissions at install time just as it would on any device running an OS below Marshmallow.

This information is taken from here :

Please check How to implement from this link :

http://www.captechconsulting.com/blogs/runtime-permissions-best-practices-and-how-to-gracefully-handle-permission-removal

Community
  • 1
  • 1
AndiGeeky
  • 11,266
  • 6
  • 50
  • 66
  • @samuel40 : If this worked for you the please check this -> http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – AndiGeeky Oct 09 '15 at 06:14
  • Thanks a lot, I'll check it. – HelloSilence Oct 09 '15 at 06:22
  • I understand why they did it, but... it's kinda a pain when you have over a dozen permissions and have to find where you use each one and add all this code... – Michael Jan 02 '17 at 03:47
  • @Michael: Yes you are right! But For us `user` is important than effort needs to invest to make their information `secure`!! – AndiGeeky Jan 02 '17 at 06:28
50

In Android 6(Marshmallow), even though the user accepted all your permissions at install time, they can later decide to take some of those permissions away from you.

Fast solution but not recommended: maybe if you change your targetSdkVersion in the gradle to 22, the problem will be solved.

How To Implement?(Best Practices)

  1. First determine if the user’s device is a Marshmallow device or not:

    private boolean shouldAskPermission(){
    
    return(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1);
    
    }
    
  2. If shouldAskPermission() return true, ask for permission you need:

    String[] perms = {"android.permission.WRITE_EXTERNAL_STORAGE"};
    
    int permsRequestCode = 200;
    
    requestPermissions(perms, permsRequestCode);
    

The method requestPermissions(String[] permissions, int requestCode); is a public method found inside of the Android Activity class.

  1. You will receive the results of your request in the method onRequestPermissionResult as shown below:

    @Override
    public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults){
    
    switch(permsRequestCode){
    
        case 200:
    
            boolean writeAccepted = grantResults[0]==PackageManager.PERMISSION_GRANTED;
    
            break;
    
    }
    
    }
    

After receiving the results, you will need to handle them appropriately.

Suggested Permissions Flow:

enter image description here

More Info:

A user with a Marshmallow device will now have the ability to revoke dangerous permissions via the application settings

Android defines some permissions as “dangerous” and some permissions as “normal.” Both are required in your application’s manifest but only dangerous permissions require a runtime request.

If you have chosen not to implement the new permissions model(runtime request), the revocation of permissions can cause unwanted user experiences and in some cases application crashes.

The table below lists all the current dangerous permissions and their respective groups:

enter image description here

If the user accepts one permission in a group/category they accept the entire group!

Source:http://www.captechconsulting.com

Using Dexter Library:

You can use Dexter. Android library that simplifies the process of requesting permissions at runtime.

Hamed Ghadirian
  • 6,159
  • 7
  • 48
  • 67
  • 1
    Great answer, thanks! One thing: the perms string should be "android.permission.WRITE_EXTERNAL_STORAGE" instead of "android.permission. WRITE_EXTERNAL_STORAGE" (without the whitespace) – Sofie Vos Jun 19 '17 at 13:51
13

You can also use ActivityCompat.requestPermissions for backwards compatible.

example:

private static final int REQUEST_CODE = 0x11;

String[] permissions = {"android.permission.WRITE_EXTERNAL_STORAGE"};
ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE); // without sdk version check

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == REQUEST_CODE) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // save file
        } else {
            Toast.makeText(getApplicationContext(), "PERMISSION_DENIED", Toast.LENGTH_SHORT).show();
        }
    }
}
c0ming
  • 3,407
  • 1
  • 21
  • 26
11

From API-23 you need to declare the permission in activity even if you have already declared in manifest.

// Storage Permissions variables
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

//persmission method.
 public static void verifyStoragePermissions(Activity activity) {
    // Check if we have read or write permission
    int writePermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    int readPermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);

    if (writePermission != PackageManager.PERMISSION_GRANTED || readPermission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(
                activity,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

To use simply call verifyStoragePermissions(this); in onCreate. That should do it hopefully.

Ronny K
  • 3,641
  • 4
  • 33
  • 43
2

If you are lazy, just downgrade targetSdkVersion to 22 (before lollipop)

gderaco
  • 2,322
  • 1
  • 16
  • 18
  • Yes this worked for me with Android 6 or later. Atleast locally can work with version 2 in repo you can still push version 23 – Testing Singh Apr 03 '17 at 17:44
2

This worked for me.

Go to Settings -> Applications -> YourApp -> Provide permissions to Storage, Contacts etc.

Uma
  • 45
  • 1
0

Google has a new feature on Android Q: filtered view for external storage. A quick fix for that is to add this code in the AndroidManifest.xml file:

<manifest ... >
    <!-- This attribute is "false" by default on apps targeting Android Q. -->
    <application android:requestLegacyExternalStorage="true" ... >
     ...
    </application>
</manifest>

You can read more about it here: https://developer.android.com/training/data-storage/compatibility

Remy
  • 788
  • 1
  • 9
  • 14
-3

For me, my phone connected as USB as MTP was the issue even after doing everything stated here. Switched it to "Charging Only" worked for me.

-4

I met the same trouble.

Maybe it is caused by your phone security mechanism. You may go to 'settings' to authorize write/read permissions.

HDQ
  • 45
  • 5