Loading api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -3172,6 +3172,7 @@ package android.app { public class AppOpsManager { method public int checkOp(int, int, java.lang.String); method public int checkOpNoThrow(int, int, java.lang.String); method public void checkPackage(int, java.lang.String); method public void finishOp(int, int, java.lang.String); method public void finishOp(int); method public int noteOp(int, int, java.lang.String); Loading Loading @@ -5624,6 +5625,7 @@ package android.content { method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle); method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public final java.lang.String getCallingPackage(); method public final android.content.Context getContext(); method public final android.content.pm.PathPermission[] getPathPermissions(); method public final java.lang.String getReadPermission(); Loading Loading @@ -20747,6 +20749,7 @@ package android.provider { method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String); method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String); method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String); method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String); method public static android.net.Uri buildRootsUri(java.lang.String); method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String); method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String); core/java/android/app/AppOpsManager.java +17 −0 Original line number Diff line number Diff line Loading @@ -615,6 +615,23 @@ public class AppOpsManager { return MODE_IGNORED; } /** * Do a quick check to validate if a package name belongs to a UID. * * @throws SecurityException if the package name doesn't belong to the given * UID, or if ownership cannot be verified. */ public void checkPackage(int uid, String packageName) { try { if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) { throw new SecurityException( "Package " + packageName + " does not belong to " + uid); } } catch (RemoteException e) { throw new SecurityException("Unable to verify package ownership", e); } } /** * Make note of an application performing an operation. Note that you must pass * in both the uid and name of the application to be checked; this function will verify Loading core/java/android/content/ContentProvider.java +91 −25 Original line number Diff line number Diff line Loading @@ -102,6 +102,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { private boolean mExported; private boolean mNoPerms; private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>(); private Transport mTransport = new Transport(); /** Loading Loading @@ -194,8 +196,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder, mCallingPackage.set(callingPkg); try { return ContentProvider.this.query( uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override Loading @@ -208,7 +216,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return rejectInsert(uri, initialValues); } mCallingPackage.set(callingPkg); try { return ContentProvider.this.insert(uri, initialValues); } finally { mCallingPackage.set(null); } } @Override Loading @@ -216,7 +229,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } mCallingPackage.set(callingPkg); try { return ContentProvider.this.bulkInsert(uri, initialValues); } finally { mCallingPackage.set(null); } } @Override Loading @@ -238,7 +256,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } } } mCallingPackage.set(callingPkg); try { return ContentProvider.this.applyBatch(operations); } finally { mCallingPackage.set(null); } } @Override Loading @@ -246,7 +269,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } mCallingPackage.set(callingPkg); try { return ContentProvider.this.delete(uri, selection, selectionArgs); } finally { mCallingPackage.set(null); } } @Override Loading @@ -255,7 +283,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } mCallingPackage.set(callingPkg); try { return ContentProvider.this.update(uri, values, selection, selectionArgs); } finally { mCallingPackage.set(null); } } @Override Loading @@ -263,8 +296,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); mCallingPackage.set(callingPkg); try { return ContentProvider.this.openFile( uri, mode, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override Loading @@ -272,13 +310,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); mCallingPackage.set(callingPkg); try { return ContentProvider.this.openAssetFile( uri, mode, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override public Bundle call(String callingPkg, String method, String arg, Bundle extras) { return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras); mCallingPackage.set(callingPkg); try { return ContentProvider.this.call(method, arg, extras); } finally { mCallingPackage.set(null); } } @Override Loading @@ -290,8 +338,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType, Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, "r"); mCallingPackage.set(callingPkg); try { return ContentProvider.this.openTypedAssetFile( uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override Loading Loading @@ -460,6 +513,28 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return mContext; } /** * Return the package name of the caller that initiated the request being * processed on the current thread. The returned package will have been * verified to belong to the calling UID. Returns {@code null} if not * currently processing a request. * <p> * This will always return {@code null} when processing * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests. * * @see Binder#getCallingUid() * @see Context#grantUriPermission(String, Uri, int) * @throws SecurityException if the calling package doesn't belong to the * calling UID. */ public final String getCallingPackage() { final String pkg = mCallingPackage.get(); if (pkg != null) { mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg); } return pkg; } /** * Change the permission required to read data from the content * provider. This is normally set for you from its manifest information Loading Loading @@ -529,8 +604,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 { /** @hide */ public final void setAppOps(int readOp, int writeOp) { if (!mNoPerms) { mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService( Context.APP_OPS_SERVICE); mTransport.mReadOp = readOp; mTransport.mWriteOp = writeOp; } Loading Loading @@ -1413,6 +1486,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { */ if (mContext == null) { mContext = context; mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService( Context.APP_OPS_SERVICE); mMyUid = Process.myUid(); if (info != null) { setReadPermission(info.readPermission); Loading Loading @@ -1451,15 +1526,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return results; } /** * @hide * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name * of the calling package. */ public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) { return call(method, arg, extras); } /** * Call a provider-defined method. This can be used to implement * interfaces that are cheaper and/or unnatural for a table-like Loading core/java/android/provider/DocumentsContract.java +17 −1 Original line number Diff line number Diff line Loading @@ -72,7 +72,9 @@ public final class DocumentsContract { public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER"; /** {@hide} */ public static final String ACTION_MANAGE_DOCUMENTS = "android.provider.action.MANAGE_DOCUMENTS"; public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT"; /** {@hide} */ public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT"; /** * Constants related to a document, including {@link Cursor} columns names Loading Loading @@ -346,6 +348,9 @@ public final class DocumentsContract { */ public static final String COLUMN_MIME_TYPES = "mime_types"; /** {@hide} */ public static final String MIME_TYPE_ITEM = "vnd.android.document/root"; /** * Type of root that represents a storage service, such as a cloud-based * service. Loading Loading @@ -461,6 +466,17 @@ public final class DocumentsContract { .authority(authority).appendPath(PATH_ROOT).build(); } /** * Build Uri representing the given {@link Root#COLUMN_ROOT_ID} in a * document provider. * * @see #getRootId(Uri) */ public static Uri buildRootUri(String authority, String rootId) { return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(authority).appendPath(PATH_ROOT).appendPath(rootId).build(); } /** * Build Uri representing the recently modified documents of a specific * root. When queried, a provider will return zero or more rows with columns Loading core/java/android/provider/DocumentsProvider.java +23 −15 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.graphics.Point; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; Loading @@ -42,8 +41,6 @@ import android.os.ParcelFileDescriptor.OnCloseListener; import android.provider.DocumentsContract.Document; import android.util.Log; import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; import java.io.FileNotFoundException; Loading Loading @@ -75,11 +72,12 @@ import java.io.FileNotFoundException; public abstract class DocumentsProvider extends ContentProvider { private static final String TAG = "DocumentsProvider"; private static final int MATCH_ROOT = 1; private static final int MATCH_RECENT = 2; private static final int MATCH_DOCUMENT = 3; private static final int MATCH_CHILDREN = 4; private static final int MATCH_SEARCH = 5; private static final int MATCH_ROOTS = 1; private static final int MATCH_ROOT = 2; private static final int MATCH_RECENT = 3; private static final int MATCH_DOCUMENT = 4; private static final int MATCH_CHILDREN = 5; private static final int MATCH_SEARCH = 6; private String mAuthority; Loading @@ -93,7 +91,8 @@ public abstract class DocumentsProvider extends ContentProvider { mAuthority = info.authority; mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(mAuthority, "root", MATCH_ROOT); mMatcher.addURI(mAuthority, "root", MATCH_ROOTS); mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT); mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT); mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT); mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN); Loading Loading @@ -256,7 +255,7 @@ public abstract class DocumentsProvider extends ContentProvider { String[] selectionArgs, String sortOrder) { try { switch (mMatcher.match(uri)) { case MATCH_ROOT: case MATCH_ROOTS: return queryRoots(projection); case MATCH_RECENT: return queryRecentDocuments(getRootId(uri), projection); Loading Loading @@ -285,6 +284,8 @@ public abstract class DocumentsProvider extends ContentProvider { public final String getType(Uri uri) { try { switch (mMatcher.match(uri)) { case MATCH_ROOT: return DocumentsContract.Root.MIME_TYPE_ITEM; case MATCH_DOCUMENT: return getDocumentType(getDocumentId(uri)); default: Loading Loading @@ -328,15 +329,22 @@ public abstract class DocumentsProvider extends ContentProvider { throw new UnsupportedOperationException("Update not supported"); } /** {@hide} */ /** * Implementation is provided by the parent class. Can be overridden to * provide additional functionality, but subclasses <em>must</em> always * call the superclass. If the superclass returns {@code null}, the subclass * may implement custom behavior. * * @see #openDocument(String, String, CancellationSignal) * @see #deleteDocument(String) */ @Override public final Bundle callFromPackage( String callingPackage, String method, String arg, Bundle extras) { public Bundle call(String method, String arg, Bundle extras) { final Context context = getContext(); if (!method.startsWith("android:")) { // Let non-platform methods pass through return super.callFromPackage(callingPackage, method, arg, extras); return super.call(method, arg, extras); } final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID); Loading Loading @@ -364,7 +372,7 @@ public abstract class DocumentsProvider extends ContentProvider { if (!callerHasManage) { final Uri newDocumentUri = DocumentsContract.buildDocumentUri( mAuthority, newDocumentId); context.grantUriPermission(callingPackage, newDocumentUri, context.grantUriPermission(getCallingPackage(), newDocumentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); Loading Loading
api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -3172,6 +3172,7 @@ package android.app { public class AppOpsManager { method public int checkOp(int, int, java.lang.String); method public int checkOpNoThrow(int, int, java.lang.String); method public void checkPackage(int, java.lang.String); method public void finishOp(int, int, java.lang.String); method public void finishOp(int); method public int noteOp(int, int, java.lang.String); Loading Loading @@ -5624,6 +5625,7 @@ package android.content { method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle); method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public final java.lang.String getCallingPackage(); method public final android.content.Context getContext(); method public final android.content.pm.PathPermission[] getPathPermissions(); method public final java.lang.String getReadPermission(); Loading Loading @@ -20747,6 +20749,7 @@ package android.provider { method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String); method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String); method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String); method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String); method public static android.net.Uri buildRootsUri(java.lang.String); method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String); method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
core/java/android/app/AppOpsManager.java +17 −0 Original line number Diff line number Diff line Loading @@ -615,6 +615,23 @@ public class AppOpsManager { return MODE_IGNORED; } /** * Do a quick check to validate if a package name belongs to a UID. * * @throws SecurityException if the package name doesn't belong to the given * UID, or if ownership cannot be verified. */ public void checkPackage(int uid, String packageName) { try { if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) { throw new SecurityException( "Package " + packageName + " does not belong to " + uid); } } catch (RemoteException e) { throw new SecurityException("Unable to verify package ownership", e); } } /** * Make note of an application performing an operation. Note that you must pass * in both the uid and name of the application to be checked; this function will verify Loading
core/java/android/content/ContentProvider.java +91 −25 Original line number Diff line number Diff line Loading @@ -102,6 +102,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { private boolean mExported; private boolean mNoPerms; private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>(); private Transport mTransport = new Transport(); /** Loading Loading @@ -194,8 +196,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder, mCallingPackage.set(callingPkg); try { return ContentProvider.this.query( uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override Loading @@ -208,7 +216,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return rejectInsert(uri, initialValues); } mCallingPackage.set(callingPkg); try { return ContentProvider.this.insert(uri, initialValues); } finally { mCallingPackage.set(null); } } @Override Loading @@ -216,7 +229,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } mCallingPackage.set(callingPkg); try { return ContentProvider.this.bulkInsert(uri, initialValues); } finally { mCallingPackage.set(null); } } @Override Loading @@ -238,7 +256,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } } } mCallingPackage.set(callingPkg); try { return ContentProvider.this.applyBatch(operations); } finally { mCallingPackage.set(null); } } @Override Loading @@ -246,7 +269,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } mCallingPackage.set(callingPkg); try { return ContentProvider.this.delete(uri, selection, selectionArgs); } finally { mCallingPackage.set(null); } } @Override Loading @@ -255,7 +283,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } mCallingPackage.set(callingPkg); try { return ContentProvider.this.update(uri, values, selection, selectionArgs); } finally { mCallingPackage.set(null); } } @Override Loading @@ -263,8 +296,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); mCallingPackage.set(callingPkg); try { return ContentProvider.this.openFile( uri, mode, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override Loading @@ -272,13 +310,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); mCallingPackage.set(callingPkg); try { return ContentProvider.this.openAssetFile( uri, mode, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override public Bundle call(String callingPkg, String method, String arg, Bundle extras) { return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras); mCallingPackage.set(callingPkg); try { return ContentProvider.this.call(method, arg, extras); } finally { mCallingPackage.set(null); } } @Override Loading @@ -290,8 +338,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType, Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, "r"); mCallingPackage.set(callingPkg); try { return ContentProvider.this.openTypedAssetFile( uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal)); } finally { mCallingPackage.set(null); } } @Override Loading Loading @@ -460,6 +513,28 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return mContext; } /** * Return the package name of the caller that initiated the request being * processed on the current thread. The returned package will have been * verified to belong to the calling UID. Returns {@code null} if not * currently processing a request. * <p> * This will always return {@code null} when processing * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests. * * @see Binder#getCallingUid() * @see Context#grantUriPermission(String, Uri, int) * @throws SecurityException if the calling package doesn't belong to the * calling UID. */ public final String getCallingPackage() { final String pkg = mCallingPackage.get(); if (pkg != null) { mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg); } return pkg; } /** * Change the permission required to read data from the content * provider. This is normally set for you from its manifest information Loading Loading @@ -529,8 +604,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 { /** @hide */ public final void setAppOps(int readOp, int writeOp) { if (!mNoPerms) { mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService( Context.APP_OPS_SERVICE); mTransport.mReadOp = readOp; mTransport.mWriteOp = writeOp; } Loading Loading @@ -1413,6 +1486,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { */ if (mContext == null) { mContext = context; mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService( Context.APP_OPS_SERVICE); mMyUid = Process.myUid(); if (info != null) { setReadPermission(info.readPermission); Loading Loading @@ -1451,15 +1526,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return results; } /** * @hide * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name * of the calling package. */ public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) { return call(method, arg, extras); } /** * Call a provider-defined method. This can be used to implement * interfaces that are cheaper and/or unnatural for a table-like Loading
core/java/android/provider/DocumentsContract.java +17 −1 Original line number Diff line number Diff line Loading @@ -72,7 +72,9 @@ public final class DocumentsContract { public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER"; /** {@hide} */ public static final String ACTION_MANAGE_DOCUMENTS = "android.provider.action.MANAGE_DOCUMENTS"; public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT"; /** {@hide} */ public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT"; /** * Constants related to a document, including {@link Cursor} columns names Loading Loading @@ -346,6 +348,9 @@ public final class DocumentsContract { */ public static final String COLUMN_MIME_TYPES = "mime_types"; /** {@hide} */ public static final String MIME_TYPE_ITEM = "vnd.android.document/root"; /** * Type of root that represents a storage service, such as a cloud-based * service. Loading Loading @@ -461,6 +466,17 @@ public final class DocumentsContract { .authority(authority).appendPath(PATH_ROOT).build(); } /** * Build Uri representing the given {@link Root#COLUMN_ROOT_ID} in a * document provider. * * @see #getRootId(Uri) */ public static Uri buildRootUri(String authority, String rootId) { return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(authority).appendPath(PATH_ROOT).appendPath(rootId).build(); } /** * Build Uri representing the recently modified documents of a specific * root. When queried, a provider will return zero or more rows with columns Loading
core/java/android/provider/DocumentsProvider.java +23 −15 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.graphics.Point; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; Loading @@ -42,8 +41,6 @@ import android.os.ParcelFileDescriptor.OnCloseListener; import android.provider.DocumentsContract.Document; import android.util.Log; import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; import java.io.FileNotFoundException; Loading Loading @@ -75,11 +72,12 @@ import java.io.FileNotFoundException; public abstract class DocumentsProvider extends ContentProvider { private static final String TAG = "DocumentsProvider"; private static final int MATCH_ROOT = 1; private static final int MATCH_RECENT = 2; private static final int MATCH_DOCUMENT = 3; private static final int MATCH_CHILDREN = 4; private static final int MATCH_SEARCH = 5; private static final int MATCH_ROOTS = 1; private static final int MATCH_ROOT = 2; private static final int MATCH_RECENT = 3; private static final int MATCH_DOCUMENT = 4; private static final int MATCH_CHILDREN = 5; private static final int MATCH_SEARCH = 6; private String mAuthority; Loading @@ -93,7 +91,8 @@ public abstract class DocumentsProvider extends ContentProvider { mAuthority = info.authority; mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(mAuthority, "root", MATCH_ROOT); mMatcher.addURI(mAuthority, "root", MATCH_ROOTS); mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT); mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT); mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT); mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN); Loading Loading @@ -256,7 +255,7 @@ public abstract class DocumentsProvider extends ContentProvider { String[] selectionArgs, String sortOrder) { try { switch (mMatcher.match(uri)) { case MATCH_ROOT: case MATCH_ROOTS: return queryRoots(projection); case MATCH_RECENT: return queryRecentDocuments(getRootId(uri), projection); Loading Loading @@ -285,6 +284,8 @@ public abstract class DocumentsProvider extends ContentProvider { public final String getType(Uri uri) { try { switch (mMatcher.match(uri)) { case MATCH_ROOT: return DocumentsContract.Root.MIME_TYPE_ITEM; case MATCH_DOCUMENT: return getDocumentType(getDocumentId(uri)); default: Loading Loading @@ -328,15 +329,22 @@ public abstract class DocumentsProvider extends ContentProvider { throw new UnsupportedOperationException("Update not supported"); } /** {@hide} */ /** * Implementation is provided by the parent class. Can be overridden to * provide additional functionality, but subclasses <em>must</em> always * call the superclass. If the superclass returns {@code null}, the subclass * may implement custom behavior. * * @see #openDocument(String, String, CancellationSignal) * @see #deleteDocument(String) */ @Override public final Bundle callFromPackage( String callingPackage, String method, String arg, Bundle extras) { public Bundle call(String method, String arg, Bundle extras) { final Context context = getContext(); if (!method.startsWith("android:")) { // Let non-platform methods pass through return super.callFromPackage(callingPackage, method, arg, extras); return super.call(method, arg, extras); } final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID); Loading Loading @@ -364,7 +372,7 @@ public abstract class DocumentsProvider extends ContentProvider { if (!callerHasManage) { final Uri newDocumentUri = DocumentsContract.buildDocumentUri( mAuthority, newDocumentId); context.grantUriPermission(callingPackage, newDocumentUri, context.grantUriPermission(getCallingPackage(), newDocumentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); Loading