From 1b404bef1d7fd4d06cc230f4bb4a57ff12826948 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 1 Mar 2019 11:31:30 -0700 Subject: [PATCH] Include UUID in MediaStore version. This allows apps to detect when a user clears data on MediaProvider, or when the internal database is wiped due to corruption. Bug: 126274540 Test: atest android.provider.cts.MediaStoreTest Change-Id: Idfcdbf441aea82c581b7270a6d4663136b8931e2 --- api/current.txt | 3 +- core/java/android/provider/MediaStore.java | 48 ++++++++++++++++------ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/api/current.txt b/api/current.txt index 395145e03dec2..9dbfd51e98710 100644 --- a/api/current.txt +++ b/api/current.txt @@ -38411,7 +38411,8 @@ package android.provider { method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri); method public static android.net.Uri getMediaScannerUri(); method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri); - method public static String getVersion(android.content.Context); + method @NonNull public static String getVersion(@NonNull android.content.Context); + method @NonNull public static String getVersion(@NonNull android.content.Context, @NonNull String); method @NonNull public static String getVolumeName(@NonNull android.net.Uri); method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri); method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri); diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index a34ac706c406c..917b5c2615dbf 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -145,6 +145,8 @@ public final class MediaStore { */ public static final String RETRANSLATE_CALL = "update_titles"; + /** {@hide} */ + public static final String GET_VERSION_CALL = "get_version"; /** {@hide} */ public static final String GET_DOCUMENT_URI_CALL = "get_document_uri"; /** {@hide} */ @@ -3318,21 +3320,41 @@ public final class MediaStore { public static final String MEDIA_IGNORE_FILENAME = ".nomedia"; /** - * Get the media provider's version. - * Applications that import data from the media provider into their own caches - * can use this to detect that the media provider changed, and reimport data - * as needed. No other assumptions should be made about the meaning of the version. - * @param context Context to use for performing the query. - * @return A version string, or null if the version could not be determined. + * Return an opaque version string describing the {@link MediaStore} state. + *

+ * Applications that import data from {@link MediaStore} into their own + * caches can use this to detect that {@link MediaStore} has undergone + * substantial changes, and that data should be rescanned. + *

+ * No other assumptions should be made about the meaning of the version. + *

+ * This method returns the version for {@link MediaStore#VOLUME_EXTERNAL}; + * to obtain a version for a different volume, use + * {@link #getVersion(Context, String)}. */ - public static String getVersion(Context context) { - final Uri uri = AUTHORITY_URI.buildUpon().appendPath("none").appendPath("version").build(); - try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) { - if (c.moveToFirst()) { - return c.getString(0); - } + public static @NonNull String getVersion(@NonNull Context context) { + return getVersion(context, VOLUME_EXTERNAL); + } + + /** + * Return an opaque version string describing the {@link MediaStore} state. + *

+ * Applications that import data from {@link MediaStore} into their own + * caches can use this to detect that {@link MediaStore} has undergone + * substantial changes, and that data should be rescanned. + *

+ * No other assumptions should be made about the meaning of the version. + */ + public static @NonNull String getVersion(@NonNull Context context, @NonNull String volumeName) { + final ContentResolver resolver = context.getContentResolver(); + try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) { + final Bundle in = new Bundle(); + in.putString(Intent.EXTRA_TEXT, volumeName); + final Bundle out = client.call(GET_VERSION_CALL, null, in); + return out.getString(Intent.EXTRA_TEXT); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); } - return null; } /**