Snap for 11164065 from b9a788afdc593c4364b7d9b0d328593bded50c5e to mainline-resolv-release

Change-Id: I0ab1d579deac82d6f256f1b75a6981c6073862aa
diff --git a/Android.bp b/Android.bp
index 785c8ee..1e9cea7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -21,6 +21,7 @@
         "modules-utils-uieventlogger-interface",
         "glide-prebuilt",
         "glide-integration-recyclerview-prebuilt",
+        "glide-integration-webpdecoder-prebuilt",
         "glide-gifdecoder-prebuilt",
         "glide-disklrucache-prebuilt",
         "glide-annotation-and-compiler-prebuilt",
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 5f4b64b..8e8eb1d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -19,6 +19,15 @@
             "name": "CtsScopedStorageDeviceOnlyTest[com.google.android.mediaprovider.apex]"
         },
         {
+            "name": "CtsScopedStorageBypassDatabaseOperationsTest[com.google.android.mediaprovider.apex]"
+        },
+        {
+            "name": "CtsScopedStorageGeneralTest[com.google.android.mediaprovider.apex]"
+        },
+        {
+            "name": "CtsScopedStorageRedactUriTest[com.google.android.mediaprovider.apex]"
+        },
+        {
             "name": "CtsMediaProviderTranscodeTests[com.google.android.mediaprovider.apex]"
         }
     ],
@@ -66,6 +75,15 @@
             "name": "CtsScopedStorageDeviceOnlyTest"
         },
         {
+            "name": "CtsScopedStorageBypassDatabaseOperationsTest"
+        },
+        {
+            "name": "CtsScopedStorageGeneralTest"
+        },
+        {
+            "name": "CtsScopedStorageRedactUriTest"
+        },
+        {
             "name": "fuse_node_test"
         }
     ],
diff --git a/apex/framework/api/current.txt b/apex/framework/api/current.txt
index 34825d1..cddfcfa 100644
--- a/apex/framework/api/current.txt
+++ b/apex/framework/api/current.txt
@@ -150,6 +150,7 @@
     field public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
     field public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
     field public static final String EXTRA_OUTPUT = "output";
+    field @FlaggedApi("com.android.providers.media.flags.pick_ordered_images") public static final String EXTRA_PICK_IMAGES_IN_ORDER = "android.provider.extra.PICK_IMAGES_IN_ORDER";
     field public static final String EXTRA_PICK_IMAGES_MAX = "android.provider.extra.PICK_IMAGES_MAX";
     field public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
     field public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
diff --git a/apex/framework/java/android/provider/CloudMediaProviderContract.java b/apex/framework/java/android/provider/CloudMediaProviderContract.java
index 4fc71c9..5e610a8 100644
--- a/apex/framework/java/android/provider/CloudMediaProviderContract.java
+++ b/apex/framework/java/android/provider/CloudMediaProviderContract.java
@@ -88,8 +88,8 @@
         public static final String DATE_TAKEN_MILLIS = "date_taken_millis";
 
         /**
-         * Number associated with a media item indicating what generation or batch the media item
-         * was synced into the media collection.
+         * Non-negative 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 sync generation number to each
          * media item which is expected to increase for each atomic modification on the media item.
diff --git a/apex/framework/java/android/provider/MediaStore.java b/apex/framework/java/android/provider/MediaStore.java
index ce76d52..b1172af 100644
--- a/apex/framework/java/android/provider/MediaStore.java
+++ b/apex/framework/java/android/provider/MediaStore.java
@@ -20,6 +20,7 @@
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.CurrentTimeSecondsLong;
 import android.annotation.DurationMillisLong;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -517,18 +518,18 @@
     public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
 
     /**
-     * The name of the Intent-extra used to control the onCompletion behavior of a MovieView.
-     * This is a boolean property that specifies whether or not to finish the MovieView activity
-     * when the movie completes playing. The default value is true, which means to automatically
-     * exit the movie player activity when the movie completes playing.
+     * The name of the Intent-extra used to control the onCompletion behavior of a MovieView. This
+     * is a boolean property that specifies whether or not to finish the MovieView activity when the
+     * movie completes playing. The default value is true, which means to automatically exit the
+     * movie player activity when the movie completes playing.
      */
-    public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
+    public static final String EXTRA_FINISH_ON_COMPLETION =
+            "android.intent.extra.finishOnCompletion";
 
-    /**
-     * The name of the Intent action used to launch a camera in still image mode.
-     */
+    /** The name of the Intent action used to launch a camera in still image mode. */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
+    public static final String INTENT_ACTION_STILL_IMAGE_CAMERA =
+            "android.media.action.STILL_IMAGE_CAMERA";
 
     /**
      * Name under which an activity handling {@link #INTENT_ACTION_STILL_IMAGE_CAMERA} or
@@ -755,42 +756,39 @@
     public final static String EXTRA_OUTPUT = "output";
 
     /**
-     * Activity Action: Allow the user to select images or videos provided by
-     * system and return it. This is different than {@link Intent#ACTION_PICK}
-     * and {@link Intent#ACTION_GET_CONTENT} in that
+     * Activity Action: Allow the user to select images or videos provided by system and return it.
+     * This is different than {@link Intent#ACTION_PICK} and {@link Intent#ACTION_GET_CONTENT} in
+     * that
+     *
      * <ul>
-     * <li> the data for this action is provided by the system
-     * <li> this action is only used for picking images and videos
-     * <li> caller gets read access to user picked items even without storage
-     * permissions
+     *   <li>the data for this action is provided by the system
+     *   <li>this action is only used for picking images and videos
+     *   <li>caller gets read access to user picked items even without storage permissions
      * </ul>
-     * <p>
-     * Callers can optionally specify MIME type (such as {@code image/*} or
-     * {@code video/*}), resulting in a range of content selection that the
-     * caller is interested in. The optional MIME type can be requested with
-     * {@link Intent#setType(String)}.
-     * <p>
-     * If the caller needs multiple returned items (or caller wants to allow
-     * multiple selection), then it can specify
-     * {@link MediaStore#EXTRA_PICK_IMAGES_MAX} to indicate this.
-     * <p>
-     * When the caller requests multiple selection, the value of
-     * {@link MediaStore#EXTRA_PICK_IMAGES_MAX} must be a positive integer
-     * greater than 1 and less than or equal to
-     * {@link MediaStore#getPickImagesMaxLimit}, otherwise
-     * {@link Activity#RESULT_CANCELED} is returned.
-     * <p>
-     * Callers may use {@link Intent#EXTRA_LOCAL_ONLY} to limit content
-     * selection to local data.
-     * <p>
-     * Output: MediaStore content URI(s) of the item(s) that was picked.
-     * Unlike other MediaStore URIs, these are referred to as 'picker' URIs and
-     * expose a limited set of read-only operations. Specifically, picker URIs
-     * can only be opened for read and queried for columns in {@link PickerMediaColumns}.
-     * <p>
-     * Before this API, apps could use {@link Intent#ACTION_GET_CONTENT}. However,
-     * {@link #ACTION_PICK_IMAGES} is now the recommended option for images and videos,
-     * since it offers a better user experience.
+     *
+     * <p>Callers can optionally specify MIME type (such as {@code image/*} or {@code video/*}),
+     * resulting in a range of content selection that the caller is interested in. The optional MIME
+     * type can be requested with {@link Intent#setType(String)}.
+     *
+     * <p>If the caller needs multiple returned items (or caller wants to allow multiple selection),
+     * then it can specify {@link MediaStore#EXTRA_PICK_IMAGES_MAX} to indicate this.
+     *
+     * <p>When the caller requests multiple selection, the value of {@link
+     * MediaStore#EXTRA_PICK_IMAGES_MAX} must be a positive integer greater than 1 and less than or
+     * equal to {@link MediaStore#getPickImagesMaxLimit}, otherwise {@link Activity#RESULT_CANCELED}
+     * is returned. Use {@link MediaStore#EXTRA_PICK_IMAGES_IN_ORDER} in multiple selection mode to
+     * allow the user to pick images in order.
+     *
+     * <p>Callers may use {@link Intent#EXTRA_LOCAL_ONLY} to limit content selection to local data.
+     *
+     * <p>Output: MediaStore content URI(s) of the item(s) that was picked. Unlike other MediaStore
+     * URIs, these are referred to as 'picker' URIs and expose a limited set of read-only
+     * operations. Specifically, picker URIs can only be opened for read and queried for columns in
+     * {@link PickerMediaColumns}.
+     *
+     * <p>Before this API, apps could use {@link Intent#ACTION_GET_CONTENT}. However, {@link
+     * #ACTION_PICK_IMAGES} is now the recommended option for images and videos, since it offers a
+     * better user experience.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PICK_IMAGES = "android.provider.action.PICK_IMAGES";
@@ -838,6 +836,20 @@
             "android.provider.action.PICK_IMAGES_SETTINGS";
 
     /**
+     * The name of an optional intent-extra used to allow ordered selection of items. Set this extra
+     * to true to allow the user to see the order of their selected items. The result returned to
+     * the caller will be the same as the user selected order. This extra is only allowed via the
+     * {@link MediaStore#ACTION_PICK_IMAGES}.
+     *
+     * <p>The value of this intent-extra should be a boolean. Default value is false.
+     *
+     * @see #ACTION_PICK_IMAGES
+     */
+    @FlaggedApi("com.android.providers.media.flags.pick_ordered_images")
+    public static final String EXTRA_PICK_IMAGES_IN_ORDER =
+            "android.provider.extra.PICK_IMAGES_IN_ORDER";
+
+    /**
      * The name of an optional intent-extra used to allow multiple selection of
      * items and constrain maximum number of items that can be returned by
      * {@link MediaStore#ACTION_PICK_IMAGES}, action may still return nothing
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 1b88251..f261ae2 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -1984,7 +1984,9 @@
         struct fuse_dirent* dirent_out = (struct fuse_dirent*)((char*)dirents_out + fro->size);
         struct stat stats;
         int err;
-        std::string child_path = path + "/" + dirent_in->name;
+
+        std::string child_name(dirent_in->name, dirent_in->namelen);
+        std::string child_path = path + "/" + child_name;
 
         in += sizeof(*dirent_in) + round_up(dirent_in->namelen, sizeof(uint64_t));
         err = stat(child_path.c_str(), &stats);
@@ -1992,9 +1994,9 @@
             ((stats.st_mode & 0001) || ((stats.st_mode & 0010) && req->ctx.gid == stats.st_gid) ||
              ((stats.st_mode & 0100) && req->ctx.uid == stats.st_uid) ||
              fuse->mp->isUidAllowedAccessToDataOrObbPath(req->ctx.uid, child_path) ||
-             strcmp(dirent_in->name, ".nomedia") == 0)) {
+             child_name == ".nomedia")) {
             *dirent_out = *dirent_in;
-            strcpy(dirent_out->name, dirent_in->name);
+            strcpy(dirent_out->name, child_name.c_str());
             fro->size += sizeof(*dirent_out) + round_up(dirent_out->namelen, sizeof(uint64_t));
         }
     }
@@ -2579,6 +2581,16 @@
     }
 }
 
+void FuseDaemon::SetupPublicVolumeLevelDbInstance(const std::string& volume_name) {
+    if (android::base::StartsWith(fuse->root->GetIoPath(), PRIMARY_VOLUME_PREFIX)) {
+        // Setup leveldb instance for both external primary and internal volume.
+        fuse->level_db_mutex.lock();
+        // Create level db instance for public volume
+        SetupLevelDbConnection(volume_name);
+        fuse->level_db_mutex.unlock();
+    }
+}
+
 std::string deriveVolumeName(const std::string& path) {
     std::string volume_name;
     if (!android::base::StartsWith(path, STORAGE_PREFIX)) {
@@ -2586,8 +2598,10 @@
     } else if (android::base::StartsWith(path, PRIMARY_VOLUME_PREFIX)) {
         volume_name = VOLUME_EXTERNAL_PRIMARY;
     } else {
-        size_t size = sizeof(STORAGE_PREFIX) / sizeof(STORAGE_PREFIX[0]);
-        volume_name = volume_name.substr(size);
+        // Return "C58E-1702" from the path like "/storage/C58E-1702/Download/1935694997673.png"
+        volume_name = path.substr(9, 9);
+        // Convert to lowercase
+        std::transform(volume_name.begin(), volume_name.end(), volume_name.begin(), ::tolower);
     }
     return volume_name;
 }
@@ -2607,8 +2621,8 @@
     }
 }
 
-void FuseDaemon::InsertInLevelDb(const std::string& key, const std::string& value) {
-    std::string volume_name = deriveVolumeName(key);
+void FuseDaemon::InsertInLevelDb(const std::string& volume_name, const std::string& key,
+                                 const std::string& value) {
     if (!CheckLevelDbConnection(volume_name)) {
         LOG(ERROR) << "InsertInLevelDb: Missing leveldb connection.";
         return;
@@ -2757,7 +2771,7 @@
 
 bool FuseDaemon::CheckLevelDbConnection(const std::string& instance_name) {
     if (fuse->level_db_connection_map.find(instance_name) == fuse->level_db_connection_map.end()) {
-        LOG(ERROR) << "Leveldb setup is missing for :" << instance_name;
+        LOG(ERROR) << "Leveldb setup is missing for: " << instance_name;
         return false;
     }
     return true;
diff --git a/jni/FuseDaemon.h b/jni/FuseDaemon.h
index a634812..a9eaf22 100644
--- a/jni/FuseDaemon.h
+++ b/jni/FuseDaemon.h
@@ -80,6 +80,11 @@
     void SetupLevelDbInstances();
 
     /**
+     * Setup leveldb instances for public volume.
+     */
+    void SetupPublicVolumeLevelDbInstance(const std::string& volume_name);
+
+    /**
      * Creates a leveldb instance and sets up a connection.
      */
     void SetupLevelDbConnection(const std::string& instance_name);
@@ -90,9 +95,10 @@
     void DeleteFromLevelDb(const std::string& key);
 
     /**
-     * Inserts in leveldb instance of volume derived from path.
+     * Inserts in leveldb instance of provided volume.
      */
-    void InsertInLevelDb(const std::string& key, const std::string& value);
+    void InsertInLevelDb(const std::string& volume_name, const std::string& key,
+                         const std::string& value);
 
     /**
      * Reads file paths for given volume from leveldb for given range.
diff --git a/jni/com_android_providers_media_FuseDaemon.cpp b/jni/com_android_providers_media_FuseDaemon.cpp
index 97a6a6e..2b78645 100644
--- a/jni/com_android_providers_media_FuseDaemon.cpp
+++ b/jni/com_android_providers_media_FuseDaemon.cpp
@@ -196,6 +196,18 @@
     daemon->SetupLevelDbInstances();
 }
 
+void com_android_providers_media_FuseDaemon_setup_public_volume_db_backup(JNIEnv* env, jobject self,
+                                                                   jlong java_daemon,
+                                                                   jstring volume_name) {
+    fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
+    ScopedUtfChars utf_chars_volumeName(env, volume_name);
+    if (!utf_chars_volumeName.c_str()) {
+        LOG(WARNING) << "Couldn't initialise FUSE device id for " << volume_name;
+        return;
+    }
+    daemon->SetupPublicVolumeLevelDbInstance(utf_chars_volumeName.c_str());
+}
+
 void com_android_providers_media_FuseDaemon_delete_db_backup(JNIEnv* env, jobject self,
                                                              jlong java_daemon, jstring java_path) {
     fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
@@ -209,15 +221,19 @@
 
 void com_android_providers_media_FuseDaemon_backup_volume_db_data(JNIEnv* env, jobject self,
                                                                   jlong java_daemon,
-                                                                  jstring java_path, jstring value) {
+                                                                  jstring volume_name,
+                                                                  jstring java_path,
+                                                                  jstring value) {
     fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
     ScopedUtfChars utf_chars_path(env, java_path);
     ScopedUtfChars utf_chars_value(env, value);
+    ScopedUtfChars utf_chars_volumeName(env, volume_name);
     if (!utf_chars_path.c_str()) {
         LOG(WARNING) << "Couldn't initialise FUSE device id";
         return;
     }
-    daemon->InsertInLevelDb(utf_chars_path.c_str(), utf_chars_value.c_str());
+    daemon->InsertInLevelDb(utf_chars_volumeName.c_str(), utf_chars_path.c_str(),
+                            utf_chars_value.c_str());
 }
 
 bool com_android_providers_media_FuseDaemon_is_fuse_thread(JNIEnv* env, jclass clazz) {
@@ -328,9 +344,11 @@
          reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_initialize_device_id)},
         {"native_setup_volume_db_backup", "(J)V",
          reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_setup_volume_db_backup)},
+         {"native_setup_public_volume_db_backup", "(JLjava/lang/String;)V",
+         reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_setup_public_volume_db_backup)},
         {"native_delete_db_backup", "(JLjava/lang/String;)V",
          reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_delete_db_backup)},
-        {"native_backup_volume_db_data", "(JLjava/lang/String;Ljava/lang/String;)V",
+        {"native_backup_volume_db_data", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
          reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_backup_volume_db_data)},
         {"native_read_backed_up_file_paths",
          "(JLjava/lang/String;Ljava/lang/String;I)[Ljava/lang/String;",
diff --git a/res/drawable/ic_artwork_camera.xml b/res/drawable/ic_artwork_camera.xml
index dc22c49..9c39e64 100644
--- a/res/drawable/ic_artwork_camera.xml
+++ b/res/drawable/ic_artwork_camera.xml
@@ -14,9 +14,11 @@
      limitations under the License.
 -->
 
+<!-- This vector draws the camera graphic that is displayed in the picker when the
+     device has no images/videos i.e. the picker is empty -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="120dp"
-    android:height="80dp"
+    android:width="100dp"
+    android:height="66.67dp"
     android:viewportWidth="120"
     android:viewportHeight="80">
   <path
diff --git a/res/drawable/picker_item_check.xml b/res/drawable/picker_item_check.xml
index fb0ef88..c73c699 100644
--- a/res/drawable/picker_item_check.xml
+++ b/res/drawable/picker_item_check.xml
@@ -1,31 +1,31 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
+    <!-- Copyright (C) 2021 The Android Open Source Project
 
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
 
-          http://www.apache.org/licenses/LICENSE-2.0
+              http://www.apache.org/licenses/LICENSE-2.0
 
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+    -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_selected="true">
-        <layer-list>
-            <item android:gravity="center"
-                  android:width="18dp"
-                  android:height="18dp">
-                <shape android:shape="oval">
-                    <solid android:color="@color/picker_background_color"/>
-                </shape>
-            </item>
-            <item android:drawable="@drawable/ic_check_circle_filled"/>
-        </layer-list>
-    </item>
-    <item android:drawable="@drawable/ic_radio_button_unchecked"/>
-</selector>
+<item android:state_selected="true">
+    <layer-list>
+        <item android:gravity="center"
+              android:width="18dp"
+              android:height="18dp">
+            <shape android:shape="oval">
+                <solid android:color="@color/picker_background_color"/>
+            </shape>
+        </item>
+        <item android:drawable="@drawable/ic_check_circle_filled"/>
+    </layer-list>
+</item>
+<item android:drawable="@drawable/ic_radio_button_unchecked"/>
+</selector>
\ No newline at end of file
diff --git a/res/drawable/picker_item_order.xml b/res/drawable/picker_item_order.xml
new file mode 100644
index 0000000..ceeae40
--- /dev/null
+++ b/res/drawable/picker_item_order.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true">
+        <layer-list>
+            <item android:gravity="center"
+                  android:width="18dp"
+                  android:height="18dp">
+                <shape android:shape="oval">
+                    <solid android:color="?attr/pickerSelectedColor"/>
+                </shape>
+            </item>
+        </layer-list>
+    </item>
+    <item android:drawable="@drawable/ic_radio_button_unchecked"/>
+</selector>
\ No newline at end of file
diff --git a/res/layout/fragment_picker_tab.xml b/res/layout/fragment_picker_tab.xml
index 90e0cc5..7dd6ea9 100644
--- a/res/layout/fragment_picker_tab.xml
+++ b/res/layout/fragment_picker_tab.xml
@@ -20,34 +20,44 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <LinearLayout
+    <!-- The nested scroll view holds the layout that is made visible when
+    the picker is empty. It has been wrapped in the scroll view to tackle
+    bugs where the "empty_text_view" gets rolled off the screen partially
+    or completely in small screen devices -->
+    <androidx.core.widget.NestedScrollView
         android:id="@android:id/empty"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="80dp"
-        android:orientation="vertical"
         android:visibility="gone">
 
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:scaleType="fitCenter"
-            android:src="@drawable/ic_artwork_camera"
-            android:contentDescription="@null"/>
-
-        <TextView
-            android:id="@+id/empty_text_view"
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/picker_empty_text_margin"
-            android:gravity="center_horizontal"
-            android:text="@string/picker_photos_empty_message"
-            android:textColor="?android:attr/textColorSecondary"
-            android:textSize="@dimen/picker_empty_text_size"
-            style="?android:attr/textAppearanceListItem"/>
+            android:orientation="vertical">
 
-    </LinearLayout>
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:scaleType="fitCenter"
+                android:src="@drawable/ic_artwork_camera"
+                android:contentDescription="@null"/>
+
+            <TextView
+                android:id="@+id/empty_text_view"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/picker_empty_text_margin"
+                android:gravity="center_horizontal"
+                android:text="@string/picker_photos_empty_message"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textSize="@dimen/picker_empty_text_size"
+                style="?android:attr/textAppearanceListItem"/>
+
+        </LinearLayout>
+
+    </androidx.core.widget.NestedScrollView>
 
     <com.android.providers.media.photopicker.ui.AutoFitRecyclerView
         android:id="@+id/picker_tab_recyclerview"
diff --git a/res/layout/item_photo_grid.xml b/res/layout/item_photo_grid.xml
index f28305c..cd19343 100644
--- a/res/layout/item_photo_grid.xml
+++ b/res/layout/item_photo_grid.xml
@@ -108,4 +108,17 @@
         android:layout_gravity="top|start"
         android:scaleType="fitCenter"/>
 
+    <TextView
+        android:id="@+id/selected_order"
+        android:layout_height="@dimen/picker_item_check_size"
+        android:layout_width="@dimen/picker_item_check_size"
+        android:layout_marginStart="@dimen/picker_item_check_margin"
+        android:layout_marginTop="@dimen/picker_item_check_margin"
+        android:background="@drawable/picker_item_order"
+        android:layout_gravity="top|start"
+        android:gravity="center"
+        android:textSize="12dp"
+        android:textColor="?attr/pickerHighlightTextColor"
+        android:scaleType="fitCenter"/>
+
 </FrameLayout>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index e9f0466..7a76c15 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Geen albums nie"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Bekyk geselekteerde"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Foto\'s"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Voorskou"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Skakel oor na werk"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index cf08f5c..2889dd6 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ምንም አልበሞች የሉም"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"የተመረጡትን አሳይ"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ፎቶዎች"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"አልበሞች"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ቅድመ-ዕይታ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ወደ የሥራ ቀይር"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 1cba3df..7d55f12 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ما مِن ألبومات"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"عرض ما تم اختياره"</string>
     <string name="picker_photos" msgid="7415035516411087392">"الصور"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"الألبومات"</string>
     <string name="picker_preview" msgid="6257414886055861039">"معاينة"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"التبديل إلى الملف الشخصي للعمل"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index ec19082..8785eba 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"কোনো এলবাম নাই"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ভিউ বাছনি কৰা হৈছে"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ফট’"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"এলবাম"</string>
     <string name="picker_preview" msgid="6257414886055861039">"পূৰ্বদৰ্শন কৰক"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"কৰ্মস্থানৰ প্ৰ’ফাইললৈ সলনি কৰক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 5fc20b0..af1f72b 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Albom yoxdur"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Seçilənə baxın"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotolar"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albomlar"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Önbaxış"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"İş profilinə keçirin"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 495ab4b..56f8648 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nema albuma"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Prikaži izabrano"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Slike"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumi"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Pregled"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Pređi na poslovni profil"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index c20866c..6421809 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Няма альбомаў"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Праглядзець выбранае"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Фота"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Альбомы"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Перадпрагляд"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Пераключыцца на працоўны"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 356cc1a..a9c7f24 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Няма албуми"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Преглед на избраното"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Снимки"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Албуми"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Визуализация"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Превкл. към служ. пoтр. профил"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 0f60019..42c3be2 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"কোনও অ্যালবাম নেই"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"কোনগুলি বাছা হয়েছে দেখুন"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ফটো"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"অ্যালবাম"</string>
     <string name="picker_preview" msgid="6257414886055861039">"প্রিভিউ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"অফিস প্রোফাইলে সুইচ করুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index f6da691..f9550a5 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nema albuma"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Prikaži odabrano"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotografije"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumi"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Pregled"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Prebacite se na radni profil"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index ed89418..7f8822b 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"No hi ha cap àlbum"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Mostra la selecció"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Àlbums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Previsualitza"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Canvia al perfil de treball"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 0b0773a..33790ca 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Žádná alba"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Zobrazit vybrané"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotky"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Alba"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Náhled"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Přepnout na pracovní profil"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index cea19ca..0bc8433 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Ingen album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Se valgte"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Billeder"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Forhåndsvisning"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Skift til arbejdsprofil"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 37a6bc6..82f878e 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Keine Alben"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Auswahl ansehen"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Alben"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Vorschau"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Zum Arbeitsprofil wechseln"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 2a44df5..0736242 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Δεν υπάρχουν άλμπουμ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Προβολή επιλεγμένων"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Φωτογραφίες"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Άλμπουμ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Προεπισκόπηση"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Μετάβαση σε προφίλ εργασίας"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index a719437..996ef60 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"No albums"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"View selected"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Photos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Preview"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Switch to work"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index c6b7563..be91653 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"No albums"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"View selected"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Photos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Preview"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Switch to work"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index a719437..996ef60 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"No albums"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"View selected"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Photos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Preview"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Switch to work"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index a719437..996ef60 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"No albums"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"View selected"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Photos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Preview"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Switch to work"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index dbc133f..6dd8620 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎No albums‎‏‎‎‏‎"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎View selected‎‏‎‎‏‎"</string>
     <string name="picker_photos" msgid="7415035516411087392">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‎‎‎Photos‎‏‎‎‏‎"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎Albums‎‏‎‎‏‎"</string>
     <string name="picker_preview" msgid="6257414886055861039">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎Preview‎‏‎‎‏‎"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎Switch to work‎‏‎‎‏‎"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 11b0976..f2b7c73 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"No hay álbumes"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Ver seleccionados"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Álbumes"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Vista previa"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Cambiar al perfil de trabajo"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index d7f2b64..c23f8ad 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"No hay ningún álbum"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Ver seleccionado"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Álbumes"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Vista previa"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Cambiar a perfil de trabajo"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 4aa4017..433ea73 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Albumeid pole"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Kuva valitud"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotod"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumid"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Eelvaade"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Lülituge tööprofiilile"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 49fb67a..aa0f303 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Ez dago albumik"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Ikusi hautatutakoak"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Argazkiak"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumak"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Aurrebista"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Aldatu laneko profilera"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 6209611..9a6a0f9 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"آلبومی موجود نیست"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"مشاهده موارد انتخاب‌شده"</string>
     <string name="picker_photos" msgid="7415035516411087392">"عکس‌ها"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"آلبوم‌ها"</string>
     <string name="picker_preview" msgid="6257414886055861039">"پیش‌نما"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"رفتن به نمایه کاری"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 3f4101b..ea1db49 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Ei albumeita"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Katso valitut"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Kuvat"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumit"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Esikatselu"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Siirry työprofiiliin"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 1d46b00..eadca62 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Aucun album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Afficher la sélection"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Photos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Aperçu"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Passez au profil professionnel"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 1122665..792e3af 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Aucun album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Afficher la sélection"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Photos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Aperçu"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Passer au profil professionnel"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 5b90bca..04d94f8 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Non hai álbums"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Ver selección"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Álbums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Vista previa"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Cambiar ao perfil de traballo"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index cbaf312..0544ced 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"કોઈ આલ્બમ નથી"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"પસંદ કરેલા ફોટા જુઓ"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ફોટા"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"આલ્બમ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"પ્રીવ્યૂ કરો"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 070b0f9..3eaa289 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"कोई एल्बम नहीं है"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"चुनी गई फ़ोटो या वीडियो देखें"</string>
     <string name="picker_photos" msgid="7415035516411087392">"फ़ोटो"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"एल्बम"</string>
     <string name="picker_preview" msgid="6257414886055861039">"झलक"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"वर्क प्रोफ़ाइल पर जाएं"</string>
@@ -69,7 +71,7 @@
     <string name="picker_profile_admin_msg_from_work" msgid="8048524337462790110">"निजी डेटा को ऑफ़िस के काम से जुड़े ऐप्लिकेशन से ऐक्सेस करने की अनुमति नहीं है"</string>
     <string name="picker_profile_work_paused_title" msgid="382212880704235925">"वर्क ऐप्लिकेशन रोक दिए गए हैं"</string>
     <string name="picker_profile_work_paused_msg" msgid="6321552322125246726">"वर्क फ़ोटो देखने के लिए, ऑफ़िस के काम से जुड़े ऐप्लिकेशन चालू करें और दोबारा कोशिश करें"</string>
-    <string name="picker_privacy_message" msgid="9132700451027116817">"इस ऐप्लिकेशन के पास आपकी उन फ़ोटो का ही ऐक्सेस होता है जिन्हें आपने चुना हो"</string>
+    <string name="picker_privacy_message" msgid="9132700451027116817">"इस ऐप्लिकेशन के पास आपकी उन फ़ोटो का ही ऐक्सेस होता है जिन्हें आपने चुना है"</string>
     <string name="picker_header_permissions" msgid="675872774407768495">"वे फ़ोटो और वीडियो चुनें जिनका ऐक्सेस इस ऐप्लिकेशन को देना है"</string>
     <string name="picker_album_item_count" msgid="4420723302534177596">"{count,plural, =1{<xliff:g id="COUNT_0">^1</xliff:g> आइटम}one{<xliff:g id="COUNT_1">^1</xliff:g> आइटम}other{<xliff:g id="COUNT_1">^1</xliff:g> आइटम}}"</string>
     <string name="picker_add_button_multi_select" msgid="4005164092275518399">"(<xliff:g id="COUNT">^1</xliff:g>) जोड़ें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index bd32b54..9339e27 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nema albuma"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Prikaži odabrano"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotografije"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumi"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Pregled"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Prijeđite na poslovni"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 0132ca5..7f62bf1 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nincsenek albumok"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Kijelöltek megnézése"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotók"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumok"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Előnézet"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Átváltás munkaprofilra"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index df9771b..b67062e 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Ալբոմներ չկան"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Դիտել ընտրվածը"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Լուսանկարներ"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Ալբոմներ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Նախադիտում"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Բացել աշխատանքային պրոֆիլը"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 5431783..3767083 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Tidak ada album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Lihat yang dipilih"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Foto"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Pratinjau"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Beralih ke profil kerja"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 211f051..c492315 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Engin albúm"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Skoða valið"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Myndir"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albúm"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Forskoða"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Skipta yfir í vinnusnið"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index c03968a..73249cb 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nessun album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Visualizza selezione"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Foto"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Anteprima"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Passa al profilo di lavoro"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 4e76d6b..abbdb8f 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"אין אלבומים"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"הצגת הפריטים שנבחרו"</string>
     <string name="picker_photos" msgid="7415035516411087392">"תמונות"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"אלבומים"</string>
     <string name="picker_preview" msgid="6257414886055861039">"תצוגה מקדימה"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"לפרופיל העבודה"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 1524313..160c68f 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"アルバムはありません"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"選択した写真を見る"</string>
     <string name="picker_photos" msgid="7415035516411087392">"写真"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"アルバム"</string>
     <string name="picker_preview" msgid="6257414886055861039">"プレビュー"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"仕事用に切り替える"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index d6700f3..382d5a1 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ალბომები არ არის"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"არჩეულის ნახვა"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ფოტოები"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ალბომები"</string>
     <string name="picker_preview" msgid="6257414886055861039">"გადახედვა"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"სამსახურზე გადართვა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 263ff2d..e59be1e 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Альбомдар жоқ."</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Таңдалғанды көру"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Фотосуреттер"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Aльбомдар"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Алғы көрініс"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Жұмыс профиліне ауысу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index a72a992..7468247 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"គ្មាន​អាល់ប៊ុម​ទេ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"មើលអ្វីដែលបានជ្រើសរើស"</string>
     <string name="picker_photos" msgid="7415035516411087392">"រូបថត"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"អាល់ប៊ុម"</string>
     <string name="picker_preview" msgid="6257414886055861039">"មើល​សាកល្បង"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ប្ដូរទៅ​កម្រងព័ត៌មាន​ការងារ"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 6baafe4..e0a5f07 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ಯಾವುದೇ ಆಲ್ಬಮ್‌ಗಳಿಲ್ಲ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ಆಯ್ಕೆಮಾಡಿರುವುದನ್ನು ವೀಕ್ಷಿಸಿ"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ಫೋಟೋಗಳು"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ಆಲ್ಬಮ್‌ಗಳು"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ಗೆ ಬದಲಿಸಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 60ac833..84b4241 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"앨범 없음"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"선택 항목 보기"</string>
     <string name="picker_photos" msgid="7415035516411087392">"사진"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"앨범"</string>
     <string name="picker_preview" msgid="6257414886055861039">"미리보기"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"직장 프로필로 전환"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 50f3f03..36cb921 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Альбомдор жок"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Тандалганды көрүү"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Сүрөттөр"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Альбомдор"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Алдын ала көрүү"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Жумуш профилине которулуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index f70953a..1806a7f 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ບໍ່ມີອະລະບ້ຳ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ເບິ່ງອັນທີ່ເລືອກໄວ້"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ຮູບພາບ"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ອະລະບ້ຳ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ຕົວຢ່າງ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ສະຫຼັບໄປໂປຣໄຟລ໌ວຽກ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index e8e06f0..a16f1f5 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nėra jokių albumų"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Žiūrėti pasirinktus"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Nuotraukos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumai"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Peržiūra"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Perjungti į darbo profilį"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 4331651..330f6cf 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nav albumu"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Skatīt atlasīto"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotoattēli"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumi"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Priekšskatījums"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Pārslēgties uz darba profilu"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 3fdc1c0..719221f 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Нема албуми"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Прикажи ги избраните"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Фотографии"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Албуми"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Преглед"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Префрлете се на работен профил"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index d02f7e7..b0e63c8 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ആൽബങ്ങളൊന്നുമില്ല"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"തിരഞ്ഞെടുത്തത് കാണുക"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ഫോട്ടോകൾ"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ആൽബങ്ങൾ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"പ്രിവ്യു"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 38d6f15..540a629 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Цомог алга"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Сонгосныг харах"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Зураг"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Цомог"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Урьдчилан үзэх"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Ажлын профайл руу сэлгэх"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 3fb8729..0f0fcc4 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"कोणतेही अल्बम नाहीत"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"निवडलेले पहा"</string>
     <string name="picker_photos" msgid="7415035516411087392">"फोटो"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"अल्बम"</string>
     <string name="picker_preview" msgid="6257414886055861039">"पूर्वावलोकन"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ऑफिसवर स्विच करा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index f96d6e4..5751c1a 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Tiada album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Lihat terpilih"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Foto"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Pratonton"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Beralih kepada kerja"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 9a1013f..00d070a 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"အယ်လ်ဘမ်များ မရှိပါ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ပြသမှုကို ရွေးချယ်ထားသည်"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ဓာတ်ပုံများ"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"အယ်လ်ဘမ်များ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"အစမ်းကြည့်ရှုခြင်း"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"အလုပ်သို့ ပြောင်းပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 901f7ed..c120204 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Ingen album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Vis valgte"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Bilder"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Forhåndsvisning"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Bytt til jobbprofilen"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index eed492e..d39dfc6 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"कुनै पनि एल्बम छैन"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"चयन गरिएका सामग्री हेर्नुहोस्"</string>
     <string name="picker_photos" msgid="7415035516411087392">"फोटोहरू"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"एल्बमहरू"</string>
     <string name="picker_preview" msgid="6257414886055861039">"प्रिभ्यू"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"कार्य प्रोफाइल प्रयोग गर्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index de4fcc2..62caff6 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Geen albums"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Selectie bekijken"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Foto\'s"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albums"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Voorbeeld"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Overschakelen naar werkprofiel"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index afcb014..b6e37dc 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"କୌଣସି ଆଲବମ ନାହିଁ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ଚୟନିତଗୁଡ଼ିକୁ ଭ୍ୟୁ କରନ୍ତୁ"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ଫଟୋ"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ଆଲବମ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ପ୍ରିଭ୍ୟୁ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ୱାର୍କକୁ ସୁଇଚ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index c17c1d0..950ad56 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ਕੋਈ ਐਲਬਮ ਨਹੀਂ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ਚੁਣੀਆਂ ਗਈਆਂ ਆਈਟਮਾਂ ਦੇਖੋ"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ਫ਼ੋਟੋਆਂ"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ਐਲਬਮਾਂ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ਪੂਰਵ-ਝਲਕ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index cc3b1c5..d08e86b 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Brak albumów"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Wyświetl wybrane"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Zdjęcia"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumy"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Podgląd"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Włącz profil służbowy"</string>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index bef70c1..feeeb74 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Sem álbuns"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Mostrar selecionados"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Álbuns"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Visualização"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Mudar para Trabalho"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index a049d92..8a824c1 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nenhum álbum"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Ver selecionado(s)"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Álbuns"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Pré-visualizar"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Mudar para trabalho"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index bef70c1..feeeb74 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Sem álbuns"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Mostrar selecionados"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotos"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Álbuns"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Visualização"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Mudar para Trabalho"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index d9d0df9..399078e 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Niciun album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Vezi elementele selectate"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotografii"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albume"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Previzualizare"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Comută la serviciu"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index b8ff7b3..edf4c87 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Альбомов нет."</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Посмотреть выбранное"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Фотографии"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Альбомы"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Предварительный просмотр"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Перейти в рабочий профиль"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index e972106..c41dad2 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ඇල්බම නැත"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"තෝරා ගත් දේවල් බලන්න"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ඡායාරූප"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ඇල්බම"</string>
     <string name="picker_preview" msgid="6257414886055861039">"පෙරදසුන"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"කාර්යාලය වෙත මාරු වන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 3a8f9fb..d20ec47 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Žiadne albumy"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Zobraziť vybrané"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotky"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumy"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Ukážka"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Prepnúť na pracovný profil"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 08cb6a1..a5bcb3c 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Ni albumov."</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Prikaži izbrano"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotografije"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumi"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Predogled"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Preklop na delovni profil"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 0b60fde..7681a67 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Nuk ka albume"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Shiko të zgjedhurat"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotografitë"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albumet"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Pamja paraprake"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Kalo te profili i punës"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 726459e..bc902e7 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Нема албума"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Прикажи изабранo"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Слике"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Албуми"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Преглед"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Пређи на пословни профил"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index d725331..d71c999 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Inga album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Visa valda"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Foton"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Förhandsgranska"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Byt till jobbprofilen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 020b5a2..d220100 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Hakuna albamu"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Angalia ulizochagua"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Picha"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albamu"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Onyesho la kukagua"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Badili utumie wasifu wa kazini"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 309ba9d..fbb05c2 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ஆல்பங்கள் இல்லை"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"தேர்ந்தெடுத்ததைக் காட்டு"</string>
     <string name="picker_photos" msgid="7415035516411087392">"படங்கள்"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ஆல்பங்கள்"</string>
     <string name="picker_preview" msgid="6257414886055861039">"மாதிரிக்காட்சி"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"பணிச் சுயவிவரத்திற்கு மாறு"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 2621a48..5913fa6 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ఆల్బమ్‌లు ఏవీ లేవు"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ఎంచుకున్న వాటిని చూడండి"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ఫోటోలు"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"ఆల్బమ్‌లు"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ప్రివ్యూ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"వర్క్ ప్రొఫైల్‌కు మార్చండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 538d732..faa59a6 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"ไม่มีอัลบั้ม"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ดูรายการที่เลือก"</string>
     <string name="picker_photos" msgid="7415035516411087392">"รูปภาพ"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"อัลบั้ม"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ตัวอย่าง"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"เปลี่ยนไปใช้โปรไฟล์งาน"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index ce60a92..6b0577d 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Walang album"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Tingnan ang napili"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Mga Larawan"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Mga Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Preview"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Lumipat sa para sa trabaho"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index c959485..9c34218 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Albüm yok"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Seçilenleri görüntüle"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Fotoğraflar"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albümler"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Önizle"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"İş profiline geç"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8ec4cfb..99039b9 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Немає альбомів"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Переглянути вибране"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Фото"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Альбоми"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Попередній перегляд"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Перейти в робочий профіль"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index dea4d10..6709e8a 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"کوئی البم نہیں"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"منتخب کردہ دیکھیں"</string>
     <string name="picker_photos" msgid="7415035516411087392">"تصاویر"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"البمز"</string>
     <string name="picker_preview" msgid="6257414886055861039">"پیش منظر"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"کام پر سوئچ کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index b97c5df..719b153 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Albom kiritilmagan"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Belgilanganlarni ochish"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Suratlar"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Albomlar"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Razm solish"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Ish profiliga almashish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index c0dd41d..4cac424 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Không có album nào"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Xem các mục được chọn"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Ảnh"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Album"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Xem trước"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Chuyển sang hồ sơ công việc"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 28c400c..a9be74e 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"无影集"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"查看所选内容"</string>
     <string name="picker_photos" msgid="7415035516411087392">"照片"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"影集"</string>
     <string name="picker_preview" msgid="6257414886055861039">"预览"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"切换到工作资料"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 870d569..a8b9e61 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"沒有相簿"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"查看所選項目"</string>
     <string name="picker_photos" msgid="7415035516411087392">"相片"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"相簿"</string>
     <string name="picker_preview" msgid="6257414886055861039">"預覽"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"切換至工作設定檔"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 4d2b5d6..13c77cc 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"沒有相簿"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"查看所選項目"</string>
     <string name="picker_photos" msgid="7415035516411087392">"相片"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"相簿"</string>
     <string name="picker_preview" msgid="6257414886055861039">"預覽"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"切換至工作資料夾"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index fd42bc1..0e53f4c 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -60,6 +60,8 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"Awekho ama-albhamu"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"Ukubuka kukhethiwe"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Izithombe"</string>
+    <!-- no translation found for picker_videos (2886971435439047097) -->
+    <skip />
     <string name="picker_albums" msgid="4822511902115299142">"Ama-albhamu"</string>
     <string name="picker_preview" msgid="6257414886055861039">"Hlola kuqala"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Shintshela kokmsebenzi"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0651c0a..748e7c5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -146,9 +146,12 @@
     <!-- PhotoPicker view selected action text. [CHAR LIMIT=17] -->
     <string name="picker_view_selected">View selected</string>
 
-    <!-- The text of the photos tab for PhotoPicker. [CHAR LIMIT=30] -->
+    <!-- The text of the photos tab in PhotoPicker for 'Image/' mime type. [CHAR LIMIT=30] -->
     <string name="picker_photos">Photos</string>
 
+    <!-- The text of the photos tab in PhotoPicker for 'Video/' mime type. [CHAR LIMIT=30] -->
+    <string name="picker_videos">@string/root_videos</string>
+
     <!-- The text of the albums tab for PhotoPicker. [CHAR LIMIT=30] -->
     <string name="picker_albums">Albums</string>
 
@@ -257,6 +260,8 @@
     <!-- A message for the Progress Dialog shown while preloading selected items before "closing" Photo Picker. [CHAR LIMIT=NONE] -->
     <string name="preloading_progress_message"><xliff:g id="number_preloaded">%1$d</xliff:g> of <xliff:g id="number_total">%2$d</xliff:g> ready</string>
 
+    <string name="preloading_cancel_button">Cancel</string>
+
     <!-- ========================= PHOTO PICKER CLOUD EDUCATION BANNERS ========================= -->
 
     <!-- Title for the banner notifying the user that the cloud media is now available in the picker [CHAR LIMIT=NONE] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 179edf8..2f9fd17 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -152,6 +152,11 @@
         <item name="materialAlertDialogTitleTextStyle">@style/AlertDialogTitleStyle</item>
     </style>
 
+    <style name="ProgressDialogCancelButtonStyle"
+           parent="@style/Widget.MaterialComponents.Button.TextButton">
+        <item name="android:textColor">?attr/colorOnSurface</item>
+    </style>
+
     <style name="AlertDialogTitleStyle"
            parent="@style/MaterialAlertDialog.MaterialComponents.Title.Text.CenterStacked">
         <item name="android:textColor">?attr/colorOnSurface</item>
diff --git a/src/com/android/providers/media/ConfigStore.java b/src/com/android/providers/media/ConfigStore.java
index cd80866..828d620 100644
--- a/src/com/android/providers/media/ConfigStore.java
+++ b/src/com/android/providers/media/ConfigStore.java
@@ -56,6 +56,7 @@
     boolean DEFAULT_USER_SELECT_FOR_APP = true;
     boolean DEFAULT_STABILISE_VOLUME_INTERNAL = false;
     boolean DEFAULT_STABILIZE_VOLUME_EXTERNAL = false;
+    boolean DEFAULT_STABILIZE_VOLUME_PUBLIC = false;
 
     boolean DEFAULT_TRANSCODE_ENABLED = true;
     boolean DEFAULT_TRANSCODE_OPT_OUT_STRATEGY_ENABLED = false;
@@ -67,7 +68,7 @@
 
     boolean DEFAULT_CLOUD_MEDIA_IN_PHOTO_PICKER_ENABLED = true;
     boolean DEFAULT_ENFORCE_CLOUD_PROVIDER_ALLOWLIST = true;
-    boolean DEFAULT_PICKER_CHOICE_MANAGED_SELECTION_ENABLED = false;
+    boolean DEFAULT_PICKER_CHOICE_MANAGED_SELECTION_ENABLED = true;
 
     /**
      * @return if the Cloud-Media-in-Photo-Picker enabled (e.g. platform will recognize and
@@ -184,6 +185,13 @@
     }
 
     /**
+     * @return if stable URI are enabled for public volumes.
+     */
+    default boolean isStableUrisForPublicVolumeEnabled() {
+        return DEFAULT_STABILIZE_VOLUME_PUBLIC;
+    }
+
+    /**
      * @return if transcoding is enabled.
      */
     default boolean isTranscodeEnabled() {
@@ -254,6 +262,8 @@
         public static final String KEY_STABILIZE_VOLUME_INTERNAL = "stabilize_volume_internal";
         @VisibleForTesting
         public static final String KEY_STABILIZE_VOLUME_EXTERNAL = "stabilize_volume_external";
+        @VisibleForTesting
+        public static final String KEY_STABILIZE_VOLUME_PUBLIC = "stabilize_volume_public";
 
         private static final String KEY_TRANSCODE_ENABLED = "transcode_enabled";
         private static final String KEY_TRANSCODE_OPT_OUT_STRATEGY_ENABLED = "transcode_default";
@@ -400,6 +410,12 @@
         }
 
         @Override
+        public boolean isStableUrisForPublicVolumeEnabled() {
+            return getBooleanDeviceConfig(NAMESPACE_MEDIAPROVIDER, KEY_STABILIZE_VOLUME_PUBLIC,
+                    DEFAULT_STABILIZE_VOLUME_PUBLIC);
+        }
+
+        @Override
         public boolean isTranscodeEnabled() {
             return getBooleanDeviceConfig(
                     KEY_TRANSCODE_ENABLED, DEFAULT_TRANSCODE_ENABLED);
diff --git a/src/com/android/providers/media/DatabaseBackupAndRecovery.java b/src/com/android/providers/media/DatabaseBackupAndRecovery.java
index ec864cd..50ee804 100644
--- a/src/com/android/providers/media/DatabaseBackupAndRecovery.java
+++ b/src/com/android/providers/media/DatabaseBackupAndRecovery.java
@@ -62,7 +62,7 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
@@ -82,12 +82,9 @@
             "/data/media/" + UserHandle.myUserId() + "/.transforms/recovery/leveldb-ownership";
 
     /**
-     * Path which stores backup of external primary volume.
-     * Lower file system path is used as upper file system does not support xattrs.
+     * Every LevelDB table name starts with this prefix.
      */
-    private static final String EXTERNAL_PRIMARY_VOLUME_BACKUP_PATH =
-            "/data/media/" + UserHandle.myUserId()
-                    + "/.transforms/recovery/leveldb-external_primary";
+    private static final String LEVEL_DB_PREFIX = "leveldb-";
 
     /**
      * Frequency at which next value of owner id is backed up in the external storage.
@@ -128,7 +125,8 @@
             MediaStore.Files.FileColumns._USER_ID,
             MediaStore.Files.FileColumns.DATE_EXPIRES,
             MediaStore.Files.FileColumns.OWNER_PACKAGE_NAME,
-            MediaStore.Files.FileColumns.GENERATION_MODIFIED
+            MediaStore.Files.FileColumns.GENERATION_MODIFIED,
+            MediaStore.Files.FileColumns.VOLUME_NAME
     };
 
     /**
@@ -153,8 +151,7 @@
     private AtomicInteger mNextOwnerIdBackup;
     private final ConfigStore mConfigStore;
     private final VolumeCache mVolumeCache;
-
-    private AtomicBoolean mIsBackupSetupComplete = new AtomicBoolean(false);
+    private Set<String> mSetupCompletePublicVolumes = ConcurrentHashMap.newKeySet();
 
     private static Map<String, String> sOwnerIdRelationMap;
 
@@ -178,7 +175,11 @@
                         "persist.sys.fuse.backup.external_volume_backup",
                         /* defaultValue */ false);
             default:
-                return false;
+                // public volume
+                return isStableUrisEnabled(MediaStore.VOLUME_EXTERNAL_PRIMARY)
+                        && mConfigStore.isStableUrisForPublicVolumeEnabled()
+                        || SystemProperties.getBoolean("persist.sys.fuse.backup.public_db_backup",
+                        /* defaultValue */ false);
         }
     }
 
@@ -189,10 +190,9 @@
      * volume on Media mount signal of EXTERNAL_PRIMARY.
      */
     protected synchronized void setupVolumeDbBackupAndRecovery(String volumeName, File volumePath) {
-        // We are setting up leveldb instance only for internal volume as of now. Since internal
-        // volume does not have any fuse daemon thread, leveldb instance is created by fuse
-        // daemon thread of EXTERNAL_PRIMARY.
-        if (!MediaStore.VOLUME_EXTERNAL_PRIMARY.equalsIgnoreCase(volumeName)) {
+        // Since internal volume does not have any fuse daemon thread, leveldb instance
+        // for internal volume is created by fuse daemon thread of EXTERNAL_PRIMARY.
+        if (MediaStore.VOLUME_INTERNAL.equalsIgnoreCase(volumeName)) {
             // Set backup only for external primary for now.
             return;
         }
@@ -202,7 +202,7 @@
             return;
         }
 
-        if (mIsBackupSetupComplete.get()) {
+        if (mSetupCompletePublicVolumes.contains(volumeName)) {
             // Return if setup is already done
             return;
         }
@@ -211,10 +211,19 @@
             if (!new File(RECOVERY_DIRECTORY_PATH).exists()) {
                 new File(RECOVERY_DIRECTORY_PATH).mkdirs();
             }
-            FuseDaemon fuseDaemon = getFuseDaemonForFileWithWait(volumePath);
+            FuseDaemon fuseDaemon = getFuseDaemonForFileWithWait(new File(
+                    DatabaseBackupAndRecovery.EXTERNAL_PRIMARY_ROOT_PATH));
             Log.d(TAG, "Received db backup Fuse Daemon for: " + volumeName);
-            fuseDaemon.setupVolumeDbBackup();
-            mIsBackupSetupComplete.set(true);
+            if (isStableUrisEnabled(volumeName)) {
+                if (MediaStore.VOLUME_EXTERNAL_PRIMARY.equalsIgnoreCase(volumeName)) {
+                    // Setup internal and external volumes
+                    fuseDaemon.setupVolumeDbBackup();
+                } else {
+                    // Setup public volume
+                    fuseDaemon.setupPublicVolumeDbBackup(volumeName);
+                }
+                mSetupCompletePublicVolumes.add(volumeName);
+            }
         } catch (IOException e) {
             Log.e(TAG, "Failure in setting up backup and recovery for volume: " + volumeName, e);
             return;
@@ -231,7 +240,15 @@
           new File(EXTERNAL_PRIMARY_ROOT_PATH));
         Log.i(TAG, "Triggering database backup");
         backupInternalDatabase(internalDatabaseHelper, signal);
-        backupExternalDatabase(externalDatabaseHelper, signal);
+        backupExternalDatabase(externalDatabaseHelper, MediaStore.VOLUME_EXTERNAL_PRIMARY, signal);
+
+        for (MediaVolume mediaVolume : mVolumeCache.getExternalVolumes()) {
+            if (mediaVolume.isPublicVolume()) {
+                setupVolumeDbBackupAndRecovery(mediaVolume.getName(),
+                        new File(EXTERNAL_PRIMARY_ROOT_PATH));
+                backupExternalDatabase(externalDatabaseHelper, mediaVolume.getName(), signal);
+            }
+        }
     }
 
     protected Optional<BackupIdRow> readDataFromBackup(String volumeName, String filePath) {
@@ -239,9 +256,9 @@
             return Optional.empty();
         }
 
-        final String fuseDaemonFilePath = getFilePathForFuseRequests(filePath);
         try {
-            final String data = getFuseDaemonForPath(fuseDaemonFilePath).readBackedUpData(filePath);
+            final String data = getFuseDaemonForPath(EXTERNAL_PRIMARY_ROOT_PATH)
+                    .readBackedUpData(filePath);
             if (data == null || data.isEmpty()) {
                 Log.w(TAG, "No backup found for path: " + filePath);
                 return Optional.empty();
@@ -261,7 +278,7 @@
             return;
         }
 
-        if (!mIsBackupSetupComplete.get()) {
+        if (!mSetupCompletePublicVolumes.contains(MediaStore.VOLUME_EXTERNAL_PRIMARY)) {
             return;
         }
 
@@ -294,13 +311,13 @@
     }
 
     protected synchronized void backupExternalDatabase(DatabaseHelper externalDbHelper,
-            CancellationSignal signal) {
-        if (!isStableUrisEnabled(MediaStore.VOLUME_EXTERNAL_PRIMARY)
+            String volumeName, CancellationSignal signal) {
+        if (!isStableUrisEnabled(volumeName)
                 || externalDbHelper.isDatabaseRecovering()) {
             return;
         }
 
-        if (!mIsBackupSetupComplete.get()) {
+        if (!mSetupCompletePublicVolumes.contains(volumeName)) {
             return;
         }
 
@@ -310,28 +327,24 @@
         } catch (FileNotFoundException e) {
             Log.e(TAG,
                     "Fuse Daemon not found for primary external storage, skipping backing up of "
-                            + "external database.",
+                            + volumeName,
                     e);
             return;
         }
 
-        // Read last backed up generation number
-        Optional<Long> lastBackedUpGenNum = getXattrOfLongValue(
-                EXTERNAL_PRIMARY_VOLUME_BACKUP_PATH, LAST_BACKEDUP_GENERATION_XATTR_KEY);
-        long lastBackedGenerationNumber = lastBackedUpGenNum.isPresent()
-                ? lastBackedUpGenNum.get() : 0;
-        if (lastBackedGenerationNumber > 0) {
-            Log.i(TAG, "Last backed up generation number is " + lastBackedGenerationNumber);
-        }
+        final String backupPath = RECOVERY_DIRECTORY_PATH + "/" + LEVEL_DB_PREFIX + volumeName;
+        long lastBackedGenerationNumber = getLastBackedGenerationNumber(backupPath);
+
         final String generationClause = MediaStore.Files.FileColumns.GENERATION_MODIFIED + " >= "
                 + lastBackedGenerationNumber;
         final String volumeClause = MediaStore.Files.FileColumns.VOLUME_NAME + " = '"
-                + MediaStore.VOLUME_EXTERNAL_PRIMARY + "'";
+                + volumeName + "'";
         final String selectionClause = generationClause + " AND " + volumeClause;
 
         externalDbHelper.runWithTransaction((db) -> {
             long maxGeneration = lastBackedGenerationNumber;
-            Log.d(TAG, "Started to back up external database, maxGeneration:" + maxGeneration);
+            Log.d(TAG, "Started to back up " + volumeName
+                    + ", maxGeneration:" + maxGeneration);
             try (Cursor c = db.query(true, "files", QUERY_COLUMNS, selectionClause, null, null,
                     null, MediaStore.MediaColumns._ID + " ASC", null, signal)) {
                 while (c.moveToNext()) {
@@ -343,14 +356,14 @@
                     backupDataValues(fuseDaemon, c);
                     maxGeneration = Math.max(maxGeneration, c.getLong(9));
                 }
-                setXattr(EXTERNAL_PRIMARY_VOLUME_BACKUP_PATH, LAST_BACKEDUP_GENERATION_XATTR_KEY,
+                setXattr(backupPath, LAST_BACKEDUP_GENERATION_XATTR_KEY,
                         String.valueOf(maxGeneration - 1));
                 Log.d(TAG, String.format(Locale.ROOT,
-                        "Backed up %d rows of external database to external storage on idle "
+                        "Backed up %d rows of " + volumeName + " to external storage on idle "
                                 + "maintenance.",
                         c.getCount()));
             } catch (Exception e) {
-                Log.e(TAG, "Failure in backing up external database to external storage.", e);
+                Log.e(TAG, "Failure in backing up " + volumeName + " to external storage.", e);
                 return null;
             }
             return null;
@@ -367,10 +380,11 @@
         final int userId = c.getInt(6);
         final String dateExpires = c.getString(7);
         final String ownerPackageName = c.getString(8);
+        final String volumeName = c.getString(10);
         BackupIdRow backupIdRow = createBackupIdRow(fuseDaemon, id, mediaType,
                 isFavorite, isPending, isTrashed, userId, dateExpires,
                 ownerPackageName);
-        fuseDaemon.backupVolumeDbData(data, BackupIdRow.serialize(backupIdRow));
+        fuseDaemon.backupVolumeDbData(volumeName, data, BackupIdRow.serialize(backupIdRow));
     }
 
     protected void deleteBackupForVolume(String volumeName) {
@@ -417,6 +431,19 @@
         }
     }
 
+    private long getLastBackedGenerationNumber(String backupPath) {
+        // Read last backed up generation number
+        Optional<Long> lastBackedUpGenNum = getXattrOfLongValue(
+                backupPath, LAST_BACKEDUP_GENERATION_XATTR_KEY);
+        long lastBackedGenerationNumber = lastBackedUpGenNum.isPresent()
+                ? lastBackedUpGenNum.get() : 0;
+        if (lastBackedGenerationNumber > 0) {
+            Log.i(TAG, "Last backed up generation number for " + backupPath + " is "
+                    + lastBackedGenerationNumber);
+        }
+        return lastBackedGenerationNumber;
+    }
+
     @NonNull
     private FuseDaemon getFuseDaemonForPath(@NonNull String path)
             throws FileNotFoundException {
@@ -438,32 +465,15 @@
         }
 
         try {
-            FuseDaemon fuseDaemon = getFuseDaemonForPath(
-                    getFilePathForFuseRequests(insertedRow.getPath()));
+            FuseDaemon fuseDaemon = getFuseDaemonForPath(EXTERNAL_PRIMARY_ROOT_PATH);
             final BackupIdRow value = createBackupIdRow(fuseDaemon, insertedRow);
-            fuseDaemon.backupVolumeDbData(insertedRow.getPath(), BackupIdRow.serialize(value));
+            fuseDaemon.backupVolumeDbData(insertedRow.getVolumeName(), insertedRow.getPath(),
+                    BackupIdRow.serialize(value));
         } catch (Exception e) {
             Log.e(TAG, "Failure in backing up data to external storage", e);
         }
     }
 
-    /**
-     * Creates a fuse daemon file path for a given path.
-     */
-    protected static String getFilePathForFuseRequests(String filePath) {
-        // For internal volume paths
-        if (!filePath.startsWith("/storage")) {
-            return EXTERNAL_PRIMARY_ROOT_PATH;
-        }
-
-        // For primary external and cloned app paths.
-        if (filePath.equalsIgnoreCase("/storage") || filePath.startsWith("/storage/emulated")) {
-            return EXTERNAL_PRIMARY_ROOT_PATH;
-        }
-
-        return filePath;
-    }
-
     private BackupIdRow createBackupIdRow(FuseDaemon fuseDaemon, FileRow insertedRow)
             throws IOException {
         return createBackupIdRow(fuseDaemon, insertedRow.getId(), insertedRow.getMediaType(),
@@ -592,7 +602,7 @@
         }
 
         try {
-            getFuseDaemonForPath(getFilePathForFuseRequests(deletedFilePath)).deleteDbBackup(
+            getFuseDaemonForPath(EXTERNAL_PRIMARY_ROOT_PATH).deleteDbBackup(
                     deletedFilePath);
         } catch (IOException e) {
             Log.w(TAG, "Failure in deleting backup data for key: " + deletedFilePath, e);
@@ -602,7 +612,7 @@
     protected boolean isBackupUpdateAllowed(DatabaseHelper databaseHelper, String volumeName) {
         // Backup only if stable uris is enabled, db is not recovering and backup setup is complete.
         return isStableUrisEnabled(volumeName) && !databaseHelper.isDatabaseRecovering()
-                && mIsBackupSetupComplete.get();
+                && mSetupCompletePublicVolumes.contains(volumeName);
     }
 
 
@@ -629,7 +639,8 @@
 
         final String updatedFilePath = updatedRow.getPath();
         try {
-            getFuseDaemonForPath(getFilePathForFuseRequests(updatedFilePath)).backupVolumeDbData(
+            getFuseDaemonForPath(EXTERNAL_PRIMARY_ROOT_PATH).backupVolumeDbData(
+                    updatedRow.getVolumeName(),
                     updatedFilePath,
                     BackupIdRow.serialize(BackupIdRow.newBuilder(updatedRow.getId()).setIsDirty(
                             true).build()));
@@ -805,6 +816,11 @@
     }
 
     protected void recoverData(SQLiteDatabase db, String volumeName) {
+        if (!MediaStore.VOLUME_EXTERNAL_PRIMARY.equalsIgnoreCase(volumeName)
+                && !MediaStore.VOLUME_INTERNAL.equalsIgnoreCase(volumeName)) {
+            // todo: implement for public volume
+            return;
+        }
         final long startTime = SystemClock.elapsedRealtime();
         final String fuseFilePath = getFuseFilePathFromVolumeName(volumeName);
         // Wait for external primary to be attached as we use same thread for internal volume.
@@ -862,8 +878,9 @@
                 volumeName));
         if (MediaStore.VOLUME_EXTERNAL_PRIMARY.equalsIgnoreCase(volumeName)) {
             // Resetting generation number
-            setXattr(EXTERNAL_PRIMARY_VOLUME_BACKUP_PATH, LAST_BACKEDUP_GENERATION_XATTR_KEY,
-                    String.valueOf(0));
+            setXattr(RECOVERY_DIRECTORY_PATH + "/" + LEVEL_DB_PREFIX
+                            + MediaStore.VOLUME_EXTERNAL_PRIMARY,
+                    LAST_BACKEDUP_GENERATION_XATTR_KEY, String.valueOf(0));
         }
         Log.i(TAG, String.format(Locale.ROOT, "Recovery time: %d ms", recoveryTime));
     }
@@ -917,7 +934,7 @@
 
         FuseDaemon fuseDaemon;
         try {
-            fuseDaemon = getFuseDaemonForPath(getFilePathForFuseRequests(oldRow.getPath()));
+            fuseDaemon = getFuseDaemonForPath(EXTERNAL_PRIMARY_ROOT_PATH);
         } catch (FileNotFoundException e) {
             Log.e(TAG,
                     "Fuse Daemon not found for primary external storage, skipping update of "
diff --git a/src/com/android/providers/media/DatabaseHelper.java b/src/com/android/providers/media/DatabaseHelper.java
index d58972f..0fb7ff3 100644
--- a/src/com/android/providers/media/DatabaseHelper.java
+++ b/src/com/android/providers/media/DatabaseHelper.java
@@ -666,6 +666,10 @@
                     "%s database inconsistent: isLastUsedDatabaseSession:%b, "
                             + "nextRowIdOptionalPresent:%b", mName, isLastUsedDatabaseSession,
                     nextRowIdFromXattrOptional.isPresent()));
+
+            // This could be a rollback, clear all media grants
+            clearMediaGrantsTable(db);
+
             // TODO(b/222313219): Add an assert to ensure that next row id xattr is always
             // present when DB session id matches across sequential open calls.
             updateNextRowIdInDatabaseAndExternalStorage(db);
@@ -673,6 +677,15 @@
         }
     }
 
+    private void clearMediaGrantsTable(SQLiteDatabase db) {
+        mSchemaLock.writeLock().lock();
+        try {
+            updateAddMediaGrantsTable(db);
+        } finally {
+            mSchemaLock.writeLock().unlock();
+        }
+    }
+
     @GuardedBy("sRecoveryLock")
     private boolean isLastUsedDatabaseSession(SQLiteDatabase db) {
         Optional<String> lastUsedSessionIdFromDatabasePathXattr = getXattr(db.getPath(),
diff --git a/src/com/android/providers/media/MediaGrants.java b/src/com/android/providers/media/MediaGrants.java
index 52f9a3e..d654ca0 100644
--- a/src/com/android/providers/media/MediaGrants.java
+++ b/src/com/android/providers/media/MediaGrants.java
@@ -25,6 +25,7 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteConstraintException;
+import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.provider.MediaStore;
@@ -55,12 +56,12 @@
     public static final String OWNER_PACKAGE_NAME_COLUMN =
             MediaStore.MediaColumns.OWNER_PACKAGE_NAME;
 
+    private static final String CREATE_TEMPORARY_TABLE_QUERY = "CREATE TEMPORARY TABLE ";
     private static final String MEDIA_GRANTS_AND_FILES_JOIN_TABLE_NAME = "media_grants LEFT JOIN "
             + "files ON media_grants.file_id = files._id";
 
     private static final String WHERE_MEDIA_GRANTS_PACKAGE_NAME_IN =
             "media_grants." + MediaGrants.OWNER_PACKAGE_NAME_COLUMN + " IN ";
-    private static final String WHERE_MEDIA_GRANTS_FILE_ID_IN = MediaGrants.FILE_ID_COLUMN + " IN ";
 
     private static final String WHERE_MEDIA_GRANTS_USER_ID =
             "media_grants." + MediaGrants.PACKAGE_USER_ID_COLUMN + " = ? ";
@@ -80,6 +81,12 @@
     private static final String WHERE_VOLUME_NAME_IN =
             "files." + MediaStore.Files.FileColumns.VOLUME_NAME + " IN ";
 
+    private static final String TEMP_TABLE_NAME_FOR_DELETION =
+            "temp_table_for_media_grants_deletion";
+
+    private static final String TEMP_TABLE_FOR_DELETION_FILE_ID_COLUMN_NAME =
+            "temp_table_for_media_grants_deletion.file_id";
+
     private static final String ARG_VALUE_FOR_FALSE = "0";
 
     private static final int VISUAL_MEDIA_TYPE_COUNT = 2;
@@ -175,24 +182,31 @@
         });
     }
 
-    int removeMediaGrantsForPackage(String[] packages, List<Uri> uris, int packageUserId) {
+    int removeMediaGrantsForPackage(@NonNull String[] packages, @NonNull List<Uri> uris,
+            int packageUserId) {
         Objects.requireNonNull(packages);
+        Objects.requireNonNull(uris);
         if (packages.length == 0) {
             throw new IllegalArgumentException(
                     "Removing grants requires a non empty package name.");
         }
 
-        final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
-        queryBuilder.setDistinct(true);
-        queryBuilder.setTables(MEDIA_GRANTS_TABLE);
-        String[] selectionArgs = buildSelectionArg(queryBuilder, QueryFilterBuilder.newInstance()
-                .setPackageNameSelection(packages)
-                .setUserIdSelection(packageUserId)
-                .setUriSelection(uris)
-                .build());
-
         return mExternalDatabase.runWithTransaction(
                 (db) -> {
+                    // create a temporary table to be used as a selection criteria for local ids.
+                    createTempTableWithLocalIdsAsColumn(uris, db);
+
+                    // Create query builder and add selection args.
+                    final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
+                    queryBuilder.setDistinct(true);
+                    queryBuilder.setTables(MEDIA_GRANTS_TABLE);
+                    String[] selectionArgs = buildSelectionArg(queryBuilder,
+                            QueryFilterBuilder.newInstance()
+                                    .setPackageNameSelection(packages)
+                                    .setUserIdSelection(packageUserId)
+                                    .setUriSelection(uris)
+                                    .build());
+                    // execute query.
                     int grantsRemoved = queryBuilder.delete(db, null, selectionArgs);
                     Log.d(
                             TAG,
@@ -201,10 +215,55 @@
                                     grantsRemoved,
                                     String.valueOf(packageUserId),
                                     Arrays.toString(packages)));
+                    // Drop the temporary table.
+                    deleteTempTableCreatedForLocalIdSelection(db);
                     return grantsRemoved;
                 });
     }
 
+    private static void createTempTableWithLocalIdsAsColumn(@NonNull List<Uri> uris,
+            @NonNull SQLiteDatabase db) {
+
+        // create a temporary table and insert the ids from received uris.
+        db.execSQL(String.format(CREATE_TEMPORARY_TABLE_QUERY + "%s (%s INTEGER)",
+                TEMP_TABLE_NAME_FOR_DELETION, FILE_ID_COLUMN));
+
+        final SQLiteQueryBuilder queryBuilderTempTable = new SQLiteQueryBuilder();
+        queryBuilderTempTable.setTables(TEMP_TABLE_NAME_FOR_DELETION);
+
+        List<List<Uri>> listOfSelectionArgsForId = splitArrayList(uris,
+                /* number of ids per query */ 50);
+
+        StringBuilder sb = new StringBuilder();
+        List<Uri> selectionArgForIdSelection;
+        for (int itr = 0; itr < listOfSelectionArgsForId.size(); itr++) {
+            selectionArgForIdSelection = listOfSelectionArgsForId.get(itr);
+            if (itr == 0 || selectionArgForIdSelection.size() != listOfSelectionArgsForId.get(
+                    itr - 1).size()) {
+                sb.setLength(0);
+                for (int i = 0; i < selectionArgForIdSelection.size() - 1; i++) {
+                    sb.append("(?)").append(",");
+                }
+                sb.append("(?)");
+            }
+            db.execSQL("INSERT INTO " + TEMP_TABLE_NAME_FOR_DELETION + " VALUES " + sb.toString(),
+                    selectionArgForIdSelection.stream().map(
+                            ContentUris::parseId).collect(Collectors.toList()).stream().toArray());
+        }
+    }
+
+    private static <T> List<List<T>> splitArrayList(List<T> list, int chunkSize) {
+        List<List<T>> subLists = new ArrayList<>();
+        for (int i = 0; i < list.size(); i += chunkSize) {
+            subLists.add(list.subList(i, Math.min(i + chunkSize, list.size())));
+        }
+        return subLists;
+    }
+
+    private static void deleteTempTableCreatedForLocalIdSelection(SQLiteDatabase db) {
+        db.execSQL("DROP TABLE " + TEMP_TABLE_NAME_FOR_DELETION);
+    }
+
     /**
      * Removes any existing media grants for the given package from the external database. This will
      * not alter the files or file metadata themselves.
@@ -298,8 +357,8 @@
 
         return isPickerUri(uri)
                 && PickerUriResolver.unwrapProviderUri(uri)
-                        .getHost()
-                        .equals(PickerSyncController.LOCAL_PICKER_PROVIDER_AUTHORITY);
+                .getHost()
+                .equals(PickerSyncController.LOCAL_PICKER_PROVIDER_AUTHORITY);
     }
 
     /**
@@ -326,14 +385,14 @@
         // Append Where clause for Uris
         if (queryFilter.mUris != null && !queryFilter.mUris.isEmpty()) {
             // Append the where clause for local id selection to the query builder.
-            qb.appendWhereStandalone(
-                    WHERE_MEDIA_GRANTS_FILE_ID_IN + buildPlaceholderForWhereClause(
-                            queryFilter.mUris.size()));
-
-            // Add local ids to the selection args.
-            selectArgs.addAll(queryFilter.mUris.stream().map(
-                    (Uri uri) -> String.valueOf(ContentUris.parseId(uri))).collect(
-                    Collectors.toList()));
+            // this query would look like this example query:
+            // WHERE EXISTS (SELECT 1 from temp_table_for_media_grants_deletion WHERE
+            // temp_table_for_media_grants_deletion.file_id = media_grants.file_id)
+            qb.appendWhereStandalone(String.format("EXISTS (SELECT %s from %s WHERE %s = %s)",
+                    TEMP_TABLE_FOR_DELETION_FILE_ID_COLUMN_NAME,
+                    TEMP_TABLE_NAME_FOR_DELETION,
+                    TEMP_TABLE_FOR_DELETION_FILE_ID_COLUMN_NAME,
+                    MediaGrants.MEDIA_GRANTS_TABLE + "." + MediaGrants.FILE_ID_COLUMN));
         }
 
         // Append where clause for userID.
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 7954565..ce1cfa8 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -978,7 +978,7 @@
 
                 if (mExternalDbFacade.onFileInserted(insertedRow.getMediaType(),
                         insertedRow.isPending())) {
-                    mPickerDataLayer.handleMediaEventNotification();
+                    mPickerDataLayer.handleMediaEventNotification(/*localOnly=*/ true);
                 }
 
                 mDatabaseBackupAndRecovery.backupVolumeDbData(helper, insertedRow);
@@ -1017,7 +1017,7 @@
                         oldRow.isPending(), newRow.isPending(),
                         oldRow.isFavorite(), newRow.isFavorite(),
                         oldRow.getSpecialFormat(), newRow.getSpecialFormat())) {
-                    mPickerDataLayer.handleMediaEventNotification();
+                    mPickerDataLayer.handleMediaEventNotification(/*localOnly=*/ true);
                 }
 
                 mDatabaseBackupAndRecovery.updateBackup(helper, oldRow, newRow);
@@ -1077,7 +1077,7 @@
 
                 if (mExternalDbFacade.onFileDeleted(deletedRow.getId(),
                         deletedRow.getMediaType())) {
-                    mPickerDataLayer.handleMediaEventNotification();
+                    mPickerDataLayer.handleMediaEventNotification(/*localOnly=*/ true);
                 }
 
                 mDatabaseBackupAndRecovery.deleteFromDbBackup(helper, deletedRow);
@@ -7096,7 +7096,7 @@
     private Bundle getResultForNotifyCloudMediaChangedEvent(String arg) {
         final boolean notifyCloudEventResult;
         if (mPickerSyncController.isProviderEnabled(arg, Binder.getCallingUid())) {
-            mPickerDataLayer.handleMediaEventNotification();
+            mPickerDataLayer.handleMediaEventNotification(/*localOnly=*/ false);
             notifyCloudEventResult = true;
         } else {
             notifyCloudEventResult = false;
diff --git a/src/com/android/providers/media/fuse/FuseDaemon.java b/src/com/android/providers/media/fuse/FuseDaemon.java
index 34836af..84dc593 100644
--- a/src/com/android/providers/media/fuse/FuseDaemon.java
+++ b/src/com/android/providers/media/fuse/FuseDaemon.java
@@ -219,6 +219,18 @@
     }
 
     /**
+     * Sets up public volume's database backup to external storage to recover during a rollback.
+     */
+    public void setupPublicVolumeDbBackup(String volumeName) throws IOException {
+        synchronized (mLock) {
+            if (mPtr == 0) {
+                throw new IOException("FUSE daemon unavailable");
+            }
+            native_setup_public_volume_db_backup(mPtr, volumeName);
+        }
+    }
+
+    /**
      * Deletes entry for given key from external storage.
      */
     public void deleteDbBackup(String key) throws IOException {
@@ -231,14 +243,14 @@
     }
 
     /**
-     * Backs up given key-value pair in external storage.
+     * Backs up given key-value pair in external storage for provided volume.
      */
-    public void backupVolumeDbData(String key, String value) throws IOException {
+    public void backupVolumeDbData(String volumeName, String key, String value) throws IOException {
         synchronized (mLock) {
             if (mPtr == 0) {
                 throw new IOException("FUSE daemon unavailable");
             }
-            native_backup_volume_db_data(mPtr, key, value);
+            native_backup_volume_db_data(mPtr, volumeName, key, value);
         }
     }
 
@@ -333,8 +345,10 @@
     private native FdAccessResult native_check_fd_access(long daemon, int fd, int uid);
     private native void native_initialize_device_id(long daemon, String path);
     private native void native_setup_volume_db_backup(long daemon);
+    private native void native_setup_public_volume_db_backup(long daemon, String volumeName);
     private native void native_delete_db_backup(long daemon, String key);
-    private native void native_backup_volume_db_data(long daemon, String key, String value);
+    private native void native_backup_volume_db_data(long daemon, String volumeName, String key,
+            String value);
     private native String[] native_read_backed_up_file_paths(long daemon, String volumeName,
             String lastReadValue, int limit);
     private native String native_read_backed_up_data(long daemon, String key);
diff --git a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
index 2b33403..48ee7fb 100644
--- a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
+++ b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
@@ -130,7 +130,6 @@
     private int mToolBarIconColor;
 
     private int mToolbarHeight = 0;
-    private boolean mIsAccessibilityEnabled;
     private boolean mShouldLogCancelledResult = true;
 
     @Override
@@ -186,10 +185,6 @@
 
         mTabLayout = findViewById(R.id.tab_layout);
 
-        final AccessibilityManager am = getSystemService(AccessibilityManager.class);
-        mIsAccessibilityEnabled = am.isEnabled();
-        am.addAccessibilityStateChangeListener(enabled -> mIsAccessibilityEnabled = enabled);
-
         initBottomSheetBehavior();
 
         // Save the fragment container layout so that we can adjust the padding based on preview or
@@ -489,7 +484,7 @@
     }
 
     private void initStateForBottomSheet() {
-        if (!mIsAccessibilityEnabled && !mSelection.canSelectMultiple()
+        if (!isAccessibilityEnabled() && !mSelection.canSelectMultiple()
                 && !isOrientationLandscape()) {
             final int peekHeight = getBottomSheetPeekHeight(this);
             mBottomSheetBehavior.setPeekHeight(peekHeight);
@@ -500,6 +495,15 @@
         }
     }
 
+    /**
+     * Warning: This method is visible for espresso tests, we are not customizing anything here.
+     * Allowing ourselves to control the accessibility state helps us mock it for these tests.
+     */
+    @VisibleForTesting
+    protected boolean isAccessibilityEnabled() {
+        return getSystemService(AccessibilityManager.class).isEnabled();
+    }
+
     private static int getBottomSheetPeekHeight(Context context) {
         final WindowManager windowManager = context.getSystemService(WindowManager.class);
         final Rect displayBounds = windowManager.getCurrentWindowMetrics().getBounds();
@@ -544,6 +548,7 @@
         if (shouldPreloadSelectedItems()) {
             final var uris = PickerResult.getPickerUrisForItems(
                     mSelection.getSelectedItems());
+            mPickerViewModel.logPreloadingStarted(uris.size());
             mPreloaderInstanceHolder.preloader =
                     SelectedMediaPreloader.preload(/* activity */ this, uris);
             deSelectUnavailableMedia(mPreloaderInstanceHolder.preloader);
@@ -572,10 +577,13 @@
         final Bundle extras = getIntent().getExtras();
         final int uid = extras.getInt(Intent.EXTRA_UID);
         final List<Uri> uris = getPickerUrisForItems(mSelection.getSelectedItemsWithoutGrants());
-        ForegroundThread.getExecutor().execute(() -> {
-            // Handle grants in another thread to not block the UI.
-            grantMediaReadForPackage(getApplicationContext(), uid, uris);
-        });
+        if (!uris.isEmpty()) {
+            ForegroundThread.getExecutor().execute(() -> {
+                // Handle grants in another thread to not block the UI.
+                grantMediaReadForPackage(getApplicationContext(), uid, uris);
+                mPickerViewModel.logPickerChoiceAddedGrantsCount(uris.size(), extras);
+            });
+        }
 
         // Revoke READ_GRANT for items that were pre-granted but now in the current session user has
         // deselected them.
@@ -587,6 +595,8 @@
                     // Handle grants in another thread to not block the UI.
                     MediaStore.revokeMediaReadForPackages(getApplicationContext(), uid,
                             urisForItemsWhoseGrantsNeedsToBeRevoked);
+                    mPickerViewModel.logPickerChoiceRevokedGrantsCount(
+                            urisForItemsWhoseGrantsNeedsToBeRevoked.size(), extras);
                 });
             }
         }
@@ -632,6 +642,7 @@
                 /* lifecycleOwner */ PhotoPickerActivity.this,
                 isFinished -> {
                     if (isFinished) {
+                        mPickerViewModel.logPreloadingFinished();
                         setResultAndFinishSelfInternal();
                     }
                 });
@@ -655,9 +666,11 @@
                             DialogUtils.showDialog(this,
                                     getResources().getString(R.string.dialog_error_title),
                                     getResources().getString(R.string.dialog_error_message));
+                            mPickerViewModel.logPreloadingFailed(unavailableMediaIndexes.size());
                         } else {
                             unavailableMediaIndexes.remove(
                                     unavailableMediaIndexes.size() - 1);
+                            mPickerViewModel.logPreloadingCancelled(unavailableMediaIndexes.size());
                         }
                         List<Item> selectedItems = mSelection.getSelectedItems();
                         for (var mediaIndex : unavailableMediaIndexes) {
diff --git a/src/com/android/providers/media/photopicker/PickerDataLayer.java b/src/com/android/providers/media/photopicker/PickerDataLayer.java
index 575f950..49b3d4b 100644
--- a/src/com/android/providers/media/photopicker/PickerDataLayer.java
+++ b/src/com/android/providers/media/photopicker/PickerDataLayer.java
@@ -93,7 +93,7 @@
     // {@link PickerSyncManager} to ensure that any request type is not blocked on other request
     // types. It is advisable to use unique work requests because in case the number of queued
     // requests grows, they should not block other work requests.
-    private static final int WORK_MANAGER_THREAD_POOL_SIZE = 5;
+    private static final int WORK_MANAGER_THREAD_POOL_SIZE = 6;
     @Nullable
     private static volatile Executor sWorkManagerExecutor;
 
@@ -547,10 +547,11 @@
     /**
      * Handles notification about media events like inserts/updates/deletes received from cloud or
      * local providers.
+     * @param localOnly - whether the media event is coming from the local provider
      */
-    public void handleMediaEventNotification() {
+    public void handleMediaEventNotification(Boolean localOnly) {
         try {
-            mSyncManager.syncAllMediaProactively();
+            mSyncManager.syncMediaProactively(localOnly);
         } catch (RuntimeException e) {
             // Catch any unchecked exceptions so that critical paths in MP that call this method are
             // not affected by Picker related issues.
diff --git a/src/com/android/providers/media/photopicker/PickerSyncController.java b/src/com/android/providers/media/photopicker/PickerSyncController.java
index 67909d5..e03b332 100644
--- a/src/com/android/providers/media/photopicker/PickerSyncController.java
+++ b/src/com/android/providers/media/photopicker/PickerSyncController.java
@@ -121,6 +121,7 @@
     private static final int SYNC_TYPE_MEDIA_INCREMENTAL = 1;
     private static final int SYNC_TYPE_MEDIA_FULL = 2;
     private static final int SYNC_TYPE_MEDIA_RESET = 3;
+    private static final int SYNC_TYPE_MEDIA_FULL_WITH_RESET = 4;
     public static final int PAGE_SIZE = 1000;
     @NonNull
     private static final Handler sBgThreadHandler = BackgroundThread.getHandler();
@@ -129,10 +130,12 @@
             SYNC_TYPE_MEDIA_INCREMENTAL,
             SYNC_TYPE_MEDIA_FULL,
             SYNC_TYPE_MEDIA_RESET,
+            SYNC_TYPE_MEDIA_FULL_WITH_RESET,
     })
     @Retention(RetentionPolicy.SOURCE)
     private @interface SyncType {}
 
+    private static final long DEFAULT_GENERATION = -1;
     private final Context mContext;
     private final ConfigStore mConfigStore;
     private final PickerDbFacade mDbFacade;
@@ -702,14 +705,22 @@
                     // Can only happen when |authority| has been set to null and we need to clean up
                     disablePickerCloudMediaQueries(isLocal);
                     return resetAllMedia(authority, isLocal);
-                case SYNC_TYPE_MEDIA_FULL:
-                    NonUiEventLogger.logPickerFullSyncStart(instanceId, MY_UID, authority);
+                case SYNC_TYPE_MEDIA_FULL_WITH_RESET:
                     disablePickerCloudMediaQueries(isLocal);
                     if (!resetAllMedia(authority, isLocal)) {
                         return false;
                     }
                     enablePickerCloudMediaQueries(authority, isLocal);
 
+                    // Cache collection id with default generation id to prevent DB reset if full
+                    // sync resumes the next time sync is triggered.
+                    cacheMediaCollectionInfo(
+                            authority, isLocal,
+                            getDefaultGenerationCollectionInfo(params.latestMediaCollectionInfo));
+                    // Fall through to run full sync
+                case SYNC_TYPE_MEDIA_FULL:
+                    NonUiEventLogger.logPickerFullSyncStart(instanceId, MY_UID, authority);
+
                     final Bundle fullSyncQueryArgs = new Bundle();
                     if (enablePagedSync) {
                         fullSyncQueryArgs.putInt(EXTRA_PAGE_SIZE, params.mPageSize);
@@ -1169,7 +1180,7 @@
         final String collectionId = mSyncPrefs.getString(
                 getPrefsKey(isLocal, MEDIA_COLLECTION_ID), /* default */ null);
         final long generation = mSyncPrefs.getLong(
-                getPrefsKey(isLocal, LAST_MEDIA_SYNC_GENERATION), /* default */ -1);
+                getPrefsKey(isLocal, LAST_MEDIA_SYNC_GENERATION), DEFAULT_GENERATION);
 
         bundle.putString(MEDIA_COLLECTION_ID, collectionId);
         bundle.putLong(LAST_MEDIA_SYNC_GENERATION, generation);
@@ -1191,6 +1202,14 @@
         }
     }
 
+    private Bundle getDefaultGenerationCollectionInfo(@NonNull Bundle latestCollectionInfo) {
+        final Bundle bundle = new Bundle();
+        final String collectionId = latestCollectionInfo.getString(MEDIA_COLLECTION_ID);
+        bundle.putString(MEDIA_COLLECTION_ID, collectionId);
+        bundle.putLong(LAST_MEDIA_SYNC_GENERATION, DEFAULT_GENERATION);
+        return bundle;
+    }
+
     @NonNull
     private SyncRequestParams getSyncRequestParams(@Nullable String authority,
             boolean isLocal) throws RequestObsoleteException, UnableToAcquireLockException {
@@ -1246,6 +1265,8 @@
             }
 
             if (!Objects.equals(latestCollectionId, cachedCollectionId)) {
+                result = SyncRequestParams.forFullMediaWithReset(latestMediaCollectionInfo);
+            } else if (cachedGeneration == DEFAULT_GENERATION) {
                 result = SyncRequestParams.forFullMedia(latestMediaCollectionInfo);
             } else if (cachedGeneration == latestGeneration) {
                 result = SyncRequestParams.forNone();
@@ -1674,7 +1695,12 @@
             return SYNC_REQUEST_MEDIA_RESET;
         }
 
-        static SyncRequestParams forFullMedia(Bundle latestMediaCollectionInfo) {
+        static SyncRequestParams forFullMediaWithReset(@NonNull Bundle latestMediaCollectionInfo) {
+            return new SyncRequestParams(SYNC_TYPE_MEDIA_FULL_WITH_RESET, /* generation */ 0,
+                    latestMediaCollectionInfo, /*pageSize */ PAGE_SIZE);
+        }
+
+        static SyncRequestParams forFullMedia(@NonNull Bundle latestMediaCollectionInfo) {
             return new SyncRequestParams(SYNC_TYPE_MEDIA_FULL, /* generation */ 0,
                     latestMediaCollectionInfo, /*pageSize */ PAGE_SIZE);
         }
@@ -1702,6 +1728,8 @@
                 return "MEDIA_FULL";
             case SYNC_TYPE_MEDIA_RESET:
                 return "MEDIA_RESET";
+            case SYNC_TYPE_MEDIA_FULL_WITH_RESET:
+                return "MEDIA_FULL_WITH_RESET";
             default:
                 return "Unknown";
         }
diff --git a/src/com/android/providers/media/photopicker/SelectedMediaPreloader.java b/src/com/android/providers/media/photopicker/SelectedMediaPreloader.java
index 8e3273a..deefc1b 100644
--- a/src/com/android/providers/media/photopicker/SelectedMediaPreloader.java
+++ b/src/com/android/providers/media/photopicker/SelectedMediaPreloader.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.os.Looper;
 import android.util.Log;
+import android.widget.Button;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -303,11 +304,17 @@
         dialog.setCancelable(false);
 
         dialog.setButton(DialogInterface.BUTTON_NEGATIVE,
-                // TODO(b/303013634): Add a Cancel string for this dialog and don't re-use an
-                // existing string.
-                context.getString(R.string.transcode_cancel), (dialog1, which) -> {
+                context.getString(R.string.preloading_cancel_button), (dialog1, which) -> {
                 mIsPreloadingCancelledLiveData.setValue(true);
             });
+        dialog.create();
+
+        Button cancelButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+        if (cancelButton != null) {
+            cancelButton.setTextAppearance(R.style.ProgressDialogCancelButtonStyle);
+            cancelButton.setAllCaps(false);
+        }
+
         dialog.show();
 
         return dialog;
@@ -355,4 +362,4 @@
         }
         return String.format("%.1f s", ms / 1000.0);
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/providers/media/photopicker/data/PickerDbFacade.java b/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
index cd51b9b..3fcdad9 100644
--- a/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
+++ b/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
@@ -33,6 +33,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.database.MergeCursor;
 import android.database.sqlite.SQLiteConstraintException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteQueryBuilder;
@@ -884,9 +885,13 @@
      * {@code limit}. They can also be filtered with {@code query}.
      */
     public Cursor queryMediaForUi(QueryFilter query) {
+        if (query.mIsLocalOnly && query.mLocalIdSelection != null
+                && !query.mLocalIdSelection.isEmpty()) {
+            return queryMediaForUiWithLocalIdSelection(query);
+        }
+
         final SQLiteQueryBuilder qb = createVisibleMediaQueryBuilder();
         final String[] selectionArgs = buildSelectionArgs(qb, query);
-
         if (query.mIsLocalOnly) {
             return queryMediaForUi(qb, selectionArgs, query.mLimit,  /* isLocalOnly*/true,
                     TABLE_MEDIA, /* cloudProvider*/ null);
@@ -901,6 +906,36 @@
                 TABLE_MEDIA, cloudProvider);
     }
 
+
+    private Cursor queryMediaForUiWithLocalIdSelection(QueryFilter query) {
+        // Since 'WHERE IN' clause has an upper limit of items that can be included in the sql
+        // statement and also there is an upper limit to the size of the sql statement.
+        // Splitting the query into multiple smaller ones.
+        // This query will now process 150 items in a batch.
+        List<List<Integer>> listOfSelectionArgsForLocalId = splitArrayList(
+                query.mLocalIdSelection,
+                /* number of ids per query */ 150);
+        List<Cursor> resultCursor = new ArrayList<>();
+
+        for (List<Integer> selectionArgForLocalIdSelection : listOfSelectionArgsForLocalId) {
+            final SQLiteQueryBuilder qb = createVisibleMediaQueryBuilder();
+            query.mLocalIdSelection = selectionArgForLocalIdSelection;
+            final String[] selectionArgs = buildSelectionArgs(qb, query);
+            resultCursor.add(queryMediaForUi(qb, selectionArgs, query.mLimit, true,
+                    TABLE_MEDIA, /* cloud provider */null));
+        }
+
+        return new MergeCursor(resultCursor.toArray(new Cursor[resultCursor.size()]));
+    }
+
+    private static <T> List<List<T>> splitArrayList(List<T> list, int chunkSize) {
+        List<List<T>> subLists = new ArrayList<>();
+        for (int i = 0; i < list.size(); i += chunkSize) {
+            subLists.add(list.subList(i, Math.min(i + chunkSize, list.size())));
+        }
+        return subLists;
+    }
+
     /**
      * Returns sorted cloud or local media items from the picker db for a given album (either cloud
      * or local).
diff --git a/src/com/android/providers/media/photopicker/data/Selection.java b/src/com/android/providers/media/photopicker/data/Selection.java
index 90bca93..d7667d3 100644
--- a/src/com/android/providers/media/photopicker/data/Selection.java
+++ b/src/com/android/providers/media/photopicker/data/Selection.java
@@ -33,6 +33,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -53,14 +54,15 @@
     private final Map<Item, Integer> mCheckedItemIndexes = new HashMap<>();
 
     // The list of selected items.
-    private Map<Uri, Item> mSelectedItems = new HashMap<>();
-
+    private Map<Uri, Item> mSelectedItems = new LinkedHashMap<>();
+    private Map<Uri, MutableLiveData<Integer>> mSelectedItemsOrder = new HashMap<>();
     private Map<String, Item> mItemGrantRevocationMap = new HashMap<>();
 
     private MutableLiveData<Integer> mSelectedItemSize = new MutableLiveData<>();
     // The list of selected items for preview. This needs to be saved separately so that if activity
     // gets killed, we will still have deselected items for preview.
     private List<Item> mSelectedItemsForPreview = new ArrayList<>();
+    private boolean mIsSelectionOrdered = false;
     private boolean mSelectMultiple = false;
     private int mMaxSelectionLimit = 1;
     // This is set to false when max selection limit is reached.
@@ -99,7 +101,8 @@
      * @return {@link #mSelectedItems} - A {@link List} of selected {@link Item}
      */
     public List<Item> getSelectedItems() {
-        return Collections.unmodifiableList(new ArrayList<>(mSelectedItems.values()));
+        ArrayList<Item> result = new ArrayList<>(mSelectedItems.values());
+        return Collections.unmodifiableList(result);
     }
 
     /**
@@ -158,6 +161,13 @@
         return mSelectedItemSize;
     }
 
+    /**
+     * @return {@link LiveData} of the item selection order.
+     */
+    public LiveData<Integer> getSelectedItemOrder(Item item) {
+        return mSelectedItemsOrder.get(item.getContentUri());
+    }
+
     private int getTotalItemsCount() {
         return mSelectedItems.size() - countOfPreGrantedItems() + mTotalNumberOfPreGrantedItems
                 - mItemGrantRevocationMap.size();
@@ -170,6 +180,10 @@
         if (item.isPreGranted() && mItemGrantRevocationMap.containsKey(item.getId())) {
             mItemGrantRevocationMap.remove(item.getId());
         }
+        if (mIsSelectionOrdered) {
+            mSelectedItemsOrder.put(
+                    item.getContentUri(), new MutableLiveData(getTotalItemsCount() + 1));
+        }
         mSelectedItems.put(item.getContentUri(), item);
         mSelectedItemSize.postValue(getTotalItemsCount());
         updateSelectionAllowed();
@@ -186,8 +200,13 @@
      * Clears {@link #mSelectedItems} and sets the selected item as given {@code item}
      */
     public void setSelectedItem(Item item) {
+        mSelectedItemsOrder.clear();
         mSelectedItems.clear();
         mSelectedItems.put(item.getContentUri(), item);
+        if (mIsSelectionOrdered) {
+            mSelectedItemsOrder.put(
+                    item.getContentUri(), new MutableLiveData(getTotalItemsCount()));
+        }
         mSelectedItemSize.postValue(getTotalItemsCount());
         updateSelectionAllowed();
     }
@@ -204,6 +223,16 @@
             // items.
             mItemGrantRevocationMap.put(item.getId(), item);
         }
+        if (mIsSelectionOrdered) {
+            MutableLiveData<Integer> removedItem = mSelectedItemsOrder.remove(item.getContentUri());
+            int removedItemOrder = removedItem.getValue().intValue();
+            mSelectedItemsOrder.values().stream()
+                    .filter(order -> order.getValue().intValue() > removedItemOrder)
+                    .forEach(
+                            order -> {
+                                order.setValue(order.getValue().intValue() - 1);
+                            });
+        }
         mSelectedItems.remove(item.getContentUri());
         mSelectedItemSize.postValue(getTotalItemsCount());
         updateSelectionAllowed();
@@ -222,6 +251,7 @@
      * Clear all selected items and checked positions
      */
     public void clearSelectedItems() {
+        mSelectedItemsOrder.clear();
         mSelectedItems.clear();
         mCheckedItemIndexes.clear();
         mSelectedItemSize.postValue(getTotalItemsCount());
@@ -303,11 +333,15 @@
         final Bundle extras = intent.getExtras();
         final boolean isExtraPickImagesMaxSet =
                 extras != null && extras.containsKey(MediaStore.EXTRA_PICK_IMAGES_MAX);
+        final boolean isExtraOrderedSelectionSet =
+                extras != null && extras.containsKey(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER);
 
         if (intent.getAction() != null
                 && intent.getAction().equals(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP)) {
             // If this is picking media for an app, enable multiselect.
             mSelectMultiple = true;
+            // disable ordered selection.
+            mIsSelectionOrdered = false;
             // Allow selections up to the limit.
             // TODO(b/255301849): Update max limit after discussing with product team.
             mMaxSelectionLimit = MediaStore.getPickImagesMaxLimit();
@@ -321,6 +355,11 @@
                         "EXTRA_PICK_IMAGES_MAX is not supported for " + "ACTION_GET_CONTENT");
             }
 
+            if (isExtraOrderedSelectionSet) {
+                throw new IllegalArgumentException(
+                        "EXTRA_PICK_IMAGES_IN_ORDER is not supported for ACTION_GET_CONTENT");
+            }
+
             mSelectMultiple = intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
             if (mSelectMultiple) {
                 mMaxSelectionLimit = MediaStore.getPickImagesMaxLimit();
@@ -329,6 +368,10 @@
             return;
         }
 
+        if (isExtraOrderedSelectionSet) {
+            mIsSelectionOrdered = extras.getBoolean(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER);
+        }
+
         // Check EXTRA_PICK_IMAGES_MAX value only if the flag is set.
         if (isExtraPickImagesMaxSet) {
             final int extraMax =
@@ -342,6 +385,7 @@
             mSelectMultiple = true;
             mMaxSelectionLimit = extraMax;
         }
+
     }
 
     /**
@@ -351,6 +395,11 @@
         return mSelectMultiple;
     }
 
+    /** Return whether ordered selection is enabled or not. */
+    public boolean isSelectionOrdered() {
+        return mIsSelectionOrdered;
+    }
+
     /**
      * Return maximum limit of items that can be selected
      */
diff --git a/src/com/android/providers/media/photopicker/metrics/NonUiEventLogger.java b/src/com/android/providers/media/photopicker/metrics/NonUiEventLogger.java
index 54a53e2..b15d2ed 100644
--- a/src/com/android/providers/media/photopicker/metrics/NonUiEventLogger.java
+++ b/src/com/android/providers/media/photopicker/metrics/NonUiEventLogger.java
@@ -50,7 +50,13 @@
         @UiEvent(doc = "Ended get media collection info in photo picker")
         PHOTO_PICKER_GET_MEDIA_COLLECTION_INFO_END(1450),
         @UiEvent(doc = "Ended get albums in photo picker")
-        PHOTO_PICKER_GET_ALBUMS_END(1451);
+        PHOTO_PICKER_GET_ALBUMS_END(1451),
+        @UiEvent(doc = "Read grants added count.")
+        PHOTO_PICKER_GRANTS_ADDED_COUNT(1528),
+        @UiEvent(doc = "Read grants revoked count.")
+        PHOTO_PICKER_GRANTS_REVOKED_COUNT(1529),
+        @UiEvent(doc = "Total initial grants count.")
+        PHOTO_PICKER_INIT_GRANTS_COUNT(1530);
 
         private final int mId;
 
@@ -221,4 +227,44 @@
         LOGGER.logWithInstanceIdAndPosition(NonUiEvent.PHOTO_PICKER_GET_ALBUMS_END, uid, authority,
                 instanceId, count);
     }
+
+    /**
+     * Log metrics for count of grants added for a package.
+     * @param instanceId   an identifier for the current session
+     * @param uid          the uid of the MediaProvider logging this metric
+     * @param packageName  the package name receiving the grant.
+     * @param count        the number of items for which the grants have been added.
+     */
+    public static void logPickerChoiceGrantsAdditionCount(InstanceId instanceId, int uid,
+            String packageName, int count) {
+        LOGGER.logWithInstanceIdAndPosition(NonUiEvent.PHOTO_PICKER_GRANTS_ADDED_COUNT, uid,
+                packageName, instanceId, count);
+    }
+
+    /**
+     * Log metrics for count of grants revoked for a package.
+     * @param instanceId   an identifier for the current session
+     * @param uid          the uid of the MediaProvider logging this metric
+     * @param packageName  the package name for which the grants are being revoked.
+     * @param count        the number of items for which the grants have been revoked.
+     */
+    public static void logPickerChoiceGrantsRemovedCount(InstanceId instanceId, int uid,
+            String packageName, int count) {
+        LOGGER.logWithInstanceIdAndPosition(NonUiEvent.PHOTO_PICKER_GRANTS_REVOKED_COUNT, uid,
+                packageName, instanceId, count);
+    }
+
+    /**
+     * Log metrics for total count of grants previously added for the package.
+     * @param instanceId   an identifier for the current session
+     * @param uid          the uid of the MediaProvider logging this metric
+     * @param packageName  the package name for which the grants are being initialized.
+     * @param count        the number of items for which the grants have been initialized.
+     */
+    public static void logPickerChoiceInitGrantsCount(InstanceId instanceId, int uid,
+            String packageName, int count) {
+        LOGGER.logWithInstanceIdAndPosition(NonUiEvent.PHOTO_PICKER_INIT_GRANTS_COUNT, uid,
+                packageName, instanceId, count);
+    }
+
 }
diff --git a/src/com/android/providers/media/photopicker/metrics/PhotoPickerUiEventLogger.java b/src/com/android/providers/media/photopicker/metrics/PhotoPickerUiEventLogger.java
index 2f1cca4..e127e05 100644
--- a/src/com/android/providers/media/photopicker/metrics/PhotoPickerUiEventLogger.java
+++ b/src/com/android/providers/media/photopicker/metrics/PhotoPickerUiEventLogger.java
@@ -113,7 +113,23 @@
         @UiEvent(doc = "Triggered create surface controller in photo picker")
         PHOTO_PICKER_CREATE_SURFACE_CONTROLLER_START(1452),
         @UiEvent(doc = "Ended create surface controller in photo picker")
-        PHOTO_PICKER_CREATE_SURFACE_CONTROLLER_END(1453);
+        PHOTO_PICKER_CREATE_SURFACE_CONTROLLER_END(1453),
+        @UiEvent(doc = "Started the selected media preloading in photo picker")
+        PHOTO_PICKER_PRELOADING_STARTED(1524),
+        @UiEvent(doc = "Finished the selected media preloading in photo picker")
+        PHOTO_PICKER_PRELOADING_FINISHED(1525),
+        @UiEvent(doc = "User cancelled the selected media preloading in photo picker")
+        PHOTO_PICKER_PRELOADING_CANCELLED(1526),
+        @UiEvent(doc = "Failed to preload some selected media items in photo picker")
+        PHOTO_PICKER_PRELOADING_FAILED(1527),
+        @UiEvent(doc = "The banner is added to display in the recycler view grids in photo picker")
+        PHOTO_PICKER_BANNER_ADDED(1539),
+        @UiEvent(doc = "The user clicks the dismiss button of the banner in photo picker")
+        PHOTO_PICKER_BANNER_DISMISSED(1540),
+        @UiEvent(doc = "The user clicks the action button of the banner in photo picker")
+        PHOTO_PICKER_BANNER_ACTION_BUTTON_CLICKED(1541),
+        @UiEvent(doc = "The user clicks on the remaining part of the banner in photo picker")
+        PHOTO_PICKER_BANNER_CLICKED(1542);
 
         private final int mId;
 
@@ -365,8 +381,8 @@
      * @param selectedItemCount the number of items selected for preview all
      */
     public void logPreviewAllSelected(InstanceId instanceId, int selectedItemCount) {
-        logger.logWithInstanceIdAndPosition(PhotoPickerEvent.PHOTO_PICKER_PREVIEW_ALL_SELECTED,
-                /* uid */ 0, /* packageName */ null, instanceId, selectedItemCount);
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_PREVIEW_ALL_SELECTED, instanceId,
+                selectedItemCount);
     }
 
     /**
@@ -407,8 +423,8 @@
      * @param backStackEntryCount the number of fragment entries currently in the back stack
      */
     public void logBackGestureWithStackCount(InstanceId instanceId, int backStackEntryCount) {
-        logger.logWithInstanceIdAndPosition(PhotoPickerEvent.PHOTO_PICKER_BACK_GESTURE, /* uid */ 0,
-                /* packageName */ null, instanceId, backStackEntryCount);
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_BACK_GESTURE, instanceId,
+                backStackEntryCount);
     }
 
     /**
@@ -417,9 +433,8 @@
      * @param backStackEntryCount the number of fragment entries currently in the back stack
      */
     public void logActionBarHomeButtonClick(InstanceId instanceId, int backStackEntryCount) {
-        logger.logWithInstanceIdAndPosition(
-                PhotoPickerEvent.PHOTO_PICKER_ACTION_BAR_HOME_BUTTON_CLICK, /* uid */ 0,
-                /* packageName */ null, instanceId, backStackEntryCount);
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_ACTION_BAR_HOME_BUTTON_CLICK,
+                instanceId, backStackEntryCount);
     }
 
     /**
@@ -500,8 +515,8 @@
      * @param position   the position of the album in the recycler view
      */
     public void logCloudAlbumOpened(InstanceId instanceId, int position) {
-        logger.logWithInstanceIdAndPosition(PhotoPickerEvent.PHOTO_PICKER_ALBUM_FROM_CLOUD_OPEN,
-                /* uid */ 0, /* packageName */ null, instanceId, position);
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_ALBUM_FROM_CLOUD_OPEN, instanceId,
+                position);
     }
 
     /**
@@ -510,8 +525,8 @@
      * @param position   the position of the album in the recycler view
      */
     public void logSelectedMainGridItem(InstanceId instanceId, int position) {
-        logger.logWithInstanceIdAndPosition(PhotoPickerEvent.PHOTO_PICKER_SELECTED_ITEM_MAIN_GRID,
-                /* uid */ 0, /* packageName */ null, instanceId, position);
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_SELECTED_ITEM_MAIN_GRID,
+                instanceId, position);
     }
 
     /**
@@ -520,8 +535,8 @@
      * @param position   the position of the album in the recycler view
      */
     public void logSelectedAlbumItem(InstanceId instanceId, int position) {
-        logger.logWithInstanceIdAndPosition(PhotoPickerEvent.PHOTO_PICKER_SELECTED_ITEM_ALBUM,
-                /* uid */ 0, /* packageName */ null, instanceId, position);
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_SELECTED_ITEM_ALBUM, instanceId,
+                position);
     }
 
     /**
@@ -530,8 +545,8 @@
      * @param position   the position of the album in the recycler view
      */
     public void logSelectedCloudOnlyItem(InstanceId instanceId, int position) {
-        logger.logWithInstanceIdAndPosition(PhotoPickerEvent.PHOTO_PICKER_SELECTED_ITEM_CLOUD_ONLY,
-                /* uid */ 0, /* packageName */ null, instanceId, position);
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_SELECTED_ITEM_CLOUD_ONLY,
+                instanceId, position);
     }
 
     /**
@@ -601,7 +616,86 @@
                 /* uid */ 0, authority, instanceId);
     }
 
+    /**
+     * Log metrics to notify that the picker has started preloading the selected media items
+     * @param instanceId an identifier for the current picker session
+     * @param count      the number of items to be preloaded
+     */
+    public void logPreloadingStarted(@NonNull InstanceId instanceId, int count) {
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_PRELOADING_STARTED, instanceId,
+                count);
+    }
+
+    /**
+     * Log metrics to notify that the picker has finished preloading the selected media items
+     * @param instanceId an identifier for the current picker session
+     */
+    public void logPreloadingFinished(@NonNull InstanceId instanceId) {
+        logWithInstance(PhotoPickerEvent.PHOTO_PICKER_PRELOADING_FINISHED, instanceId);
+    }
+
+    /**
+     * Log metrics to notify that the user cancelled the selected media preloading
+     * @param instanceId an identifier for the current picker session
+     * @param count      the number of items pending to preload
+     */
+    public void logPreloadingCancelled(@NonNull InstanceId instanceId, int count) {
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_PRELOADING_CANCELLED, instanceId,
+                count);
+    }
+
+    /**
+     * Log metrics to notify that the selected media preloading failed for some items
+     * @param instanceId an identifier for the current picker session
+     * @param count      the number of items pending / failed to preload
+     */
+    public void logPreloadingFailed(@NonNull InstanceId instanceId, int count) {
+        logWithInstanceAndPosition(PhotoPickerEvent.PHOTO_PICKER_PRELOADING_FAILED, instanceId,
+                count);
+    }
+
+    /**
+     * Log metrics to notify that the banner is added to display in the recycler view grids
+     * @param instanceId an identifier for the current picker session
+     * @param bannerName the name of the banner added,
+     *                   refer {@link com.android.providers.media.photopicker.ui.TabAdapter.Banner}
+     */
+    public void logBannerAdded(@NonNull InstanceId instanceId, @NonNull String bannerName) {
+        logger.logWithInstanceId(PhotoPickerEvent.PHOTO_PICKER_BANNER_ADDED, /* uid= */ 0,
+                bannerName, instanceId);
+    }
+
+    /**
+     * Log metrics to notify that the banner is dismissed by the user
+     * @param instanceId an identifier for the current picker session
+     */
+    public void logBannerDismissed(@NonNull InstanceId instanceId) {
+        logWithInstance(PhotoPickerEvent.PHOTO_PICKER_BANNER_DISMISSED, instanceId);
+    }
+
+    /**
+     * Log metrics to notify that the user clicked the banner action button
+     * @param instanceId an identifier for the current picker session
+     */
+    public void logBannerActionButtonClicked(@NonNull InstanceId instanceId) {
+        logWithInstance(PhotoPickerEvent.PHOTO_PICKER_BANNER_ACTION_BUTTON_CLICKED, instanceId);
+    }
+
+    /**
+     * Log metrics to notify that the user clicked on the remaining part of the banner
+     * @param instanceId an identifier for the current picker session
+     */
+    public void logBannerClicked(@NonNull InstanceId instanceId) {
+        logWithInstance(PhotoPickerEvent.PHOTO_PICKER_BANNER_CLICKED, instanceId);
+    }
+
     private void logWithInstance(@NonNull UiEventLogger.UiEventEnum event, InstanceId instance) {
         logger.logWithInstanceId(event, /* uid */ 0, /* packageName */ null, instance);
     }
+
+    private void logWithInstanceAndPosition(@NonNull UiEventLogger.UiEventEnum event,
+            @NonNull InstanceId instance, int position) {
+        logger.logWithInstanceIdAndPosition(event, /* uid= */ 0, /* packageName= */ null, instance,
+                position);
+    }
 }
diff --git a/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java b/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java
index ab94d20..b086967 100644
--- a/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java
+++ b/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java
@@ -93,6 +93,7 @@
     private static final int RESET_ALBUM_MEDIA_PERIODIC_WORK_INTERVAL = 12; // Time unit is hours.
 
     private static final String PERIODIC_SYNC_WORK_NAME;
+    private static final String PROACTIVE_LOCAL_SYNC_WORK_NAME;
     private static final String PROACTIVE_SYNC_WORK_NAME;
     public static final String IMMEDIATE_LOCAL_SYNC_WORK_NAME;
     private static final String IMMEDIATE_CLOUD_SYNC_WORK_NAME;
@@ -109,6 +110,7 @@
 
         PERIODIC_ALBUM_RESET_WORK_NAME = "RESET_ALBUM_MEDIA_PERIODIC";
         PERIODIC_SYNC_WORK_NAME = syncPeriodicPrefix + syncAllSuffix;
+        PROACTIVE_LOCAL_SYNC_WORK_NAME = syncProactivePrefix + syncLocalSuffix;
         PROACTIVE_SYNC_WORK_NAME = syncProactivePrefix + syncAllSuffix;
         IMMEDIATE_LOCAL_SYNC_WORK_NAME = syncImmediatePrefix + syncLocalSuffix;
         IMMEDIATE_CLOUD_SYNC_WORK_NAME = syncImmediatePrefix + syncCloudSuffix;
@@ -231,16 +233,23 @@
     /**
      * Use this method for proactive syncs. The sync might take a while to start. Some device state
      * conditions may apply before the sync can start like battery level etc.
+     *
+     * @param localOnly - whether the proactive sync should only sync with the local provider.
      */
-    public void syncAllMediaProactively() {
-        final Data inputData =
-                new Data(Map.of(SYNC_WORKER_INPUT_SYNC_SOURCE, SYNC_LOCAL_AND_CLOUD));
+    public void syncMediaProactively(Boolean localOnly) {
+
+        final int syncSource = localOnly ? SYNC_LOCAL_ONLY : SYNC_LOCAL_AND_CLOUD;
+        final String workName =
+                localOnly ? PROACTIVE_LOCAL_SYNC_WORK_NAME : PROACTIVE_SYNC_WORK_NAME;
+
+        final Data inputData = new Data(Map.of(SYNC_WORKER_INPUT_SYNC_SOURCE, syncSource));
         final OneTimeWorkRequest syncRequest = getOneTimeProactiveSyncRequest(inputData);
 
-        // Don't wait for the sync operation to enqueue so that Picker sync enqueue requests in
+        // Don't wait for the sync operation to enqueue so that Picker sync enqueue
+        // requests in
         // order to avoid adding latency to critical MP code paths.
-        mWorkManager.enqueueUniqueWork(PROACTIVE_SYNC_WORK_NAME, ExistingWorkPolicy.KEEP,
-                syncRequest);
+
+        mWorkManager.enqueueUniqueWork(workName, ExistingWorkPolicy.KEEP, syncRequest);
     }
 
     /**
@@ -351,41 +360,40 @@
         return new PeriodicWorkRequest.Builder(
                 ProactiveSyncWorker.class, SYNC_MEDIA_PERIODIC_WORK_INTERVAL, TimeUnit.HOURS)
                 .setInputData(inputData)
-                .setConstraints(getProactiveSyncConstraints())
+                .setConstraints(getRequiresChargingAndIdleConstraints())
                 .build();
     }
 
     @NotNull
     private PeriodicWorkRequest getPeriodicAlbumResetRequest(@NotNull Data inputData) {
 
-        Constraints constraints =
-                new Constraints.Builder()
-                        .setRequiresBatteryNotLow(true)
-                        .setRequiresDeviceIdle(true)
-                        .build();
-
         return new PeriodicWorkRequest.Builder(
                         MediaResetWorker.class,
                         RESET_ALBUM_MEDIA_PERIODIC_WORK_INTERVAL,
                         TimeUnit.HOURS)
                 .setInputData(inputData)
-                .setConstraints(constraints)
+                .setConstraints(getRequiresChargingAndIdleConstraints())
                 .addTag(SYNC_WORKER_TAG_IS_PERIODIC)
                 .build();
     }
 
     @NotNull
     private OneTimeWorkRequest getOneTimeProactiveSyncRequest(@NotNull Data inputData) {
+        Constraints constraints =  new Constraints.Builder()
+                .setRequiresBatteryNotLow(true)
+                .build();
+
         return new OneTimeWorkRequest.Builder(ProactiveSyncWorker.class)
                 .setInputData(inputData)
-                .setConstraints(getProactiveSyncConstraints())
+                .setConstraints(constraints)
                 .build();
     }
 
     @NotNull
-    private static Constraints getProactiveSyncConstraints() {
+    private static Constraints getRequiresChargingAndIdleConstraints() {
         return new Constraints.Builder()
-                .setRequiresBatteryNotLow(true)
+                .setRequiresCharging(true)
+                .setRequiresDeviceIdle(true)
                 .build();
     }
 
diff --git a/src/com/android/providers/media/photopicker/ui/ImageLoader.java b/src/com/android/providers/media/photopicker/ui/ImageLoader.java
index 6c44f4d..12433fc 100644
--- a/src/com/android/providers/media/photopicker/ui/ImageLoader.java
+++ b/src/com/android/providers/media/photopicker/ui/ImageLoader.java
@@ -20,12 +20,9 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.ImageDecoder;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
 import android.provider.CloudMediaProviderContract;
 import android.provider.MediaStore;
-import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -59,6 +56,7 @@
             RequestOptions.option(THUMBNAIL_REQUEST, /* enableThumbnail */ true);
     private final Context mContext;
     private final PreferredColorSpace mPreferredColorSpace;
+    private static final String PREVIEW_PREFIX = "preview_";
 
     public ImageLoader(Context context) {
         mContext = context;
@@ -122,13 +120,17 @@
             loadWithGlide(
                     getGifRequestBuilder(loadable),
                     /* requestOptions */ null,
-                    getGlideSignature(loadable, /* prefix= */ null),
+                    getGlideSignature(loadable, /* prefix= */ PREVIEW_PREFIX),
                     imageView);
             return;
         }
 
         if (item.isAnimatedWebp()) {
-            loadAnimatedWebpPreview(loadable, imageView);
+            loadWithGlide(
+                    getDrawableRequestBuilder(loadable),
+                    /* requestOptions */ null,
+                    getGlideSignature(loadable, PREVIEW_PREFIX),
+                    imageView);
             return;
         }
 
@@ -136,30 +138,7 @@
         loadWithGlide(
                 getBitmapRequestBuilder(loadable),
                 /* requestOptions */ null,
-                getGlideSignature(loadable, /* prefix= */ null),
-                imageView);
-    }
-
-    private void loadAnimatedWebpPreview(
-            @NonNull GlideLoadable loadable, @NonNull ImageView imageView) {
-        final Uri uri = loadable.getLoadableUri();
-        final ImageDecoder.Source source =
-                ImageDecoder.createSource(mContext.getContentResolver(), uri);
-        Drawable drawable = null;
-        try {
-            drawable = ImageDecoder.decodeDrawable(source);
-        } catch (Exception e) {
-            Log.d(TAG, "Failed to decode drawable for uri: " + uri, e);
-        }
-
-        // If we failed to decode drawable for a source using ImageDecoder, then try
-        // using uri directly. Glide will show static image for an animated webp. That
-        // is okay as we tried our best to load animated webp but couldn't, and we
-        // anyway show the GIF badge in preview.
-        loadWithGlide(
-                getDrawableRequestBuilder(drawable == null ? loadable : drawable),
-                /* requestOptions */ null,
-                getGlideSignature(loadable, null),
+                getGlideSignature(loadable, /* prefix= */ PREVIEW_PREFIX),
                 imageView);
     }
 
@@ -171,7 +150,7 @@
         loadWithGlide(
                 getBitmapRequestBuilder(loadable),
                 new RequestOptions().frame(1000),
-                getGlideSignature(loadable, "Preview"),
+                getGlideSignature(loadable, /* prefix= */ PREVIEW_PREFIX),
                 imageView);
     }
 
diff --git a/src/com/android/providers/media/photopicker/ui/MediaItemGridViewHolder.java b/src/com/android/providers/media/photopicker/ui/MediaItemGridViewHolder.java
index c6aa300..fef4ad3 100644
--- a/src/com/android/providers/media/photopicker/ui/MediaItemGridViewHolder.java
+++ b/src/com/android/providers/media/photopicker/ui/MediaItemGridViewHolder.java
@@ -25,6 +25,8 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LiveData;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.providers.media.R;
@@ -35,6 +37,7 @@
  * a video).
  */
 class MediaItemGridViewHolder extends RecyclerView.ViewHolder {
+    private final LifecycleOwner mLifecycleOwner;
     private final ImageLoader mImageLoader;
     private final ImageView mIconThumb;
     private final ImageView mIconGif;
@@ -43,14 +46,24 @@
     private final TextView mVideoDuration;
     private final View mOverlayGradient;
     private final boolean mCanSelectMultiple;
+    private final boolean mShowOrderedSelectionLabel;
+    private final TextView mSelectedOrderText;
+    private LiveData<Integer> mSelectionOrder;
+    private final ImageView mCheckIcon;
 
     private final View.OnHoverListener mOnMediaItemHoverListener;
     private final PhotosTabAdapter.OnMediaItemClickListener mOnMediaItemClickListener;
 
-    MediaItemGridViewHolder(@NonNull View itemView, @NonNull ImageLoader imageLoader,
+    MediaItemGridViewHolder(
+            @NonNull LifecycleOwner lifecycleOwner,
+            @NonNull View itemView,
+            @NonNull ImageLoader imageLoader,
             @NonNull PhotosTabAdapter.OnMediaItemClickListener onMediaItemClickListener,
-            View.OnHoverListener onMediaItemHoverListener, boolean canSelectMultiple) {
+            View.OnHoverListener onMediaItemHoverListener,
+            boolean canSelectMultiple,
+            boolean isOrderedSelection) {
         super(itemView);
+        mLifecycleOwner = lifecycleOwner;
         mIconThumb = itemView.findViewById(R.id.icon_thumbnail);
         mIconGif = itemView.findViewById(R.id.icon_gif);
         mIconMotionPhoto = itemView.findViewById(R.id.icon_motion_photo);
@@ -60,14 +73,19 @@
         mImageLoader = imageLoader;
         mOnMediaItemClickListener = onMediaItemClickListener;
         mCanSelectMultiple = canSelectMultiple;
+        mShowOrderedSelectionLabel = isOrderedSelection;
         mOnMediaItemHoverListener = onMediaItemHoverListener;
-
-        itemView.findViewById(R.id.icon_check).setVisibility(mCanSelectMultiple ? VISIBLE : GONE);
+        mSelectedOrderText = itemView.findViewById(R.id.selected_order);
+        mCheckIcon = itemView.findViewById(R.id.icon_check);
+        mCheckIcon.setVisibility(
+                (mCanSelectMultiple && !mShowOrderedSelectionLabel) ? VISIBLE : GONE);
+        mSelectedOrderText.setVisibility(
+                (mCanSelectMultiple && mShowOrderedSelectionLabel) ? VISIBLE : GONE);
     }
 
     public void bind(@NonNull Item item, boolean isSelected) {
         int position = getAbsoluteAdapterPosition();
-        itemView.setOnClickListener(v -> mOnMediaItemClickListener.onItemClick(v, position));
+        itemView.setOnClickListener(v -> mOnMediaItemClickListener.onItemClick(v, position, this));
         itemView.setOnLongClickListener(v ->
                 mOnMediaItemClickListener.onItemLongClick(v, position));
         itemView.setOnHoverListener(mOnMediaItemHoverListener);
@@ -95,6 +113,7 @@
 
         if (mCanSelectMultiple) {
             itemView.setSelected(isSelected);
+            mSelectedOrderText.setText("");
             // There is an issue b/223695510 about not selected in Accessibility mode. It only
             // says selected state, but it doesn't say not selected state. Add the not selected
             // only to avoid that it says selected twice.
@@ -103,6 +122,24 @@
         }
     }
 
+    /** Sets the LiveData selection order for the current grid item view. */
+    public void setSelectionOrder(LiveData<Integer> selectionOrder) {
+        if (selectionOrder == null) {
+            mSelectedOrderText.setText("");
+            if (mSelectionOrder != null) {
+                mSelectionOrder.removeObservers(mLifecycleOwner);
+            }
+        } else {
+            mSelectedOrderText.setText(selectionOrder.getValue().toString());
+            selectionOrder.observe(
+                    mLifecycleOwner,
+                    val -> {
+                        mSelectedOrderText.setText(val.toString());
+                    });
+        }
+        mSelectionOrder = selectionOrder;
+    }
+
     @NonNull
     private Context getContext() {
         return itemView.getContext();
@@ -122,4 +159,12 @@
                 || item.isVideo()
                 || item.isMotionPhoto();
     }
+
+    /** Release any non-reusable resources, as the view is being recycled. */
+    public void release() {
+        if (mSelectionOrder != null) {
+            mSelectionOrder.removeObservers(mLifecycleOwner);
+            mSelectionOrder = null;
+        }
+    }
 }
diff --git a/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java b/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
index 38d2fc9..1a4f4e7 100644
--- a/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
+++ b/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
@@ -45,7 +45,7 @@
 public class PhotosTabAdapter extends TabAdapter {
 
     private static final int RECENT_MINIMUM_COUNT = 12;
-
+    private final LifecycleOwner mLifecycleOwner;
     private final boolean mShowRecentSection;
     private final OnMediaItemClickListener mOnMediaItemClickListener;
     private final Selection mSelection;
@@ -75,6 +75,7 @@
                 shouldShowAccountUpdatedBanner, shouldShowChooseAccountBanner,
                 onChooseAppBannerEventListener, onCloudMediaAvailableBannerEventListener,
                 onAccountUpdatedBannerEventListener, onChooseAccountBannerEventListener);
+        mLifecycleOwner = lifecycleOwner;
         mShowRecentSection = showRecentSection;
         mSelection = selection;
         mOnMediaItemClickListener = onMediaItemClickListener;
@@ -95,11 +96,13 @@
         final View view = getView(viewGroup, R.layout.item_photo_grid);
         final MediaItemGridViewHolder viewHolder =
                 new MediaItemGridViewHolder(
+                        mLifecycleOwner,
                         view,
                         mImageLoader,
                         mOnMediaItemClickListener,
                         mOnMediaItemHoverListener,
-                        mSelection.canSelectMultiple());
+                        mSelection.canSelectMultiple(),
+                        mSelection.isSelectionOrdered());
         mPreloadSizeProvider.setView(viewHolder.getThumbnailImageView());
         return viewHolder;
     }
@@ -119,12 +122,15 @@
 
         final boolean isSelected = mSelection.canSelectMultiple()
                 && mSelection.isItemSelected(item);
+
         if (isSelected) {
             mSelection.addCheckedItemIndex(item, position);
         }
 
         mediaItemVH.bind(item, isSelected);
-
+        if (isSelected && mSelection.isSelectionOrdered()) {
+            mediaItemVH.setSelectionOrder(mSelection.getSelectedItemOrder(item));
+        }
         // We also need to set Item as a tag so that OnClick/OnLongClickListeners can then
         // retrieve it.
         mediaItemVH.itemView.setTag(item);
@@ -207,7 +213,7 @@
     }
 
     interface OnMediaItemClickListener {
-        void onItemClick(@NonNull View view, int position);
+        void onItemClick(@NonNull View view, int position, MediaItemGridViewHolder viewHolder);
 
         boolean onItemLongClick(@NonNull View view, int position);
     }
diff --git a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
index f329a44..0917b55 100644
--- a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
@@ -153,8 +153,8 @@
                         showRecentSection,
                         mSelection,
                         mImageLoader,
-                        mOnMediaItemClickListener, /* lifecycleOwner */
-                        this,
+                        mOnMediaItemClickListener,
+                        this, /* lifecycleOwner */
                         mPickerViewModel.getCloudMediaProviderAppTitleLiveData(),
                         mPickerViewModel.getCloudMediaAccountNameLiveData(),
                         showChooseAppBanner,
@@ -231,14 +231,19 @@
         mRecyclerView.setAdapter(adapter);
         mRecyclerView.addItemDecoration(itemDecoration);
 
-        // Listen for views as they are being recycled and attempt to cancel any pending glide load
-        // requests to prevent a large backlog of requests building up in the event of really
-        // large scrolls.
         mRecyclerView.addRecyclerListener(
                 new RecyclerView.RecyclerListener() {
                     @Override
                     public void onViewRecycled(RecyclerView.ViewHolder holder) {
-                        cancelGlideLoadForViewHolder(holder);
+                        if (mGlideRequestManager != null
+                                && holder.getItemViewType() == ITEM_TYPE_MEDIA_ITEM) {
+                            // This cast is safe as we've already checked the view type is
+                            MediaItemGridViewHolder vh = (MediaItemGridViewHolder) holder;
+                            // Cancel pending glide load requests on recycling, to prevent a large
+                            // backlog of requests building up in the event of large scrolls.
+                            cancelGlideLoadForViewHolder(vh);
+                            vh.release();
+                        }
                     }
                 });
         mRecyclerView.setItemViewCacheSize(10);
@@ -414,7 +419,8 @@
     private final PhotosTabAdapter.OnMediaItemClickListener mOnMediaItemClickListener =
             new PhotosTabAdapter.OnMediaItemClickListener() {
                 @Override
-                public void onItemClick(@NonNull View view, int position) {
+                public void onItemClick(
+                        @NonNull View view, int position, MediaItemGridViewHolder viewHolder) {
 
                     if (mSelection.canSelectMultiple()) {
                         final boolean isSelectedBefore =
@@ -423,6 +429,9 @@
 
                         Item item = (Item) view.getTag();
                         if (isSelectedBefore) {
+                            if (mSelection.isSelectionOrdered()) {
+                                viewHolder.setSelectionOrder(null);
+                            }
                             mSelection.removeSelectedItem((Item) view.getTag());
                             mSelection.removeCheckedItemIndex((Item) view.getTag());
                         } else {
@@ -432,14 +441,19 @@
                                 final CharSequence quantityText =
                                         StringUtils.getICUFormatString(
                                                 getResources(), maxCount, R.string.select_up_to);
-                                final String itemCountString = NumberFormat
-                                        .getInstance(Locale.getDefault()).format(maxCount);
-                                final CharSequence message = TextUtils.expandTemplate(quantityText,
-                                        itemCountString);
+                                final String itemCountString =
+                                        NumberFormat.getInstance(Locale.getDefault())
+                                                .format(maxCount);
+                                final CharSequence message =
+                                        TextUtils.expandTemplate(quantityText, itemCountString);
                                 Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show();
                                 return;
                             } else {
                                 mSelection.addSelectedItem(item);
+                                if (mSelection.isSelectionOrdered()) {
+                                    viewHolder.setSelectionOrder(
+                                            mSelection.getSelectedItemOrder(item));
+                                }
                                 mPickerViewModel.logMediaItemSelected(item, mCategory, position);
                             }
                         }
@@ -478,7 +492,8 @@
 
                     try {
                         // Transition to PreviewFragment.
-                        PreviewFragment.show(requireActivity().getSupportFragmentManager(),
+                        PreviewFragment.show(
+                                requireActivity().getSupportFragmentManager(),
                                 PreviewFragment.getArgsForPreviewOnLongPress());
                     } catch (RuntimeException e) {
                         Log.e(TAG, "Fragment is likely not attached to an activity. ", e);
@@ -596,15 +611,10 @@
      *
      * @param holder The View holder in the RecyclerView to cancel requests for.
      */
-    private void cancelGlideLoadForViewHolder(RecyclerView.ViewHolder holder) {
-
-        if (mGlideRequestManager != null && holder.getItemViewType() == ITEM_TYPE_MEDIA_ITEM) {
-            // This cast is safe as we've already checked the view type is
-            MediaItemGridViewHolder vh = (MediaItemGridViewHolder) holder;
-            // Attempt to clear the potential pending load out of glide's request
-            // manager.
-            mGlideRequestManager.clear(vh.getThumbnailImageView());
-        }
+    private void cancelGlideLoadForViewHolder(MediaItemGridViewHolder vh) {
+        // Attempt to clear the potential pending load out of glide's request
+        // manager.
+        mGlideRequestManager.clear(vh.getThumbnailImageView());
     }
 
     @Override
diff --git a/src/com/android/providers/media/photopicker/ui/PreviewFragment.java b/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
index 8e4f120..31209d1 100644
--- a/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
@@ -243,7 +243,9 @@
                                             /* context= */ getContext(),
                                             /* size= */ selectedItemCount,
                                             /* isUserSelectForApp= */ mPickerViewModel
-                                                    .isUserSelectForApp()));
+                                                    .isUserSelectForApp(),
+                                            /* isManagedSelectionEnabled */
+                                            mPickerViewModel.isManagedSelectionEnabled()));
                         });
 
         selectedCheckButton.setOnClickListener(
@@ -391,7 +393,11 @@
 
     // TODO: There is a same method in TabFragment. To find a way to reuse it.
     private static String generateAddButtonString(
-            @NonNull Context context, int size, boolean isUserSelectForApp) {
+            @NonNull Context context, int size, boolean isUserSelectForApp,
+            boolean isManagedSelection) {
+        if (isManagedSelection && size == 0) {
+            return context.getString(R.string.picker_add_button_allow_none_option);
+        }
         final String sizeString = NumberFormat.getInstance(Locale.getDefault()).format(size);
         final String template =
                 isUserSelectForApp
diff --git a/src/com/android/providers/media/photopicker/ui/TabAdapter.java b/src/com/android/providers/media/photopicker/ui/TabAdapter.java
index 3295941..86f2de7 100644
--- a/src/com/android/providers/media/photopicker/ui/TabAdapter.java
+++ b/src/com/android/providers/media/photopicker/ui/TabAdapter.java
@@ -216,7 +216,7 @@
                 mBanner = banner;
                 mOnBannerEventListener = onBannerEventListener;
                 notifyItemInserted(/* position */ 0);
-                mOnBannerEventListener.onBannerAdded();
+                mOnBannerEventListener.onBannerAdded(banner.name());
             } else {
                 mBanner = banner;
                 mOnBannerEventListener = onBannerEventListener;
@@ -385,11 +385,9 @@
 
         void onDismissButtonClick();
 
-        default void onBannerClick() {
-            onActionButtonClick();
-        }
+        void onBannerClick();
 
-        void onBannerAdded();
+        void onBannerAdded(@NonNull String name);
 
         default boolean shouldShowActionButton() {
             return true;
diff --git a/src/com/android/providers/media/photopicker/ui/TabContainerFragment.java b/src/com/android/providers/media/photopicker/ui/TabContainerFragment.java
index 2832dcd..8e070b5 100644
--- a/src/com/android/providers/media/photopicker/ui/TabContainerFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/TabContainerFragment.java
@@ -15,6 +15,8 @@
  */
 package com.android.providers.media.photopicker.ui;
 
+import static com.android.providers.media.util.MimeUtils.isVideoMimeType;
+
 import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -32,6 +34,7 @@
 import androidx.viewpager2.widget.ViewPager2;
 
 import com.android.providers.media.R;
+import com.android.providers.media.photopicker.util.MimeFilterUtils;
 import com.android.providers.media.photopicker.viewmodel.PickerViewModel;
 
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
@@ -101,13 +104,19 @@
         }
 
         final TabLayout tabLayout = getActivity().findViewById(R.id.tab_layout);
+
         mTabLayoutMediator = new TabLayoutMediator(tabLayout, mViewPager, (tab, pos) -> {
             if (pos == PHOTOS_TAB_POSITION) {
-                tab.setText(R.string.picker_photos);
+                if (isOnlyVideoMimeTypeFilterAvailable()) {
+                    tab.setText(R.string.picker_videos);
+                } else {
+                    tab.setText(R.string.picker_photos);
+                }
             } else if (pos == ALBUMS_TAB_POSITION) {
                 tab.setText(R.string.picker_albums);
             }
         });
+
         mTabLayoutMediator.attach();
         // TabLayout only supports colorDrawable in xml. And if we set the color in the drawable by
         // setSelectedTabIndicator method, it doesn't apply the color. So, we set color in xml and
@@ -116,6 +125,22 @@
         tabLayout.addOnTabSelectedListener(mOnTabSelectedListener);
     }
 
+    private boolean isOnlyVideoMimeTypeFilterAvailable() {
+        String [] mimeTypeFilters = MimeFilterUtils.getMimeTypeFilters(getActivity().getIntent());
+        boolean hasVideoMimeTypeFilterOnly = false;
+        if (mimeTypeFilters != null && mimeTypeFilters.length > 0) {
+            for (String mimeTypeFilter : mimeTypeFilters) {
+                if (isVideoMimeType(mimeTypeFilter)) {
+                    hasVideoMimeTypeFilterOnly = true;
+                } else {
+                    hasVideoMimeTypeFilterOnly = false;
+                    break;
+                }
+            }
+        }
+        return hasVideoMimeTypeFilterOnly;
+    }
+
     @Override
     public void onDestroyView() {
         mTabLayoutMediator.detach();
diff --git a/src/com/android/providers/media/photopicker/ui/TabFragment.java b/src/com/android/providers/media/photopicker/ui/TabFragment.java
index 9d0b107..46a410f 100644
--- a/src/com/android/providers/media/photopicker/ui/TabFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/TabFragment.java
@@ -539,29 +539,28 @@
     private abstract class OnBannerEventListener implements TabAdapter.OnBannerEventListener {
         @Override
         public void onActionButtonClick() {
+            mPickerViewModel.logBannerActionButtonClicked();
             dismissBanner();
-
-            final Intent accountChangeIntent =
-                    mPickerViewModel.getChooseCloudMediaAccountActivityIntent();
-
-            try {
-                if (accountChangeIntent != null) {
-                    requirePickerActivity().startActivity(accountChangeIntent);
-                } else {
-                    requirePickerActivity().startSettingsActivity();
-                }
-            } catch (RuntimeException e) {
-                Log.e(TAG, "Fragment is likely not attached to an activity. ", e);
-            }
+            launchCloudProviderSettings();
         }
 
         @Override
         public void onDismissButtonClick() {
+            mPickerViewModel.logBannerDismissed();
             dismissBanner();
         }
 
         @Override
-        public void onBannerAdded() {
+        public void onBannerClick() {
+            mPickerViewModel.logBannerClicked();
+            dismissBanner();
+            launchCloudProviderSettings();
+        }
+
+        @Override
+        public void onBannerAdded(@NonNull String name) {
+            mPickerViewModel.logBannerAdded(name);
+
             // Should scroll to the banner only if the first completely visible item is the one
             // just below it. The possible adapter item positions of such an item are 0 and 1.
             // During onViewCreated, before restoring the state, the first visible item position
@@ -581,6 +580,21 @@
         }
 
         abstract void dismissBanner();
+
+        private void launchCloudProviderSettings() {
+            final Intent accountChangeIntent =
+                    mPickerViewModel.getChooseCloudMediaAccountActivityIntent();
+
+            try {
+                if (accountChangeIntent != null) {
+                    requirePickerActivity().startActivity(accountChangeIntent);
+                } else {
+                    requirePickerActivity().startSettingsActivity();
+                }
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Fragment is likely not attached to an activity. ", e);
+            }
+        }
     }
 
     protected final OnBannerEventListener mOnChooseAppBannerEventListener =
diff --git a/src/com/android/providers/media/photopicker/ui/settings/CloudMediaProviderAccount.java b/src/com/android/providers/media/photopicker/ui/settings/CloudMediaProviderAccount.java
deleted file mode 100644
index fc2d332..0000000
--- a/src/com/android/providers/media/photopicker/ui/settings/CloudMediaProviderAccount.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.providers.media.photopicker.ui.settings;
-
-import static java.util.Objects.requireNonNull;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/* POJO for encapsulating cloud provider authority and it's linked account name. */
-class CloudMediaProviderAccount {
-    @NonNull
-    private final String mCloudProviderAuthority;
-    @Nullable
-    private final String mCloudProviderAccountName;
-
-    CloudMediaProviderAccount(
-            @NonNull String cloudProviderAuthority,
-            @Nullable String cloudProviderAccountName) {
-        mCloudProviderAuthority = requireNonNull(cloudProviderAuthority);
-        mCloudProviderAccountName = cloudProviderAccountName;
-    }
-
-    @NonNull
-    String getCloudProviderAuthority() {
-        return mCloudProviderAuthority;
-    }
-
-    @Nullable
-    String getCloudProviderAccountName() {
-        return mCloudProviderAccountName;
-    }
-}
diff --git a/src/com/android/providers/media/photopicker/ui/settings/CloudProviderMediaCollectionInfo.java b/src/com/android/providers/media/photopicker/ui/settings/CloudProviderMediaCollectionInfo.java
new file mode 100644
index 0000000..7c6d546
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/ui/settings/CloudProviderMediaCollectionInfo.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.ui.settings;
+
+import static java.util.Objects.requireNonNull;
+
+import android.content.Intent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/* POJO for encapsulating the cloud provider authority and it's media collection info. */
+class CloudProviderMediaCollectionInfo {
+    @NonNull
+    private final String mAuthority;
+    @Nullable
+    private final String mAccountName;
+    @Nullable
+    private final Intent mAccountConfigurationIntent;
+
+    CloudProviderMediaCollectionInfo(@NonNull String authority) {
+        mAuthority = requireNonNull(authority);
+        mAccountName = null;
+        mAccountConfigurationIntent = null;
+    }
+
+    CloudProviderMediaCollectionInfo(@NonNull String authority, @Nullable String accountName,
+            @Nullable Intent accountConfigurationIntent) {
+        mAuthority = requireNonNull(authority);
+        mAccountName = accountName;
+        mAccountConfigurationIntent = accountConfigurationIntent;
+    }
+
+    @NonNull
+    String getAuthority() {
+        return mAuthority;
+    }
+
+    @Nullable
+    String getAccountName() {
+        return mAccountName;
+    }
+
+    @Nullable
+    Intent getAccountConfigurationIntent() {
+        return mAccountConfigurationIntent;
+    }
+}
diff --git a/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaSelectFragment.java b/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaSelectFragment.java
index c8d1cc7..f08bd75 100644
--- a/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaSelectFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaSelectFragment.java
@@ -21,6 +21,7 @@
 import static java.util.Objects.requireNonNull;
 
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -67,7 +68,7 @@
     public void onResume() {
         super.onResume();
 
-        mSettingsCloudMediaViewModel.loadAccountNameAsync();
+        mSettingsCloudMediaViewModel.loadMediaCollectionInfoAsync();
     }
 
     @UiThread
@@ -93,7 +94,7 @@
         super.addPreferencesFromResource(R.xml.pref_screen_picker_settings);
 
         mSettingsCloudMediaViewModel.loadData(getConfigStore());
-        observeAccountNameChanges();
+        observeMediaCollectionInfoChanges();
         refreshUI();
     }
 
@@ -111,23 +112,34 @@
         updateSelectedRadioButton();
     }
 
-    private void observeAccountNameChanges() {
-        mSettingsCloudMediaViewModel.getCurrentProviderAccount()
-                .observe(this, accountDetails -> {
-                    // Only update current account name on the UI if cloud provider linked to the
-                    // account name matches the current provider.
-                    if (accountDetails != null
-                            && accountDetails.getCloudProviderAuthority()
-                            .equals(mSettingsCloudMediaViewModel.getSelectedProviderAuthority())) {
-                        final Preference selectedPref = findPreference(
-                                mSettingsCloudMediaViewModel.getSelectedPreferenceKey());
-                        // TODO(b/262002538): {@code selectedPref} could be null if the selected
-                        //  cloud provider is not in the allowed list. This is not something a
-                        //  typical user will encounter.
-                        if (selectedPref != null) {
-                            selectedPref.setSummary(accountDetails.getCloudProviderAccountName());
-                        }
+    private void observeMediaCollectionInfoChanges() {
+        mSettingsCloudMediaViewModel.getCurrentProviderMediaCollectionInfo().observe(this,
+                providerMediaCollectionInfo -> {
+                    // Only update the UI preference if the cloud provider linked to the media
+                    // collection info matches the current provider.
+                    if (providerMediaCollectionInfo == null
+                            || !TextUtils.equals(providerMediaCollectionInfo.getAuthority(),
+                            mSettingsCloudMediaViewModel.getSelectedProviderAuthority())) {
+                        return;
                     }
+
+                    final SelectorWithWidgetPreference selectedPref =
+                            findPreference(mSettingsCloudMediaViewModel.getSelectedPreferenceKey());
+
+                    // TODO(b/262002538): {@code selectedPref} could be null if the selected
+                    //  cloud provider is not in the allowed list. This is not something a
+                    //  typical user will encounter.
+                    if (selectedPref == null) {
+                        return;
+                    }
+
+                    selectedPref.setSummary(providerMediaCollectionInfo.getAccountName());
+
+                    final Intent accountConfigurationIntent =
+                            providerMediaCollectionInfo.getAccountConfigurationIntent();
+                    selectedPref.setExtraWidgetOnClickListener(
+                            accountConfigurationIntent == null ? null : v ->
+                                    requireActivity().startActivity(accountConfigurationIntent));
                 });
     }
 
@@ -137,19 +149,19 @@
                 mSettingsCloudMediaViewModel.getSelectedPreferenceKey();
         for (CloudMediaProviderOption providerOption
                 : mSettingsCloudMediaViewModel.getProviderOptions()) {
-            final Preference pref = findPreference(providerOption.getKey());
-            if (pref instanceof SelectorWithWidgetPreference) {
-                final SelectorWithWidgetPreference providerPref =
-                        (SelectorWithWidgetPreference) pref;
+            final SelectorWithWidgetPreference preference = findPreference(providerOption.getKey());
+            if (preference == null) {
+                continue;
+            }
 
-                final boolean newSelectionState =
-                        TextUtils.equals(providerPref.getKey(), selectedPreferenceKey);
-                providerPref.setChecked(newSelectionState);
+            final boolean isSelected = TextUtils.equals(preference.getKey(), selectedPreferenceKey);
+            preference.setChecked(isSelected);
 
-                providerPref.setSummary(null);
-                if (newSelectionState) {
-                    mSettingsCloudMediaViewModel.loadAccountNameAsync();
-                }
+            preference.setSummary(null);
+            preference.setExtraWidgetOnClickListener(null);
+
+            if (isSelected) {
+                mSettingsCloudMediaViewModel.loadMediaCollectionInfoAsync();
             }
         }
     }
diff --git a/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaViewModel.java b/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaViewModel.java
index ca9be63..e316970 100644
--- a/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaViewModel.java
+++ b/src/com/android/providers/media/photopicker/ui/settings/SettingsCloudMediaViewModel.java
@@ -20,17 +20,21 @@
 
 import static com.android.providers.media.photopicker.util.CloudProviderUtils.fetchProviderAuthority;
 import static com.android.providers.media.photopicker.util.CloudProviderUtils.getAvailableCloudProviders;
-import static com.android.providers.media.photopicker.util.CloudProviderUtils.getCloudMediaAccountName;
+import static com.android.providers.media.photopicker.util.CloudProviderUtils.getCloudMediaCollectionInfo;
 import static com.android.providers.media.photopicker.util.CloudProviderUtils.persistSelectedProvider;
 
 import static java.util.Objects.requireNonNull;
 
 import android.content.ContentProviderClient;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.Looper;
 import android.os.UserHandle;
+import android.provider.CloudMediaProviderContract;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -56,12 +60,13 @@
 public class SettingsCloudMediaViewModel extends ViewModel {
     static final String NONE_PREF_KEY = "none";
     private static final String TAG = "SettingsFragVM";
-    private static final long GET_ACCOUNT_NAME_TIMEOUT_IN_MILLIS = 10000L;
+    private static final long GET_CLOUD_MEDIA_COLLECTION_INFO_TIMEOUT_IN_MILLIS = 10000L;
 
     @NonNull
     private final Context mContext;
     @NonNull
-    private final MutableLiveData<CloudMediaProviderAccount> mCurrentProviderAccount;
+    private final MutableLiveData<CloudProviderMediaCollectionInfo>
+            mCurrentProviderMediaCollectionInfo;
     @NonNull
     private final List<CloudMediaProviderOption> mProviderOptions;
     @NonNull
@@ -78,7 +83,7 @@
         mUserId = requireNonNull(userId);
         mProviderOptions = new ArrayList<>();
         mSelectedProviderAuthority = null;
-        mCurrentProviderAccount = new MutableLiveData<CloudMediaProviderAccount>();
+        mCurrentProviderMediaCollectionInfo = new MutableLiveData<>();
     }
 
     @NonNull
@@ -92,11 +97,11 @@
     }
 
     @NonNull
-    LiveData<CloudMediaProviderAccount> getCurrentProviderAccount() {
-        return mCurrentProviderAccount;
+    LiveData<CloudProviderMediaCollectionInfo> getCurrentProviderMediaCollectionInfo() {
+        return mCurrentProviderMediaCollectionInfo;
     }
 
-    @Nullable
+    @NonNull
     String getSelectedPreferenceKey() {
         return getPreferenceKey(mSelectedProviderAuthority);
     }
@@ -141,7 +146,7 @@
                 ? null : preferenceKey;
     }
 
-    @Nullable
+    @NonNull
     private String getPreferenceKey(@Nullable String providerAuthority) {
         return providerAuthority == null
                 ? SettingsCloudMediaViewModel.NONE_PREF_KEY : providerAuthority;
@@ -172,39 +177,50 @@
     }
 
     @UiThread
-    void loadAccountNameAsync() {
+    void loadMediaCollectionInfoAsync() {
         if (!Looper.getMainLooper().isCurrentThread()) {
-            // This method should only be run from the UI thread so that fetch account name
+            // This method should only be run from the UI thread so that fetch media collection info
             // requests are executed serially.
-            Log.d(TAG, "loadAccountNameAsync method needs to be called from the UI thread");
+            Log.w(TAG, "loadMediaCollectionInfoAsync method needs to be called from the UI thread");
             return;
         }
 
         final String providerAuthority = getSelectedProviderAuthority();
         // Foreground thread internally uses a queue to execute each request in a serialized manner.
         ForegroundThread.getExecutor().execute(() -> {
-            mCurrentProviderAccount.postValue(
-                    fetchAccountFromProvider(providerAuthority));
+            mCurrentProviderMediaCollectionInfo.postValue(
+                    fetchMediaCollectionInfoFromProvider(providerAuthority));
         });
     }
 
     @Nullable
-    private CloudMediaProviderAccount fetchAccountFromProvider(
+    private CloudProviderMediaCollectionInfo fetchMediaCollectionInfoFromProvider(
             @Nullable String currentProviderAuthority) {
+        // If the selected cloud provider preference is "None", the media collection info is not
+        // applicable.
         if (currentProviderAuthority == null) {
-            // If the selected cloud provider preference is "None", account name is not applicable.
             return null;
-        } else {
-            try {
-                final String accountName = getCloudMediaAccountName(
-                        mUserId.getContentResolver(mContext), currentProviderAuthority,
-                        GET_ACCOUNT_NAME_TIMEOUT_IN_MILLIS);
-                return new CloudMediaProviderAccount(currentProviderAuthority, accountName);
-            } catch (Exception e) {
-                Log.w(TAG, "Failed to fetch account name from the cloud media provider.", e);
-                return null;
-            }
         }
+
+        Bundle cloudMediaCollectionInfo = null;
+        try {
+            final ContentResolver currentUserContentResolver = mUserId.getContentResolver(mContext);
+            cloudMediaCollectionInfo = getCloudMediaCollectionInfo(currentUserContentResolver,
+                    currentProviderAuthority, GET_CLOUD_MEDIA_COLLECTION_INFO_TIMEOUT_IN_MILLIS);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to fetch media collection info from the cloud media provider.", e);
+        }
+
+        if (cloudMediaCollectionInfo == null) {
+            return new CloudProviderMediaCollectionInfo(currentProviderAuthority);
+        }
+
+        final String accountName = cloudMediaCollectionInfo.getString(
+                CloudMediaProviderContract.MediaCollectionInfo.ACCOUNT_NAME);
+        final Intent cloudProviderSettingsActivityIntent = cloudMediaCollectionInfo.getParcelable(
+                CloudMediaProviderContract.MediaCollectionInfo.ACCOUNT_CONFIGURATION_INTENT);
+        return new CloudProviderMediaCollectionInfo(currentProviderAuthority, accountName,
+                cloudProviderSettingsActivityIntent);
     }
 
     @NonNull
diff --git a/src/com/android/providers/media/photopicker/util/CloudProviderUtils.java b/src/com/android/providers/media/photopicker/util/CloudProviderUtils.java
index a859ba3..57e6f75 100644
--- a/src/com/android/providers/media/photopicker/util/CloudProviderUtils.java
+++ b/src/com/android/providers/media/photopicker/util/CloudProviderUtils.java
@@ -18,7 +18,6 @@
 
 import static android.provider.CloudMediaProviderContract.MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION;
 import static android.provider.CloudMediaProviderContract.METHOD_GET_MEDIA_COLLECTION_INFO;
-import static android.provider.CloudMediaProviderContract.MediaCollectionInfo.ACCOUNT_NAME;
 import static android.provider.MediaStore.EXTRA_ALBUM_AUTHORITY;
 import static android.provider.MediaStore.EXTRA_ALBUM_ID;
 import static android.provider.MediaStore.EXTRA_CLOUD_PROVIDER;
@@ -258,30 +257,6 @@
      * @param resolver                    {@link ContentResolver} for the related user
      * @param cloudMediaProviderAuthority authority {@link String} of the {@link CloudMediaProvider}
      * @param timeout                     timeout in milliseconds for this query (<= 0 for timeout)
-     * @return the current cloud media account name for the {@link CloudMediaProvider} with the
-     *         given {@code cloudMediaProviderAuthority}.
-     */
-    @Nullable
-    public static String getCloudMediaAccountName(@NonNull ContentResolver resolver,
-            @Nullable String cloudMediaProviderAuthority, @DurationMillisLong long timeout)
-            throws ExecutionException, InterruptedException, TimeoutException {
-        if (cloudMediaProviderAuthority == null) {
-            return null;
-        }
-
-        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
-            final Bundle out = resolver.call(getMediaCollectionInfoUri(cloudMediaProviderAuthority),
-                    METHOD_GET_MEDIA_COLLECTION_INFO, /* arg */ null, /* extras */ null);
-            return (out == null) ? null : out.getString(ACCOUNT_NAME);
-        });
-
-        return (timeout > 0) ? future.get(timeout, MILLISECONDS) : future.get();
-    }
-
-    /**
-     * @param resolver                    {@link ContentResolver} for the related user
-     * @param cloudMediaProviderAuthority authority {@link String} of the {@link CloudMediaProvider}
-     * @param timeout                     timeout in milliseconds for this query (<= 0 for timeout)
      * @return the current cloud media collection info for the {@link CloudMediaProvider} with the
      *         given {@code cloudMediaProviderAuthority}.
      */
diff --git a/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java b/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
index 5b65155..f51d9cc 100644
--- a/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
+++ b/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
@@ -82,6 +82,7 @@
 import com.android.providers.media.photopicker.data.model.Category;
 import com.android.providers.media.photopicker.data.model.Item;
 import com.android.providers.media.photopicker.data.model.UserId;
+import com.android.providers.media.photopicker.metrics.NonUiEventLogger;
 import com.android.providers.media.photopicker.metrics.PhotoPickerUiEventLogger;
 import com.android.providers.media.photopicker.ui.ItemsAction;
 import com.android.providers.media.photopicker.util.CategoryOrganiserUtils;
@@ -407,10 +408,12 @@
             String[] mimeTypeFilters) {
         if (isManagedSelectionEnabled() && selection.getPreGrantedItems() == null) {
             DataLoaderThread.getHandler().postDelayed(() -> {
-                selection.setPreGrantedItemSet(mItemsProvider.fetchReadGrantedItemsUrisForPackage(
-                        intentExtras.getInt(Intent.EXTRA_UID), mimeTypeFilters)
+                Set<String> preGrantedItems = mItemsProvider.fetchReadGrantedItemsUrisForPackage(
+                                intentExtras.getInt(Intent.EXTRA_UID), mimeTypeFilters)
                         .stream().map((Uri uri) -> String.valueOf(ContentUris.parseId(uri)))
-                        .collect(Collectors.toSet()));
+                        .collect(Collectors.toSet());
+                selection.setPreGrantedItemSet(preGrantedItems);
+                logPickerChoiceInitGrantsCount(preGrantedItems.size(), intentExtras);
             }, TOKEN, DELAY_MILLIS);
         }
     }
@@ -875,7 +878,9 @@
             mPackageUid = intent.getExtras().getInt(Intent.EXTRA_UID);
         }
         // Must init banner manager on mIsUserSelectForApp / mIsLocalOnly updates
-        initBannerManager();
+        if (mBannerManager == null) {
+            initBannerManager();
+        }
     }
 
     private void initBannerManager() {
@@ -1174,6 +1179,103 @@
         mLogger.logPickerCreateSurfaceControllerEnd(mInstanceId, authority);
     }
 
+    /**
+     * Log metrics to notify that the selected media preloading started
+     * @param count the number of items to preload
+     */
+    public void logPreloadingStarted(int count) {
+        mLogger.logPreloadingStarted(mInstanceId, count);
+    }
+
+    /**
+     * Log metrics to notify that the selected media preloading finished
+     */
+    public void logPreloadingFinished() {
+        mLogger.logPreloadingFinished(mInstanceId);
+    }
+
+    /**
+     * Log metrics to notify that the user cancelled the selected media preloading
+     * @param count the number of items pending to preload
+     */
+    public void logPreloadingCancelled(int count) {
+        mLogger.logPreloadingCancelled(mInstanceId, count);
+    }
+
+    /**
+     * Log metrics to notify that the selected media preloading failed for some items
+     * @param count the number of items pending / failed to preload
+     */
+    public void logPreloadingFailed(int count) {
+        mLogger.logPreloadingFailed(mInstanceId, count);
+    }
+
+    /**
+     * Logs metrics for count of grants initialised for a package.
+     */
+    public void logPickerChoiceInitGrantsCount(int numberOfGrants, Bundle intentExtras) {
+        NonUiEventLogger.logPickerChoiceInitGrantsCount(mInstanceId, android.os.Process.myUid(),
+                getPackageNameForUid(intentExtras), numberOfGrants);
+
+    }
+
+    /**
+     * Logs metrics for count of grants added for a package.
+     */
+    public void logPickerChoiceAddedGrantsCount(int numberOfGrants, Bundle intentExtras) {
+        NonUiEventLogger.logPickerChoiceGrantsAdditionCount(mInstanceId, android.os.Process.myUid(),
+                getPackageNameForUid(intentExtras), numberOfGrants);
+    }
+
+    /**
+     * Logs metrics for count of grants removed for a package.
+     */
+    public void logPickerChoiceRevokedGrantsCount(int numberOfGrants, Bundle intentExtras) {
+        NonUiEventLogger.logPickerChoiceGrantsRemovedCount(mInstanceId, android.os.Process.myUid(),
+                getPackageNameForUid(intentExtras), numberOfGrants);
+    }
+
+    /**
+     * Log metrics to notify that the banner is added to display in the recycler view grids
+     * @param bannerName the name of the banner added,
+     *                   refer {@link com.android.providers.media.photopicker.ui.TabAdapter.Banner}
+     */
+    public void logBannerAdded(@NonNull String bannerName) {
+        mLogger.logBannerAdded(mInstanceId, bannerName);
+    }
+
+    /**
+     * Log metrics to notify that the banner is dismissed by the user
+     */
+    public void logBannerDismissed() {
+        mLogger.logBannerDismissed(mInstanceId);
+    }
+
+    /**
+     * Log metrics to notify that the user clicked the banner action button
+     */
+    public void logBannerActionButtonClicked() {
+        mLogger.logBannerActionButtonClicked(mInstanceId);
+    }
+
+    /**
+     * Log metrics to notify that the user clicked on the remaining part of the banner
+     */
+    public void logBannerClicked() {
+        mLogger.logBannerClicked(mInstanceId);
+    }
+
+    @NonNull
+    private String getPackageNameForUid(Bundle extras) {
+        final int uid = extras.getInt(Intent.EXTRA_UID);
+        final PackageManager pm = mAppContext.getPackageManager();
+        String[] packageNames = pm.getPackagesForUid(uid);
+        if (packageNames.length != 0) {
+            return packageNames[0];
+        }
+        return new String();
+    }
+
     public InstanceId getInstanceId() {
         return mInstanceId;
     }
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index ee78c19..7132276 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -55,6 +55,20 @@
             </intent-filter>
         </activity>
 
+        <!-- Intent Action "android.intent.action.MAIN"
+
+             This intent action is used to start the activity as a main entry point, does not expect
+             to receive data.
+
+             {@link androidx.test.core.app.ActivityScenario#launchActivityForResult(Class)} launches
+             the activity with the intent action {@link android.content.Intent#ACTION_MAIN}.
+        -->
+        <activity android:name="com.android.providers.media.photopicker.espresso.PhotoPickerAccessibilityDisabledTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+            </intent-filter>
+        </activity>
+
         <provider android:name="com.android.providers.media.photopicker.LocalProvider"
             android:authorities="com.android.providers.media.photopicker.tests.local"
             android:exported="false" />
diff --git a/tests/src/com/android/providers/media/ConfigStoreTest.java b/tests/src/com/android/providers/media/ConfigStoreTest.java
index 5f29d8f..10728b8 100644
--- a/tests/src/com/android/providers/media/ConfigStoreTest.java
+++ b/tests/src/com/android/providers/media/ConfigStoreTest.java
@@ -61,7 +61,7 @@
         assertEquals(60000, mConfigStore.getTranscodeMaxDurationMs());
         assertTrue(mConfigStore.isCloudMediaInPhotoPickerEnabled());
         assertFalse(mConfigStore.isGetContentTakeOverEnabled());
-        assertFalse(mConfigStore.isPickerChoiceManagedSelectionEnabled());
+        assertTrue(mConfigStore.isPickerChoiceManagedSelectionEnabled());
         assertFalse(mConfigStore.isStableUrisForExternalVolumeEnabled());
         assertFalse(mConfigStore.isStableUrisForInternalVolumeEnabled());
         assertTrue(mConfigStore.isTranscodeEnabled());
diff --git a/tests/src/com/android/providers/media/DatabaseBackupAndRecoveryTest.java b/tests/src/com/android/providers/media/DatabaseBackupAndRecoveryTest.java
index 447a98f..6b45993 100644
--- a/tests/src/com/android/providers/media/DatabaseBackupAndRecoveryTest.java
+++ b/tests/src/com/android/providers/media/DatabaseBackupAndRecoveryTest.java
@@ -25,7 +25,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.os.UserHandle;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.runner.AndroidJUnit4;
@@ -78,16 +77,4 @@
         assertThat(DatabaseBackupAndRecovery.getInvalidUsersList(xattrData, /* validUserIds */
                 Arrays.asList("0", "13"))).containsExactly("10", "11", "12");
     }
-
-    @Test
-    public void testGetFilePathForFuseRequests() {
-        assertThat(DatabaseBackupAndRecovery.getFilePathForFuseRequests("/storage")).isEqualTo(
-                "/storage/emulated/" + UserHandle.myUserId());
-        assertThat(DatabaseBackupAndRecovery.getFilePathForFuseRequests(
-                "/storage/emulated/" + UserHandle.myUserId() + "/Android/media")).isEqualTo(
-                "/storage/emulated/" + UserHandle.myUserId());
-        assertThat(
-                DatabaseBackupAndRecovery.getFilePathForFuseRequests("/storage/ABC-DEF")).isEqualTo(
-                "/storage/ABC-DEF");
-    }
 }
diff --git a/tests/src/com/android/providers/media/MediaGrantsTest.java b/tests/src/com/android/providers/media/MediaGrantsTest.java
index 1f126fd..622c790 100644
--- a/tests/src/com/android/providers/media/MediaGrantsTest.java
+++ b/tests/src/com/android/providers/media/MediaGrantsTest.java
@@ -302,6 +302,27 @@
             assertTrue(expectedFileIdsList2.contains(Long.valueOf(ContentUris.parseId(uri))));
         }
     }
+
+    @Test
+    public void testRemoveMediaGrantsForPackagesLargerDataSet() throws Exception {
+        List<Uri> inputFiles = new ArrayList<>();
+        for (int itr = 1; itr < 110; itr++) {
+            inputFiles.add(buildValidPickerUri(
+                    insertFileInResolver(mIsolatedResolver, "test_file" + itr)));
+        }
+        mGrants.addMediaGrantsForPackage(TEST_OWNER_PACKAGE_NAME, inputFiles, TEST_USER_ID);
+
+        String[] mimeTypes = {PNG_MIME_TYPE};
+        String[] volumes = {MediaStore.VOLUME_EXTERNAL_PRIMARY};
+
+        // The query used inside remove grants is batched by 50 ids, hence having a test like this
+        // would help ensure the batching worked perfectly.
+        mGrants.removeMediaGrantsForPackage(new String[]{TEST_OWNER_PACKAGE_NAME},
+                inputFiles.subList(0, 101), TEST_USER_ID);
+        List<Uri> fileUris3 = convertToListOfUri(mGrants.getMediaGrantsForPackages(
+                new String[]{TEST_OWNER_PACKAGE_NAME}, TEST_USER_ID, mimeTypes, volumes));
+        assertEquals(8, fileUris3.size());
+    }
     @Test
     public void testAddDuplicateMediaGrants() throws Exception {
 
diff --git a/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java b/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java
index b2d86ca..302a061 100644
--- a/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java
+++ b/tests/src/com/android/providers/media/photopicker/ItemsProviderTest.java
@@ -826,6 +826,41 @@
     /**
      * Tests {@link ItemsProvider#getLocalItemsForSelection(Category, List, String[],
      * UserId, CancellationSignal)} to return only selected items from the media table for ids
+     * defined in the localId selection list.
+     */
+    @Test
+    public void testGetItemsImages_withLocalIdSelection_largeDataSet() throws Exception {
+        List<Uri> imageFilesUris = assertCreateNewImagesWithSameDateModifiedTimesAndReturnUri(200);
+        // Try to fetch all items via selection. 200 items, this will hit the split query and
+        // verify that it is working.
+        List<Integer> inputIdsAsIntegers = imageFilesUris.stream().map(ContentUris::parseId).map(
+                Long::intValue).collect(Collectors.toList());
+        try {
+            // get the item objects for the provided ids.
+            final Cursor res = mItemsProvider.getLocalItemsForSelection(Category.DEFAULT,
+                    /* local id selection list */ inputIdsAsIntegers,
+                    /* mimeType */ new String[]{"image/*"}, /* userId */ null,
+                    /* cancellationSignal */ null);
+
+            // verify that the correct number of items are returned and that they have the correct
+            // ids.
+            assertThat(res).isNotNull();
+            assertThat(res.getCount()).isEqualTo(inputIdsAsIntegers.size());
+            res.moveToPosition(0);
+            while (res.moveToNext()) {
+                Item item = Item.fromCursor(res, UserId.CURRENT_USER);
+                assertTrue(inputIdsAsIntegers.contains(Integer.parseInt(item.getId())));
+            }
+            assertThatOnlyImages(res);
+        } finally {
+            // clean up.
+            deleteAllFilesNoThrow();
+        }
+    }
+
+    /**
+     * Tests {@link ItemsProvider#getLocalItemsForSelection(Category, List, String[],
+     * UserId, CancellationSignal)} to return only selected items from the media table for ids
      * defined in the localId selection list. Here the list is empty so the parameter is ignored and
      * the list is returned without any selection.
      */
diff --git a/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java b/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java
index e51678b..1d06576 100644
--- a/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java
+++ b/tests/src/com/android/providers/media/photopicker/PickerSyncControllerTest.java
@@ -20,7 +20,7 @@
 import static com.android.providers.media.PickerUriResolver.REFRESH_UI_PICKER_INTERNAL_OBSERVABLE_URI;
 import static com.android.providers.media.photopicker.NotificationContentObserver.MEDIA;
 
-import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -44,8 +44,8 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.providers.media.PickerProviderMediaGenerator;
 import com.android.providers.media.TestConfigStore;
@@ -152,7 +152,7 @@
         mCloudSecondaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
         mCloudFlakyMediaGenerator.setMediaCollectionId(COLLECTION_1);
 
-        mContext = InstrumentationRegistry.getTargetContext();
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
 
         // Delete db so it's recreated on next access and previous test state is cleared
         final File dbPath = mContext.getDatabasePath(DB_NAME);
@@ -198,18 +198,22 @@
 
         PickerSyncController controller =
                 PickerSyncController.initialize(mContext, mFacade, configStore, mLockManager);
-        assertThat(controller.getCurrentCloudProviderInfo()).isEqualTo(CloudProviderInfo.EMPTY);
+        assertWithMessage(
+                "CloudProviderInfo should have been EMPTY when CloudMediaFeature is disabled.")
+                .that(controller.getCurrentCloudProviderInfo()).isEqualTo(CloudProviderInfo.EMPTY);
         configStore.setDefaultCloudProviderPackage(PACKAGE_NAME);
         configStore.enableCloudMediaFeatureAndSetAllowedCloudProviderPackages(PACKAGE_NAME);
 
         // Ensure the cloud provider is set to something. (The test package name here actually
         // has multiple cloud providers in it, so just ensure something got set.)
-        assertThat(controller.getCurrentCloudProviderInfo().authority).isNotNull();
+        assertWithMessage("Failed to set cloud provider on config change.")
+                .that(controller.getCurrentCloudProviderInfo().authority).isNotNull();
 
         configStore.clearAllowedCloudProviderPackagesAndDisableCloudMediaFeature();
 
         // Ensure the cloud provider is correctly nulled out when the config changes again.
-        assertThat(controller.getCurrentCloudProviderInfo().authority).isNull();
+        assertWithMessage("Failed to nullify cloud provider on config change.")
+                .that(controller.getCurrentCloudProviderInfo().authority).isNull();
     }
 
     @Test
@@ -252,7 +256,9 @@
         // The cursor should only contain the items from the local provider. (Even though we've
         // added a total of 4 items to the linked providers.)
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage("Cursor should only contain the items from the local provider.")
+                    .that(cr.getCount()).isEqualTo(2);
+
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -271,7 +277,9 @@
 
         mController.syncAllMedia();
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding two local only media.")
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
@@ -282,7 +290,10 @@
         mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after deleting one local-only "
+                            + "media.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -292,7 +303,10 @@
         mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after resetting media without "
+                            + "version bump.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -317,7 +331,10 @@
         mController.syncAlbumMedia(ALBUM_ID_1, true);
 
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, true)) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of album medias in album albumId = "
+                            + ALBUM_ID_1)
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
@@ -329,7 +346,10 @@
         mController.syncAlbumMedia(ALBUM_ID_1, true);
 
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, true)) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of album medias in album albumId = "
+                            + ALBUM_ID_1)
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
@@ -339,7 +359,10 @@
         mController.syncAlbumMedia(ALBUM_ID_2, true);
 
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_2, true)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album medias in album albumId = "
+                            + ALBUM_ID_2)
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -350,7 +373,10 @@
 
         assertEmptyCursorFromAlbumMediaQuery(ALBUM_ID_1, true);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_2, true)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album medias in album albumId = "
+                            + ALBUM_ID_2)
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -376,7 +402,9 @@
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after syncing all media")
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -389,7 +417,9 @@
         // 5. Set primary cloud provider once again
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after second sync of all media.")
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -406,7 +436,9 @@
         addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1);
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after syncing all media.")
+                    .that(cr.getCount()).isEqualTo(1);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
 
@@ -420,7 +452,9 @@
         mController.syncAllMediaFromLocalProvider(/* cancellationSignal=*/ null);
         // Verify that the sync only synced local items
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(3);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after local sync")
+                    .that(cr.getCount()).isEqualTo(3);
 
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
@@ -448,7 +482,10 @@
         mController.syncAlbumMedia(ALBUM_ID_1, false);
 
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, false)) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of album medias on queryAlbumMedia() after setting cloud "
+                            + "providers and syncing cloud album media")
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -463,7 +500,10 @@
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         mController.syncAlbumMedia(ALBUM_ID_1, false);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, false)) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of album medias on queryAlbumMedia() after setting cloud "
+                            + "providers and syncing cloud album media for the second time")
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -498,7 +538,10 @@
 
         mController.syncAlbumMedia(ALBUM_ID_1, false);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, false)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album media on queryAlbumMedia() after syncing first "
+                            + "album from cloud provider")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -515,7 +558,10 @@
         // 4a. Sync the first album and query local albums
         mController.syncAlbumMedia(ALBUM_ID_1, true);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, true)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album media on queryAlbumMedia() after syncing first "
+                            + "album from local provider")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -523,7 +569,10 @@
         // 4b. Sync the second album
         mController.syncAlbumMedia(ALBUM_ID_2, true);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_2, true)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album media on queryAlbumMedia() after syncing second "
+                            + "album from local provider")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -531,7 +580,10 @@
         // 5. Sync and query cloud albums
         mController.syncAlbumMedia(ALBUM_ID_1, false);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, false)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album media on queryAlbumMedia() after syncing first "
+                            + "album from cloud provider")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -554,7 +606,9 @@
 
         mController.syncAllMedia();
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after syncing all media")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -569,7 +623,10 @@
         mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after setting valid cloud version"
+                            + " and syncing all media.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -590,7 +647,10 @@
 
         mController.syncAlbumMedia(ALBUM_ID_1, false);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, false)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album media on queryAlbumMedia() after syncing album "
+                            + "from cloud provider")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -606,7 +666,10 @@
 
         mController.syncAlbumMedia(ALBUM_ID_1, false);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, false)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album media on queryAlbumMedia() after cloud provider "
+                            + "reset and syncing album from cloud provider")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -629,7 +692,9 @@
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after syncing all media")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -639,7 +704,9 @@
         mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after deleting local-only item.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -649,7 +716,9 @@
         mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after re-adding local-only item.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -659,7 +728,9 @@
         mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after deleting cloud+local item.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -674,69 +745,95 @@
     @Test
     public void testSetCloudProvider() {
         //1. Get local provider assertion out of the way
-        assertThat(mController.getLocalProvider()).isEqualTo(LOCAL_PROVIDER_AUTHORITY);
+        assertWithMessage("Unexpected local provider.")
+                .that(mController.getLocalProvider()).isEqualTo(LOCAL_PROVIDER_AUTHORITY);
 
         // Assert that no cloud provider set on facade
-        assertThat(mFacade.getCloudProvider()).isNull();
+        assertWithMessage("Facade cloud provider should have been null.")
+                .that(mFacade.getCloudProvider()).isNull();
 
         // 2. Can set cloud provider
-        assertThat(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
-        assertThat(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Failed to set cloud provider. ")
+                .that(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
+        assertWithMessage("Unexpected cloud provider.")
+                .that(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Assert that setting cloud provider clears facade cloud provider
         // And after syncing, the latest provider is set on the facade
-        assertThat(mFacade.getCloudProvider()).isNull();
+        assertWithMessage("Setting cloud provider failed to clear facade cloud provider.")
+                .that(mFacade.getCloudProvider()).isNull();
         mController.syncAllMedia();
-        assertThat(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Failed to set latest provider on the facade post sync.")
+                .that(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // 3. Can clear cloud provider
-        assertThat(setCloudProviderAndSyncAllMedia(null)).isTrue();
-        assertThat(mController.getCloudProvider()).isNull();
+        assertWithMessage("Failed to clear cloud provider.")
+                .that(setCloudProviderAndSyncAllMedia(null)).isTrue();
+        assertWithMessage("Cloud provider should have been null.")
+                .that(mController.getCloudProvider()).isNull();
 
         // Assert that setting cloud provider clears facade cloud provider
         // And after syncing, the latest provider is set on the facade
-        assertThat(mFacade.getCloudProvider()).isNull();
+        assertWithMessage("Setting cloud provider failed to clear facade cloud provider.")
+                .that(mFacade.getCloudProvider()).isNull();
         mController.syncAllMedia();
-        assertThat(mFacade.getCloudProvider()).isNull();
+        assertWithMessage("Facade Cloud provider should have been null post sync.")
+                .that(mFacade.getCloudProvider()).isNull();
 
         // 4. Can set cloud proivder
-        assertThat(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
-        assertThat(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Failed to set cloud provider. ")
+                .that(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
+        assertWithMessage("Unexpected cloud provider.")
+                .that(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Assert that setting cloud provider clears facade cloud provider
         // And after syncing, the latest provider is set on the facade
-        assertThat(mFacade.getCloudProvider()).isNull();
+        assertWithMessage("Setting cloud provider failed to clear facade cloud provider.")
+                .that(mFacade.getCloudProvider()).isNull();
         mController.syncAllMedia();
-        assertThat(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Failed to set latest provider on the facade post sync.")
+                .that(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Invalid cloud provider is ignored
-        assertThat(setCloudProviderAndSyncAllMedia(LOCAL_PROVIDER_AUTHORITY)).isFalse();
-        assertThat(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Setting invalid cloud provider should have failed.")
+                .that(setCloudProviderAndSyncAllMedia(LOCAL_PROVIDER_AUTHORITY)).isFalse();
+        assertWithMessage("Unexpected cloud provider.")
+                .that(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Assert that unsuccessfully setting cloud provider doesn't clear facade cloud provider
         // And after syncing, nothing changes
-        assertThat(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage(
+                "Unsuccessfully setting cloud provider should have failed to clear facade cloud "
+                        + "provider.")
+                .that(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         mController.syncAllMedia();
-        assertThat(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Unexpected facade cloud provider post sync.")
+                .that(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
     }
 
     @Test
     public void testEnableCloudQueriesAfterMPRestart() {
         //1. Get local provider assertion out of the way
-        assertThat(mController.getLocalProvider()).isEqualTo(LOCAL_PROVIDER_AUTHORITY);
+        assertWithMessage("Unexpected local provider.")
+                .that(mController.getLocalProvider()).isEqualTo(LOCAL_PROVIDER_AUTHORITY);
 
         // Assert that no cloud provider set on facade
-        assertThat(mFacade.getCloudProvider()).isNull();
+        assertWithMessage("Facade cloud provider should have been null.")
+                .that(mFacade.getCloudProvider()).isNull();
 
         // 2. Can set cloud provider
-        assertThat(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
-        assertThat(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Failed to set cloud provider.")
+                .that(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
+        assertWithMessage("Unexpected cloud provider.")
+                .that(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Assert that setting cloud provider clears facade cloud provider
         // And after syncing, the latest provider is set on the facade
-        assertThat(mFacade.getCloudProvider()).isNull();
+        assertWithMessage("Setting cloud provider failed to clear facade cloud provider.")
+                .that(mFacade.getCloudProvider()).isNull();
         mController.syncAllMedia();
-        assertThat(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Unexpected facade cloud provider post sync.")
+                .that(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // 3. Clear facade cloud provider to simulate MP restart.
         mFacade.setCloudProvider(null);
@@ -744,7 +841,8 @@
         // 4. Assert that latest provider is set in the facade after sync even when no sync was
         // required.
         mController.syncAllMedia();
-        assertThat(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Failed to set latest provider in the facade after MP restart.")
+                .that(mFacade.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
     }
 
 
@@ -762,7 +860,9 @@
                 new CloudProviderInfo(
                         FLAKY_CLOUD_PROVIDER_AUTHORITY, PACKAGE_NAME, Process.myUid());
 
-        assertThat(providers).containsExactly(primaryInfo, secondaryInfo, flakyInfo);
+        assertWithMessage(
+                "Unexpected cloud provider in the list returned by getAvailableCloudProviders().")
+                .that(providers).containsExactly(primaryInfo, secondaryInfo, flakyInfo);
     }
 
     @Test
@@ -779,23 +879,34 @@
         final PickerSyncController controller = PickerSyncController.initialize(
                 mContext, mFacade, mConfigStore, mLockManager, LOCAL_PROVIDER_AUTHORITY);
         final List<CloudProviderInfo> providers = controller.getAvailableCloudProviders();
-        assertThat(providers).containsExactly(primaryInfo, secondaryInfo, flakyInfo);
+        assertWithMessage(
+                "Unexpected cloud provider in the list returned by getAvailableCloudProviders() "
+                        + "when using allowList.")
+                .that(providers).containsExactly(primaryInfo, secondaryInfo, flakyInfo);
     }
 
     @Test
     public void testNotifyPackageRemoval_NoDefaultCloudProviderPackage() {
         mConfigStore.clearDefaultCloudProviderPackage();
 
-        assertThat(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
-        assertThat(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Failed to set cloud provider.")
+                .that(mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
+        assertWithMessage("Unexpected cloud provider.")
+                .that(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Assert passing wrong package name doesn't clear the current cloud provider
         mController.notifyPackageRemoval(PACKAGE_NAME + "invalid");
-        assertThat(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage(
+                "Unexpected cloud provider, passing wrong package shouldn't have cleared the "
+                        + "current cloud provider.")
+                .that(mController.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Assert passing the current cloud provider package name clears the current cloud provider
         mController.notifyPackageRemoval(PACKAGE_NAME);
-        assertThat(mController.getCloudProvider()).isNull();
+        assertWithMessage(
+                "Unexpected cloud provider, passing current package should have cleared the "
+                        + "current cloud provider.")
+                .that(mController.getCloudProvider()).isNull();
 
         // Assert that the cloud provider state was not UNSET after the last cloud provider removal
         mConfigStore.setDefaultCloudProviderPackage(PACKAGE_NAME);
@@ -803,7 +914,11 @@
         mController = PickerSyncController.initialize(mContext, mFacade, mConfigStore,
                 mLockManager, LOCAL_PROVIDER_AUTHORITY);
 
-        assertThat(mController.getCurrentCloudProviderInfo().packageName).isEqualTo(PACKAGE_NAME);
+        assertWithMessage(
+                "Unexpected cloud provider, cloud provider state got UNSET after the last cloud "
+                        + "provider removal")
+                .that(mController.getCurrentCloudProviderInfo().packageName).isEqualTo(
+                        PACKAGE_NAME);
     }
 
     // TODO(b/278687585): Add test for PickerSyncController#notifyPackageRemoval with a different
@@ -812,33 +927,45 @@
     @Test
     public void testSelectDefaultCloudProvider_NoDefaultAuthority() {
         PickerSyncController controller = createControllerWithDefaultProvider(null);
-        assertThat(controller.getCloudProvider()).isNull();
+        assertWithMessage("Default provider was set to null.")
+                .that(controller.getCloudProvider()).isNull();
     }
 
     @Test
     public void testSelectDefaultCloudProvider_defaultAuthoritySet() {
         PickerSyncController controller = createControllerWithDefaultProvider(PACKAGE_NAME);
-        assertThat(controller.getCurrentCloudProviderInfo().packageName).isEqualTo(PACKAGE_NAME);
+        assertWithMessage("Default provider was set to " + PACKAGE_NAME)
+                .that(controller.getCurrentCloudProviderInfo().packageName).isEqualTo(PACKAGE_NAME);
     }
 
     @Test
     public void testIsProviderAuthorityEnabled() {
-        assertThat(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY)).isTrue();
-        assertThat(mController.isProviderEnabled(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isFalse();
-        assertThat(mController.isProviderEnabled(CLOUD_SECONDARY_PROVIDER_AUTHORITY)).isFalse();
+        assertWithMessage("Expected " + LOCAL_PROVIDER_AUTHORITY + " to be enabled.")
+                .that(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY)).isTrue();
+        assertWithMessage("Expected " + CLOUD_PRIMARY_PROVIDER_AUTHORITY + " to be disabled")
+                .that(mController.isProviderEnabled(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isFalse();
+        assertWithMessage("Expected " + CLOUD_SECONDARY_PROVIDER_AUTHORITY + " to be disabled")
+                .that(mController.isProviderEnabled(CLOUD_SECONDARY_PROVIDER_AUTHORITY)).isFalse();
 
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
-        assertThat(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY)).isTrue();
-        assertThat(mController.isProviderEnabled(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
-        assertThat(mController.isProviderEnabled(CLOUD_SECONDARY_PROVIDER_AUTHORITY)).isFalse();
+        assertWithMessage("Expected " + LOCAL_PROVIDER_AUTHORITY + " to be enabled.")
+                .that(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY)).isTrue();
+        assertWithMessage("Expected " + CLOUD_PRIMARY_PROVIDER_AUTHORITY + " to be enabled.")
+                .that(mController.isProviderEnabled(CLOUD_PRIMARY_PROVIDER_AUTHORITY)).isTrue();
+        assertWithMessage("Expected " + CLOUD_SECONDARY_PROVIDER_AUTHORITY + " to be disabled.")
+                .that(mController.isProviderEnabled(CLOUD_SECONDARY_PROVIDER_AUTHORITY)).isFalse();
     }
 
     @Test
     public void testIsProviderUidEnabled() {
-        assertThat(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY, Process.myUid()))
+        assertWithMessage("Expected " + LOCAL_PROVIDER_AUTHORITY + " uid = " + Process.myUid()
+                + " to be enabled.")
+                .that(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY, Process.myUid()))
                 .isTrue();
-        assertThat(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY, 1000)).isFalse();
+        assertWithMessage(
+                "Expected " + LOCAL_PROVIDER_AUTHORITY + " uid = 1000" + " to be disabled.")
+                .that(mController.isProviderEnabled(LOCAL_PROVIDER_AUTHORITY, 1000)).isFalse();
     }
 
     @Test
@@ -856,7 +983,8 @@
         controller.syncAllMedia();
 
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage("Unexpected number of media after adding one local-only media.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -873,14 +1001,16 @@
 
         // Initially empty db
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(0);
+            assertWithMessage("Unexpected number of media after deleting and recreating the db.")
+                    .that(cr.getCount()).isEqualTo(0);
         }
 
         controller.syncAllMedia();
 
         // Fully synced db
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage("Unexpected number of media after fully syncing the recreated db.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -900,7 +1030,8 @@
         controller.syncAllMedia();
 
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage("Unexpected number of media after adding one local-only media.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -914,14 +1045,16 @@
 
         // Initially empty db
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(0);
+            assertWithMessage("Unexpected number of media after upgrading the db version.")
+                    .that(cr.getCount()).isEqualTo(0);
         }
 
         controller.syncAllMedia();
 
         // Fully synced db
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage("Unexpected number of media after fully syncing the upgraded db.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -941,7 +1074,8 @@
         controller.syncAllMedia();
 
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage("Unexpected number of media after adding one local-only media.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -956,14 +1090,16 @@
 
         // Initially empty db
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(0);
+            assertWithMessage("Unexpected number of media after downgrading the db version.")
+                    .that(cr.getCount()).isEqualTo(0);
         }
 
         controller.syncAllMedia();
 
         // Fully synced db
         try (Cursor cr = queryMedia(facade)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage("Unexpected number of media after fully syncing the downgraded db.")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
         }
@@ -984,7 +1120,10 @@
         // 5. Sync and verify media
         mController.syncAllMedia();
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on syncing all media with correct "
+                            + "extra_media_collection_id")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -997,7 +1136,10 @@
         // 7. Sync and verify media after retry succeeded
         mController.syncAllMedia();
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of media on syncing all media with incorrect "
+                            + "extra_media_collection_id")
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -1018,7 +1160,7 @@
         // 1. Set cloud provider
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
-        // 2. Force the next 2 syncs (including retry) to have correct extra_media_collection_id
+        // 2. Force the next 2 syncs (including retry) to have correct extra_honored_args
         mCloudPrimaryMediaGenerator.setNextCursorExtras(2, COLLECTION_1,
                 /* honoredSyncGeneration */ true, /* honoredAlbumId */ false, true);
 
@@ -1028,7 +1170,10 @@
         // 4. Sync and verify media
         mController.syncAllMedia();
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on syncing all media with correct "
+                            + "extra_honored_args")
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -1041,7 +1186,10 @@
         // 6. Sync and verify media after retry succeeded
         mController.syncAllMedia();
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(2);
+            assertWithMessage(
+                    "Unexpected number of media on syncing all media with incorrect "
+                            + "extra_honored_args")
+                    .that(cr.getCount()).isEqualTo(2);
 
             assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -1064,7 +1212,8 @@
         // 4. Sync and verify media
         mController.syncAllMedia();
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(/* expected= */ 2);
+            assertWithMessage("Unexpected number of media")
+                    .that(cr.getCount()).isEqualTo(/* expected= */ 2);
 
             assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -1087,7 +1236,9 @@
         // 4. Sync and verify album_media
         mController.syncAlbumMedia(ALBUM_ID_1, false);
         try (Cursor cr = queryAlbumMedia(ALBUM_ID_1, false)) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of album media from album with albumId = " + ALBUM_ID_1)
+                    .that(cr.getCount()).isEqualTo(1);
 
             assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
@@ -1112,7 +1263,8 @@
                 mContext, facade, mConfigStore, mLockManager, LOCAL_PROVIDER_AUTHORITY);
 
         controller.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
-        assertThat(controller.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Unexpected cloud provider on db set up.")
+                .that(controller.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         // Downgrade db version
         dbHelperV1.close();
@@ -1122,7 +1274,8 @@
         controller = PickerSyncController.initialize(
                 mContext, facade, mConfigStore, mLockManager, LOCAL_PROVIDER_AUTHORITY);
 
-        assertThat(controller.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Unexpected cloud provider after db version downgrade.")
+                .that(controller.getCloudProvider()).isEqualTo(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
     }
 
     @Test
@@ -1135,7 +1288,9 @@
                 PickerSyncController.initialize(
                         mContext, mFacade, mConfigStore, mLockManager, LOCAL_PROVIDER_AUTHORITY);
 
-        assertThat(mController.getCurrentCloudProviderInfo().packageName).isEqualTo(PACKAGE_NAME);
+        assertWithMessage("Unexpected cloud provider on testing the default NOT_SET state.")
+                .that(mController.getCurrentCloudProviderInfo().packageName).isEqualTo(
+                        PACKAGE_NAME);
 
         // Set and test the UNSET state
         mController.setCloudProvider(/* authority */ null);
@@ -1144,7 +1299,8 @@
                 PickerSyncController.initialize(
                         mContext, mFacade, mConfigStore, mLockManager, LOCAL_PROVIDER_AUTHORITY);
 
-        assertThat(mController.getCloudProvider()).isNull();
+        assertWithMessage("Unexpected cloud provider on setting and testing the NOT_SET state.")
+                .that(mController.getCloudProvider()).isNull();
 
         // Set and test the SET state
         mController.setCloudProvider(CLOUD_SECONDARY_PROVIDER_AUTHORITY);
@@ -1153,14 +1309,19 @@
                 PickerSyncController.initialize(
                         mContext, mFacade, mConfigStore, mLockManager, LOCAL_PROVIDER_AUTHORITY);
 
-        assertThat(mController.getCloudProvider()).isEqualTo(CLOUD_SECONDARY_PROVIDER_AUTHORITY);
+        assertWithMessage("Unexpected cloud provider on setting and testing the SET state.")
+                .that(mController.getCloudProvider()).isEqualTo(CLOUD_SECONDARY_PROVIDER_AUTHORITY);
     }
 
     @Test
     public void testAvailableCloudProviders_CloudFeatureDisabled() {
-        assertThat(mController.getAvailableCloudProviders()).isNotEmpty();
+        assertWithMessage("Empty list returned by getAvailableCloudProviders().")
+                .that(mController.getAvailableCloudProviders()).isNotEmpty();
         mConfigStore.disableCloudMediaFeature();
-        assertThat(mController.getAvailableCloudProviders()).isEmpty();
+        assertWithMessage(
+                "Non-empty list returned by getAvailableCloudProviders() after disabling the "
+                        + "cloud media feature.")
+                .that(mController.getAvailableCloudProviders()).isEmpty();
     }
 
     @Test
@@ -1181,7 +1342,9 @@
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(9);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding 9 cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(9);
             assertCursor(cr, CLOUD_ID_9, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_8, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_7, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -1212,7 +1375,9 @@
         setCloudProviderAndSyncAllMedia(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(9);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding 9 cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(9);
             assertCursor(cr, CLOUD_ID_9, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_8, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_7, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
@@ -1236,14 +1401,17 @@
         mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(1);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after deleting 8 out the 9 "
+                            + "cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(1);
             assertCursor(cr, CLOUD_ID_9, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
         }
 
     }
 
     @Test
-    public void testResumableSyncOperation() {
+    public void testResumableIncrementalSyncOperation() {
         // First Page
         addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_1);
         addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_2);
@@ -1253,10 +1421,14 @@
 
         // Complete a full sync since it hasn't synced before.
         setCloudProviderAndSyncAllMedia(FLAKY_CLOUD_PROVIDER_AUTHORITY);
+        mController.syncAllMedia();
+        mController.syncAllMedia();
 
         try (Cursor cr = queryMedia()) {
             // Should only have the first page since the sync is flaky
-            assertThat(cr.getCount()).isEqualTo(5);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding 5 cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(5);
             assertCursor(cr, CLOUD_ID_5, FLAKY_CLOUD_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_4, FLAKY_CLOUD_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_3, FLAKY_CLOUD_PROVIDER_AUTHORITY);
@@ -1283,7 +1455,10 @@
 
         try (Cursor cr = queryMedia()) {
             // Should have all pages now
-            assertThat(cr.getCount()).isEqualTo(14);
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding 9 cloud-only media, "
+                            + "in addition to previously added 5 cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(14);
             assertCursor(cr, CLOUD_ID_14, FLAKY_CLOUD_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_13, FLAKY_CLOUD_PROVIDER_AUTHORITY);
             assertCursor(cr, CLOUD_ID_12, FLAKY_CLOUD_PROVIDER_AUTHORITY);
@@ -1302,6 +1477,180 @@
     }
 
     @Test
+    public void testResumableFullSyncOperation() {
+        // First Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_1);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_2);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_3);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_4);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_5);
+        // Second Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_6);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_7);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_8);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_9);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_10);
+        // Third Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_11);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_12);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_13);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_14);
+
+        mController.setCloudProvider(FLAKY_CLOUD_PROVIDER_AUTHORITY);
+        try (Cursor cr = queryMedia()) {
+            // Db should be empty since we haven't synced yet.
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() before sync.")
+                    .that(cr.getCount()).isEqualTo(0);
+        }
+
+        // FlakyCloudMediaProvider will throw errors on 2 out of 3 requests, if we sync once, it
+        // should not be able to complete the sync.
+        mController.syncAllMedia();
+
+        try (Cursor cr = queryMedia()) {
+            // Assert that the sync is not complete.
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia().")
+                    .that(cr.getCount()).isLessThan(14);
+        }
+
+        // Resume sync and complete it. It will take a few sync calls to complete the sync.
+        mController.syncAllMedia();
+        mController.syncAllMedia();
+        mController.syncAllMedia();
+        mController.syncAllMedia();
+
+        try (Cursor cr = queryMedia()) {
+            // Should have all pages now
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding 14 cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(14);
+            assertCursor(cr, CLOUD_ID_14, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_13, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_12, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_11, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_10, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_9, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_8, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_7, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_6, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_5, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_4, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_3, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_2, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_1, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+        }
+    }
+
+    @Test
+    public void testFullSyncWithCollectionIdChange() {
+        mController.setCloudProvider(FLAKY_CLOUD_PROVIDER_AUTHORITY);
+        mCloudFlakyMediaGenerator.setMediaCollectionId(COLLECTION_1);
+
+        // First Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_1);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_2);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_3);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_4);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_5);
+        // Second Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_6);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_7);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_8);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_9);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_10);
+        // Third Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_11);
+
+        // FlakyCloudMediaProvider will throw errors on 2 out of 3 requests, if we sync once, it
+        // should not be able to complete the sync.
+        mController.syncAllMedia();
+
+        try (Cursor cr = queryMedia()) {
+            // Assert that the sync is not complete.
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia().")
+                    .that(cr.getCount()).isLessThan(11);
+        }
+
+        // Reset data and change collection id.
+        mCloudFlakyMediaGenerator.resetAll();
+        mCloudFlakyMediaGenerator.setMediaCollectionId(COLLECTION_2);
+
+        // First Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_12);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_13);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_14);
+
+        // FlakyCloudMediaProvider will throw errors on 2 out of 3 requests. It will take a few
+        // tries to complete the sync.
+        mController.syncAllMedia();
+        mController.syncAllMedia();
+        mController.syncAllMedia();
+
+        try (Cursor cr = queryMedia()) {
+            // Db should be empty since we haven't synced yet.
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding 3 cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(3);
+            assertCursor(cr, CLOUD_ID_14, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_13, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_12, FLAKY_CLOUD_PROVIDER_AUTHORITY);
+        }
+    }
+
+    @Test
+    public void testFullSyncWithCloudProviderChange() {
+        mController.setCloudProvider(FLAKY_CLOUD_PROVIDER_AUTHORITY);
+
+        // First Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_1);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_2);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_3);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_4);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_5);
+        // Second Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_6);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_7);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_8);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_9);
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_10);
+        // Third Page of data
+        addMedia(mCloudFlakyMediaGenerator, CLOUD_ONLY_11);
+
+        // FlakyCloudMediaProvider will throw errors on 2 out of 3 requests, if we sync once, it
+        // should not be able to complete the sync.
+        mController.syncAllMedia();
+
+        try (Cursor cr = queryMedia()) {
+            // Assert that the sync is not complete.
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia().")
+                    .that(cr.getCount()).isLessThan(11);
+        }
+
+        mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+
+        // First Page of data
+        addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_12);
+        addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_13);
+        addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_14);
+
+        mController.syncAllMedia();
+
+        try (Cursor cr = queryMedia()) {
+            // Db should be empty since we haven't synced yet.
+            assertWithMessage(
+                    "Unexpected number of media on queryMedia() after adding 3 cloud-only media.")
+                    .that(cr.getCount()).isEqualTo(3);
+            assertCursor(cr, CLOUD_ID_14, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_13, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+            assertCursor(cr, CLOUD_ID_12, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
+        }
+    }
+
+    @Test
     public void testContentAddNotifications() throws Exception {
         NotificationContentObserver observer = new NotificationContentObserver(null);
         observer.register(mContext.getContentResolver());
@@ -1374,7 +1723,8 @@
             contentResolver.registerContentObserver(REFRESH_UI_PICKER_INTERNAL_OBSERVABLE_URI,
                     /* notifyForDescendants */ false, refreshUiNotificationObserver);
 
-            assertThat(refreshUiNotificationObserver.mNotificationReceived).isFalse();
+            assertWithMessage("Refresh ui notification should have not been received.")
+                    .that(refreshUiNotificationObserver.mNotificationReceived).isFalse();
 
             mConfigStore.enableCloudMediaFeatureAndSetAllowedCloudProviderPackages(PACKAGE_NAME);
             mConfigStore.setDefaultCloudProviderPackage(PACKAGE_NAME);
@@ -1383,14 +1733,18 @@
             mController = PickerSyncController
                     .initialize(mContext, mFacade, mConfigStore, mLockManager);
             TimeUnit.MILLISECONDS.sleep(100);
-            assertThat(refreshUiNotificationObserver.mNotificationReceived).isTrue();
+            assertWithMessage(
+                    "Failed to receive refresh ui notification on change in cloud provider.")
+                    .that(refreshUiNotificationObserver.mNotificationReceived).isTrue();
 
             refreshUiNotificationObserver.mNotificationReceived = false;
 
             // The SET_CLOUD_PROVIDER is called using a different cloud provider from before
             mController.setCloudProvider(CLOUD_SECONDARY_PROVIDER_AUTHORITY);
             TimeUnit.MILLISECONDS.sleep(100);
-            assertThat(refreshUiNotificationObserver.mNotificationReceived).isTrue();
+            assertWithMessage(
+                    "Failed to receive refresh ui notification on change in cloud provider.")
+                    .that(refreshUiNotificationObserver.mNotificationReceived).isTrue();
 
             refreshUiNotificationObserver.mNotificationReceived = false;
 
@@ -1398,12 +1752,18 @@
             mController = PickerSyncController
                     .initialize(mContext, mFacade, mConfigStore, mLockManager);
             TimeUnit.MILLISECONDS.sleep(100);
-            assertThat(refreshUiNotificationObserver.mNotificationReceived).isFalse();
+            assertWithMessage(
+                    "Refresh ui notification should have not been received when cloud provider "
+                            + "remains unchanged.")
+                    .that(refreshUiNotificationObserver.mNotificationReceived).isFalse();
 
             // The SET_CLOUD_PROVIDER is called using the same cloud provider as before
             mController.setCloudProvider(CLOUD_SECONDARY_PROVIDER_AUTHORITY);
             TimeUnit.MILLISECONDS.sleep(100);
-            assertThat(refreshUiNotificationObserver.mNotificationReceived).isFalse();
+            assertWithMessage(
+                    "Refresh ui notification should have not been received when setCloudProvider "
+                            + "is called using the same cloud provider as before.")
+                    .that(refreshUiNotificationObserver.mNotificationReceived).isFalse();
         } finally {
             contentResolver.unregisterContentObserver(refreshUiNotificationObserver);
         }
@@ -1448,13 +1808,15 @@
 
     private void assertEmptyCursorFromMediaQuery() {
         try (Cursor cr = queryMedia()) {
-            assertThat(cr.getCount()).isEqualTo(0);
+            assertWithMessage("Cursor should have been empty.")
+                    .that(cr.getCount()).isEqualTo(0);
         }
     }
 
     private void assertEmptyCursorFromAlbumMediaQuery(String albumId, boolean isLocal) {
         try (Cursor cr = queryAlbumMedia(albumId, isLocal)) {
-            assertThat(cr.getCount()).isEqualTo(0);
+            assertWithMessage("Cursor from queryAlbumMedia should have been empty.")
+                    .that(cr.getCount()).isEqualTo(0);
         }
     }
 
@@ -1484,9 +1846,11 @@
 
     private static void assertCursor(Cursor cursor, String id, String expectedAuthority) {
         cursor.moveToNext();
-        assertThat(cursor.getString(cursor.getColumnIndex(MediaColumns.ID)))
+        assertWithMessage("Unexpected value of MediaColumns.ID in the cursor.")
+                .that(cursor.getString(cursor.getColumnIndex(MediaColumns.ID)))
                 .isEqualTo(id);
-        assertThat(cursor.getString(cursor.getColumnIndex( MediaColumns.AUTHORITY)))
+        assertWithMessage("Unexpected value of MediaColumns.AUTHORITY in the cursor.")
+                .that(cursor.getString(cursor.getColumnIndex(MediaColumns.AUTHORITY)))
                 .isEqualTo(expectedAuthority);
     }
 
diff --git a/tests/src/com/android/providers/media/photopicker/SafetyProtectionUtilsTest.java b/tests/src/com/android/providers/media/photopicker/SafetyProtectionUtilsTest.java
index f176325..745acc0 100644
--- a/tests/src/com/android/providers/media/photopicker/SafetyProtectionUtilsTest.java
+++ b/tests/src/com/android/providers/media/photopicker/SafetyProtectionUtilsTest.java
@@ -34,7 +34,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -74,7 +73,6 @@
         });
     }
 
-    @Ignore("Enable once b/269874157 is fixed")
     @Test
     public void testWhetherShouldUseSafetyProtectionResourcesWhenTOrAboveAndFeatureFlagOn() {
         assumeTrue(SdkLevel.isAtLeastT());
diff --git a/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java b/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java
index bce370b..189f122 100644
--- a/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java
@@ -62,6 +62,22 @@
     }
 
     @Test
+    public void testAddSelectedItem_orderedSelection() {
+        try {
+            enableOrderedSelection();
+            final Item item1 = generateFakeImageItem("1");
+            final Item item2 = generateFakeImageItem("2");
+
+            mSelection.addSelectedItem(item1);
+            mSelection.addSelectedItem(item2);
+            assertThat(mSelection.getSelectedItemOrder(item1).getValue().intValue()).isEqualTo(1);
+            assertThat(mSelection.getSelectedItemOrder(item2).getValue().intValue()).isEqualTo(2);
+        } finally {
+            disableOrderedSelection();
+        }
+    }
+
+    @Test
     public void testDeleteSelectedItem() {
         final String id = "1";
         final Item item = generateFakeImageItem(id);
@@ -76,6 +92,56 @@
     }
 
     @Test
+    public void testDeleteSelectedItem_orderedSelection() {
+        try {
+            enableOrderedSelection();
+            final Item item1 = generateFakeImageItem("1");
+            final Item item2 = generateFakeImageItem("2");
+            final Item item3 = generateFakeImageItem("3");
+
+            mSelection.addSelectedItem(item1);
+            mSelection.addSelectedItem(item2);
+            mSelection.addSelectedItem(item3);
+
+            assertThat(mSelection.getSelectedItemOrder(item1).getValue().intValue()).isEqualTo(1);
+            assertThat(mSelection.getSelectedItemOrder(item2).getValue().intValue()).isEqualTo(2);
+            assertThat(mSelection.getSelectedItemOrder(item3).getValue().intValue()).isEqualTo(3);
+
+            mSelection.removeSelectedItem(item1);
+
+            assertThat(mSelection.getSelectedItemOrder(item2).getValue().intValue()).isEqualTo(1);
+            assertThat(mSelection.getSelectedItemOrder(item3).getValue().intValue()).isEqualTo(2);
+
+            mSelection.removeSelectedItem(item3);
+
+            assertThat(mSelection.getSelectedItemOrder(item2).getValue().intValue()).isEqualTo(1);
+        } finally {
+            disableOrderedSelection();
+        }
+    }
+
+    @Test
+    public void testGetSelectedItems_orderedSelection() {
+        try {
+            enableOrderedSelection();
+            final Item item1 = generateFakeImageItem("1");
+            final Item item2 = generateFakeImageItem("2");
+            final Item item3 = generateFakeImageItem("3");
+
+            mSelection.addSelectedItem(item1);
+            mSelection.addSelectedItem(item2);
+            mSelection.addSelectedItem(item3);
+
+            List<Item> itemsSorted = mSelection.getSelectedItems();
+            assertThat(itemsSorted.get(0).getId()).isEqualTo("1");
+            assertThat(itemsSorted.get(1).getId()).isEqualTo("2");
+            assertThat(itemsSorted.get(2).getId()).isEqualTo("3");
+        } finally {
+            disableOrderedSelection();
+        }
+    }
+
+    @Test
     public void testClearSelectedItem() {
         final String id = "1";
         final Item item = generateFakeImageItem(id);
@@ -164,6 +230,39 @@
     }
 
     @Test
+    public void testParseValuesFromIntent_orderedSelection() {
+        final Intent intent = new Intent();
+        intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER, true);
+
+        mSelection.parseSelectionValuesFromIntent(intent);
+
+        assertThat(mSelection.isSelectionOrdered()).isTrue();
+    }
+
+    @Test
+    public void testParseValuesFromIntent_InvalidOrderedSelectionGetContent_throwsException() {
+        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER, true);
+
+        try {
+            mSelection.parseSelectionValuesFromIntent(intent);
+            fail("Ordered selection not allowed for GET_CONTENT");
+        } catch (IllegalArgumentException expected) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testParseValuesFromIntent_OrderedSelectionDisabledInPermissionMode() {
+        final Intent intent = new Intent(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP);
+        intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER, true);
+
+        mSelection.parseSelectionValuesFromIntent(intent);
+
+        assertThat(mSelection.isSelectionOrdered()).isFalse();
+    }
+
+    @Test
     public void testParseValuesFromIntent_allowMultipleNotSupported() {
         final Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
@@ -276,4 +375,16 @@
 
         return generateJpegItem(id, dateTakenMs, /* generationModified */ 1L);
     }
+
+    private void enableOrderedSelection() {
+        final Intent intent = new Intent();
+        intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER, true);
+        mSelection.parseSelectionValuesFromIntent(intent);
+    }
+
+    private void disableOrderedSelection() {
+        final Intent intent = new Intent();
+        intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER, false);
+        mSelection.parseSelectionValuesFromIntent(intent);
+    }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/BottomSheetIdlingResource.java b/tests/src/com/android/providers/media/photopicker/espresso/BottomSheetIdlingResource.java
index 693b445..a36531f 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/BottomSheetIdlingResource.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/BottomSheetIdlingResource.java
@@ -99,7 +99,8 @@
      *     given {@link ActivityScenarioRule}.
      * @param scenario
      */
-    public static BottomSheetIdlingResource register(ActivityScenario scenario) {
+    public static <T extends PhotoPickerTestActivity> BottomSheetIdlingResource register(
+            ActivityScenario<T> scenario) {
         final BottomSheetIdlingResource[] idlingResources = new BottomSheetIdlingResource[1];
         scenario.onActivity(
                 (activity -> {
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/DisabledAccessibilityTest.java b/tests/src/com/android/providers/media/photopicker/espresso/DisabledAccessibilityTest.java
new file mode 100644
index 0000000..3e17e2f
--- /dev/null
+++ b/tests/src/com/android/providers/media/photopicker/espresso/DisabledAccessibilityTest.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.espresso;
+
+import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_NONE;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isNotSelected;
+import static androidx.test.espresso.matcher.ViewMatchers.isSelected;
+import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.providers.media.photopicker.espresso.BottomSheetTestUtils.assertBottomSheetState;
+import static com.android.providers.media.photopicker.espresso.CustomSwipeAction.customSwipeDownPartialScreen;
+import static com.android.providers.media.photopicker.espresso.CustomSwipeAction.swipeLeftAndWait;
+import static com.android.providers.media.photopicker.espresso.CustomSwipeAction.swipeRightAndWait;
+import static com.android.providers.media.photopicker.espresso.OrientationUtils.setLandscapeOrientation;
+import static com.android.providers.media.photopicker.espresso.OrientationUtils.setPortraitOrientation;
+import static com.android.providers.media.photopicker.espresso.OverflowMenuUtils.assertOverflowMenuNotShown;
+import static com.android.providers.media.photopicker.espresso.RecyclerViewMatcher.withRecyclerView;
+import static com.android.providers.media.photopicker.espresso.RecyclerViewTestUtils.longClickItem;
+
+import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED;
+import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.not;
+
+import android.app.Activity;
+
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.espresso.IdlingRegistry;
+import androidx.test.espresso.action.ViewActions;
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+
+import com.android.providers.media.R;
+import com.android.providers.media.library.RunOnlyOnPostsubmit;
+import com.android.providers.media.photopicker.metrics.PhotoPickerUiEventLogger;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * {@link DisabledAccessibilityTest} tests the
+ * {@link com.android.providers.media.photopicker.PhotoPickerActivity} behaviors that require it to
+ * launch in partial screen.
+ */
+@RunOnlyOnPostsubmit
+@RunWith(AndroidJUnit4ClassRunner.class)
+public class DisabledAccessibilityTest extends PhotoPickerBaseTest {
+
+    private ActivityScenario<PhotoPickerAccessibilityDisabledTestActivity> mScenario;
+
+    /**
+     * Note - {@link ActivityScenario#launchActivityForResult(Class)} launches the activity with the
+     * intent action {@link android.content.Intent#ACTION_MAIN}.
+     */
+    @Before
+    public void launchActivity() {
+        mScenario = ActivityScenario.launchActivityForResult(
+                PhotoPickerAccessibilityDisabledTestActivity.class);
+    }
+
+    @After
+    public void closeActivity() {
+        if (mScenario != null) {
+            mScenario.close();
+        }
+    }
+
+    @Test
+    @Ignore("b/313489524")
+    // TODO(b/313489524): Fix flaky orientation change in the photo picker espresso tests
+    public void testBottomSheetState() {
+        // Bottom sheet assertions are different based on the orientation
+        setPortraitOrientation(mScenario);
+
+        // Register bottom sheet idling resource so that we don't read bottom sheet state when
+        // in between changing states
+        final BottomSheetIdlingResource bottomSheetIdlingResource =
+                BottomSheetIdlingResource.register(mScenario);
+
+        try {
+            // Single select PhotoPicker is launched in partial screen mode
+            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
+            onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
+            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
+            mScenario.onActivity(
+                    activity -> {
+                        assertBottomSheetState(activity, STATE_COLLAPSED);
+                    });
+
+            // Swipe up and check that the PhotoPicker is in full screen mode
+            bottomSheetIdlingResource.setExpectedState(STATE_EXPANDED);
+            onView(withId(PRIVACY_TEXT_ID)).perform(ViewActions.swipeUp());
+            mScenario.onActivity(
+                    activity -> {
+                        assertBottomSheetState(activity, STATE_EXPANDED);
+                    });
+
+            // Swipe down and check that the PhotoPicker is in partial screen mode
+            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
+            onView(withId(PRIVACY_TEXT_ID)).perform(ViewActions.swipeDown());
+            mScenario.onActivity(
+                    activity -> {
+                        assertBottomSheetState(activity, STATE_COLLAPSED);
+                    });
+
+            // Swiping down on drag bar is not strong enough as closing the bottomsheet requires a
+            // stronger downward swipe using espresso.
+            // Simply swiping down on R.id.bottom_sheet throws an error from espresso, as the view
+            // is only 60% visible, but downward swipe is only successful on an element which is 90%
+            // visible.
+            onView(withId(R.id.bottom_sheet)).perform(customSwipeDownPartialScreen());
+        } finally {
+            IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
+        }
+        assertThat(mScenario.getResult().getResultCode()).isEqualTo(Activity.RESULT_CANCELED);
+    }
+
+    @Test
+    @Ignore("b/313489524")
+    // TODO(b/313489524): Fix flaky orientation change in the photo picker espresso tests
+    public void testBottomSheetStateInLandscapeMode() {
+        // Bottom sheet assertions are different based on the orientation
+        setLandscapeOrientation(mScenario);
+
+        // Register bottom sheet idling resource so that we don't read bottom sheet state when
+        // in between changing states
+        final BottomSheetIdlingResource bottomSheetIdlingResource =
+                BottomSheetIdlingResource.register(mScenario);
+
+        try {
+            // Single select PhotoPicker is launched in full screen mode in Landscape orientation
+            mScenario.onActivity(
+                    activity -> {
+                        assertBottomSheetState(activity, STATE_EXPANDED);
+                    });
+
+            // Swiping down on drag bar / privacy text is not strong enough as closing the
+            // bottomsheet requires a stronger downward swipe using espresso.
+            onView(withId(R.id.bottom_sheet)).perform(ViewActions.swipeDown());
+        } finally {
+            IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
+        }
+        assertThat(mScenario.getResult().getResultCode()).isEqualTo(Activity.RESULT_CANCELED);
+    }
+
+    @Test
+    public void testTabSwiping() throws Exception {
+        // Bottom sheet assertions are different based on the orientation
+        setPortraitOrientation(mScenario);
+
+        onView(withId(TAB_LAYOUT_ID)).check(matches(isDisplayed()));
+
+        // If we want to swipe the viewPager2 of tabContainerFragment in Espresso tests, at least 90
+        // percent of the view's area is displayed to the user. Swipe up the bottom Sheet to make
+        // sure it is in full Screen mode.
+        // Register bottom sheet idling resource so that we don't read bottom sheet state when
+        // in between changing states
+        final BottomSheetIdlingResource bottomSheetIdlingResource =
+                BottomSheetIdlingResource.register(mScenario);
+
+        try {
+            // Single select PhotoPicker is launched in partial screen mode
+            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
+            mScenario.onActivity(activity -> {
+                assertBottomSheetState(activity, STATE_COLLAPSED);
+            });
+
+            // Swipe up and check that the PhotoPicker is in full screen mode.
+            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
+            onView(withId(PRIVACY_TEXT_ID)).perform(ViewActions.swipeUp());
+            bottomSheetIdlingResource.setExpectedState(STATE_EXPANDED);
+            mScenario.onActivity(
+                    activity -> {
+                        assertBottomSheetState(activity, STATE_EXPANDED);
+                    });
+        } finally {
+            IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
+        }
+
+        try (ViewPager2IdlingResource idlingResource =
+                     ViewPager2IdlingResource.register(mScenario, TAB_VIEW_PAGER_ID)) {
+            // Swipe left, we should see albums tab
+            swipeLeftAndWait(TAB_VIEW_PAGER_ID);
+
+            onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                    .check(matches(isSelected()));
+            onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                    .check(matches(isNotSelected()));
+            // Verify Camera album is shown, we are in albums tab
+            onView(allOf(withText(R.string.picker_category_camera),
+                    isDescendantOfA(withId(PICKER_TAB_RECYCLERVIEW_ID)))).check(
+                    matches(isDisplayed()));
+
+            // Swipe right, we should see photos tab
+            swipeRightAndWait(TAB_VIEW_PAGER_ID);
+
+            onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                    .check(matches(isSelected()));
+            onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                    .check(matches(isNotSelected()));
+            // Verify first item is recent header, we are in photos tab
+            onView(withRecyclerView(PICKER_TAB_RECYCLERVIEW_ID)
+                    .atPositionOnView(0, R.id.date_header_title))
+                    .check(matches(withText(R.string.recent)));
+        }
+    }
+
+    @Test
+    public void testPreview_singleSelect_image() throws Exception {
+        // Bottom sheet assertions are different based on the orientation
+        setPortraitOrientation(mScenario);
+
+        onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
+
+        final BottomSheetIdlingResource bottomSheetIdlingResource =
+                BottomSheetIdlingResource.register(mScenario);
+
+        try {
+            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
+            onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
+            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
+            mScenario.onActivity(activity -> {
+                assertBottomSheetState(activity, STATE_COLLAPSED);
+            });
+
+            // Navigate to preview
+            longClickItem(PICKER_TAB_RECYCLERVIEW_ID, IMAGE_1_POSITION, ICON_THUMBNAIL_ID);
+
+            UiEventLoggerTestUtils.verifyLogWithInstanceIdAndPosition(mScenario,
+                    PhotoPickerUiEventLogger.PhotoPickerEvent.PHOTO_PICKER_PREVIEW_ITEM_MAIN_GRID,
+                    _SPECIAL_FORMAT_NONE, JPEG_IMAGE_MIME_TYPE, IMAGE_1_POSITION);
+
+            try (ViewPager2IdlingResource idlingResource =
+                         ViewPager2IdlingResource.register(mScenario, PREVIEW_VIEW_PAGER_ID)) {
+                // No dragBar in preview
+                bottomSheetIdlingResource.setExpectedState(STATE_EXPANDED);
+                onView(withId(DRAG_BAR_ID)).check(matches(not(isDisplayed())));
+                // No privacy text in preview
+                onView(withId(PRIVACY_TEXT_ID)).check(matches(not(isDisplayed())));
+                mScenario.onActivity(activity -> {
+                    assertBottomSheetState(activity, STATE_EXPANDED);
+                });
+
+                // Verify image is previewed
+                PreviewFragmentAssertionUtils.assertSingleSelectCommonLayoutMatches();
+                onView(withId(R.id.preview_imageView)).check(matches(isDisplayed()));
+                // Verify no special format icon is previewed
+                onView(withId(PREVIEW_MOTION_PHOTO_ID)).check(doesNotExist());
+                onView(withId(PREVIEW_GIF_ID)).check(doesNotExist());
+                // Verify the overflow menu is not shown for PICK_IMAGES intent
+                assertOverflowMenuNotShown();
+            }
+            // Navigate back to Photo grid
+            onView(withContentDescription("Navigate up")).perform(click());
+
+            onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
+            onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
+            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
+
+            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
+            // Shows dragBar and privacy text after we are back to Photos tab
+            mScenario.onActivity(activity -> {
+                assertBottomSheetState(activity, STATE_COLLAPSED);
+            });
+        } finally {
+            IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
+        }
+    }
+}
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/MimeTypeFilterTest.java b/tests/src/com/android/providers/media/photopicker/espresso/MimeTypeFilterTest.java
index e248e27..1905838 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/MimeTypeFilterTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/MimeTypeFilterTest.java
@@ -22,19 +22,21 @@
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isSelected;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withParent;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.Matchers.allOf;
 
-import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.core.app.ActivityScenario;
 import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
 
 import com.android.providers.media.R;
 import com.android.providers.media.library.RunOnlyOnPostsubmit;
 
-import org.junit.Rule;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -43,14 +45,23 @@
 public class MimeTypeFilterTest extends PhotoPickerBaseTest {
 
     private static final String IMAGE_MIME_TYPE = "image/*";
+    private static final String VIDEO_MIME_TYPE = "video/*";
+    public ActivityScenario<PhotoPickerTestActivity> mScenario;
 
-    @Rule
-    public ActivityScenarioRule<PhotoPickerTestActivity> mRule = new ActivityScenarioRule<>(
-            PhotoPickerBaseTest.getSingleSelectMimeTypeFilterIntent(IMAGE_MIME_TYPE));
+    @Before
+    public void launchActivity() {
+        mScenario =
+                ActivityScenario.launchActivityForResult(
+                        PhotoPickerBaseTest.getSingleSelectMimeTypeFilterIntent(IMAGE_MIME_TYPE));
+    }
+
+    @After
+    public void closeActivity() {
+        mScenario.close();
+    }
 
     @Test
     public void testPhotosTabOnlyImageItems() {
-
         onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
 
         // Two image items and one recent date header
@@ -92,4 +103,21 @@
         onView(allOf(withId(itemCountId),
                 withParent(withId(PICKER_TAB_RECYCLERVIEW_ID)))).check(doesNotExist());
     }
+
+    @Test
+    public void testPickerTabTitleText_forVariousMimeTypeFilters() {
+        onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                .check(matches(isSelected()));
+
+        mScenario = ActivityScenario.launchActivityForResult(
+                PhotoPickerBaseTest.getSingleSelectMimeTypeFilterIntent(VIDEO_MIME_TYPE));
+        onView(allOf(withText(PICKER_VIDEOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                .check(matches(isSelected()));
+
+        mScenario = ActivityScenario.launchActivityForResult(
+                PhotoPickerBaseTest.getSingleSelectionIntent());
+        onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                .check(matches(isSelected()));
+
+    }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java
index 778c1ce..aed2d96 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java
@@ -55,7 +55,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -63,8 +62,6 @@
 @RunWith(AndroidJUnit4ClassRunner.class)
 public class MultiSelectTest extends PhotoPickerBaseTest {
 
-    private static final int TAB_VIEW_PAGER_ID = R.id.picker_tab_viewpager;
-
     private ActivityScenario<PhotoPickerTestActivity> mScenario;
 
     @Before
@@ -80,11 +77,6 @@
     }
 
     @Test
-    public void testMultiSelectDoesNotShowProfileButton() {
-        assertProfileButtonNotShown();
-    }
-
-    @Test
     public void testMultiselect_showDragBar() {
         onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
     }
@@ -256,7 +248,6 @@
     }
 
     @Test
-    @Ignore("Enable after b/228574741 is fixed")
     public void testMultiSelectTabSwiping() throws Exception {
         onView(withId(TAB_LAYOUT_ID)).check(matches(isDisplayed()));
 
@@ -289,7 +280,6 @@
     }
 
     @Test
-    @Ignore("Enable after b/222013536 is fixed")
     public void testMultiSelectScrollDownToClose() {
         final BottomSheetIdlingResource bottomSheetIdlingResource =
                 BottomSheetIdlingResource.register(mScenario);
@@ -302,15 +292,6 @@
                 assertBottomSheetState(activity, STATE_EXPANDED);
             });
 
-            // Shows dragBar and privacy text after we are back to Photos tab
-            onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
-            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
-            mScenario.onActivity(activity -> {
-                assertBottomSheetState(activity, STATE_EXPANDED);
-            });
-
-            // Swiping down on drag bar or toolbar is not closing the bottom sheet as closing the
-            // bottomsheet requires a stronger downward swipe.
             onView(withId(R.id.bottom_sheet)).perform(ViewActions.swipeDown());
         } finally {
             IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
@@ -319,29 +300,4 @@
         assertThat(mScenario.getResult().getResultCode()).isEqualTo(
                 Activity.RESULT_CANCELED);
     }
-
-
-    private void assertProfileButtonNotShown() {
-        // Partial screen does not show profile button
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-
-        // Navigate to Albums tab
-        onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                .perform(click());
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-
-        final int cameraStringId = R.string.picker_category_camera;
-        // Navigate to photos in Camera album
-        onView(allOf(withText(cameraStringId),
-                isDescendantOfA(withId(PICKER_TAB_RECYCLERVIEW_ID)))).perform(click());
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-
-        // Click back button
-        onView(withContentDescription("Navigate up")).perform(click());
-
-        // on clicking back button we are back to Album grid
-        onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                .check(matches(isSelected()));
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-    }
 }
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/OrientationUtils.java b/tests/src/com/android/providers/media/photopicker/espresso/OrientationUtils.java
index 9d0be47..2cc03f6 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/OrientationUtils.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/OrientationUtils.java
@@ -28,16 +28,18 @@
 import androidx.test.core.app.ActivityScenario;
 
 class OrientationUtils {
-    public static void setLandscapeOrientation(ActivityScenario<PhotoPickerTestActivity> scenario) {
+    public static <T extends PhotoPickerTestActivity> void setLandscapeOrientation(
+            ActivityScenario<T> scenario) {
         changeOrientation(scenario, SCREEN_ORIENTATION_LANDSCAPE, ORIENTATION_LANDSCAPE);
     }
 
-    public static void setPortraitOrientation(ActivityScenario<PhotoPickerTestActivity> scenario) {
+    public static <T extends PhotoPickerTestActivity> void setPortraitOrientation(
+            ActivityScenario<T> scenario) {
         changeOrientation(scenario, SCREEN_ORIENTATION_PORTRAIT, ORIENTATION_PORTRAIT);
     }
 
-    private static void changeOrientation(
-            ActivityScenario<PhotoPickerTestActivity> scenario,
+    private static <T extends PhotoPickerTestActivity> void changeOrientation(
+            ActivityScenario<T> scenario,
             int screenOrientation,
             int configOrientation) {
         scenario.onActivity(
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerAccessibilityDisabledTestActivity.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerAccessibilityDisabledTestActivity.java
new file mode 100644
index 0000000..26d722e
--- /dev/null
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerAccessibilityDisabledTestActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.espresso;
+
+/**
+ * In espresso tests, the default accessibility mode, evaluated by
+ * {@link android.view.accessibility.AccessibilityManager#isEnabled()}, is enabled.
+ *
+ * {@link PhotoPickerAccessibilityDisabledTestActivity} is used to cover the code that requires the
+ * accessibility to be disabled.
+ *
+ * This {@link android.app.Activity} is launched using the {@link android.content.Intent}
+ * {@link android.content.Intent#ACTION_MAIN}.
+ */
+public class PhotoPickerAccessibilityDisabledTestActivity extends PhotoPickerTestActivity {
+    @Override
+    protected boolean isAccessibilityEnabled() {
+        return false;
+    }
+}
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java
index a7a5412..3d0bdc1 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java
@@ -31,15 +31,10 @@
 
 import static com.android.providers.media.PickerUriResolver.REFRESH_UI_PICKER_INTERNAL_OBSERVABLE_URI;
 import static com.android.providers.media.photopicker.espresso.BottomSheetTestUtils.assertBottomSheetState;
-import static com.android.providers.media.photopicker.espresso.CustomSwipeAction.customSwipeDownPartialScreen;
-import static com.android.providers.media.photopicker.espresso.CustomSwipeAction.swipeLeftAndWait;
-import static com.android.providers.media.photopicker.espresso.CustomSwipeAction.swipeRightAndWait;
 import static com.android.providers.media.photopicker.espresso.OrientationUtils.setLandscapeOrientation;
-import static com.android.providers.media.photopicker.espresso.OrientationUtils.setPortraitOrientation;
 import static com.android.providers.media.photopicker.espresso.OverflowMenuUtils.assertOverflowMenuNotShown;
 import static com.android.providers.media.photopicker.espresso.RecyclerViewMatcher.withRecyclerView;
 
-import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED;
 import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED;
 import static com.google.common.truth.Truth.assertThat;
 
@@ -71,8 +66,6 @@
 @RunWith(AndroidJUnit4ClassRunner.class)
 public class PhotoPickerActivityTest extends PhotoPickerBaseTest {
 
-    private static final int TAB_VIEW_PAGER_ID = R.id.picker_tab_viewpager;
-
     public ActivityScenario<PhotoPickerTestActivity> mScenario;
 
     @Before
@@ -96,7 +89,8 @@
         onView(withId(R.id.fragment_container)).check(matches(isDisplayed()));
         onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
         onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
-        // Partial screen does not show profile button
+        // Assuming by default, the tests run without a managed user
+        // Single user mode does not show profile button
         onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
         onView(withId(android.R.id.empty)).check(matches(not(isDisplayed())));
 
@@ -108,75 +102,29 @@
     }
 
     @Test
-    public void testDoesNotShowProfileButton_partialScreen() {
-        assertProfileButtonNotShown();
-    }
+    public void testProfileButtonHiddenInSingleUserMode() {
+        // Assuming that the test runs without a managed user
 
-    @Test
-    @Ignore("Enable after b/222013536 is fixed")
-    public void testDoesNotShowProfileButton_fullScreen() {
-        // Bottomsheet assertions are different for landscape mode
-        setPortraitOrientation(mScenario);
-
-        // Partial screen does not show profile button
+        // Single user mode does not show profile button in the main grid
         onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
 
-        BottomSheetTestUtils.swipeUp(mScenario);
+        onView(withId(TAB_LAYOUT_ID)).check(matches(isDisplayed()));
 
-        assertProfileButtonNotShown();
+        // On clicking albums tab item, we should see albums tab
+        onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                .perform(click());
+        onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                .check(matches(isSelected()));
+        onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
+                .check(matches(isNotSelected()));
+
+        // Single user mode does not show profile button in the albums grid
+        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
     }
 
     @Test
-    @Ignore("Enable after b/222013536 is fixed")
-    public void testBottomSheetState() {
-        // Bottom sheet assertions are different for landscape mode
-        setPortraitOrientation(mScenario);
-
-        // Register bottom sheet idling resource so that we don't read bottom sheet state when
-        // in between changing states
-        final BottomSheetIdlingResource bottomSheetIdlingResource =
-                BottomSheetIdlingResource.register(mScenario);
-
-        try {
-            // Single select PhotoPicker is launched in partial screen mode
-            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
-            onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
-            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
-            mScenario.onActivity(
-                    activity -> {
-                        assertBottomSheetState(activity, STATE_COLLAPSED);
-                    });
-
-            // Swipe up and check that the PhotoPicker is in full screen mode
-            bottomSheetIdlingResource.setExpectedState(STATE_EXPANDED);
-            onView(withId(PRIVACY_TEXT_ID)).perform(ViewActions.swipeUp());
-            mScenario.onActivity(
-                    activity -> {
-                        assertBottomSheetState(activity, STATE_EXPANDED);
-                    });
-
-            // Swipe down and check that the PhotoPicker is in partial screen mode
-            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
-            onView(withId(PRIVACY_TEXT_ID)).perform(ViewActions.swipeDown());
-            mScenario.onActivity(
-                    activity -> {
-                        assertBottomSheetState(activity, STATE_COLLAPSED);
-                    });
-
-            // Swiping down on drag bar is not strong enough as closing the bottomsheet requires a
-            // stronger downward swipe using espresso.
-            // Simply swiping down on R.id.bottom_sheet throws an error from espresso, as the view
-            // is only 60% visible, but downward swipe is only successful on an element which is 90%
-            // visible.
-            onView(withId(R.id.bottom_sheet)).perform(customSwipeDownPartialScreen());
-        } finally {
-            IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
-        }
-        assertThat(mScenario.getResult().getResultCode()).isEqualTo(Activity.RESULT_CANCELED);
-    }
-
-    @Test
-    @Ignore("Enable after b/222013536 is fixed")
+    @Ignore("b/313489524")
+    // TODO(b/313489524): Fix flaky orientation change in the photo picker espresso tests
     public void testBottomSheetStateInLandscapeMode() {
         // Bottom sheet assertions are different for landscape mode
         setLandscapeOrientation(mScenario);
@@ -254,69 +202,6 @@
     }
 
     @Test
-    @Ignore("Enable after b/222013536 is fixed")
-    public void testTabSwiping() throws Exception {
-        onView(withId(TAB_LAYOUT_ID)).check(matches(isDisplayed()));
-
-        // If we want to swipe the viewPager2 of tabContainerFragment in Espresso tests, at least 90
-        // percent of the view's area is displayed to the user. Swipe up the bottom Sheet to make
-        // sure it is in full Screen mode.
-        // Register bottom sheet idling resource so that we don't read bottom sheet state when
-        // in between changing states
-        final BottomSheetIdlingResource bottomSheetIdlingResource =
-                BottomSheetIdlingResource.register(mScenario);
-
-        try {
-
-            // When accessibility is enabled, we always launch the photo picker in full screen mode.
-            // Accessibility is enabled in Espresso test, so we can't check the COLLAPSED state.
-            //            // Single select PhotoPicker is launched in partial screen mode
-            //            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
-            //            mScenario.onActivity(activity -> {
-            //                assertBottomSheetState(activity, STATE_COLLAPSED);
-            //            });
-
-            // Swipe up and check that the PhotoPicker is in full screen mode.
-            //            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
-            //            onView(withId(PRIVACY_TEXT_ID)).perform(ViewActions.swipeUp());
-            bottomSheetIdlingResource.setExpectedState(STATE_EXPANDED);
-            mScenario.onActivity(
-                    activity -> {
-                        assertBottomSheetState(activity, STATE_EXPANDED);
-                    });
-        } finally {
-            IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
-        }
-
-        try (ViewPager2IdlingResource idlingResource =
-                ViewPager2IdlingResource.register(mScenario, TAB_VIEW_PAGER_ID)) {
-            // Swipe left, we should see albums tab
-            swipeLeftAndWait(TAB_VIEW_PAGER_ID);
-
-            onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                    .check(matches(isSelected()));
-            onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                    .check(matches(isNotSelected()));
-            // Verify Camera album is shown, we are in albums tab
-            onView(allOf(withText(R.string.picker_category_camera),
-                    isDescendantOfA(withId(PICKER_TAB_RECYCLERVIEW_ID)))).check(
-                    matches(isDisplayed()));
-
-            // Swipe right, we should see photos tab
-            swipeRightAndWait(TAB_VIEW_PAGER_ID);
-
-            onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                    .check(matches(isSelected()));
-            onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                    .check(matches(isNotSelected()));
-            // Verify first item is recent header, we are in photos tab
-            onView(withRecyclerView(PICKER_TAB_RECYCLERVIEW_ID)
-                    .atPositionOnView(0, R.id.date_header_title))
-                    .check(matches(withText(R.string.recent)));
-        }
-    }
-
-    @Test
     public void testResetOnCloudProviderChange() throws InterruptedException {
         // Enable cloud media feature for the activity through the test config store
         mScenario.onActivity(
@@ -350,28 +235,4 @@
         onView(allOf(withText(PICKER_PHOTOS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
                 .check(matches(isSelected()));
     }
-
-    private void assertProfileButtonNotShown() {
-        // Partial screen does not show profile button
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-
-        // Navigate to Albums tab
-        onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                .perform(click());
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-
-        final int cameraStringId = R.string.picker_category_camera;
-        // Navigate to photos in Camera album
-        onView(allOf(withText(cameraStringId),
-                isDescendantOfA(withId(PICKER_TAB_RECYCLERVIEW_ID)))).perform(click());
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-
-        // Click back button
-        onView(withContentDescription("Navigate up")).perform(click());
-
-        // on clicking back button we are back to Album grid
-        onView(allOf(withText(PICKER_ALBUMS_STRING_ID), isDescendantOfA(withId(TAB_LAYOUT_ID))))
-                .check(matches(isSelected()));
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
-    }
 }
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java
index e254445..cc9626f 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java
@@ -57,9 +57,11 @@
 
 public class PhotoPickerBaseTest {
     protected static final int PICKER_TAB_RECYCLERVIEW_ID = R.id.picker_tab_recyclerview;
+    protected static final int TAB_VIEW_PAGER_ID = R.id.picker_tab_viewpager;
     protected static final int TAB_LAYOUT_ID = R.id.tab_layout;
     protected static final int PICKER_PHOTOS_STRING_ID = R.string.picker_photos;
     protected static final int PICKER_ALBUMS_STRING_ID = R.string.picker_albums;
+    protected static final int PICKER_VIDEOS_STRING_ID = R.string.picker_videos;
     protected static final int PREVIEW_VIEW_PAGER_ID = R.id.preview_viewPager;
     protected static final int ICON_CHECK_ID = R.id.icon_check;
     protected static final int ICON_THUMBNAIL_ID = R.id.icon_thumbnail;
@@ -75,6 +77,8 @@
     protected static final String JPEG_IMAGE_MIME_TYPE = "image/jpeg";
     protected static final String MP4_VIDEO_MIME_TYPE = "video/mp4";
 
+    protected static final String MANAGED_SELECTION_ENABLED_EXTRA = "MANAGED_SELECTION_ENABLE";
+
     protected static final int DIMEN_PREVIEW_ADD_OR_SELECT_WIDTH
             = R.dimen.preview_add_or_select_width;
 
@@ -123,6 +127,17 @@
         sUserSelectImagesForAppIntent.putExtras(extras);
     }
 
+    private static final Intent sPickerChoiceManagedSelectionIntent;
+    static {
+        sPickerChoiceManagedSelectionIntent = new Intent(
+                MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP);
+        sPickerChoiceManagedSelectionIntent.addCategory(
+                Intent.CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST);
+        Bundle extras = new Bundle();
+        extras.putInt(Intent.EXTRA_UID, Process.myUid());
+        extras.putBoolean(MANAGED_SELECTION_ENABLED_EXTRA, true);
+        sPickerChoiceManagedSelectionIntent.putExtras(extras);
+    }
     private static final File IMAGE_1_FILE = new File(Environment.getExternalStorageDirectory(),
             Environment.DIRECTORY_DCIM + "/Camera"
                     + "/image_" + System.currentTimeMillis() + ".jpeg");
@@ -155,6 +170,9 @@
         return sUserSelectImagesForAppIntent;
     }
 
+    public static Intent getPickerChoiceManagedSelectionIntent() {
+        return sPickerChoiceManagedSelectionIntent;
+    }
     public static Intent getMultiSelectionIntent(int max) {
         final Intent intent = new Intent(sMultiSelectionIntent);
         Bundle extras = new Bundle();
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java
index 5bfedba..5026235 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java
@@ -16,7 +16,7 @@
 
 package com.android.providers.media.photopicker.espresso;
 
-import static com.android.providers.media.photopicker.espresso.PhotoPickerUserSelectActivityTest.MANAGED_SELECTION_ENABLED_EXTRA;
+import static com.android.providers.media.photopicker.espresso.PhotoPickerBaseTest.MANAGED_SELECTION_ENABLED_EXTRA;
 
 import static org.mockito.Mockito.RETURNS_SMART_NULLS;
 import static org.mockito.Mockito.mock;
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerUserSelectActivityTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerUserSelectActivityTest.java
index a37a466..110fbb7 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerUserSelectActivityTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerUserSelectActivityTest.java
@@ -16,11 +16,13 @@
 
 package com.android.providers.media.photopicker.espresso;
 
+import static androidx.test.InstrumentationRegistry.getTargetContext;
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isNotSelected;
 import static androidx.test.espresso.matcher.ViewMatchers.isSelected;
 import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
@@ -39,6 +41,7 @@
 import android.content.Intent;
 import android.provider.MediaStore;
 
+import androidx.lifecycle.ViewModelProvider;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.core.app.ActivityScenario;
 import androidx.test.filters.SdkSuppress;
@@ -46,6 +49,8 @@
 
 import com.android.providers.media.R;
 import com.android.providers.media.library.RunOnlyOnPostsubmit;
+import com.android.providers.media.photopicker.data.Selection;
+import com.android.providers.media.photopicker.viewmodel.PickerViewModel;
 
 import org.junit.After;
 import org.junit.Test;
@@ -56,8 +61,6 @@
 @RunWith(AndroidJUnit4ClassRunner.class)
 public class PhotoPickerUserSelectActivityTest extends PhotoPickerBaseTest {
 
-    public static final String MANAGED_SELECTION_ENABLED_EXTRA = "MANAGED_SELECTION_ENABLE";
-
     public ActivityScenario<PhotoPickerTestActivity> mScenario;
 
     @After
@@ -89,7 +92,7 @@
     @Test
     public void testActivityProfileButtonNotShown() {
         launchValidActivity();
-        // Partial screen does not show profile button
+        // User select mode does not show profile button
         onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
 
         // Navigate to Albums tab
@@ -174,6 +177,60 @@
     }
 
     @Test
+    public void testPreview_deselectAll_showAllowNone() throws Exception {
+        launchValidActivityWithManagedSelectionEnabled();
+        onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
+
+        // Select first and second image
+        clickItem(PICKER_TAB_RECYCLERVIEW_ID, IMAGE_1_POSITION, ICON_THUMBNAIL_ID);
+        // Navigate to preview
+        onView(withId(VIEW_SELECTED_BUTTON_ID)).perform(click());
+
+        try (ViewPager2IdlingResource idlingResource =
+                     ViewPager2IdlingResource.register(mScenario, PREVIEW_VIEW_PAGER_ID)) {
+            final int previewAddButtonId = R.id.preview_add_button;
+            final int previewSelectButtonId = R.id.preview_selected_check_button;
+            final String selectedString =
+                    getTargetContext().getResources().getString(R.string.selected);
+
+            // Verify that, initially, we show "selected" check button
+            onView(withId(previewSelectButtonId)).check(matches(isSelected()));
+            onView(withId(previewSelectButtonId)).check(matches(withText(selectedString)));
+            // Verify that the text in Add button matches "Allow (1)"
+            onView(withId(previewAddButtonId))
+                    .check(matches(withText("Allow (1)")));
+
+            // Deselect item in preview
+            onView(withId(previewSelectButtonId)).perform(click());
+            onView(withId(previewSelectButtonId)).check(matches(isNotSelected()));
+            onView(withId(previewSelectButtonId)).check(matches(withText(R.string.deselected)));
+            // Verify that the text in Add button now changes to "Allow none"
+            onView(withId(previewAddButtonId))
+                    .check(matches(withText("Allow none")));
+            // Verify that we have 0 items in selected items
+            mScenario.onActivity(activity -> {
+                Selection selection =
+                        new ViewModelProvider(activity).get(PickerViewModel.class).getSelection();
+                assertThat(selection.getSelectedItemCount().getValue()).isEqualTo(0);
+            });
+
+            // Select the item again
+            onView(withId(previewSelectButtonId)).perform(click());
+            onView(withId(previewSelectButtonId)).check(matches(isSelected()));
+            onView(withId(previewSelectButtonId)).check(matches(withText(selectedString)));
+            // Verify that the text in Add button now changes back to "Allow (1)"
+            onView(withId(previewAddButtonId))
+                    .check(matches(withText("Allow (1)")));
+            // Verify that we have 1 item in selected items
+            mScenario.onActivity(activity -> {
+                Selection selection =
+                        new ViewModelProvider(activity).get(PickerViewModel.class).getSelection();
+                assertThat(selection.getSelectedItemCount().getValue()).isEqualTo(1);
+            });
+        }
+    }
+
+    @Test
     public void testUserSelectCorrectHeaderTextIsShown() {
         launchValidActivity();
         onView(withText(R.string.picker_header_permissions)).check(matches(isDisplayed()));
@@ -188,9 +245,7 @@
 
     /** Test helper to launch a valid test activity. */
     private void launchValidActivityWithManagedSelectionEnabled() {
-        Intent intent = PhotoPickerBaseTest.getUserSelectImagesForAppIntent();
-        intent.putExtra(MANAGED_SELECTION_ENABLED_EXTRA, true);
-        mScenario =
-                ActivityScenario.launchActivityForResult(intent);
+        mScenario = ActivityScenario.launchActivityForResult(
+                PhotoPickerBaseTest.getPickerChoiceManagedSelectionIntent());
     }
 }
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewFragmentAssertionUtils.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewFragmentAssertionUtils.java
new file mode 100644
index 0000000..fefc641
--- /dev/null
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewFragmentAssertionUtils.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.espresso;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.hamcrest.Matchers.not;
+
+import com.android.providers.media.R;
+
+class PreviewFragmentAssertionUtils {
+    private static final int PREVIEW_ADD_OR_SELECT_BUTTON_ID = R.id.preview_add_or_select_button;
+
+    static void assertSingleSelectCommonLayoutMatches() {
+        onView(withId(R.id.preview_viewPager)).check(matches(isDisplayed()));
+        onView(withId(PREVIEW_ADD_OR_SELECT_BUTTON_ID)).check(matches(isDisplayed()));
+        // Verify that the text in Add button
+        onView(withId(PREVIEW_ADD_OR_SELECT_BUTTON_ID)).check(matches(withText(R.string.add)));
+
+        onView(withId(R.id.preview_selected_check_button)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.preview_add_button)).check(matches(not(isDisplayed())));
+    }
+}
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
index f5480f3..3de3575 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
@@ -29,13 +29,11 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withParent;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
-import static com.android.providers.media.photopicker.espresso.BottomSheetTestUtils.assertBottomSheetState;
 import static com.android.providers.media.photopicker.espresso.OrientationUtils.setLandscapeOrientation;
 import static com.android.providers.media.photopicker.espresso.OrientationUtils.setPortraitOrientation;
 import static com.android.providers.media.photopicker.espresso.OverflowMenuUtils.assertOverflowMenuNotShown;
 import static com.android.providers.media.photopicker.espresso.RecyclerViewTestUtils.longClickItem;
 
-import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED;
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.hamcrest.Matchers.allOf;
@@ -47,7 +45,6 @@
 import android.view.View;
 
 import androidx.appcompat.widget.Toolbar;
-import androidx.test.espresso.IdlingRegistry;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
 
@@ -68,74 +65,6 @@
             = new ActivityScenarioRule<>(PhotoPickerBaseTest.getSingleSelectionIntent());
 
     @Test
-    public void testPreview_singleSelect_image() throws Exception {
-        onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
-
-        // Bottomsheet assertions are different for landscape mode
-        setPortraitOrientation(mRule.getScenario());
-
-        final BottomSheetIdlingResource bottomSheetIdlingResource =
-                BottomSheetIdlingResource.register(mRule.getScenario());
-
-        try {
-            // TODO(b/226318844): When accessibility is enabled, we always launch the photo picker
-            // in full screen mode. Accessibility is enabled in Espresso test, we can't check the
-            // COLLAPSED state.
-//            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
-//            onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
-//            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
-//            mRule.getScenario().onActivity(activity -> {
-//                assertBottomSheetState(activity, STATE_COLLAPSED);
-//            });
-
-            // Navigate to preview
-            longClickItem(PICKER_TAB_RECYCLERVIEW_ID, IMAGE_1_POSITION, ICON_THUMBNAIL_ID);
-
-            UiEventLoggerTestUtils.verifyLogWithInstanceIdAndPosition(
-                    mRule, PhotoPickerEvent.PHOTO_PICKER_PREVIEW_ITEM_MAIN_GRID,
-                    _SPECIAL_FORMAT_NONE, JPEG_IMAGE_MIME_TYPE, IMAGE_1_POSITION);
-
-            try (ViewPager2IdlingResource idlingResource =
-                    ViewPager2IdlingResource.register(mRule.getScenario(), PREVIEW_VIEW_PAGER_ID)) {
-                // No dragBar in preview
-                bottomSheetIdlingResource.setExpectedState(STATE_EXPANDED);
-                onView(withId(DRAG_BAR_ID)).check(matches(not(isDisplayed())));
-                // No privacy text in preview
-                onView(withId(PRIVACY_TEXT_ID)).check(matches(not(isDisplayed())));
-                mRule.getScenario().onActivity(activity -> {
-                    assertBottomSheetState(activity, STATE_EXPANDED);
-                });
-
-                // Verify image is previewed
-                assertSingleSelectCommonLayoutMatches();
-                onView(withId(R.id.preview_imageView)).check(matches(isDisplayed()));
-                // Verify no special format icon is previewed
-                onView(withId(PREVIEW_MOTION_PHOTO_ID)).check(doesNotExist());
-                onView(withId(PREVIEW_GIF_ID)).check(doesNotExist());
-                // Verify the overflow menu is not shown for PICK_IMAGES intent
-                assertOverflowMenuNotShown();
-            }
-            // Navigate back to Photo grid
-            onView(withContentDescription("Navigate up")).perform(click());
-
-            onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
-            onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
-            onView(withId(PRIVACY_TEXT_ID)).check(matches(isDisplayed()));
-
-            // TODO(b/226318844): When accessibility is enabled, we always launch the photo picker
-            // in full screen mode. Accessibility is enabled in Espresso test, we can't check the
-            // COLLAPSED state.
-//            bottomSheetIdlingResource.setExpectedState(STATE_COLLAPSED);
-//            // Shows dragBar and privacy text after we are back to Photos tab
-//            mRule.getScenario().onActivity(activity -> {
-//                assertBottomSheetState(activity, STATE_COLLAPSED);
-//            });
-        } finally {
-            IdlingRegistry.getInstance().unregister(bottomSheetIdlingResource);
-        }
-    }
-
-    @Test
     public void testPreview_singleSelect_video() throws Exception {
         onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
 
@@ -148,7 +77,7 @@
 
         try (ViewPager2IdlingResource idlingResource =
                 ViewPager2IdlingResource.register(mRule.getScenario(), PREVIEW_VIEW_PAGER_ID)) {
-            assertSingleSelectCommonLayoutMatches();
+            PreviewFragmentAssertionUtils.assertSingleSelectCommonLayoutMatches();
             // Verify thumbnail view is displayed
             onView(withId(R.id.preview_video_image)).check(matches(isDisplayed()));
             // TODO (b/232792753): Assert video player visibility using custom IdlingResource
@@ -182,7 +111,7 @@
         try (ViewPager2IdlingResource idlingResource =
                 ViewPager2IdlingResource.register(mRule.getScenario(), PREVIEW_VIEW_PAGER_ID)) {
             // Verify image is previewed
-            assertSingleSelectCommonLayoutMatches();
+            PreviewFragmentAssertionUtils.assertSingleSelectCommonLayoutMatches();
             onView(withId(R.id.preview_imageView)).check(matches(isDisplayed()));
         }
 
@@ -263,14 +192,4 @@
         assertThat(bottomBarDrawable).isInstanceOf(ColorDrawable.class);
         assertThat(((ColorDrawable) bottomBarDrawable).getColor()).isEqualTo(expectedColor);
     }
-
-    private void assertSingleSelectCommonLayoutMatches() {
-        onView(withId(R.id.preview_viewPager)).check(matches(isDisplayed()));
-        onView(withId(PREVIEW_ADD_OR_SELECT_BUTTON_ID)).check(matches(isDisplayed()));
-        // Verify that the text in Add button
-        onView(withId(PREVIEW_ADD_OR_SELECT_BUTTON_ID)).check(matches(withText(R.string.add)));
-
-        onView(withId(R.id.preview_selected_check_button)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.preview_add_button)).check(matches(not(isDisplayed())));
-    }
 }
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/SpecialFormatSingleSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/SpecialFormatSingleSelectTest.java
index 74f37b4..2567296 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/SpecialFormatSingleSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/SpecialFormatSingleSelectTest.java
@@ -40,7 +40,6 @@
 import com.android.providers.media.library.RunOnlyOnPostsubmit;
 import com.android.providers.media.photopicker.metrics.PhotoPickerUiEventLogger.PhotoPickerEvent;
 
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -158,7 +157,6 @@
     }
 
     @Test
-    @Ignore("Enable after b/222013536 is fixed")
     public void testPreview_singleSelect_nonAnimatedWebp() throws Exception {
         onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
 
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/UiEventLoggerTestUtils.java b/tests/src/com/android/providers/media/photopicker/espresso/UiEventLoggerTestUtils.java
index 06c9643..f088253 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/UiEventLoggerTestUtils.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/UiEventLoggerTestUtils.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.Mockito.verify;
 
+import androidx.test.core.app.ActivityScenario;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 
 import com.android.internal.logging.UiEventLogger;
@@ -45,8 +46,15 @@
     static void verifyLogWithInstanceIdAndPosition(
             ActivityScenarioRule<PhotoPickerTestActivity> rule, UiEventLogger.UiEventEnum event,
             int uid, String packageName, int position) {
-        rule.getScenario().onActivity(activity ->
-                verify(activity.getLogger()).logWithInstanceIdAndPosition(
-                        event, uid, packageName, activity.getInstanceId(), position));
+        verifyLogWithInstanceIdAndPosition(rule.getScenario(), event, uid, packageName, position);
+    }
+
+    static <T extends PhotoPickerTestActivity> void verifyLogWithInstanceIdAndPosition(
+            ActivityScenario<T> scenario, UiEventLogger.UiEventEnum event,
+            int uid, String packageName, int position) {
+        scenario.onActivity(activity ->
+                verify(activity.getLogger())
+                        .logWithInstanceIdAndPosition(
+                                event, uid, packageName, activity.getInstanceId(), position));
     }
 }
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/ViewPager2IdlingResource.java b/tests/src/com/android/providers/media/photopicker/espresso/ViewPager2IdlingResource.java
index a7de9d6..27521ba 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/ViewPager2IdlingResource.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/ViewPager2IdlingResource.java
@@ -68,8 +68,8 @@
      * @return {@link ViewPager2IdlingResource} that is registered to the activity related to the
      *     given {@link ActivityScenarioRule} and the resource ID of the ViewPager2.
      */
-    public static ViewPager2IdlingResource register(
-            ActivityScenario<PhotoPickerTestActivity> scenario, int viewPager2Id) {
+    public static <T extends PhotoPickerTestActivity> ViewPager2IdlingResource register(
+            ActivityScenario<T> scenario, int viewPager2Id) {
         final ViewPager2IdlingResource[] idlingResources = new ViewPager2IdlingResource[1];
         scenario.onActivity(
                 (activity -> {
diff --git a/tests/src/com/android/providers/media/photopicker/sync/PickerSyncManagerTest.java b/tests/src/com/android/providers/media/photopicker/sync/PickerSyncManagerTest.java
index 3cd2858..ae7221c 100644
--- a/tests/src/com/android/providers/media/photopicker/sync/PickerSyncManagerTest.java
+++ b/tests/src/com/android/providers/media/photopicker/sync/PickerSyncManagerTest.java
@@ -111,7 +111,8 @@
         assertThat(periodicWorkRequest.getWorkSpec().expedited).isFalse();
         assertThat(periodicWorkRequest.getWorkSpec().isPeriodic()).isTrue();
         assertThat(periodicWorkRequest.getWorkSpec().id).isNotNull();
-        assertThat(periodicWorkRequest.getWorkSpec().constraints.requiresBatteryNotLow()).isTrue();
+        assertThat(periodicWorkRequest.getWorkSpec().constraints.requiresCharging()).isTrue();
+        assertThat(periodicWorkRequest.getWorkSpec().constraints.requiresDeviceIdle()).isTrue();
         assertThat(periodicWorkRequest.getWorkSpec().input
                 .getInt(SYNC_WORKER_INPUT_SYNC_SOURCE, -1))
                 .isEqualTo(SYNC_LOCAL_AND_CLOUD);
@@ -123,7 +124,7 @@
         assertThat(periodicResetRequest.getWorkSpec().expedited).isFalse();
         assertThat(periodicResetRequest.getWorkSpec().isPeriodic()).isTrue();
         assertThat(periodicResetRequest.getWorkSpec().id).isNotNull();
-        assertThat(periodicResetRequest.getWorkSpec().constraints.requiresBatteryNotLow()).isTrue();
+        assertThat(periodicResetRequest.getWorkSpec().constraints.requiresCharging()).isTrue();
         assertThat(periodicResetRequest.getWorkSpec().constraints.requiresDeviceIdle()).isTrue();
         assertThat(periodicResetRequest.getWorkSpec().input
                 .getInt(SYNC_WORKER_INPUT_SYNC_SOURCE, -1))
@@ -162,7 +163,8 @@
         assertThat(periodicWorkRequest.getWorkSpec().expedited).isFalse();
         assertThat(periodicWorkRequest.getWorkSpec().isPeriodic()).isTrue();
         assertThat(periodicWorkRequest.getWorkSpec().id).isNotNull();
-        assertThat(periodicWorkRequest.getWorkSpec().constraints.requiresBatteryNotLow()).isTrue();
+        assertThat(periodicWorkRequest.getWorkSpec().constraints.requiresCharging()).isTrue();
+        assertThat(periodicWorkRequest.getWorkSpec().constraints.requiresDeviceIdle()).isTrue();
         assertThat(periodicWorkRequest.getWorkSpec().input
                 .getInt(SYNC_WORKER_INPUT_SYNC_SOURCE, -1))
                 .isEqualTo(SYNC_LOCAL_AND_CLOUD);
@@ -174,7 +176,7 @@
         assertThat(periodicResetRequest.getWorkSpec().expedited).isFalse();
         assertThat(periodicResetRequest.getWorkSpec().isPeriodic()).isTrue();
         assertThat(periodicResetRequest.getWorkSpec().id).isNotNull();
-        assertThat(periodicResetRequest.getWorkSpec().constraints.requiresBatteryNotLow()).isTrue();
+        assertThat(periodicResetRequest.getWorkSpec().constraints.requiresCharging()).isTrue();
         assertThat(periodicResetRequest.getWorkSpec().constraints.requiresDeviceIdle()).isTrue();
         assertThat(periodicResetRequest.getWorkSpec().input
                 .getInt(SYNC_WORKER_INPUT_SYNC_SOURCE, -1))
@@ -189,10 +191,32 @@
     }
 
     @Test
+    public void testAdhocProactiveSyncLocalOnly() {
+        setupPickerSyncManager(/* schedulePeriodicSyncs */ false);
+
+        mPickerSyncManager.syncMediaProactively(/* localOnly */ true);
+        verify(mMockWorkManager, times(1))
+                .enqueueUniqueWork(anyString(),
+                        any(),
+                        mOneTimeWorkRequestArgumentCaptor.capture());
+
+        final OneTimeWorkRequest workRequest = mOneTimeWorkRequestArgumentCaptor.getValue();
+        assertThat(workRequest.getWorkSpec().workerClassName)
+                .isEqualTo(ProactiveSyncWorker.class.getName());
+        assertThat(workRequest.getWorkSpec().expedited).isFalse();
+        assertThat(workRequest.getWorkSpec().isPeriodic()).isFalse();
+        assertThat(workRequest.getWorkSpec().id).isNotNull();
+        assertThat(workRequest.getWorkSpec().constraints.requiresBatteryNotLow()).isTrue();
+        assertThat(workRequest.getWorkSpec().input
+                .getInt(SYNC_WORKER_INPUT_SYNC_SOURCE, -1))
+                .isEqualTo(SYNC_LOCAL_ONLY);
+    }
+
+    @Test
     public void testAdhocProactiveSync() {
         setupPickerSyncManager(/* schedulePeriodicSyncs */ false);
 
-        mPickerSyncManager.syncAllMediaProactively();
+        mPickerSyncManager.syncMediaProactively(/* localOnly */ false);
         verify(mMockWorkManager, times(1))
                 .enqueueUniqueWork(anyString(),
                         any(),
diff --git a/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java b/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java
index 113ecfc..4ca8dd9 100644
--- a/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java
+++ b/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java
@@ -63,6 +63,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.lifecycle.LiveData;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.providers.media.TestConfigStore;
@@ -70,6 +71,7 @@
 import com.android.providers.media.photopicker.PickerSyncController;
 import com.android.providers.media.photopicker.data.ItemsProvider;
 import com.android.providers.media.photopicker.data.PaginationParameters;
+import com.android.providers.media.photopicker.data.Selection;
 import com.android.providers.media.photopicker.data.UserIdManager;
 import com.android.providers.media.photopicker.data.model.Category;
 import com.android.providers.media.photopicker.data.model.Item;
@@ -84,6 +86,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
@@ -119,6 +122,7 @@
         when(mApplication.getApplicationContext()).thenReturn(sTargetContext);
         mConfigStore = new TestConfigStore();
         mConfigStore.enableCloudMediaFeatureAndSetAllowedCloudProviderPackages(TEST_PACKAGE_NAME);
+        mConfigStore.enablePickerChoiceManagedSelectionEnabled();
 
         getInstrumentation().runOnMainSync(() -> {
             mPickerViewModel = new PickerViewModel(mApplication) {
@@ -209,8 +213,8 @@
 
         LiveData<PickerViewModel.PaginatedItemsResult> testItems =
                 mPickerViewModel.getPaginatedItemsForAction(
-                ACTION_VIEW_CREATED,
-                new PaginationParameters());
+                        ACTION_VIEW_CREATED,
+                        new PaginationParameters());
         DataLoaderThread.waitForIdle();
 
         assertThat(testItems).isNotNull();
@@ -224,6 +228,45 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 34, codeName = "UpsideDownCake")
+    @Test
+    public void test_getRemainingPreGrantedItems_correctItemsLoaded() {
+        // Enable managed selection for this test.
+        Intent intent = new Intent(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP);
+        intent.putExtra(Intent.EXTRA_UID, 0);
+        mPickerViewModel.parseValuesFromIntent(intent);
+
+        final int numberOfTestItems = 4;
+        final List<Item> expectedItems = generateFakeImageItemList(numberOfTestItems);
+        for (Item item : expectedItems) {
+            item.setPreGranted();
+        }
+        mItemsProvider.setItems(expectedItems);
+        List<String> preGrantedItems = List.of(expectedItems.get(0).getId(),
+                expectedItems.get(1).getId(),
+                expectedItems.get(2).getId());
+        Selection selection = mPickerViewModel.getSelection();
+        // Add 3 item ids is preGranted set.
+        selection.setPreGrantedItemSet(new HashSet<>(preGrantedItems));
+
+        // adding 1 item in selection item set.
+        selection.addSelectedItem(expectedItems.get(1));
+
+        // revoking grant for 1 id.
+        selection.removeSelectedItem(expectedItems.get(0));
+
+        // since only one item is added in selection set, the size should be one.
+        assertThat(selection.getSelectedItems().size()).isEqualTo(1);
+
+        // Since out of 3 one grant was removed, so there would be one item loaded when remaining
+        // grants are loaded.
+        mPickerViewModel.getRemainingPreGrantedItems();
+        DataLoaderThread.waitForIdle();
+
+        // Now the selection set should have 2 items.
+        assertThat(selection.getSelectedItems().size()).isEqualTo(2);
+    }
+
     private static Item generateFakeImageItem(String id) {
         final long dateTakenMs = System.currentTimeMillis()
                 + Long.parseLong(id) * DateUtils.DAY_IN_MILLIS;
@@ -367,6 +410,60 @@
             return c;
         }
 
+        @Override
+        public Cursor getLocalItemsForSelection(Category category,
+                @NonNull List<Integer> localIdSelection,
+                @Nullable String[] mimeTypes,
+                @Nullable UserId userId,
+                @Nullable CancellationSignal cancellationSignal) throws IllegalArgumentException {
+            final String[] all_projection = new String[]{
+                    ID,
+                    // This field is unique to the cursor received by the pickerVIewModel.
+                    // It is not a part of cloud provider contract.
+                    ROW_ID,
+                    DATE_TAKEN_MILLIS,
+                    SYNC_GENERATION,
+                    MIME_TYPE,
+                    STANDARD_MIME_TYPE_EXTENSION,
+                    SIZE_BYTES,
+                    MEDIA_STORE_URI,
+                    DURATION_MILLIS,
+                    IS_FAVORITE,
+                    WIDTH,
+                    HEIGHT,
+                    ORIENTATION,
+                    DATA,
+                    AUTHORITY,
+            };
+            final MatrixCursor c = new MatrixCursor(all_projection);
+
+            int itr = 1;
+            for (Item item : mItemList) {
+                if (localIdSelection.contains(Integer.parseInt(item.getId()))) {
+                    c.addRow(new String[]{
+                            item.getId(),
+                            String.valueOf(itr),
+                            String.valueOf(item.getDateTaken()),
+                            String.valueOf(item.getGenerationModified()),
+                            item.getMimeType(),
+                            String.valueOf(item.getSpecialFormat()),
+                            "1", // size_bytes
+                            null, // media_store_uri
+                            String.valueOf(item.getDuration()),
+                            "0", // is_favorite
+                            String.valueOf(800), // width
+                            String.valueOf(500), // height
+                            String.valueOf(0), // orientation
+                            "/storage/emulated/0/foo",
+                            PickerSyncController.LOCAL_PICKER_PROVIDER_AUTHORITY
+                    });
+                    itr++;
+                }
+            }
+            return c;
+
+        }
+
         @Nullable
         public Cursor getAllCategories(@Nullable String[] mimeType, @Nullable UserId userId,
                 @Nullable CancellationSignal cancellationSignal) {
diff --git a/tests/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceServiceTest.java b/tests/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceServiceTest.java
index 12b46ef..efba7ab 100644
--- a/tests/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceServiceTest.java
+++ b/tests/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceServiceTest.java
@@ -16,6 +16,10 @@
 
 package com.android.providers.media.stableuris.job;
 
+import static com.android.providers.media.tests.utils.PublicVolumeSetupHelper.createNewPublicVolume;
+import static com.android.providers.media.tests.utils.PublicVolumeSetupHelper.deletePublicVolumes;
+import static com.android.providers.media.util.FileUtils.getVolumePath;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -34,6 +38,7 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.MediaStore;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SdkSuppress;
@@ -49,7 +54,6 @@
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -68,14 +72,18 @@
 
     private static final String OWNERSHIP_BACKUP_NAME = "leveldb-ownership";
 
+    private static final String PUBLIC_VOLUME_BACKUP_NAME = "leveldb-";
+
     private static boolean sInitialDeviceConfigValueForInternal = false;
 
     private static boolean sInitialDeviceConfigValueForExternal = false;
 
+    private static boolean sInitialDeviceConfigValueForPublic = false;
+
     private static final int IDLE_JOB_ID = -500;
 
     @BeforeClass
-    public static void setUpClass() {
+    public static void setUpClass() throws Exception {
         adoptShellPermission();
 
         // Read existing value of the flag
@@ -91,10 +99,20 @@
         DeviceConfig.setProperty(ConfigStore.NAMESPACE_MEDIAPROVIDER,
                 ConfigStore.ConfigStoreImpl.KEY_STABILIZE_VOLUME_EXTERNAL, Boolean.TRUE.toString(),
                 false);
+        sInitialDeviceConfigValueForPublic = Boolean.parseBoolean(
+                DeviceConfig.getProperty(ConfigStore.NAMESPACE_MEDIAPROVIDER,
+                        ConfigStore.ConfigStoreImpl.KEY_STABILIZE_VOLUME_PUBLIC));
+        DeviceConfig.setProperty(ConfigStore.NAMESPACE_MEDIAPROVIDER,
+                ConfigStore.ConfigStoreImpl.KEY_STABILIZE_VOLUME_PUBLIC, Boolean.TRUE.toString(),
+                false);
+
+        createNewPublicVolume();
     }
 
     @AfterClass
-    public static void tearDownClass() throws IOException {
+    public static void tearDownClass() throws Exception {
+        deletePublicVolumes();
+
         // Restore previous value of the flag
         DeviceConfig.setProperty(ConfigStore.NAMESPACE_MEDIAPROVIDER,
                 ConfigStore.ConfigStoreImpl.KEY_STABILIZE_VOLUME_INTERNAL,
@@ -102,6 +120,9 @@
         DeviceConfig.setProperty(ConfigStore.NAMESPACE_MEDIAPROVIDER,
                 ConfigStore.ConfigStoreImpl.KEY_STABILIZE_VOLUME_EXTERNAL,
                 String.valueOf(sInitialDeviceConfigValueForExternal), false);
+        DeviceConfig.setProperty(ConfigStore.NAMESPACE_MEDIAPROVIDER,
+                ConfigStore.ConfigStoreImpl.KEY_STABILIZE_VOLUME_PUBLIC,
+                String.valueOf(sInitialDeviceConfigValueForPublic), false);
         SystemClock.sleep(3000);
         dropShellPermission();
     }
@@ -192,6 +213,63 @@
     }
 
     @Test
+    public void testDataMigrationForPublicVolume() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final ContentResolver resolver = context.getContentResolver();
+        final Set<String> volNames = MediaStore.getExternalVolumeNames(context);
+
+        for (String volName : volNames) {
+            if (!MediaStore.VOLUME_EXTERNAL_PRIMARY.equalsIgnoreCase(volName)
+                    && !MediaStore.VOLUME_INTERNAL.equalsIgnoreCase(volName)) {
+                // public volume
+                Set<String> newFilePaths = new HashSet<String>();
+                Map<String, Long> pathToIdMap = new HashMap<>();
+                MediaStore.waitForIdle(resolver);
+
+                try {
+                    for (int i = 0; i < 10; i++) {
+                        File volPath = getVolumePath(context, volName);
+                        final File dir = new File(volPath.getAbsoluteFile() + "/Download");
+                        final File file = new File(dir, System.nanoTime() + ".png");
+
+                        // Write 1 byte because 0 byte files are not valid in the db
+                        try (FileOutputStream fos = new FileOutputStream(file)) {
+                            fos.write(1);
+                        }
+
+                        Uri uri = MediaStore.scanFile(resolver, file);
+                        long id = ContentUris.parseId(uri);
+                        newFilePaths.add(file.getAbsolutePath());
+                        pathToIdMap.put(file.getAbsolutePath(), id);
+                    }
+
+                    assertFalse(newFilePaths.isEmpty());
+                    MediaStore.waitForIdle(resolver);
+                    // Creates backup
+                    MediaStore.runIdleMaintenanceForStableUris(resolver);
+
+                    verifyLevelDbPresence(resolver, PUBLIC_VOLUME_BACKUP_NAME + volName);
+                    verifyLevelDbPresence(resolver, OWNERSHIP_BACKUP_NAME);
+                    // Verify that all internal files are backed up
+                    for (String filePath : newFilePaths) {
+                        BackupIdRow backupIdRow = BackupIdRow.deserialize(
+                                MediaStore.readBackup(resolver, volName, filePath));
+                        assertNotNull(backupIdRow);
+                        assertEquals(pathToIdMap.get(filePath).longValue(), backupIdRow.getId());
+                        assertEquals(UserHandle.myUserId(), backupIdRow.getUserId());
+                        assertEquals(context.getPackageName(),
+                                MediaStore.getOwnerPackageName(resolver, backupIdRow.getOwnerPackageId()));
+                    }
+                } finally {
+                    for (String path : newFilePaths) {
+                        new File(path).delete();
+                    }
+                }
+            }
+        }
+    }
+
+    @Test
     public void testJobScheduling() {
         try {
             final Context context = InstrumentationRegistry.getTargetContext();
diff --git a/tools/photopicker/res/layout/activity_main.xml b/tools/photopicker/res/layout/activity_main.xml
index 441cd0f..6348a4e 100644
--- a/tools/photopicker/res/layout/activity_main.xml
+++ b/tools/photopicker/res/layout/activity_main.xml
@@ -100,6 +100,13 @@
             android:textSize="16sp" />
     </LinearLayout>
 
+    <CheckBox
+        android:id="@+id/cbx_ordered_selection"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="ORDERED SELECTION"
+        android:textSize="16sp" />
+
     <Button
         android:id="@+id/launch_button"
         android:layout_width="match_parent"
diff --git a/tools/photopicker/src/com/android/providers/media/tools/photopicker/PhotoPickerToolActivity.java b/tools/photopicker/src/com/android/providers/media/tools/photopicker/PhotoPickerToolActivity.java
index fc91077..1d549f3 100644
--- a/tools/photopicker/src/com/android/providers/media/tools/photopicker/PhotoPickerToolActivity.java
+++ b/tools/photopicker/src/com/android/providers/media/tools/photopicker/PhotoPickerToolActivity.java
@@ -63,6 +63,7 @@
     private CheckBox mSetSelectionCountCheckBox;
     private CheckBox mAllowMultipleCheckBox;
     private CheckBox mGetContentCheckBox;
+    private CheckBox mOrderedSelectionCheckBox;
     private EditText mMaxCountText;
     private EditText mMimeTypeText;
 
@@ -77,6 +78,7 @@
         mSetMimeTypeCheckBox = findViewById(R.id.cbx_set_mime_type);
         mSetSelectionCountCheckBox = findViewById(R.id.cbx_set_selection_count);
         mSetVideoOnlyCheckBox = findViewById(R.id.cbx_set_video_only);
+        mOrderedSelectionCheckBox = findViewById(R.id.cbx_ordered_selection);
         mMaxCountText = findViewById(R.id.edittext_max_count);
         mMimeTypeText = findViewById(R.id.edittext_mime_type);
         mScrollView = findViewById(R.id.scrollview);
@@ -169,6 +171,10 @@
                 intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
             } else {
                 intent.putExtra(EXTRA_PICK_IMAGES_MAX, PICK_IMAGES_MAX_LIMIT);
+                // ordered selection is not allowed in get content.
+                if (mOrderedSelectionCheckBox.isChecked()) {
+                    intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_IN_ORDER, true);
+                }
             }
         }