Samidh T Samidh T - 3 years ago 158
Android Question

How to persist permission in android API 19 (KitKat)?

In my application I store the path of image in my SQlite db for further use. The path that I get is

content://com.android.providers.media.documents/document/image%3A71964


When I retrieve this path from the database and try to retrieve the image from that path android throws

java.lang.SecurityException: Permission Denial: opening provider
com.android.providers.media.MediaDocumentsProvider
from ProcessRecord{42c84ec8 23911:com.gots.gb/u0a248} (pid=23911, uid=10248)
requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS


According https://developer.android.com/guide/topics/providers/document-provider.html#permissions I need to persist permission by adding the following code

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


When I added this code to my ImageAdapter class which extends BaseAdapter android throws

08-21 02:14:38.530: W/System.err(24452): java.lang.SecurityException:
No permission grant found for UID 10248 and Uri
content://com.android.providers.media.documents/document/image:71964


This is the relevant part of my ImageAdapter code

public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView ;


if (convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(185, 185));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);

}
else{
imageView = (ImageView)convertView ;
}

InputStream is = null;
Bitmap bitmap = null ;

try {

Log.d(TAG,String.valueOf(list.get(position)));
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
final int takeFlags = intent.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.

if (Build.VERSION.SDK_INT >= 19){
mContext.getContentResolver().takePersistableUriPermission(list.get(position), takeFlags);
}


is = mContext.getContentResolver().openInputStream(list.get(position));

final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
bitmap = BitmapFactory.decodeStream(is,null, options);
is.close();
imageView.setImageBitmap(bitmap);

return imageView;

}
catch (Exception e) {
e.printStackTrace();

return null;
}


what am I doing wrong?
Thanks

Answer Source

I believe I've solved it. The request intent:

Intent intent;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
    intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}else{
    intent = new Intent(Intent.ACTION_GET_CONTENT);
}
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.form_pick_photos)), REQUEST_PICK_PHOTO);

and onActivityResult

...
// kitkat fixed (broke) content access; to keep the URIs valid over restarts need to persist access permission
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    final int takeFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
    ContentResolver resolver = getActivity().getContentResolver();
    for (Uri uri : images) {
        resolver.takePersistableUriPermission(uri, takeFlags);
    }
}
...

I haven't tested this pre-kitkat, my phone is running 5.1, can anyone verify this on older phones?

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download