Merge "Switch from commit() to apply()." into sc-mainline-prod
diff --git a/apex/framework/java/android/provider/CloudMediaProvider.java b/apex/framework/java/android/provider/CloudMediaProvider.java
index 7fd9ea2..00fa772 100644
--- a/apex/framework/java/android/provider/CloudMediaProvider.java
+++ b/apex/framework/java/android/provider/CloudMediaProvider.java
@@ -24,14 +24,13 @@
import static android.provider.CloudMediaProviderContract.EXTRA_SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED;
import static android.provider.CloudMediaProviderContract.EXTRA_SURFACE_EVENT_CALLBACK;
import static android.provider.CloudMediaProviderContract.METHOD_CREATE_SURFACE_CONTROLLER;
-import static android.provider.CloudMediaProviderContract.METHOD_GET_ACCOUNT_INFO;
import static android.provider.CloudMediaProviderContract.METHOD_GET_ASYNC_CONTENT_PROVIDER;
-import static android.provider.CloudMediaProviderContract.METHOD_GET_MEDIA_INFO;
+import static android.provider.CloudMediaProviderContract.METHOD_GET_MEDIA_COLLECTION_INFO;
import static android.provider.CloudMediaProviderContract.URI_PATH_ALBUM;
import static android.provider.CloudMediaProviderContract.URI_PATH_DELETED_MEDIA;
import static android.provider.CloudMediaProviderContract.URI_PATH_MEDIA;
import static android.provider.CloudMediaProviderContract.URI_PATH_MEDIA_EXACT;
-import static android.provider.CloudMediaProviderContract.URI_PATH_MEDIA_INFO;
+import static android.provider.CloudMediaProviderContract.URI_PATH_MEDIA_COLLECTION_INFO;
import static android.provider.CloudMediaProviderContract.URI_PATH_SURFACE_CONTROLLER;
import android.annotation.DurationMillisLong;
@@ -102,7 +101,8 @@
* zero or more albums. Albums cannot contain other albums.
* <p>
* Each item under a provider is uniquely referenced by its media or album id, which must not
- * change without changing the provider version as returned by {@link #onGetMediaInfo}.
+ * change which must be unique across all collection IDs as returned by
+ * {@link #onGetMediaCollectionInfo}.
*
* @see MediaStore#ACTION_PICK_IMAGES
*
@@ -115,7 +115,7 @@
private static final int MATCH_MEDIA_ID = 2;
private static final int MATCH_DELETED_MEDIAS = 3;
private static final int MATCH_ALBUMS = 4;
- private static final int MATCH_MEDIA_INFO = 5;
+ private static final int MATCH_MEDIA_COLLECTION_INFO = 5;
private static final int MATCH_SURFACE_CONTROLLER = 6;
private static final boolean DEFAULT_LOOPING_PLAYBACK_ENABLED = true;
@@ -142,30 +142,11 @@
mMatcher.addURI(authority, URI_PATH_MEDIA_EXACT, MATCH_MEDIA_ID);
mMatcher.addURI(authority, URI_PATH_DELETED_MEDIA, MATCH_DELETED_MEDIAS);
mMatcher.addURI(authority, URI_PATH_ALBUM, MATCH_ALBUMS);
- mMatcher.addURI(authority, URI_PATH_MEDIA_INFO, MATCH_MEDIA_INFO);
+ mMatcher.addURI(authority, URI_PATH_MEDIA_COLLECTION_INFO, MATCH_MEDIA_COLLECTION_INFO);
mMatcher.addURI(authority, URI_PATH_SURFACE_CONTROLLER, MATCH_SURFACE_CONTROLLER);
}
/**
- * Returns account related information for the media collection.
- * <p>
- * This is useful for the OS to populate a settings page with account information and allow
- * users configure their media collection account.
- *
- * @param extras containing keys to filter result:
- * <ul>
- * <li> {@link CloudMediaProviderContract.AccountInfo#ACTIVE_ACCOUNT_NAME}
- * <li> {@link CloudMediaProviderContract.AccountInfo#ACCOUNT_CONFIGURATION_INTENT}
- * </ul>
- *
- * @return {@link Bundle} containing {@link CloudMediaProviderContract.AccountInfo}
- */
- @NonNull
- public Bundle onGetAccountInfo(@Nullable Bundle extras) {
- throw new UnsupportedOperationException("getAccountInfo not supported");
- }
-
- /**
* Returns {@link Bundle} containing binder to {@link IAsyncContentProvider}.
*
* @hide
@@ -194,11 +175,17 @@
* <li> {@link CloudMediaProviderContract#EXTRA_FILTER_ALBUM}
* </ul>
*
- * @return {@link Bundle} containing {@link CloudMediaProviderContract.MediaInfo}
+ * @return {@link Bundle} containing {@link CloudMediaProviderContract.MediaCollectionInfo}
+ * <ul>
+ * <li> {@link CloudMediaProviderContract.MediaCollectionInfo#MEDIA_COLLECTION_ID}
+ * <li> {@link CloudMediaProviderContract.MediaCollectionInfo#LAST_MEDIA_SYNC_GENERATION}
+ * <li> {@link CloudMediaProviderContract.MediaCollectionInfo#ACCOUNT_NAME}
+ * <li> {@link CloudMediaProviderContract.MediaCollectionInfo#ACCOUNT_CONFIGURATION_INTENT}
+ * </ul>
*/
@SuppressWarnings("unused")
@NonNull
- public abstract Bundle onGetMediaInfo(@Nullable Bundle extras);
+ public abstract Bundle onGetMediaCollectionInfo(@NonNull Bundle extras);
/**
* Returns a {@link Cursor} to a single media item containing the columns representing the media
@@ -225,7 +212,7 @@
*
* @param extras containing keys to filter media items:
* <ul>
- * <li> {@link CloudMediaProviderContract#EXTRA_GENERATION}
+ * <li> {@link CloudMediaProviderContract#EXTRA_SYNC_GENERATION}
* <li> {@link CloudMediaProviderContract#EXTRA_PAGE_TOKEN}
* <li> {@link CloudMediaProviderContract#EXTRA_FILTER_ALBUM}
* </ul>
@@ -234,12 +221,12 @@
*/
@SuppressWarnings("unused")
@NonNull
- public abstract Cursor onQueryMedia(@Nullable Bundle extras);
+ public abstract Cursor onQueryMedia(@NonNull Bundle extras);
/**
* Returns a {@link Cursor} representing all deleted media items in the entire media collection
- * within the current provider version as returned by {@link #onGetMediaInfo}. These items can
- * be optionally filtered by {@code extras}.
+ * within the current provider version as returned by {@link #onGetMediaCollectionInfo}. These
+ * items can be optionally filtered by {@code extras}.
* <p>
* If the provider handled any filters in {@code extras}, it must add the key to
* the {@link ContentResolver#EXTRA_HONORED_ARGS} as part of the returned
@@ -247,7 +234,7 @@
*
* @param extras containing keys to filter deleted media items:
* <ul>
- * <li> {@link CloudMediaProviderContract#EXTRA_GENERATION}
+ * <li> {@link CloudMediaProviderContract#EXTRA_SYNC_GENERATION}
* <li> {@link CloudMediaProviderContract#EXTRA_PAGE_TOKEN}
* </ul>
* @return cursor representing deleted media items containing just the
@@ -255,7 +242,7 @@
*/
@SuppressWarnings("unused")
@NonNull
- public abstract Cursor onQueryDeletedMedia(@Nullable Bundle extras);
+ public abstract Cursor onQueryDeletedMedia(@NonNull Bundle extras);
/**
* Returns a cursor representing all album items in the media collection optionally filtered
@@ -269,7 +256,7 @@
*
* @param extras containing keys to filter album items:
* <ul>
- * <li> {@link CloudMediaProviderContract#EXTRA_GENERATION}
+ * <li> {@link CloudMediaProviderContract#EXTRA_SYNC_GENERATION}
* <li> {@link CloudMediaProviderContract#EXTRA_PAGE_TOKEN}
* </ul>
* @return cursor representing album items containing all
@@ -277,12 +264,12 @@
*/
@SuppressWarnings("unused")
@NonNull
- public Cursor onQueryAlbums(@Nullable Bundle extras) {
+ public Cursor onQueryAlbums(@NonNull Bundle extras) {
throw new UnsupportedOperationException("queryAlbums not supported");
}
/**
- * Returns a preview of {@code size} for a media item identified by {@code mediaId}.
+ * Returns a thumbnail of {@code size} for a media item identified by {@code mediaId}.
* <p>
* This is expected to be a much lower resolution version than the item returned by
* {@link #onOpenMedia}.
@@ -372,10 +359,8 @@
private Bundle callUnchecked(String method, String arg, Bundle extras)
throws FileNotFoundException {
- if (METHOD_GET_MEDIA_INFO.equals(method)) {
- return onGetMediaInfo(extras);
- } else if (METHOD_GET_ACCOUNT_INFO.equals(method)) {
- return onGetAccountInfo(extras);
+ if (METHOD_GET_MEDIA_COLLECTION_INFO.equals(method)) {
+ return onGetMediaCollectionInfo(extras);
} else if (METHOD_CREATE_SURFACE_CONTROLLER.equals(method)) {
return onCreateSurfaceController(extras);
} else if (METHOD_GET_ASYNC_CONTENT_PROVIDER.equals(method)) {
diff --git a/apex/framework/java/android/provider/CloudMediaProviderContract.java b/apex/framework/java/android/provider/CloudMediaProviderContract.java
index f2b89fc..d0d5a69 100644
--- a/apex/framework/java/android/provider/CloudMediaProviderContract.java
+++ b/apex/framework/java/android/provider/CloudMediaProviderContract.java
@@ -90,20 +90,22 @@
public static final String DATE_TAKEN_MILLIS = "date_taken_millis";
/**
- * Generation number associated with a media item.
+ * Number associated with a media item indicating what generation or batch the media item
+ * was synced into the media collection.
* <p>
- * Providers should associate a monotonically increasing generation number to each media
- * item which is expected to increase for each atomic modification on the media item. This
- * is useful for the OS to quickly identify that a media item has changed since a previous
- * point in time. Note that this does not need to be unique across all media items, i.e.,
- * multiple media items can have the same GENERATION_MODIFIED value. However, the
- * modification of a media item should increase the {@link MediaInfo#MEDIA_GENERATION}.
+ * Providers should associate a monotonically increasing sync generation number to each
+ * media item which is expected to increase for each atomic modification on the media item.
+ * This is useful for the OS to quickly identify that a media item has changed since a
+ * previous point in time. Note that this does not need to be unique across all media items,
+ * i.e. multiple media items can have the same SYNC_GENERATION value. However, the
+ * modification of a media item should increase the
+ * {@link MediaCollectionInfo#LAST_MEDIA_SYNC_GENERATION}.
* <p>
* Type: LONG
*
- * @see MediaInfo#MEDIA_GENERATION
+ * @see MediaCollectionInfo#LAST_MEDIA_SYNC_GENERATION
*/
- public static final String GENERATION_MODIFIED = "generation_modified";
+ public static final String SYNC_GENERATION = "sync_generation";
/**
* Concrete MIME type of a media file. For example, "image/png" or
@@ -216,7 +218,7 @@
* Unique ID of an album. This ID is both provided by and interpreted
* by a {@link CloudMediaProvider}.
* <p>
- * Each album item must have a unique ID within a provider and a given version.
+ * Each album item must have a unique ID within a media collection.
* <p>
* A provider should return durable IDs, since they will be used to cache
* album information in the OS.
@@ -308,81 +310,64 @@
public static final String TYPE_UNRELIABLE_VOLUME = "UNRELIABLE_VOLUME";
}
- /** Constants related to the entire media collection */
- public static final class MediaInfo {
- private MediaInfo() {}
+ /** Constants related to a media collection */
+ public static final class MediaCollectionInfo {
+ private MediaCollectionInfo() {}
/**
- * Media collection version identifier
+ * Media collection identifier
* <p>
- * The only requirement on the value of a version is uniqueness on a device, i.e. a
- * a version should never be reused on a device.
+ * The only requirement on the collection ID is uniqueness on a device.
* <p>
* This value will not be interpreted by the OS, however it will be used to check the
- * validity of cached data and URI grants to client apps. Anytime the media or album ids get
- * re-indexed, the version should change so that the OS can clear its cache and more
- * importantly, revoke any URI grants to apps.
+ * validity of cached data and URI grants to client apps. Anytime the media or album ids
+ * get re-indexed, a new collection with a new and unique id should be created so that the
+ * OS can clear its cache and more importantly, revoke any URI grants to apps.
* <p>
- * Apps are recommended to generate unique versions with, {@link UUID#randomUUID}. This is
- * preferred to using a simple monotonic sequence because the provider data could get
- * cleared and it might have to re-index media items on the device without any history of
- * its last version. With random UUIDs, if data gets cleared, a new one can easily be
+ * Apps are recommended to generate unique collection ids with, {@link UUID#randomUUID}.
+ * This is preferred to using a simple monotonic sequence because the provider data could
+ * get cleared and it might have to re-index media items on the device without any history
+ * of its last ID. With random UUIDs, if data gets cleared, a new one can easily be
* generated safely.
* <p>
* Type: STRING
*
- * @see CloudMediaProvider#onGetMediaInfo
+ * @see CloudMediaProvider#onGetMediaCollectionInfo
*/
- public static final String MEDIA_VERSION = "media_version";
+ public static final String MEDIA_COLLECTION_ID = "media_collection_id";
/**
- * Maximum generation number of media items in the entire media collection.
+ * Last {@link CloudMediaProviderContract.MediaColumns#SYNC_GENERATION} in the media
+ * collection including deleted media items.
* <p>
- * Providers should associate a monotonically increasing generation number to each media
- * item change (insertion/deletion/update). This is useful for the OS to quickly identify
- * exactly which media items have changed since a previous point in time.
+ * Providers should associate a monotonically increasing sync generation to each
+ * media item change (insertion/deletion/update). This is useful for the OS to quickly
+ * identify exactly which media items have changed since a previous point in time.
* <p>
* Type: LONG
*
- * @see CloudMediaProviderContract#EXTRA_GENERATION
- * @see CloudMediaProvider#onGetMediaInfo
- * @see CloudMediaProviderContract.MediaColumns#GENERATION_MODIFIED
+ * @see CloudMediaProviderContract#EXTRA_SYNC_GENERATION
+ * @see CloudMediaProvider#onGetMediaCollectionInfo
+ * @see CloudMediaProviderContract.MediaColumns#SYNC_GENERATION
*/
- public static final String MEDIA_GENERATION = "media_generation";
+ public static final String LAST_MEDIA_SYNC_GENERATION = "last_media_sync_generation";
/**
- * Total count of the media items in the entire media collection.
- * <p>
- * Along with the {@link #MEDIA_GENERATION} this helps the OS identify if there have been
- * changes to media items in the media collection.
- * <p>
- * Type: LONG
- *
- * @see CloudMediaProvider#onGetMediaInfo
- */
- public static final String MEDIA_COUNT = "media_count";
- }
-
- /** Constants related to the account information */
- public static final class AccountInfo {
- private AccountInfo() {}
-
- /**
- * Name of the account owning the media collection synced from the cloud provider.
+ * Name of the account that owns the media collection.
* <p>
* Type: STRING
*
- * @see CloudMediaProvider#onGetAccountInfo
+ * @see CloudMediaProvider#onGetMediaCollectionInfo
*/
- public static final String ACTIVE_ACCOUNT_NAME = "active_account_name";
+ public static final String ACCOUNT_NAME = "account_name";
/**
* {@link Intent} Intent to launch an {@link Activity} to allow users configure their media
- * collection account information like the active account.
+ * collection account information like the account name.
* <p>
* Type: PARCELABLE
*
- * @see CloudMediaProvider#onGetAccountInfo
+ * @see CloudMediaProvider#onGetMediaCollectionInfo
*/
public static final String ACCOUNT_CONFIGURATION_INTENT = "account_configuration_intent";
}
@@ -411,43 +396,43 @@
* Generation number to fetch the latest media or album metadata changes from the media
* collection.
* <p>
- * The provider should associate a monotonically increasing generation number to each media item
- * change (insertion/deletion/update). This is useful to quickly identify exactly which media
- * items have changed since a previous point in time.
+ * The provider should associate a monotonically increasing sync generation to each media
+ * item change (insertion/deletion/update). This is useful to quickly identify exactly which
+ * media items have changed since a previous point in time.
* <p>
- * Providers should associate a separate monotonically increasing generation number for album
- * item changes (insertion/deletion/update). Unlike the media generation number, the album
- * generation number should also record insertions and deletions to media items within the
- * album. E.g., a direct change to an albums
+ * Providers should also associate a separate monotonically increasing sync generation
+ * for album changes (insertion/deletion/update). This album sync generation, should record
+ * both changes to the album metadata itself and changes to the media items contained in the
+ * album. E.g. a direct change to an album's
* {@link CloudMediaProviderContract.AlbumColumns#DISPLAY_NAME} will increase the
- * album generation number, likewise adding a photo to that album.
+ * album sync generation, likewise adding a photo to that album should also increase the
+ * sync generation.
* <p>
- * Note that multiple media (or album) items can share a generation number as long as the entire
+ * Note that multiple media (or album) items can share a sync generation as long as the entire
* change appears atomic from the perspective of the query APIs. E.g. each item in a batch photo
- * sync from the cloud can have the same generation number if they all occurred within the same
- * database transaction and hence guarantee that a db query result either has all they synced
- * items or none.
+ * sync from the cloud can have the same sync generation if they were all synced atomically into
+ * the collection from the perspective of an external observer.
* <p>
* This extra can be passed as a {@link Bundle} parameter to the media or album query methods
- * and the provider should only return items with a generation number that are strictly greater
- * than the filter.
+ * and the provider should only return items with a sync generation that is strictly greater
+ * than the one provided in the filter.
* <p>
* If the provider supports this filter, it must support the respective
- * {@link CloudMediaProvider#onGetMediaInfo} methods to return the {@code count} and
+ * {@link CloudMediaProvider#onGetMediaCollectionInfo} methods to return the {@code count} and
* {@code max generation} for media or albums.
* <p>
* If the provider handled the generation, they must add the
- * {@link #EXTRA_GENERATION} key to the array of {@link ContentResolver#EXTRA_HONORED_ARGS}
+ * {@link #EXTRA_SYNC_GENERATION} key to the array of {@link ContentResolver#EXTRA_HONORED_ARGS}
* as part of the returned {@link Cursor#setExtras} {@link Bundle}.
*
- * @see MediaInfo#MEDIA_GENERATION
+ * @see MediaCollectionInfo#LAST_MEDIA_SYNC_GENERATION
* @see CloudMediaProvider#onQueryMedia
* @see CloudMediaProvider#onQueryAlbums
* @see MediaStore.MediaColumns#GENERATION_MODIFIED
* <p>
* Type: LONG
*/
- public static final String EXTRA_GENERATION = "android.provider.extra.GENERATION";
+ public static final String EXTRA_SYNC_GENERATION = "android.provider.extra.SYNC_GENERATION";
/**
* Limits the query results to only media items matching the given album id.
@@ -500,20 +485,12 @@
"android.provider.extra.PREVIEW_THUMBNAIL";
/**
- * Constant used to execute {@link CloudMediaProvider#onGetMediaInfo} via
+ * Constant used to execute {@link CloudMediaProvider#onGetMediaCollectionInfo} via
* {@link ContentProvider#call}.
*
* {@hide}
*/
- public static final String METHOD_GET_MEDIA_INFO = "android:getMediaInfo";
-
- /**
- * Constant used to execute {@link CloudMediaProvider#onGetAccountInfo} via
- * {@link ContentProvider#call}.
- *
- * {@hide}
- */
- public static final String METHOD_GET_ACCOUNT_INFO = "android:getAccountInfo";
+ public static final String METHOD_GET_MEDIA_COLLECTION_INFO = "android:getMediaCollectionInfo";
/**
* Constant used to execute {@link CloudMediaProvider#onCreateSurfaceController} via
@@ -627,18 +604,11 @@
public static final String URI_PATH_ALBUM = "album";
/**
- * URI path for {@link CloudMediaProvider#onGetMediaInfo}
+ * URI path for {@link CloudMediaProvider#onGetMediaCollectionInfo}
*
* {@hide}
*/
- public static final String URI_PATH_MEDIA_INFO = "media_info";
-
- /**
- * URI path for {@link CloudMediaProvider#onGetAccountInfo}
- *
- * {@hide}
- */
- public static final String URI_PATH_ACCOUNT_INFO = "account_info";
+ public static final String URI_PATH_MEDIA_COLLECTION_INFO = "media_collection_info";
/**
* URI path for {@link CloudMediaProvider#onCreateSurfaceController}
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 3d26564..4e73f4a 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -68,7 +68,7 @@
<string name="permission_progress_write_audio" msgid="6029375427984180097">"{count,plural, =1{Audio fayl oʻzgartirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta audio fayl oʻzgartirilmoqda…}}"</string>
<string name="permission_write_video" msgid="103902551603700525">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni oʻzgartirishi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni oʻzgartirishi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_write_video" msgid="7014908418349819148">"{count,plural, =1{Video oʻzgartirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta video oʻzgartirilmoqda…}}"</string>
- <string name="permission_write_image" msgid="3518991791620523786">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni oʻzgartirishi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni oʻzgartirishi uchun ruxsat berilsinmi?}}"</string>
+ <string name="permission_write_image" msgid="3518991791620523786">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> uchun bu suratni oʻzgartirishga ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> uchun <xliff:g id="COUNT">^2</xliff:g> ta suratni oʻzgartirishga ruxsat berilsinmi?}}"</string>
<string name="permission_progress_write_image" msgid="3623580315590025262">"{count,plural, =1{Rasm oʻzgartirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta rasm oʻzgartirilmoqda…}}"</string>
<string name="permission_write_generic" msgid="7431128739233656991">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni oʻzgartirishi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni oʻzgartirishi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_write_generic" msgid="2806560971318391443">"{count,plural, =1{Element oʻzgartirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta element oʻzgartirilmoqda…}}"</string>
@@ -76,7 +76,7 @@
<string name="permission_progress_trash_audio" msgid="3116279868733641329">"{count,plural, =1{Audio fayl chiqitdonga tashlanmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta audio fayl chiqitdonga tashlanmoqda…}}"</string>
<string name="permission_trash_video" msgid="7555850843259959642">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni chiqitdonga tashlashi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni chiqitdonga tashlashi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_trash_video" msgid="4637821778329459681">"{count,plural, =1{Video chiqitdonga tashlanmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta video chiqitdonga tashlanmoqda…}}"</string>
- <string name="permission_trash_image" msgid="3333128084684156675">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni chiqitdonga tashlashi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni chiqitdonga tashlashi uchun ruxsat berilsinmi?}}"</string>
+ <string name="permission_trash_image" msgid="3333128084684156675">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> uchun bu suratni chiqitdonga tashlashga ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> uchun <xliff:g id="COUNT">^2</xliff:g> ta suratni chiqitdonga tashlashga ruxsat berilsinmi?}}"</string>
<string name="permission_progress_trash_image" msgid="3063857679090024764">"{count,plural, =1{Rasm chiqitdonga tashlanmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta rasm chiqitdonga tashlanmoqda…}}"</string>
<string name="permission_trash_generic" msgid="5545420534785075362">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni chiqitdonga tashlashi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni chiqitdonga tashlashi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_trash_generic" msgid="7815124979717814057">"{count,plural, =1{Element chiqitdonga tashlanmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta element chiqitdonga tashlanmoqda…}}"</string>
@@ -84,7 +84,7 @@
<string name="permission_progress_untrash_audio" msgid="2775372344946464508">"{count,plural, =1{Audio fayl chiqitdondan chiqarilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta audio fayl chiqitdondan chiqarilmoqda…}}"</string>
<string name="permission_untrash_video" msgid="3178914827607608162">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_untrash_video" msgid="5500929409733841567">"{count,plural, =1{Video chiqitdondan chiqarilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta video chiqitdondan chiqarilmoqda…}}"</string>
- <string name="permission_untrash_image" msgid="3397523279351032265">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?}}"</string>
+ <string name="permission_untrash_image" msgid="3397523279351032265">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> uchun bu suratni chiqitdondan qayta tiklashga ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> uchun <xliff:g id="COUNT">^2</xliff:g> ta suratni chiqitdondan qayta tiklashga ruxsat berilsinmi?}}"</string>
<string name="permission_progress_untrash_image" msgid="5295061520504846264">"{count,plural, =1{Rasm chiqitdondan chiqarilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta rasm chiqitdondan chiqarilmoqda…}}"</string>
<string name="permission_untrash_generic" msgid="2118366929431671046">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_untrash_generic" msgid="1489511601966842579">"{count,plural, =1{Element chiqitdondan chiqarilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta element chiqitdondan chiqarilmoqda…}}"</string>
@@ -92,7 +92,7 @@
<string name="permission_progress_delete_audio" msgid="1734871539021696401">"{count,plural, =1{Audio fayl oʻchirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta audio fayl oʻchirilmoqda…}}"</string>
<string name="permission_delete_video" msgid="604024971828349279">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni oʻchirib tashlashi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni oʻchirib tashlashi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_delete_video" msgid="1846702435073793157">"{count,plural, =1{Video oʻchirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta video oʻchirilmoqda…}}"</string>
- <string name="permission_delete_image" msgid="3109056012794330510">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni oʻchirib tashlashi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni oʻchirib tashlashi uchun ruxsat berilsinmi?}}"</string>
+ <string name="permission_delete_image" msgid="3109056012794330510">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> uchun bu suratni oʻchirishga ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> uchun <xliff:g id="COUNT">^2</xliff:g> ta suratni oʻchirishga ruxsat berilsinmi?}}"</string>
<string name="permission_progress_delete_image" msgid="8580517204901148906">"{count,plural, =1{Rasm oʻchirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta rasm oʻchirilmoqda…}}"</string>
<string name="permission_delete_generic" msgid="7891939881065520271">"{count,plural, =1{<xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni oʻchirib tashlashi uchun ruxsat berilsinmi?}other{<xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni oʻchirib tashlashi uchun ruxsat berilsinmi?}}"</string>
<string name="permission_progress_delete_generic" msgid="6709118146245087898">"{count,plural, =1{Element oʻchirilmoqda…}other{<xliff:g id="COUNT">^1</xliff:g> ta element oʻchirilmoqda…}}"</string>
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index d64c4e6..777b6f2 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -1755,7 +1755,7 @@
extractSyntheticRelativePathSegements(path, userId);
final int segmentCount = syntheticRelativePathSegments.size();
- if (segmentCount < 1 || segmentCount > 4) {
+ if (segmentCount < 1 || segmentCount > 5) {
throw new IllegalStateException("Unexpected synthetic picker path: " + file);
}
@@ -1770,19 +1770,30 @@
}
break;
case 2:
- // .../picker/<authority>
- result = preparePickerAuthorityPathSegment(file, lastSegment, uid);
+ // .../picker/<user-id>
+ try {
+ Integer.parseInt(lastSegment);
+ result = file.exists() || file.mkdir();
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Invalid user id for picker file lookup: " + lastSegment
+ + ". File: " + file);
+ }
break;
case 3:
- // .../picker/<authority>/media
+ // .../picker/<user-id>/<authority>
+ result = preparePickerAuthorityPathSegment(file, lastSegment, uid);
+ break;
+ case 4:
+ // .../picker/<user-id>/<authority>/media
if (lastSegment.equals("media")) {
result = file.exists() || file.mkdir();
}
break;
- case 4:
- // .../picker/<authority>/media/<media-id.extension>
- final String authority = syntheticRelativePathSegments.get(1);
- result = preparePickerMediaIdPathSegment(file, authority, lastSegment);
+ case 5:
+ // .../picker/<user-id>/<authority>/media/<media-id.extension>
+ final String fileUserId = syntheticRelativePathSegments.get(1);
+ final String authority = syntheticRelativePathSegments.get(2);
+ result = preparePickerMediaIdPathSegment(file, authority, lastSegment, fileUserId);
break;
}
@@ -1794,17 +1805,17 @@
private FileOpenResult handlePickerFileOpen(String path, int uid) {
final String[] segments = path.split("/");
- if (segments.length != 10) {
+ if (segments.length != 11) {
Log.e(TAG, "Picker file open failed. Unexpected segments: " + path);
return new FileOpenResult(OsConstants.ENOENT /* status */, uid, /* transformsUid */ 0,
new long[0]);
}
- // ['', 'storage', 'emulated', '0', 'transforms', 'synthetic', 'picker', '<host>',
- // 'media', '<fileName>']
- final String userId = segments[3];
- final String fileName = segments[9];
- final String host = segments[7];
+ // ['', 'storage', 'emulated', '0', 'transforms', 'synthetic', 'picker', '<user-id>',
+ // '<host>', 'media', '<fileName>']
+ final String userId = segments[7];
+ final String fileName = segments[10];
+ final String host = segments[8];
final String authority = userId + "@" + host;
final int lastDotIndex = fileName.lastIndexOf('.');
@@ -1848,17 +1859,21 @@
private boolean preparePickerAuthorityPathSegment(File file, String authority, int uid) {
if (mPickerSyncController.isProviderEnabled(authority)) {
- return file.mkdir();
+ return file.exists() || file.mkdir();
}
return false;
}
- private boolean preparePickerMediaIdPathSegment(File file, String authority, String fileName) {
+ private boolean preparePickerMediaIdPathSegment(File file, String authority, String fileName,
+ String userId) {
final String mediaId = extractFileName(fileName);
+ final String[] projection = new String[] { MediaStore.PickerMediaColumns.SIZE };
- try (Cursor cursor = mPickerDbFacade.queryMediaIdForApps(authority, mediaId,
- new String[] { MediaStore.PickerMediaColumns.SIZE })) {
+ final Uri uri = Uri.parse("content://media/picker/" + userId + "/" + authority + "/media/"
+ + mediaId);
+ try (Cursor cursor = mPickerUriResolver.query(uri, projection, /* queryArgs */ null,
+ /* signal */ null, 0, android.os.Process.myUid())) {
if (cursor != null && cursor.moveToFirst()) {
final int sizeBytesIdx = cursor.getColumnIndex(MediaStore.PickerMediaColumns.SIZE);
@@ -9614,12 +9629,15 @@
final boolean allowHidden = isCallingPackageAllowedHidden();
final int table = matchUri(uri, allowHidden);
+ final String selection = extras.getString(QUERY_ARG_SQL_SELECTION);
+ final String[] selectionArgs = extras.getStringArray(QUERY_ARG_SQL_SELECTION_ARGS);
+
// First, check to see if caller has direct write access
if (forWrite) {
final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_UPDATE, table, uri, extras, null);
qb.allowColumn(SQLiteQueryBuilder.ROWID_COLUMN);
try (Cursor c = qb.query(helper, new String[] { SQLiteQueryBuilder.ROWID_COLUMN },
- null, null, null, null, null, null, null)) {
+ selection, selectionArgs, null, null, null, null, null)) {
if (c.moveToFirst()) {
// Direct write access granted, yay!
return;
@@ -9643,7 +9661,7 @@
final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_QUERY, table, uri, extras, null);
qb.allowColumn(SQLiteQueryBuilder.ROWID_COLUMN);
try (Cursor c = qb.query(helper, new String[] { SQLiteQueryBuilder.ROWID_COLUMN },
- null, null, null, null, null, null, null)) {
+ selection, selectionArgs, null, null, null, null, null)) {
if (c.moveToFirst()) {
if (!forWrite) {
// Direct read access granted, yay!
diff --git a/src/com/android/providers/media/PickerUriResolver.java b/src/com/android/providers/media/PickerUriResolver.java
index bd251c8..14e1e21 100644
--- a/src/com/android/providers/media/PickerUriResolver.java
+++ b/src/com/android/providers/media/PickerUriResolver.java
@@ -221,14 +221,9 @@
+ CloudMediaProviderContract.URI_PATH_DELETED_MEDIA);
}
- public static Uri getMediaInfoUri(String authority) {
+ public static Uri getMediaCollectionInfoUri(String authority) {
return Uri.parse("content://" + authority + "/"
- + CloudMediaProviderContract.URI_PATH_MEDIA_INFO);
- }
-
- public static Uri getAccountInfoUri(String authority) {
- return Uri.parse("content://" + authority + "/"
- + CloudMediaProviderContract.URI_PATH_ACCOUNT_INFO);
+ + CloudMediaProviderContract.URI_PATH_MEDIA_COLLECTION_INFO);
}
public static Uri getAlbumUri(String authority) {
@@ -255,6 +250,9 @@
try (Cursor cursor = queryPickerUri(uri, projection)) {
if (cursor != null && cursor.getCount() == 1 && cursor.moveToFirst()) {
String path = getCursorString(cursor, MediaStore.PickerMediaColumns.DATA);
+ // First replace /sdcard with /storage/emulated path
+ path = path.replaceFirst("/sdcard", "/storage/emulated/" + MediaStore.MY_USER_ID);
+ // Then convert /storage/emulated patht to /mnt/user/ path
return toFuseFile(new File(path));
}
}
diff --git a/src/com/android/providers/media/photopicker/PhotoPickerProvider.java b/src/com/android/providers/media/photopicker/PhotoPickerProvider.java
index 820161b..653f732 100644
--- a/src/com/android/providers/media/photopicker/PhotoPickerProvider.java
+++ b/src/com/android/providers/media/photopicker/PhotoPickerProvider.java
@@ -18,7 +18,7 @@
import static android.provider.CloudMediaProviderContract.EXTRA_LOOPING_PLAYBACK_ENABLED;
import static android.provider.CloudMediaProvider.SurfaceEventCallback.PLAYBACK_EVENT_READY;
-import static android.provider.CloudMediaProviderContract.MediaInfo;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import android.annotation.DurationMillisLong;
import android.content.ContentProviderClient;
@@ -141,20 +141,21 @@
}
@Override
- public Bundle onGetMediaInfo(@Nullable Bundle extras) {
+ public Bundle onGetMediaCollectionInfo(@Nullable Bundle extras) {
final CloudProviderQueryExtras queryExtras =
CloudProviderQueryExtras.fromCloudMediaBundle(extras);
// TODO(b/190713331): Handle extra_filter_albums
Bundle bundle = new Bundle();
- try (Cursor cursor = mDbFacade.getMediaInfo(queryExtras.getGeneration())) {
+ try (Cursor cursor = mDbFacade.getMediaCollectionInfo(queryExtras.getGeneration())) {
if (cursor.moveToFirst()) {
- int generationIndex = cursor.getColumnIndexOrThrow(MediaInfo.MEDIA_GENERATION);
- int countIndex = cursor.getColumnIndexOrThrow(MediaInfo.MEDIA_COUNT);
+ int generationIndex = cursor.getColumnIndexOrThrow(
+ MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION);
- bundle.putString(MediaInfo.MEDIA_VERSION, MediaStore.getVersion(getContext()));
- bundle.putLong(MediaInfo.MEDIA_GENERATION, cursor.getLong(generationIndex));
- bundle.putLong(MediaInfo.MEDIA_COUNT, cursor.getLong(countIndex));
+ bundle.putString(MediaCollectionInfo.MEDIA_COLLECTION_ID,
+ MediaStore.getVersion(getContext()));
+ bundle.putLong(MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION,
+ cursor.getLong(generationIndex));
}
}
return bundle;
diff --git a/src/com/android/providers/media/photopicker/PickerDataLayer.java b/src/com/android/providers/media/photopicker/PickerDataLayer.java
index b51bf88..98f6d08 100644
--- a/src/com/android/providers/media/photopicker/PickerDataLayer.java
+++ b/src/com/android/providers/media/photopicker/PickerDataLayer.java
@@ -16,15 +16,14 @@
package com.android.providers.media.photopicker;
-import static android.provider.CloudMediaProviderContract.EXTRA_GENERATION;
-import static android.provider.CloudMediaProviderContract.METHOD_GET_ACCOUNT_INFO;
+import static android.provider.CloudMediaProviderContract.EXTRA_SYNC_GENERATION;
+import static android.provider.CloudMediaProviderContract.METHOD_GET_MEDIA_COLLECTION_INFO;
import static android.provider.CloudMediaProviderContract.MediaColumns;
-import static android.provider.CloudMediaProviderContract.MediaInfo;
-import static com.android.providers.media.PickerUriResolver.getAccountInfoUri;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import static com.android.providers.media.PickerUriResolver.getAlbumUri;
import static com.android.providers.media.PickerUriResolver.getMediaUri;
import static com.android.providers.media.PickerUriResolver.getDeletedMediaUri;
-import static com.android.providers.media.PickerUriResolver.getMediaInfoUri;
+import static com.android.providers.media.PickerUriResolver.getMediaCollectionInfoUri;
import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.LIMIT_DEFAULT;
import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.LONG_DEFAULT;
import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.STRING_DEFAULT;
@@ -130,12 +129,12 @@
try {
final Bundle accountBundle = mContext.getContentResolver().call(
- getAccountInfoUri(cloudProvider), METHOD_GET_ACCOUNT_INFO, /* arg */ null,
- /* extras */ null);
+ getMediaCollectionInfoUri(cloudProvider), METHOD_GET_MEDIA_COLLECTION_INFO,
+ /* arg */ null, /* extras */ null);
final String accountName = accountBundle.getString(
- CloudMediaProviderContract.AccountInfo.ACTIVE_ACCOUNT_NAME);
+ CloudMediaProviderContract.MediaCollectionInfo.ACCOUNT_NAME);
final Intent configIntent = (Intent) accountBundle.getParcelable(
- CloudMediaProviderContract.AccountInfo.ACCOUNT_CONFIGURATION_INTENT);
+ CloudMediaProviderContract.MediaCollectionInfo.ACCOUNT_CONFIGURATION_INTENT);
if (accountName == null) {
return null;
diff --git a/src/com/android/providers/media/photopicker/PickerSyncController.java b/src/com/android/providers/media/photopicker/PickerSyncController.java
index 716c16b..74b9a03 100644
--- a/src/com/android/providers/media/photopicker/PickerSyncController.java
+++ b/src/com/android/providers/media/photopicker/PickerSyncController.java
@@ -16,12 +16,12 @@
package com.android.providers.media.photopicker;
-import static android.provider.CloudMediaProviderContract.EXTRA_GENERATION;
+import static android.provider.CloudMediaProviderContract.EXTRA_SYNC_GENERATION;
import static android.provider.CloudMediaProviderContract.EXTRA_PAGE_TOKEN;
-import static android.provider.CloudMediaProviderContract.MediaInfo;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import static com.android.providers.media.PickerUriResolver.getMediaUri;
import static com.android.providers.media.PickerUriResolver.getDeletedMediaUri;
-import static com.android.providers.media.PickerUriResolver.getMediaInfoUri;
+import static com.android.providers.media.PickerUriResolver.getMediaCollectionInfoUri;
import android.annotation.IntDef;
import android.content.Context;
@@ -69,7 +69,8 @@
private static final String DEFAULT_CLOUD_PROVIDER_PKG = null;
private static final int DEFAULT_CLOUD_PROVIDER_UID = -1;
- private static final long DEFAULT_SYNC_DELAY_MS = 1000;
+ private static final long DEFAULT_SYNC_DELAY_MS =
+ PickerDbFacade.getDefaultPickerDbSyncDelayMs();
private static final int SYNC_TYPE_NONE = 0;
private static final int SYNC_TYPE_INCREMENTAL = 1;
@@ -202,7 +203,7 @@
if (authority == null || !newProviderInfo.isEmpty()) {
synchronized (mLock) {
setCloudProviderInfo(newProviderInfo);
- resetCachedMediaInfo(newProviderInfo.authority);
+ resetCachedMediaCollectionInfo(newProviderInfo.authority);
// Disable cloud provider queries on the db until next sync
// This will temporarily *clear* the cloud provider on the db facade and prevent
@@ -276,30 +277,30 @@
switch (params.syncType) {
case SYNC_TYPE_RESET:
- // Odd! Can only happen if provider gave us unexpected MediaInfo
+ // Odd! Can only happen if provider gave us unexpected MediaCollectionInfo
// We reset the cloud media in the picker db
executeSyncReset(authority);
- // And clear our cached MediaInfo, so that whenever the provider recovers,
+ // And clear our cached MediaCollectionInfo, so that whenever the provider recovers,
// we force a full sync
- resetCachedMediaInfo(authority);
+ resetCachedMediaCollectionInfo(authority);
return;
case SYNC_TYPE_FULL:
executeSyncReset(authority);
executeSyncAdd(authority, new Bundle() /* queryArgs */);
// Commit sync position
- cacheMediaInfo(authority, params.latestMediaInfo);
+ cacheMediaCollectionInfo(authority, params.latestMediaCollectionInfo);
return;
case SYNC_TYPE_INCREMENTAL:
final Bundle queryArgs = new Bundle();
- queryArgs.putLong(EXTRA_GENERATION, params.syncGeneration);
+ queryArgs.putLong(EXTRA_SYNC_GENERATION, params.syncGeneration);
executeSyncAdd(authority, queryArgs);
executeSyncRemove(authority, queryArgs);
// Commit sync position
- cacheMediaInfo(authority, params.latestMediaInfo);
+ cacheMediaCollectionInfo(authority, params.latestMediaCollectionInfo);
return;
case SYNC_TYPE_NONE:
return;
@@ -361,7 +362,7 @@
editor.apply();
}
- private void cacheMediaInfo(String authority, Bundle bundle) {
+ private void cacheMediaCollectionInfo(String authority, Bundle bundle) {
if (authority == null) {
Log.d(TAG, "Ignoring cache media info for null authority with bundle: " + bundle);
return;
@@ -370,47 +371,46 @@
final SharedPreferences.Editor editor = mSyncPrefs.edit();
if (bundle == null) {
- editor.remove(getPrefsKey(authority, MediaInfo.MEDIA_VERSION));
- editor.remove(getPrefsKey(authority, MediaInfo.MEDIA_GENERATION));
- editor.remove(getPrefsKey(authority, MediaInfo.MEDIA_COUNT));
+ editor.remove(getPrefsKey(authority, MediaCollectionInfo.MEDIA_COLLECTION_ID));
+ editor.remove(getPrefsKey(authority, MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION));
} else {
- final String version = bundle.getString(MediaInfo.MEDIA_VERSION);
- final long generation = bundle.getLong(MediaInfo.MEDIA_GENERATION);
- final long count = bundle.getLong(MediaInfo.MEDIA_COUNT);
+ final String collectionId = bundle.getString(MediaCollectionInfo.MEDIA_COLLECTION_ID);
+ final long generation = bundle.getLong(
+ MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION);
- editor.putString(getPrefsKey(authority, MediaInfo.MEDIA_VERSION), version);
- editor.putLong(getPrefsKey(authority, MediaInfo.MEDIA_GENERATION), generation);
- editor.putLong(getPrefsKey(authority, MediaInfo.MEDIA_COUNT), count);
+ editor.putString(getPrefsKey(authority, MediaCollectionInfo.MEDIA_COLLECTION_ID),
+ collectionId);
+ editor.putLong(getPrefsKey(authority, MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION),
+ generation);
}
editor.apply();
}
- private void resetCachedMediaInfo(String authority) {
- cacheMediaInfo(authority, /* bundle */ null);
+ private void resetCachedMediaCollectionInfo(String authority) {
+ cacheMediaCollectionInfo(authority, /* bundle */ null);
}
- private Bundle getCachedMediaInfo(String authority) {
+ private Bundle getCachedMediaCollectionInfo(String authority) {
final Bundle bundle = new Bundle();
- final String version = mSyncPrefs.getString(getPrefsKey(authority, MediaInfo.MEDIA_VERSION),
+ final String collectionId = mSyncPrefs.getString(
+ getPrefsKey(authority, MediaCollectionInfo.MEDIA_COLLECTION_ID),
/* default */ null);
final long generation = mSyncPrefs.getLong(
- getPrefsKey(authority, MediaInfo.MEDIA_GENERATION), /* default */ -1);
- final long count = mSyncPrefs.getLong(getPrefsKey(authority, MediaInfo.MEDIA_COUNT),
+ getPrefsKey(authority, MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION),
/* default */ -1);
- bundle.putString(MediaInfo.MEDIA_VERSION, version);
- bundle.putLong(MediaInfo.MEDIA_GENERATION, generation);
- bundle.putLong(MediaInfo.MEDIA_COUNT, count);
+ bundle.putString(MediaCollectionInfo.MEDIA_COLLECTION_ID, collectionId);
+ bundle.putLong(MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION, generation);
return bundle;
}
- private Bundle getLatestMediaInfo(String authority) {
+ private Bundle getLatestMediaCollectionInfo(String authority) {
try {
- return mContext.getContentResolver().call(getMediaInfoUri(authority),
- CloudMediaProviderContract.METHOD_GET_MEDIA_INFO, /* arg */ null,
+ return mContext.getContentResolver().call(getMediaCollectionInfoUri(authority),
+ CloudMediaProviderContract.METHOD_GET_MEDIA_COLLECTION_INFO, /* arg */ null,
/* extras */ null);
} catch (Exception e) {
Log.w(TAG, "Failed to fetch latest media info from authority: " + authority, e);
@@ -426,40 +426,44 @@
return SyncRequestParams.forReset();
}
- final Bundle cachedMediaInfo = getCachedMediaInfo(authority);
- final Bundle latestMediaInfo = getLatestMediaInfo(authority);
+ final Bundle cachedMediaCollectionInfo = getCachedMediaCollectionInfo(authority);
+ final Bundle latestMediaCollectionInfo = getLatestMediaCollectionInfo(authority);
- final String latestVersion = latestMediaInfo.getString(MediaInfo.MEDIA_VERSION);
- final long latestGeneration = latestMediaInfo.getLong(MediaInfo.MEDIA_GENERATION);
- final long latestCount = latestMediaInfo.getLong(MediaInfo.MEDIA_COUNT);
+ final String latestCollectionId =
+ latestMediaCollectionInfo.getString(MediaCollectionInfo.MEDIA_COLLECTION_ID);
+ final long latestGeneration =
+ latestMediaCollectionInfo.getLong(MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION);
- final String cachedVersion = cachedMediaInfo.getString(MediaInfo.MEDIA_VERSION);
- final long cachedGeneration = cachedMediaInfo.getLong(MediaInfo.MEDIA_GENERATION);
- final long cachedCount = cachedMediaInfo.getLong(MediaInfo.MEDIA_COUNT);
+ final String cachedCollectionId =
+ cachedMediaCollectionInfo.getString(MediaCollectionInfo.MEDIA_COLLECTION_ID);
+ final long cachedGeneration = cachedMediaCollectionInfo.getLong(
+ MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION);
- Log.d(TAG, "Fetching SyncRequestParams. Authority: " + authority + ". LatestMediaInfo: "
- + latestMediaInfo + ". CachedMediaInfo: " + cachedMediaInfo);
+ Log.d(TAG, "Fetching SyncRequestParams. Authority: " + authority
+ + ". LatestMediaCollectionInfo: " + latestMediaCollectionInfo
+ + ". CachedMediaCollectionInfo: " + cachedMediaCollectionInfo);
- if (TextUtils.isEmpty(latestVersion) || latestGeneration < 0 || latestCount < 0) {
- // If results from |latestMediaInfo| are unexpected, we reset the cloud provider
+ if (TextUtils.isEmpty(latestCollectionId) || latestGeneration < 0) {
+ // If results from |latestMediaCollectionInfo| are unexpected, we reset the
+ // cloud provider
Log.w(TAG, "SyncRequestParams. Authority: " + authority
- + ". Result: SYNC_TYPE_RESET. Unexpected results: " + latestMediaInfo);
+ + ". Result: SYNC_TYPE_RESET. Unexpected result: " + latestMediaCollectionInfo);
return SyncRequestParams.forReset();
}
- if (!Objects.equals(latestVersion, cachedVersion)) {
+ if (!Objects.equals(latestCollectionId, cachedCollectionId)) {
Log.d(TAG, "SyncRequestParams. Authority: " + authority + ". Result: SYNC_TYPE_FULL");
- return SyncRequestParams.forFull(latestMediaInfo);
+ return SyncRequestParams.forFull(latestMediaCollectionInfo);
}
- if (cachedGeneration == latestGeneration && cachedCount == latestCount) {
+ if (cachedGeneration == latestGeneration) {
Log.d(TAG, "SyncRequestParams. Authority: " + authority + ". Result: SYNC_TYPE_NONE");
return SyncRequestParams.forNone();
}
Log.d(TAG, "SyncRequestParams. Authority: " + authority
+ ". Result: SYNC_TYPE_INCREMENTAL");
- return SyncRequestParams.forIncremental(cachedGeneration, latestMediaInfo);
+ return SyncRequestParams.forIncremental(cachedGeneration, latestMediaCollectionInfo);
}
private String getPrefsKey(String authority, String key) {
@@ -572,17 +576,17 @@
// Only valid for SYNC_TYPE_INCREMENTAL
private final long syncGeneration;
// Only valid for SYNC_TYPE_[INCREMENTAL|FULL]
- private final Bundle latestMediaInfo;
+ private final Bundle latestMediaCollectionInfo;
private SyncRequestParams(@SyncType int syncType) {
- this(syncType, /* syncGeneration */ 0, /* latestMediaInfo */ null);
+ this(syncType, /* syncGeneration */ 0, /* latestMediaCollectionInfo */ null);
}
private SyncRequestParams(@SyncType int syncType, long syncGeneration,
- Bundle latestMediaInfo) {
+ Bundle latestMediaCollectionInfo) {
this.syncType = syncType;
this.syncGeneration = syncGeneration;
- this.latestMediaInfo = latestMediaInfo;
+ this.latestMediaCollectionInfo = latestMediaCollectionInfo;
}
static SyncRequestParams forNone() {
@@ -593,12 +597,14 @@
return SYNC_REQUEST_RESET;
}
- static SyncRequestParams forFull(Bundle latestMediaInfo) {
- return new SyncRequestParams(SYNC_TYPE_FULL, /* generation */ 0, latestMediaInfo);
+ static SyncRequestParams forFull(Bundle latestMediaCollectionInfo) {
+ return new SyncRequestParams(SYNC_TYPE_FULL, /* generation */ 0,
+ latestMediaCollectionInfo);
}
- static SyncRequestParams forIncremental(long generation, Bundle latestMediaInfo) {
- return new SyncRequestParams(SYNC_TYPE_INCREMENTAL, generation, latestMediaInfo);
+ static SyncRequestParams forIncremental(long generation, Bundle latestMediaCollectionInfo) {
+ return new SyncRequestParams(SYNC_TYPE_INCREMENTAL, generation,
+ latestMediaCollectionInfo);
}
}
}
diff --git a/src/com/android/providers/media/photopicker/data/CloudProviderQueryExtras.java b/src/com/android/providers/media/photopicker/data/CloudProviderQueryExtras.java
index c2ce8a2..6ad121e 100644
--- a/src/com/android/providers/media/photopicker/data/CloudProviderQueryExtras.java
+++ b/src/com/android/providers/media/photopicker/data/CloudProviderQueryExtras.java
@@ -98,7 +98,7 @@
final long sizeBytes = bundle.getLong(CloudMediaProviderContract.EXTRA_FILTER_SIZE_BYTES,
LONG_DEFAULT);
- final long generation = bundle.getLong(CloudMediaProviderContract.EXTRA_GENERATION,
+ final long generation = bundle.getLong(CloudMediaProviderContract.EXTRA_SYNC_GENERATION,
LONG_DEFAULT);
final int limit = LIMIT_DEFAULT;
diff --git a/src/com/android/providers/media/photopicker/data/ExternalDbFacade.java b/src/com/android/providers/media/photopicker/data/ExternalDbFacade.java
index 42dbbea..d985f01 100644
--- a/src/com/android/providers/media/photopicker/data/ExternalDbFacade.java
+++ b/src/com/android/providers/media/photopicker/data/ExternalDbFacade.java
@@ -16,6 +16,7 @@
package com.android.providers.media.photopicker.data;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import static com.android.providers.media.photopicker.util.CursorUtils.getCursorLong;
import static com.android.providers.media.photopicker.util.CursorUtils.getCursorString;
import static com.android.providers.media.util.DatabaseUtils.replaceMatchAnyChar;
@@ -66,7 +67,7 @@
"COALESCE(" + MediaColumns.DATE_TAKEN + "," + MediaColumns.DATE_MODIFIED +
"* 1000) AS " + CloudMediaProviderContract.MediaColumns.DATE_TAKEN_MILLIS,
MediaColumns.GENERATION_MODIFIED + " AS " +
- CloudMediaProviderContract.MediaColumns.GENERATION_MODIFIED,
+ CloudMediaProviderContract.MediaColumns.SYNC_GENERATION,
MediaColumns.SIZE + " AS " + CloudMediaProviderContract.MediaColumns.SIZE_BYTES,
MediaColumns.MIME_TYPE + " AS " + CloudMediaProviderContract.MediaColumns.MIME_TYPE,
FileColumns._SPECIAL_FORMAT + " AS " +
@@ -75,14 +76,8 @@
MediaColumns.IS_FAVORITE + " AS " + CloudMediaProviderContract.MediaColumns.IS_FAVORITE
};
private static final String[] PROJECTION_MEDIA_INFO = new String[] {
- "COUNT(" + MediaColumns.GENERATION_MODIFIED + ") AS "
- + CloudMediaProviderContract.MediaInfo.MEDIA_COUNT,
"MAX(" + MediaColumns.GENERATION_MODIFIED + ") AS "
- + CloudMediaProviderContract.MediaInfo.MEDIA_GENERATION
- };
- private static final String[] PROJECTION_DELETED_MEDIA_INFO = new String[] {
- "MAX(" + MediaColumns.GENERATION_MODIFIED + ") AS "
- + CloudMediaProviderContract.MediaInfo.MEDIA_GENERATION
+ + MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION
};
private static final String[] PROJECTION_ALBUM_DB = new String[] {
"COUNT(" + MediaColumns._ID + ") AS " + CloudMediaProviderContract.AlbumColumns.MEDIA_COUNT,
@@ -292,11 +287,10 @@
* Returns the total count and max {@link MediaColumns#GENERATION_MODIFIED} value
* of the media items in the files table greater than {@code generation}.
*/
- public Cursor getMediaInfo(long generation) {
+ public Cursor getMediaCollectionInfo(long generation) {
final String[] selectionArgs = new String[] {String.valueOf(generation)};
final String[] projection = new String[] {
- CloudMediaProviderContract.MediaInfo.MEDIA_COUNT,
- CloudMediaProviderContract.MediaInfo.MEDIA_GENERATION
+ MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION
};
return mDatabaseHelper.runWithTransaction(db -> {
@@ -307,19 +301,15 @@
try (Cursor mediaCursor = query(qbMedia, db, PROJECTION_MEDIA_INFO, selectionArgs);
Cursor deletedMediaCursor = query(qbDeletedMedia, db,
- PROJECTION_DELETED_MEDIA_INFO, selectionArgs)) {
- final int mediaCountIndex = mediaCursor.getColumnIndexOrThrow(
- CloudMediaProviderContract.MediaInfo.MEDIA_COUNT);
+ PROJECTION_MEDIA_INFO, selectionArgs)) {
final int mediaGenerationIndex = mediaCursor.getColumnIndexOrThrow(
- CloudMediaProviderContract.MediaInfo.MEDIA_GENERATION);
+ MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION);
final int deletedMediaGenerationIndex =
deletedMediaCursor.getColumnIndexOrThrow(
- CloudMediaProviderContract.MediaInfo.MEDIA_GENERATION);
+ MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION);
- long mediaCount = 0;
long mediaGeneration = 0;
if (mediaCursor.moveToFirst()) {
- mediaCount = mediaCursor.getLong(mediaCountIndex);
mediaGeneration = mediaCursor.getLong(mediaGenerationIndex);
}
@@ -331,7 +321,7 @@
long maxGeneration = Math.max(mediaGeneration, deletedMediaGeneration);
MatrixCursor result = new MatrixCursor(projection);
- result.addRow(new Long[] { mediaCount, maxGeneration });
+ result.addRow(new Long[] { maxGeneration });
return result;
}
diff --git a/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java b/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java
index 946df63..b7f72dc 100644
--- a/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java
+++ b/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java
@@ -37,7 +37,7 @@
@VisibleForTesting
static final String PICKER_DATABASE_NAME = "picker.db";
- private static final int VERSION_T = 4;
+ private static final int VERSION_T = 5;
private static final int VERSION_LATEST = VERSION_T;
final Context mContext;
@@ -116,7 +116,7 @@
+ "cloud_id TEXT UNIQUE,"
+ "is_visible INTEGER CHECK(is_visible == 1),"
+ "date_taken_ms INTEGER NOT NULL CHECK(date_taken_ms >= 0),"
- + "generation_modified INTEGER NOT NULL CHECK(generation_modified >= 0),"
+ + "sync_generation INTEGER NOT NULL CHECK(sync_generation >= 0),"
+ "size_bytes INTEGER NOT NULL CHECK(size_bytes > 0),"
+ "duration_ms INTEGER CHECK(duration_ms >= 0),"
+ "mime_type TEXT NOT NULL,"
diff --git a/src/com/android/providers/media/photopicker/data/PickerDbFacade.java b/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
index 3f9b243..205af85 100644
--- a/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
+++ b/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
@@ -54,6 +54,10 @@
* MediaProvider for the Photo Picker.
*/
public class PickerDbFacade {
+ public static final String PROP_ENABLED = "sys.photopicker.pickerdb.enabled";
+ public static final String PROP_DEFAULT_SYNC_DELAY_MS =
+ "persist.sys.photopicker.pickerdb.default_sync_delay_ms";
+
private final Object mLock = new Object();
private final Context mContext;
private final SQLiteDatabase mDatabase;
@@ -83,8 +87,10 @@
private static final int FAIL = -1;
private static final String TABLE_MEDIA = "media";
- private static final String PICKER_PATH = buildPrimaryVolumeFile(MediaStore.MY_USER_ID,
- getPickerRelativePath()).getAbsolutePath();
+ // Intentionally use /sdcard path so that the receiving app resolves it to it's per-user
+ // external storage path, e.g. /storage/emulated/<userid>. That way FUSE cross-user access is
+ // not required for picker paths sent across users
+ private static final String PICKER_PATH = "/sdcard/" + getPickerRelativePath();
@VisibleForTesting
public static final String KEY_ID = "_id";
@@ -97,7 +103,7 @@
@VisibleForTesting
public static final String KEY_DATE_TAKEN_MS = "date_taken_ms";
@VisibleForTesting
- public static final String KEY_GENERATION_MODIFIED = "generation_modified";
+ public static final String KEY_SYNC_GENERATION = "sync_generation";
@VisibleForTesting
public static final String KEY_SIZE_BYTES = "size_bytes";
@VisibleForTesting
@@ -679,7 +685,11 @@
}
public static boolean isPickerDbEnabled() {
- return SystemProperties.getBoolean("sys.photopicker.pickerdb.enabled", true);
+ return SystemProperties.getBoolean(PROP_ENABLED, true);
+ }
+
+ public static int getDefaultPickerDbSyncDelayMs() {
+ return SystemProperties.getInt(PROP_DEFAULT_SYNC_DELAY_MS, 1000);
}
private boolean isLocal(String authority) {
@@ -712,7 +722,7 @@
getProjectionDataLocked(MediaColumns.DATA),
getProjectionId(MediaColumns.ID),
getProjectionSimple(KEY_DATE_TAKEN_MS, MediaColumns.DATE_TAKEN_MILLIS),
- getProjectionSimple(KEY_GENERATION_MODIFIED, MediaColumns.GENERATION_MODIFIED),
+ getProjectionSimple(KEY_SYNC_GENERATION, MediaColumns.SYNC_GENERATION),
getProjectionSimple(KEY_SIZE_BYTES, MediaColumns.SIZE_BYTES),
getProjectionSimple(KEY_DURATION_MS, MediaColumns.DURATION_MILLIS),
getProjectionSimple(KEY_MIME_TYPE, MediaColumns.MIME_TYPE),
@@ -770,15 +780,15 @@
private String getProjectionDataLocked(String asColumn) {
// _data format:
- // /storage/emulated/<user-id>/.transforms/synthetic/<authority>/media/<display-name>
+ // /sdcard/.transforms/synthetic/picker/<user-id>/<authority>/media/<display-name>
// See PickerUriResolver#getMediaUri
final String authority = String.format("CASE WHEN %s IS NULL THEN '%s' ELSE '%s' END",
KEY_CLOUD_ID, mLocalProvider, mCloudProvider);
final String fullPath = "'" + PICKER_PATH + "/'"
+ + "||" + "'" + MediaStore.MY_USER_ID + "/'"
+ "||" + authority
+ "||" + "'/" + CloudMediaProviderContract.URI_PATH_MEDIA + "/'"
+ "||" + getDisplayNameSql();
-
return String.format("%s AS %s", fullPath, asColumn);
}
@@ -833,8 +843,8 @@
case CloudMediaProviderContract.MediaColumns.DATE_TAKEN_MILLIS:
values.put(KEY_DATE_TAKEN_MS, cursor.getLong(index));
break;
- case CloudMediaProviderContract.MediaColumns.GENERATION_MODIFIED:
- values.put(KEY_GENERATION_MODIFIED, cursor.getLong(index));
+ case CloudMediaProviderContract.MediaColumns.SYNC_GENERATION:
+ values.put(KEY_SYNC_GENERATION, cursor.getLong(index));
break;
case CloudMediaProviderContract.MediaColumns.SIZE_BYTES:
values.put(KEY_SIZE_BYTES, cursor.getLong(index));
diff --git a/src/com/android/providers/media/photopicker/data/model/Item.java b/src/com/android/providers/media/photopicker/data/model/Item.java
index 8d03c38..def58e2 100644
--- a/src/com/android/providers/media/photopicker/data/model/Item.java
+++ b/src/com/android/providers/media/photopicker/data/model/Item.java
@@ -48,7 +48,7 @@
// TODO(b/195009139): Remove after fully switching to picker db
public static String DATE_MODIFIED = MediaStore.MediaColumns.DATE_MODIFIED;
public static String GENERATION_MODIFIED =
- CloudMediaProviderContract.MediaColumns.GENERATION_MODIFIED;
+ CloudMediaProviderContract.MediaColumns.SYNC_GENERATION;
public static String DURATION = CloudMediaProviderContract.MediaColumns.DURATION_MILLIS;
public static String SIZE = CloudMediaProviderContract.MediaColumns.SIZE_BYTES;
public static String AUTHORITY = CloudMediaProviderContract.MediaColumns.AUTHORITY;
diff --git a/src/com/android/providers/media/util/SyntheticPathUtils.java b/src/com/android/providers/media/util/SyntheticPathUtils.java
index 0b7cb94..aa0db93 100644
--- a/src/com/android/providers/media/util/SyntheticPathUtils.java
+++ b/src/com/android/providers/media/util/SyntheticPathUtils.java
@@ -81,8 +81,8 @@
public static List<String> extractSyntheticRelativePathSegements(String path, int userId) {
final List<String> segments = new ArrayList<>();
- final String syntheticDir = buildPrimaryVolumeFile(userId, getSyntheticRelativePath())
- .getAbsolutePath();
+ final String syntheticDir = buildPrimaryVolumeFile(userId,
+ getSyntheticRelativePath()).getAbsolutePath();
if (path.toLowerCase(Locale.ROOT).indexOf(syntheticDir.toLowerCase(Locale.ROOT)) < 0) {
return segments;
diff --git a/tests/src/com/android/providers/media/PickerProviderMediaGenerator.java b/tests/src/com/android/providers/media/PickerProviderMediaGenerator.java
index 67cc992..3591c45 100644
--- a/tests/src/com/android/providers/media/PickerProviderMediaGenerator.java
+++ b/tests/src/com/android/providers/media/PickerProviderMediaGenerator.java
@@ -16,8 +16,8 @@
package com.android.providers.media;
-import static android.provider.CloudMediaProviderContract.AccountInfo;
import static android.provider.CloudMediaProviderContract.AlbumColumns;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import static android.provider.CloudMediaProviderContract.MediaColumns;
import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.LONG_DEFAULT;
import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.STRING_DEFAULT;
@@ -47,7 +47,7 @@
MediaColumns.MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION,
MediaColumns.DATE_TAKEN_MILLIS,
- MediaColumns.GENERATION_MODIFIED,
+ MediaColumns.SYNC_GENERATION,
MediaColumns.SIZE_BYTES,
MediaColumns.DURATION_MILLIS,
MediaColumns.IS_FAVORITE,
@@ -75,8 +75,8 @@
private final List<TestMedia> mMedia = new ArrayList<>();
private final List<TestMedia> mDeletedMedia = new ArrayList<>();
private final List<TestAlbum> mAlbums = new ArrayList<>();
- private String mVersion;
- private long mGeneration;
+ private String mCollectionId;
+ private long mLastSyncGeneration;
private String mAccountName;
private Intent mAccountConfigurationIntent;
@@ -97,10 +97,12 @@
/* isDeleted */ true);
}
- public Bundle getAccountInfo() {
+ public Bundle getMediaCollectionInfo() {
Bundle bundle = new Bundle();
- bundle.putString(AccountInfo.ACTIVE_ACCOUNT_NAME, mAccountName);
- bundle.putParcelable(AccountInfo.ACCOUNT_CONFIGURATION_INTENT,
+ bundle.putString(MediaCollectionInfo.MEDIA_COLLECTION_ID, mCollectionId);
+ bundle.putLong(MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION, mLastSyncGeneration);
+ bundle.putString(MediaCollectionInfo.ACCOUNT_NAME, mAccountName);
+ bundle.putParcelable(MediaCollectionInfo.ACCOUNT_CONFIGURATION_INTENT,
mAccountConfigurationIntent);
return bundle;
@@ -140,16 +142,8 @@
mAlbums.clear();
}
- public void setVersion(String version) {
- mVersion = version;
- }
-
- public String getVersion() {
- return mVersion;
- }
-
- public long getGeneration() {
- return mGeneration;
+ public void setMediaCollectionId(String id) {
+ mCollectionId = id;
}
public long getCount() {
@@ -162,7 +156,7 @@
private TestMedia createTestMedia(String localId, String cloudId) {
// Increase generation
- return new TestMedia(localId, cloudId, ++mGeneration);
+ return new TestMedia(localId, cloudId, ++mLastSyncGeneration);
}
private TestMedia createTestMedia(String localId, String cloudId, String albumId,
@@ -170,7 +164,7 @@
boolean isFavorite) {
// Increase generation
return new TestMedia(localId, cloudId, albumId, mimeType, standardMimeTypeExtension,
- sizeBytes, /* durationMs */ 0, ++mGeneration, isFavorite);
+ sizeBytes, /* durationMs */ 0, ++mLastSyncGeneration, isFavorite);
}
private static TestMedia createPlaceholderMedia(String localId, String cloudId) {
diff --git a/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoIntentFilter.java b/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoIntentFilter.java
index 8c0989c..f440b1e 100644
--- a/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoIntentFilter.java
+++ b/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoIntentFilter.java
@@ -63,7 +63,7 @@
}
@Override
- public Bundle onGetMediaInfo(Bundle extras) {
- throw new UnsupportedOperationException("onGetMediaInfo not supported");
+ public Bundle onGetMediaCollectionInfo(Bundle extras) {
+ throw new UnsupportedOperationException("onGetMediaCollectionInfo not supported");
}
}
diff --git a/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoPermission.java b/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoPermission.java
index 4bc2c40..97b4aec 100644
--- a/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoPermission.java
+++ b/tests/src/com/android/providers/media/cloudproviders/CloudProviderNoPermission.java
@@ -63,7 +63,7 @@
}
@Override
- public Bundle onGetMediaInfo(Bundle extras) {
- throw new UnsupportedOperationException("onGetMediaInfo not supported");
+ public Bundle onGetMediaCollectionInfo(Bundle extras) {
+ throw new UnsupportedOperationException("onGetMediaCollectionInfo not supported");
}
}
diff --git a/tests/src/com/android/providers/media/cloudproviders/CloudProviderPrimary.java b/tests/src/com/android/providers/media/cloudproviders/CloudProviderPrimary.java
index 9306c56..eca46ab 100644
--- a/tests/src/com/android/providers/media/cloudproviders/CloudProviderPrimary.java
+++ b/tests/src/com/android/providers/media/cloudproviders/CloudProviderPrimary.java
@@ -16,7 +16,7 @@
package com.android.providers.media.cloudproviders;
-import static android.provider.CloudMediaProviderContract.MediaInfo;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import static com.android.providers.media.PickerProviderMediaGenerator.MediaGenerator;
import android.content.res.AssetFileDescriptor;
@@ -92,17 +92,7 @@
}
@Override
- public Bundle onGetMediaInfo(Bundle extras) {
- Bundle bundle = new Bundle();
- bundle.putString(MediaInfo.MEDIA_VERSION, mMediaGenerator.getVersion());
- bundle.putLong(MediaInfo.MEDIA_GENERATION, mMediaGenerator.getGeneration());
- bundle.putLong(MediaInfo.MEDIA_COUNT, mMediaGenerator.getCount());
-
- return bundle;
- }
-
- @Override
- public Bundle onGetAccountInfo(Bundle extras) {
- return mMediaGenerator.getAccountInfo();
+ public Bundle onGetMediaCollectionInfo(Bundle extras) {
+ return mMediaGenerator.getMediaCollectionInfo();
}
}
diff --git a/tests/src/com/android/providers/media/cloudproviders/CloudProviderSecondary.java b/tests/src/com/android/providers/media/cloudproviders/CloudProviderSecondary.java
index b975f96..2aafb0a 100644
--- a/tests/src/com/android/providers/media/cloudproviders/CloudProviderSecondary.java
+++ b/tests/src/com/android/providers/media/cloudproviders/CloudProviderSecondary.java
@@ -16,7 +16,7 @@
package com.android.providers.media.cloudproviders;
-import static android.provider.CloudMediaProviderContract.MediaInfo;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import static com.android.providers.media.PickerProviderMediaGenerator.MediaGenerator;
import android.content.res.AssetFileDescriptor;
@@ -92,12 +92,7 @@
}
@Override
- public Bundle onGetMediaInfo(Bundle extras) {
- Bundle bundle = new Bundle();
- bundle.putString(MediaInfo.MEDIA_VERSION, mMediaGenerator.getVersion());
- bundle.putLong(MediaInfo.MEDIA_GENERATION, mMediaGenerator.getGeneration());
- bundle.putLong(MediaInfo.MEDIA_COUNT, mMediaGenerator.getCount());
-
- return bundle;
+ public Bundle onGetMediaCollectionInfo(Bundle extras) {
+ return mMediaGenerator.getMediaCollectionInfo();
}
}
diff --git a/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java b/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java
index 49dfaf6..a9eb6bf 100644
--- a/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java
+++ b/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java
@@ -18,6 +18,7 @@
import static android.provider.MediaStore.VOLUME_EXTERNAL;
+import static com.android.providers.media.photopicker.data.PickerDbFacade.PROP_DEFAULT_SYNC_DELAY_MS;
import static com.android.providers.media.util.MimeUtils.isImageMimeType;
import static com.android.providers.media.util.MimeUtils.isVideoMimeType;
@@ -25,6 +26,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
import android.Manifest;
+import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -70,12 +72,18 @@
@Before
public void setUp() {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
+ final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+
+ uiAutomation.adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.INTERACT_ACROSS_USERS);
+ // Remove sync delay to avoid flaky tests
+ final String setSyncDelayCommand = "setprop " + PROP_DEFAULT_SYNC_DELAY_MS + " 0";
+ uiAutomation.executeShellCommand(setSyncDelayCommand);
+
final Context context = InstrumentationRegistry.getTargetContext();
final Context isolatedContext
= new IsolatedContext(context, "databases", /*asFuseThread*/ false);
diff --git a/tests/src/com/android/providers/media/photopicker/LocalProvider.java b/tests/src/com/android/providers/media/photopicker/LocalProvider.java
index e6fb3a1..40eb092 100644
--- a/tests/src/com/android/providers/media/photopicker/LocalProvider.java
+++ b/tests/src/com/android/providers/media/photopicker/LocalProvider.java
@@ -16,7 +16,7 @@
package com.android.providers.media.photopicker;
-import static android.provider.CloudMediaProviderContract.MediaInfo;
+import static android.provider.CloudMediaProviderContract.MediaCollectionInfo;
import static com.android.providers.media.PickerProviderMediaGenerator.MediaGenerator;
import android.content.res.AssetFileDescriptor;
@@ -91,12 +91,7 @@
}
@Override
- public Bundle onGetMediaInfo(Bundle extras) {
- Bundle bundle = new Bundle();
- bundle.putString(MediaInfo.MEDIA_VERSION, mMediaGenerator.getVersion());
- bundle.putLong(MediaInfo.MEDIA_GENERATION, mMediaGenerator.getGeneration());
- bundle.putLong(MediaInfo.MEDIA_COUNT, mMediaGenerator.getCount());
-
- return bundle;
+ public Bundle onGetMediaCollectionInfo(Bundle extras) {
+ return mMediaGenerator.getMediaCollectionInfo();
}
}
diff --git a/tests/src/com/android/providers/media/photopicker/PickerDataLayerTest.java b/tests/src/com/android/providers/media/photopicker/PickerDataLayerTest.java
index 9b9fff1..72a94db 100644
--- a/tests/src/com/android/providers/media/photopicker/PickerDataLayerTest.java
+++ b/tests/src/com/android/providers/media/photopicker/PickerDataLayerTest.java
@@ -93,8 +93,8 @@
private static final Pair<String, String> CLOUD_AND_LOCAL_1
= Pair.create(LOCAL_ID_1, CLOUD_ID_1);
- private static final String VERSION_1 = "1";
- private static final String VERSION_2 = "2";
+ private static final String COLLECTION_1 = "1";
+ private static final String COLLECTION_2 = "2";
private static final String IMAGE_MIME_TYPE = "image/jpeg";
private static final String VIDEO_MIME_TYPE = "video/mp4";
@@ -112,9 +112,9 @@
mCloudPrimaryMediaGenerator.resetAll();
mCloudSecondaryMediaGenerator.resetAll();
- mLocalMediaGenerator.setVersion(VERSION_1);
- mCloudPrimaryMediaGenerator.setVersion(VERSION_1);
- mCloudSecondaryMediaGenerator.setVersion(VERSION_1);
+ mLocalMediaGenerator.setMediaCollectionId(COLLECTION_1);
+ mCloudPrimaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
+ mCloudSecondaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
mContext = InstrumentationRegistry.getTargetContext();
diff --git a/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java b/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java
index 603f568..f30d8de 100644
--- a/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java
+++ b/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java
@@ -88,8 +88,8 @@
private static final Pair<String, String> CLOUD_AND_LOCAL_1
= Pair.create(LOCAL_ID_1, CLOUD_ID_1);
- private static final String VERSION_1 = "1";
- private static final String VERSION_2 = "2";
+ private static final String COLLECTION_1 = "1";
+ private static final String COLLECTION_2 = "2";
private static final String IMAGE_MIME_TYPE = "image/jpeg";
private static final String VIDEO_MIME_TYPE = "video/mp4";
@@ -112,9 +112,9 @@
mCloudPrimaryMediaGenerator.resetAll();
mCloudSecondaryMediaGenerator.resetAll();
- mLocalMediaGenerator.setVersion(VERSION_1);
- mCloudPrimaryMediaGenerator.setVersion(VERSION_1);
- mCloudSecondaryMediaGenerator.setVersion(VERSION_1);
+ mLocalMediaGenerator.setMediaCollectionId(COLLECTION_1);
+ mCloudPrimaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
+ mCloudSecondaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
mContext = InstrumentationRegistry.getTargetContext();
@@ -173,7 +173,7 @@
}
// 5. Bump version
- mLocalMediaGenerator.setVersion(VERSION_2);
+ mLocalMediaGenerator.setMediaCollectionId(COLLECTION_2);
mController.syncAllMedia();
assertEmptyCursor();
@@ -244,12 +244,12 @@
}
// 3. Set invalid cloud version
- mCloudPrimaryMediaGenerator.setVersion(/* version */ null);
+ mCloudPrimaryMediaGenerator.setMediaCollectionId(/* version */ null);
mController.syncAllMedia();
assertEmptyCursor();
// 4. Set valid cloud version
- mCloudPrimaryMediaGenerator.setVersion(VERSION_1);
+ mCloudPrimaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
mController.syncAllMedia();
try (Cursor cr = queryMedia()) {
diff --git a/tests/src/com/android/providers/media/photopicker/data/ExternalDbFacadeTest.java b/tests/src/com/android/providers/media/photopicker/data/ExternalDbFacadeTest.java
index e0c4e8a..d24dcab 100644
--- a/tests/src/com/android/providers/media/photopicker/data/ExternalDbFacadeTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/ExternalDbFacadeTest.java
@@ -690,7 +690,7 @@
}
@Test
- public void testGetMediaInfoFiltering() throws Exception {
+ public void testGetMediaCollectionInfoFiltering() throws Exception {
try (DatabaseHelper helper = new TestDatabaseHelper(sIsolatedContext)) {
ExternalDbFacade facade = new ExternalDbFacade(sIsolatedContext, helper);
@@ -701,31 +701,31 @@
cv.put(MediaColumns.GENERATION_MODIFIED, GENERATION_MODIFIED2);
helper.runWithTransaction(db -> db.insert(TABLE_FILES, null, cv));
- try (Cursor cursor = facade.getMediaInfo(/* generation */ 0)) {
+ try (Cursor cursor = facade.getMediaCollectionInfo(/* generation */ 0)) {
assertThat(cursor.getCount()).isEqualTo(1);
cursor.moveToFirst();
- assertMediaInfo(facade, cursor, /* count */ 2, /* generation */ 2);
+ assertMediaCollectionInfo(facade, cursor, /* count */ 2, /* generation */ 2);
}
- try (Cursor cursor = facade.getMediaInfo(GENERATION_MODIFIED1)) {
+ try (Cursor cursor = facade.getMediaCollectionInfo(GENERATION_MODIFIED1)) {
assertThat(cursor.getCount()).isEqualTo(1);
cursor.moveToFirst();
- assertMediaInfo(facade, cursor, /* count */ 1, GENERATION_MODIFIED2);
+ assertMediaCollectionInfo(facade, cursor, /* count */ 1, GENERATION_MODIFIED2);
}
- try (Cursor cursor = facade.getMediaInfo(GENERATION_MODIFIED2)) {
+ try (Cursor cursor = facade.getMediaCollectionInfo(GENERATION_MODIFIED2)) {
assertThat(cursor.getCount()).isEqualTo(1);
cursor.moveToFirst();
- assertMediaInfo(facade, cursor, /* count */ 0, /* generation */ 0);
+ assertMediaCollectionInfo(facade, cursor, /* count */ 0, /* generation */ 0);
}
}
}
@Test
- public void testGetMediaInfoWithDeleted() throws Exception {
+ public void testGetMediaCollectionInfoWithDeleted() throws Exception {
try (DatabaseHelper helper = new TestDatabaseHelper(sIsolatedContext)) {
ExternalDbFacade facade = new ExternalDbFacade(sIsolatedContext, helper);
@@ -737,11 +737,11 @@
cvDeleted.put(MediaColumns.GENERATION_MODIFIED, GENERATION_MODIFIED2);
helper.runWithTransaction(db -> db.insert(TABLE_DELETED_MEDIA, null, cvDeleted));
- try (Cursor cursor = facade.getMediaInfo(/* generation */ 0)) {
+ try (Cursor cursor = facade.getMediaCollectionInfo(/* generation */ 0)) {
assertThat(cursor.getCount()).isEqualTo(1);
cursor.moveToFirst();
- assertMediaInfo(facade, cursor, /* count */ 1, /* generation */ 2);
+ assertMediaCollectionInfo(facade, cursor, /* count */ 1, /* generation */ 2);
}
}
}
@@ -948,13 +948,11 @@
assertThat(cursor.getLong(countIndex)).isEqualTo(count);
}
- private static void assertMediaInfo(ExternalDbFacade facade, Cursor cursor,
+ private static void assertMediaCollectionInfo(ExternalDbFacade facade, Cursor cursor,
long count, long generation) {
- int countIndex = cursor.getColumnIndex(CloudMediaProviderContract.MediaInfo.MEDIA_COUNT);
int generationIndex = cursor.getColumnIndex(
- CloudMediaProviderContract.MediaInfo.MEDIA_GENERATION);
+ CloudMediaProviderContract.MediaCollectionInfo.LAST_MEDIA_SYNC_GENERATION);
- assertThat(cursor.getLong(countIndex)).isEqualTo(count);
assertThat(cursor.getLong(generationIndex)).isEqualTo(generation);
}
diff --git a/tests/src/com/android/providers/media/photopicker/data/PickerDatabaseHelperTest.java b/tests/src/com/android/providers/media/photopicker/data/PickerDatabaseHelperTest.java
index 554de5b..28d1bab 100644
--- a/tests/src/com/android/providers/media/photopicker/data/PickerDatabaseHelperTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/PickerDatabaseHelperTest.java
@@ -45,7 +45,7 @@
private static final String KEY_CLOUD_ID = "cloud_id";
private static final String KEY_IS_VISIBLE = "is_visible";
private static final String KEY_DATE_TAKEN_MS = "date_taken_ms";
- private static final String KEY_GENERATION_MODIFIED = "generation_modified";
+ private static final String KEY_SYNC_GENERATION = "sync_generation";
private static final String KEY_SIZE_BYTES = "size_bytes";
private static final String KEY_DURATION_MS = "duration_ms";
private static final String KEY_MIME_TYPE = "mime_type";
@@ -76,7 +76,7 @@
KEY_CLOUD_ID,
KEY_IS_VISIBLE,
KEY_DATE_TAKEN_MS,
- KEY_GENERATION_MODIFIED,
+ KEY_SYNC_GENERATION,
KEY_SIZE_BYTES,
KEY_DURATION_MS,
KEY_MIME_TYPE,
@@ -282,13 +282,13 @@
// generation_modified=NULL
ContentValues values = getBasicContentValues();
- values.remove(KEY_GENERATION_MODIFIED);
+ values.remove(KEY_SYNC_GENERATION);
values.put(KEY_CLOUD_ID, CLOUD_ID);
assertThat(db.insert(MEDIA_TABLE, null, values)).isEqualTo(-1);
// generation_modified=-1
values = getBasicContentValues();
- values.put(KEY_GENERATION_MODIFIED, -1);
+ values.put(KEY_SYNC_GENERATION, -1);
values.put(KEY_CLOUD_ID, CLOUD_ID);
assertThat(db.insert(MEDIA_TABLE, null, values)).isEqualTo(-1);
}
@@ -316,7 +316,7 @@
private static ContentValues getBasicContentValues() {
ContentValues values = new ContentValues();
values.put(KEY_DATE_TAKEN_MS, DATE_TAKEN_MS);
- values.put(KEY_GENERATION_MODIFIED, GENERATION_MODIFIED);
+ values.put(KEY_SYNC_GENERATION, GENERATION_MODIFIED);
values.put(KEY_DURATION_MS, DURATION_MS);
values.put(KEY_MIME_TYPE, MIME_TYPE);
values.put(KEY_STANDARD_MIME_TYPE_EXTENSION, STANDARD_MIME_TYPE_EXTENSION);
diff --git a/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java b/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java
index 9b378a9..5173e74 100644
--- a/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java
@@ -991,7 +991,7 @@
MediaColumns.ID,
MediaColumns.MEDIA_STORE_URI,
MediaColumns.DATE_TAKEN_MILLIS,
- MediaColumns.GENERATION_MODIFIED,
+ MediaColumns.SYNC_GENERATION,
MediaColumns.SIZE_BYTES,
MediaColumns.MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION,
@@ -1043,7 +1043,7 @@
}
private static String getData(String authority, String displayName) {
- return "/storage/emulated/0/.transforms/synthetic/picker/" + authority + "/media/"
+ return "/sdcard/.transforms/synthetic/picker/0/" + authority + "/media/"
+ displayName;
}
@@ -1083,7 +1083,7 @@
.isEqualTo(STANDARD_MIME_TYPE_EXTENSION);
assertThat(cursor.getLong(cursor.getColumnIndex(MediaColumns.DATE_TAKEN_MILLIS)))
.isEqualTo(dateTakenMs);
- assertThat(cursor.getLong(cursor.getColumnIndex(MediaColumns.GENERATION_MODIFIED)))
+ assertThat(cursor.getLong(cursor.getColumnIndex(MediaColumns.SYNC_GENERATION)))
.isEqualTo(GENERATION_MODIFIED);
assertThat(cursor.getLong(cursor.getColumnIndex(MediaColumns.SIZE_BYTES)))
.isEqualTo(SIZE_BYTES);