Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android KitKat securityException when trying to read from MediaStore

java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{430b1748 29271:com.x.x.x/u0a88} (pid=29271, uid=10088) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

I've added the MANAGE_DOCUMENTS and READ_EXTERNAL_STORAGE permissions but I am still getting this error. The offending code:

 public static String getImagePath(HailoDriverApplication app, Uri uri) {
    Cursor cursor = null;
    if (uri == null) {
        return null;
    }
    try {
        cursor = app.getContentResolver().query(uri, new String[] {
            MediaStore.Images.Media.DATA
        }, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        if (cursor.moveToFirst()) {
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return null;
}

As requested snippet of manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.x.x.x" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="16" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COURSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission
    android:name="android.permission.UPDATE_DEVICE_STATS"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.intent.action.BATTERY_CHANGED" />
<uses-permission
    android:name="android.permission.INSTALL_PACKAGES"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
like image 881
serenskye Avatar asked Nov 07 '13 13:11

serenskye


3 Answers

Had the same problem for the last couple of days. Tried a few solutions, but for some reason I was getting permission denial on Uri content provider for some images even when I had the android.permission.MANAGE_DOCUMENTS permission added to my manifest.

Here's a workaround, for the time being:

i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, CHOOSE_IMAGE);

This forces the older image gallery to open instead of the new Kitkat documents view.

Now, you can get the Uri by calling the following in your onActivityResult:

Uri selectedImageURI = data.getData();

Hope this helps.

like image 86
rahulritesh Avatar answered Nov 01 '22 04:11

rahulritesh


In the Intent used to prompt the user to add a file, use Intent.ACTION_OPEN_DOCUMENT (on KitKat API 19 or higher) instead of Intent.ACTION_GET_CONTENT or Intent.ACTION_PICK. Then, when you want to use the Uri, take the previous persistent permissions that were set by Intent.ACTION_OPEN_DOCUMENT as described in @feri's link ( https://developer.android.com/guide/topics/providers/document-provider.html#permissions):

final int takeFlags = data.getFlags()
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(originalUri, takeFlags);

You can read more about the differences between Intent.ACTION_GET_CONTENT, Intent.ACTION_PICK, and Intent.ACTION_OPEN_DOCUMENT here: http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT

like image 42
Tony Wickham Avatar answered Nov 01 '22 04:11

Tony Wickham


OK, I found a working sample that gets past the issue:

            intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("image/*");
            startActivityForResult(intent, myClassConstant.SELECT_PICTURE);

Here's what I've learned...this is a change in KitKat, and this code only works on API 19 and up. It will not work for older versions so you need to have methods for pre-KitKat as well. Once you get the file using the Category_Openable argument, in my case an image, you can then use it by referencing it as the URI. In my case, I store the URIString (file path) and I'm able to do what I want with it after the open occurs.

The issue I'm now trying to figure out is how long the file permissions persist. It appears that it expired since yesterday, as my code looks for the UriString, then tries to open the file. If I use the code above to select the image, it works - it stores the name, and I was able to exit the program, go back in and it still worked...however, my first run of the program this morning (after not touching it in 12+ hours), it acted like it couldn't find the file (and I'm sure if watching through the debugger, I'd see the non-critical error appear again.

So now the question is: How do we persist the permissions once I know what the file (name) is?

like image 12
user1082348 Avatar answered Nov 01 '22 05:11

user1082348