04-15 11:00:33.959 8427 8427 D AndroidRuntime: Shutting down VM 04-15 11:00:33.965 8427 8427 E AndroidRuntime: FATAL EXCEPTION: main 04-15 11:00:33.965 8427 8427 E AndroidRuntime: Process: com.android.gallery3d, PID: 8427 04-15 11:00:33.965 8427 8427 E AndroidRuntime: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaDocumentsProvider uri content://com.android.providers.media.documents/document/image%3A593 from pid=8427, uid=10065 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission() 04-15 11:00:33.965 8427 8427 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:1620) 04-15 11:00:33.965 8427 8427 E AndroidRuntime: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183) 04-15 11:00:33.965 8427 8427 E AndroidRuntime: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135) 04-15 11:00:33.965 8427 8427 E AndroidRuntime: at android.content.ContentProviderProxy.query(ContentProviderNative.java:421) 04-15 11:00:33.965 8427 8427 E AndroidRuntime: at android.content.ContentResolver.query(ContentResolver.java:493) 04-15 11:00:33.965 8427 8427 E AndroidRuntime: at android.content.ContentResolver.query(ContentResolver.java:435) 04-15 11:00:33.965 8427 8427 E AndroidRuntime: at com.android.gallery3d.filtershow.cache.ImageLoader.getLocalPathFromUri(ImageLoader.java:85)
没有删除这张照片之前,选择打印是正常的,为何删除了照片就报权限问题了呢?经过代码分析,Gallery是没有权限访问MediaDocumentsProvider,MediaDocumentsProvider是可以接受 android:grantUriPermissions="true"传递权限的,而文件管理器documentsui是申请了
final Intent view = new Intent(Intent.ACTION_VIEW); view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); view.setData(doc.derivedUri); try { startActivity(view); } catch (ActivityNotFoundException ex) { Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); }
http://androidxref.com/6.0.0_r1/xref/frameworks/base/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
从而Gallery可以访问MediaDocumentsProvider,而删除了照片的时候,一并将该权限删除了 MediaDocumentsProvider.onMediaStoreDelete(getContext(),
4069 volumeName, FileColumns.MEDIA_TYPE_IMAGE, id);,所以再次访问就报权限问题了
if (mediaType == FileColumns.MEDIA_TYPE_IMAGE) { deleteIfAllowed(uri, data); MediaDocumentsProvider.onMediaStoreDelete(getContext(), volumeName, FileColumns.MEDIA_TYPE_IMAGE, id); idvalue[0] = String.valueOf(id); database.mNumQueries++; Cursor cc = db.query("thumbnails", sDataOnlyColumn, "image_id=?", idvalue, null, null, null); try { while (cc.moveToNext()) { deleteIfAllowed(uri, cc.getString(0)); } database.mNumDeletes++; db.delete("thumbnails", "image_id=?", idvalue); } finally { IoUtils.closeQuietly(cc); } }
http://androidxref.com/6.0.0_r1/xref/packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
revokeUriPermission删除权限
/** * When deleting an item, we need to revoke any outstanding Uri grants. */ static void onMediaStoreDelete(Context context, String volumeName, int type, long id) { if (!"external".equals(volumeName)) return; if (type == FileColumns.MEDIA_TYPE_IMAGE) { final Uri uri = DocumentsContract.buildDocumentUri( AUTHORITY, getDocIdForIdent(TYPE_IMAGE, id)); context.revokeUriPermission(uri, ~0); } else if (type == FileColumns.MEDIA_TYPE_VIDEO) { final Uri uri = DocumentsContract.buildDocumentUri( AUTHORITY, getDocIdForIdent(TYPE_VIDEO, id)); context.revokeUriPermission(uri, ~0); } else if (type == FileColumns.MEDIA_TYPE_AUDIO) { final Uri uri = DocumentsContract.buildDocumentUri( AUTHORITY, getDocIdForIdent(TYPE_AUDIO, id)); context.revokeUriPermission(uri, ~0); } }
http://androidxref.com/6.0.0_r1/xref/packages/providers/MediaProvider/src/com/android/providers/media/MediaDocumentsProvider.java