summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt7
-rw-r--r--api/removed.txt3
-rw-r--r--core/java/android/provider/MediaStore.java212
3 files changed, 217 insertions, 5 deletions
diff --git a/api/current.txt b/api/current.txt
index beddae39f5f8..47086164d5ec 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38713,6 +38713,10 @@ package android.provider {
public final class MediaStore {
ctor public MediaStore();
+ method @NonNull public static android.app.PendingIntent createDeleteRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>);
+ method @NonNull public static android.app.PendingIntent createFavoriteRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>, boolean);
+ method @NonNull public static android.app.PendingIntent createTrashRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>, boolean);
+ method @NonNull public static android.app.PendingIntent createWriteRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>);
method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri);
method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
method public static android.net.Uri getMediaScannerUri();
@@ -38723,9 +38727,6 @@ package android.provider {
method @NonNull public static String getVolumeName(@NonNull android.net.Uri);
method @Deprecated @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
- method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
- method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
- method public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
field public static final String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
field public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
field public static final String ACTION_REVIEW = "android.provider.action.REVIEW";
diff --git a/api/removed.txt b/api/removed.txt
index 1a2f43450d7b..4e8e325bce15 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -441,6 +441,9 @@ package android.provider {
method @Deprecated public static boolean getIncludePending(@NonNull android.net.Uri);
method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
+ method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
+ method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
+ method @Deprecated public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
}
public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 2fa3386bccb8..701ba91a8daf 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -32,6 +32,7 @@ import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
import android.app.AppGlobals;
+import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -86,6 +87,7 @@ import java.lang.annotation.RetentionPolicy;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
@@ -162,6 +164,15 @@ public final class MediaStore {
/** {@hide} */
public static final String SUICIDE_CALL = "suicide";
+ /** {@hide} */
+ public static final String CREATE_WRITE_REQUEST_CALL = "create_write_request";
+ /** {@hide} */
+ public static final String CREATE_TRASH_REQUEST_CALL = "create_trash_request";
+ /** {@hide} */
+ public static final String CREATE_FAVORITE_REQUEST_CALL = "create_favorite_request";
+ /** {@hide} */
+ public static final String CREATE_DELETE_REQUEST_CALL = "create_delete_request";
+
/**
* Extra used with {@link #SCAN_FILE_CALL} or {@link #SCAN_VOLUME_CALL} to indicate that
* the file path originated from shell.
@@ -199,6 +210,13 @@ public final class MediaStore {
/** {@hide} */
public static final String DELETE_CONTRIBUTED_MEDIA_CALL = "delete_contributed_media";
+ /** {@hide} */
+ public static final String EXTRA_CLIP_DATA = "clip_data";
+ /** {@hide} */
+ public static final String EXTRA_CONTENT_VALUES = "content_values";
+ /** {@hide} */
+ public static final String EXTRA_RESULT = "result";
+
/**
* This is for internal use by the media scanner only.
* Name of the (optional) Uri parameter that determines whether to skip deleting
@@ -606,6 +624,10 @@ public final class MediaStore {
* {@link ContentResolver#delete}.
* <p>
* By default, trashed items are filtered away from operations.
+ *
+ * @see MediaColumns#IS_TRASHED
+ * @see MediaStore#QUERY_ARG_MATCH_TRASHED
+ * @see MediaStore#createTrashRequest
*/
@Match
public static final String QUERY_ARG_MATCH_TRASHED = "android:query-arg-match-trashed";
@@ -620,6 +642,10 @@ public final class MediaStore {
* <p>
* By default, favorite items are <em>not</em> filtered away from
* operations.
+ *
+ * @see MediaColumns#IS_FAVORITE
+ * @see MediaStore#QUERY_ARG_MATCH_FAVORITE
+ * @see MediaStore#createFavoriteRequest
*/
@Match
public static final String QUERY_ARG_MATCH_FAVORITE = "android:query-arg-match-favorite";
@@ -952,7 +978,9 @@ public final class MediaStore {
* @see MediaStore#setIncludeTrashed(Uri)
* @see MediaStore#trash(Context, Uri)
* @see MediaStore#untrash(Context, Uri)
+ * @removed
*/
+ @Deprecated
public static void trash(@NonNull Context context, @NonNull Uri uri) {
trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS);
}
@@ -970,7 +998,9 @@ public final class MediaStore {
* @see MediaStore#setIncludeTrashed(Uri)
* @see MediaStore#trash(Context, Uri)
* @see MediaStore#untrash(Context, Uri)
+ * @removed
*/
+ @Deprecated
public static void trash(@NonNull Context context, @NonNull Uri uri,
@DurationMillisLong long timeoutMillis) {
if (timeoutMillis < 0) {
@@ -992,7 +1022,9 @@ public final class MediaStore {
* @see MediaStore#setIncludeTrashed(Uri)
* @see MediaStore#trash(Context, Uri)
* @see MediaStore#untrash(Context, Uri)
+ * @removed
*/
+ @Deprecated
public static void untrash(@NonNull Context context, @NonNull Uri uri) {
final ContentValues values = new ContentValues();
values.put(MediaColumns.IS_TRASHED, 0);
@@ -1010,6 +1042,180 @@ public final class MediaStore {
return uri.buildUpon().authority(MediaStore.AUTHORITY_LEGACY).build();
}
+ private static @NonNull PendingIntent createRequest(@NonNull ContentResolver resolver,
+ @NonNull String method, @NonNull Collection<Uri> uris, @Nullable ContentValues values) {
+ Objects.requireNonNull(resolver);
+ Objects.requireNonNull(uris);
+
+ final Iterator<Uri> it = uris.iterator();
+ final ClipData clipData = ClipData.newRawUri(null, it.next());
+ while (it.hasNext()) {
+ clipData.addItem(new ClipData.Item(it.next()));
+ }
+
+ final Bundle extras = new Bundle();
+ extras.putParcelable(EXTRA_CLIP_DATA, clipData);
+ extras.putParcelable(EXTRA_CONTENT_VALUES, values);
+ return resolver.call(AUTHORITY, method, null, extras).getParcelable(EXTRA_RESULT);
+ }
+
+ /**
+ * Create a {@link PendingIntent} that will prompt the user to grant your
+ * app write access for the requested media items.
+ * <p>
+ * This call only generates the request for a prompt; to display the prompt,
+ * call {@link Activity#startIntentSenderForResult} with
+ * {@link PendingIntent#getIntentSender()}. You can then determine if the
+ * user granted your request by testing for {@link Activity#RESULT_OK} in
+ * {@link Activity#onActivityResult}.
+ * <p>
+ * Permissions granted through this mechanism are tied to the lifecycle of
+ * the {@link Activity} that requests them. If you need to retain
+ * longer-term access for background actions, you can place items into a
+ * {@link ClipData} or {@link Intent} which can then be passed to
+ * {@link Context#startService} or
+ * {@link android.app.job.JobInfo.Builder#setClipData}. Be sure to include
+ * any relevant access modes you want to retain, such as
+ * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
+ * <p>
+ * The displayed prompt will reflect all the media items you're requesting,
+ * including those for which you already hold write access. If you want to
+ * determine if you already hold write access before requesting access, use
+ * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
+ * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
+ * <p>
+ * For security and performance reasons this method does not support
+ * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} or
+ * {@link Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
+ *
+ * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
+ * Typically this value is {@link Context#getContentResolver()},
+ * but if you need more explicit lifecycle controls, you can
+ * obtain a {@link ContentProviderClient} and wrap it using
+ * {@link ContentResolver#wrap(ContentProviderClient)}.
+ * @param uris The set of media items to include in this request. Each item
+ * must be hosted by {@link MediaStore#AUTHORITY} and must
+ * reference a specific media item by {@link BaseColumns#_ID}.
+ */
+ public static @NonNull PendingIntent createWriteRequest(@NonNull ContentResolver resolver,
+ @NonNull Collection<Uri> uris) {
+ return createRequest(resolver, CREATE_WRITE_REQUEST_CALL, uris, null);
+ }
+
+ /**
+ * Create a {@link PendingIntent} that will prompt the user to trash the
+ * requested media items. When the user approves this request,
+ * {@link MediaColumns#IS_TRASHED} is set on these items.
+ * <p>
+ * This call only generates the request for a prompt; to display the prompt,
+ * call {@link Activity#startIntentSenderForResult} with
+ * {@link PendingIntent#getIntentSender()}. You can then determine if the
+ * user granted your request by testing for {@link Activity#RESULT_OK} in
+ * {@link Activity#onActivityResult}.
+ * <p>
+ * The displayed prompt will reflect all the media items you're requesting,
+ * including those for which you already hold write access. If you want to
+ * determine if you already hold write access before requesting access, use
+ * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
+ * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
+ *
+ * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
+ * Typically this value is {@link Context#getContentResolver()},
+ * but if you need more explicit lifecycle controls, you can
+ * obtain a {@link ContentProviderClient} and wrap it using
+ * {@link ContentResolver#wrap(ContentProviderClient)}.
+ * @param uris The set of media items to include in this request. Each item
+ * must be hosted by {@link MediaStore#AUTHORITY} and must
+ * reference a specific media item by {@link BaseColumns#_ID}.
+ * @param value The {@link MediaColumns#IS_TRASHED} value to apply.
+ * @see MediaColumns#IS_TRASHED
+ * @see MediaStore#QUERY_ARG_MATCH_TRASHED
+ */
+ public static @NonNull PendingIntent createTrashRequest(@NonNull ContentResolver resolver,
+ @NonNull Collection<Uri> uris, boolean value) {
+ final ContentValues values = new ContentValues();
+ if (value) {
+ values.put(MediaColumns.IS_TRASHED, 1);
+ values.put(MediaColumns.DATE_EXPIRES,
+ (System.currentTimeMillis() + DateUtils.WEEK_IN_MILLIS) / 1000);
+ } else {
+ values.put(MediaColumns.IS_TRASHED, 0);
+ values.putNull(MediaColumns.DATE_EXPIRES);
+ }
+ return createRequest(resolver, CREATE_TRASH_REQUEST_CALL, uris, values);
+ }
+
+ /**
+ * Create a {@link PendingIntent} that will prompt the user to favorite the
+ * requested media items. When the user approves this request,
+ * {@link MediaColumns#IS_FAVORITE} is set on these items.
+ * <p>
+ * This call only generates the request for a prompt; to display the prompt,
+ * call {@link Activity#startIntentSenderForResult} with
+ * {@link PendingIntent#getIntentSender()}. You can then determine if the
+ * user granted your request by testing for {@link Activity#RESULT_OK} in
+ * {@link Activity#onActivityResult}.
+ * <p>
+ * The displayed prompt will reflect all the media items you're requesting,
+ * including those for which you already hold write access. If you want to
+ * determine if you already hold write access before requesting access, use
+ * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
+ * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
+ *
+ * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
+ * Typically this value is {@link Context#getContentResolver()},
+ * but if you need more explicit lifecycle controls, you can
+ * obtain a {@link ContentProviderClient} and wrap it using
+ * {@link ContentResolver#wrap(ContentProviderClient)}.
+ * @param uris The set of media items to include in this request. Each item
+ * must be hosted by {@link MediaStore#AUTHORITY} and must
+ * reference a specific media item by {@link BaseColumns#_ID}.
+ * @param value The {@link MediaColumns#IS_FAVORITE} value to apply.
+ * @see MediaColumns#IS_FAVORITE
+ * @see MediaStore#QUERY_ARG_MATCH_FAVORITE
+ */
+ public static @NonNull PendingIntent createFavoriteRequest(@NonNull ContentResolver resolver,
+ @NonNull Collection<Uri> uris, boolean value) {
+ final ContentValues values = new ContentValues();
+ if (value) {
+ values.put(MediaColumns.IS_FAVORITE, 1);
+ } else {
+ values.put(MediaColumns.IS_FAVORITE, 0);
+ }
+ return createRequest(resolver, CREATE_FAVORITE_REQUEST_CALL, uris, values);
+ }
+
+ /**
+ * Create a {@link PendingIntent} that will prompt the user to permanently
+ * delete the requested media items. When the user approves this request,
+ * {@link ContentResolver#delete} will be called on these items.
+ * <p>
+ * This call only generates the request for a prompt; to display the prompt,
+ * call {@link Activity#startIntentSenderForResult} with
+ * {@link PendingIntent#getIntentSender()}. You can then determine if the
+ * user granted your request by testing for {@link Activity#RESULT_OK} in
+ * {@link Activity#onActivityResult}.
+ * <p>
+ * The displayed prompt will reflect all the media items you're requesting,
+ * including those for which you already hold write access. If you want to
+ * determine if you already hold write access before requesting access, use
+ * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
+ * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
+ *
+ * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
+ * Typically this value is {@link Context#getContentResolver()},
+ * but if you need more explicit lifecycle controls, you can
+ * obtain a {@link ContentProviderClient} and wrap it using
+ * {@link ContentResolver#wrap(ContentProviderClient)}.
+ * @param uris The set of media items to include in this request. Each item
+ * must be hosted by {@link MediaStore#AUTHORITY} and must
+ * reference a specific media item by {@link BaseColumns#_ID}.
+ */
+ public static @NonNull PendingIntent createDeleteRequest(@NonNull ContentResolver resolver,
+ @NonNull Collection<Uri> uris) {
+ return createRequest(resolver, CREATE_DELETE_REQUEST_CALL, uris, null);
+ }
+
/**
* Common media metadata columns.
*/
@@ -1127,9 +1333,9 @@ public final class MediaStore {
* Trashed items are retained until they expire as defined by
* {@link #DATE_EXPIRES}.
*
+ * @see MediaColumns#IS_TRASHED
* @see MediaStore#QUERY_ARG_MATCH_TRASHED
- * @see MediaStore#trash(Context, Uri)
- * @see MediaStore#untrash(Context, Uri)
+ * @see MediaStore#createTrashRequest
*/
@Column(Cursor.FIELD_TYPE_INTEGER)
public static final String IS_TRASHED = "is_trashed";
@@ -1302,7 +1508,9 @@ public final class MediaStore {
* Flag indicating if the media item has been marked as being a
* "favorite" by the user.
*
+ * @see MediaColumns#IS_FAVORITE
* @see MediaStore#QUERY_ARG_MATCH_FAVORITE
+ * @see MediaStore#createFavoriteRequest
*/
@Column(Cursor.FIELD_TYPE_INTEGER)
public static final String IS_FAVORITE = "is_favorite";