Merging from ub-launcher3-master @ build 6586492

Bug:154410862
Test: manual, presubmit on the source branch
x20/teams/android-launcher/merge/ub-launcher3-master_rvc-d1-dev_6586492.html

Change-Id: Idf7dd47b2116e64d31c425c608291f1eb7017428
diff --git a/res/color/bottom_nav_item_color.xml b/res/color/bottom_nav_item_color.xml
index 17d8fce..bf94de9 100644
--- a/res/color/bottom_nav_item_color.xml
+++ b/res/color/bottom_nav_item_color.xml
@@ -20,5 +20,5 @@
         android:color="?android:colorAccent" />
     <item
         android:state_checked="false"
-        android:color="@color/material_grey500" />
+        android:color="@color/bottom_bar_icon_unchecked_color" />
 </selector>
\ No newline at end of file
diff --git a/res/drawable/color_chip.xml b/res/drawable/color_chip.xml
deleted file mode 100644
index 11301b1..0000000
--- a/res/drawable/color_chip.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
-     Copyright (C) 2019 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_activated="true"
-        android:drawable="@drawable/color_chip_hollow" />
-    <item
-        android:state_activated="false"
-        android:drawable="@drawable/color_chip_filled" />
-    <item
-        android:drawable="@drawable/color_chip_filled"/>
-</selector>
\ No newline at end of file
diff --git a/res/drawable/color_chip_hollow.xml b/res/drawable/color_chip_hollow.xml
index 699dc60..49e6a4d 100644
--- a/res/drawable/color_chip_hollow.xml
+++ b/res/drawable/color_chip_hollow.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-
      Copyright (C) 2019 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +16,7 @@
 -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
+        android:id="@+id/center_fill"
         android:height="@dimen/component_color_chip_size"
         android:width="@dimen/component_color_chip_size"
         android:gravity="center">
@@ -34,7 +34,7 @@
             android:innerRadius="24dp"
             android:thickness="@dimen/option_border_width"
             android:useLevel="false">
-        <solid android:color="@android:color/black"/>
+        <solid android:color="?android:colorAccent"/>
         </shape>
     </item>
 </layer-list>
diff --git a/res/drawable/ic_check_circle_filled_24px.xml b/res/drawable/ic_check_circle_filled_24px.xml
deleted file mode 100644
index 01d2091..0000000
--- a/res/drawable/ic_check_circle_filled_24px.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-     Copyright (C) 2019 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:fillColor="@color/accent_color"
-      android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM10,17l-4,-4l1.4,-1.4l2.6,2.6l6.6,-6.6L18,9L10,17z"/>
-  <path
-      android:pathData="m8.0085,14.9866 l-1.9939,-1.994 0.6892,-0.6889 0.6892,-0.6889 1.2925,1.2926c0.7109,0.711 1.3035,1.2926 1.3169,1.2926 0.0134,0 1.5034,-1.4789 3.3111,-3.2865l3.2866,-3.2865 0.689,0.689 0.689,0.689 -3.9878,3.9878 -3.9878,3.9878z"
-      android:strokeWidth="0.02439024"
-      android:fillColor="@color/selected_check_color"/>
-</vector>
diff --git a/res/layout/fragment_custom_theme_name.xml b/res/layout/fragment_custom_theme_name.xml
index ab3c459..532e904 100644
--- a/res/layout/fragment_custom_theme_name.xml
+++ b/res/layout/fragment_custom_theme_name.xml
@@ -36,7 +36,7 @@
             android:clipToPadding="false"
             android:background="@color/fullscreen_preview_background"
             app:layout_constrainedHeight="true"
-            app:layout_constraintBottom_toTopOf="@+id/component_options_title"
+            app:layout_constraintBottom_toTopOf="@+id/component_scroll_view"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintHeight_max="@dimen/preview_pager_max_height"
             app:layout_constraintStart_toStartOf="parent"
@@ -47,40 +47,41 @@
             <include layout="@layout/theme_preview_card"/>
         </FrameLayout>
 
-        <TextView
-            android:id="@+id/component_options_title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginVertical="18dp"
-            android:layout_marginHorizontal="16dp"
-            android:textAlignment="center"
-            android:textAppearance="@style/TitleTextAppearance"
-            android:textSize="@dimen/component_options_title_size"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/component_preview_container"
-            app:layout_constraintBottom_toTopOf="@+id/edit_text_container"/>
+        <ScrollView
+                android:id="@+id/component_scroll_view"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/component_preview_container"
+                app:layout_constraintBottom_toBottomOf="parent">
 
-        <FrameLayout
-            android:id="@+id/edit_text_container"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/component_options_title"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintVertical_bias="1">
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical">
 
-            <EditText
-                android:id="@+id/custom_theme_name"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginVertical="16dp"
-                android:layout_marginHorizontal="16dp"
-                android:layout_gravity="center|top"
-                android:importantForAutofill="no"
-                android:minWidth="300dp"
-                style="@style/CustomThemeNameEditText"/>
-        </FrameLayout>
+                <TextView
+                        android:id="@+id/component_options_title"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginVertical="18dp"
+                        android:layout_marginHorizontal="16dp"
+                        android:textAlignment="center"
+                        android:textAppearance="@style/TitleTextAppearance"
+                        android:textSize="@dimen/component_options_title_size"/>
+
+                <EditText
+                        android:id="@+id/custom_theme_name"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginVertical="16dp"
+                        android:layout_marginHorizontal="16dp"
+                        android:layout_gravity="center|top"
+                        android:importantForAutofill="no"
+                        android:minWidth="300dp"
+                        style="@style/CustomThemeNameEditText"/>
+            </LinearLayout>
+        </ScrollView>
     </androidx.constraintlayout.widget.ConstraintLayout>
 </LinearLayout>
diff --git a/res/layout/fragment_grid_picker.xml b/res/layout/fragment_grid_picker.xml
index 7f35689..84c8163 100644
--- a/res/layout/fragment_grid_picker.xml
+++ b/res/layout/fragment_grid_picker.xml
@@ -38,7 +38,7 @@
                 android:layout_height="0dp"
                 android:paddingTop="@dimen/preview_content_padding_top"
                 android:paddingBottom="@dimen/preview_content_padding_bottom"
-                android:background="@color/fullscreen_preview_background"
+                android:background="@color/preview_pager_background"
                 android:clipToPadding="false"
                 app:layout_constrainedHeight="true"
                 app:layout_constraintStart_toStartOf="parent"
diff --git a/res/layout/fragment_theme_picker.xml b/res/layout/fragment_theme_picker.xml
index a773207..2e3a6bb 100644
--- a/res/layout/fragment_theme_picker.xml
+++ b/res/layout/fragment_theme_picker.xml
@@ -36,7 +36,7 @@
                 android:layout_height="0dp"
                 android:paddingTop="@dimen/preview_content_padding_top"
                 android:paddingBottom="@dimen/preview_content_padding_bottom"
-                android:background="@color/fullscreen_preview_background"
+                android:background="@color/preview_pager_background"
                 android:clipToPadding="false"
                 app:layout_constrainedHeight="true"
                 app:layout_constraintStart_toStartOf="parent"
diff --git a/res/layout/grid_preview_card.xml b/res/layout/grid_preview_card.xml
index 2939f80..e824460 100644
--- a/res/layout/grid_preview_card.xml
+++ b/res/layout/grid_preview_card.xml
@@ -17,6 +17,8 @@
 <androidx.cardview.widget.CardView
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/FullContentPreviewCard"
+    android:id="@+id/grid_preview_card"
+    android:contentDescription="@string/grid_preview_card_content_description"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="center">
@@ -35,5 +37,6 @@
     <FrameLayout
         android:id="@+id/grid_preview_container"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"
+        android:importantForAccessibility="noHideDescendants" />
 </androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/res/layout/theme_color_option.xml b/res/layout/theme_color_option.xml
index 9a3c4c4..8d55626 100644
--- a/res/layout/theme_color_option.xml
+++ b/res/layout/theme_color_option.xml
@@ -26,6 +26,5 @@
         android:layout_width="@dimen/component_color_chip_container_size"
         android:layout_height="@dimen/component_color_chip_container_size"
         android:layout_gravity="center"
-        android:scaleType="center"
-        android:src="@drawable/color_chip"/>
+        android:scaleType="center"/>
 </FrameLayout>
diff --git a/res/layout/theme_info_view.xml b/res/layout/theme_info_view.xml
index 2bb8701..f228668 100644
--- a/res/layout/theme_info_view.xml
+++ b/res/layout/theme_info_view.xml
@@ -49,6 +49,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center"
             android:layout_marginHorizontal="@dimen/theme_info_margin"
+            android:importantForAccessibility="no"
             android:textSize="@dimen/theme_info_text_size"
             android:textColor="?android:attr/colorForeground"
             android:text="@string/font_component_option_thumbnail"/>
diff --git a/res/layout/theme_preview_card.xml b/res/layout/theme_preview_card.xml
index 74d1e68..e1e3491 100644
--- a/res/layout/theme_preview_card.xml
+++ b/res/layout/theme_preview_card.xml
@@ -17,6 +17,8 @@
 <androidx.cardview.widget.CardView
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/FullContentPreviewCard"
+    android:id="@+id/theme_preview_card"
+    android:contentDescription="@string/theme_preview_card_content_description"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="center">
@@ -35,5 +37,6 @@
     <FrameLayout
         android:id="@+id/theme_preview_container"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
+        android:layout_height="match_parent"
+        android:importantForAccessibility="noHideDescendants" />
 </androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/res/layout/theme_preview_color_icons.xml b/res/layout/theme_preview_color_icons.xml
index ccfb300..f1e7522 100644
--- a/res/layout/theme_preview_color_icons.xml
+++ b/res/layout/theme_preview_color_icons.xml
@@ -19,8 +19,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/color_icons_section"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@color/primary_color">
+    android:layout_height="match_parent">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="match_parent"
@@ -28,7 +27,8 @@
         android:paddingHorizontal="@dimen/preview_theme_color_icons_padding_horizontal"
         android:paddingTop="@dimen/preview_theme_color_icons_padding_top"
         android:paddingBottom="@dimen/preview_theme_color_icons_padding_bottom"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:background="@color/theme_preview_color_icons_background">
 
         <!-- Title -->
         <TextView
@@ -37,6 +37,7 @@
             android:layout_height="wrap_content"
             android:text="@string/theme_preview_icons_section_title"
             android:textSize="@dimen/preview_theme_color_icons_title_text_size"
+            android:textColor="@color/theme_preview_color_icons_title_color"
             android:lineHeight="16dp"
             android:gravity="center"
             app:layout_constraintStart_toStartOf="parent"
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index c6b2a3f..4f369a7 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -20,6 +20,9 @@
 
     <color name="icon_thumbnail_color">@color/white_88_alpha</color>
 
+    <color name="theme_preview_color_icons_background">@color/material_black_100</color>
+    <color name="theme_preview_color_icons_title_color">@color/material_white_100</color>
+
     <color name="control_grey">#b3b3b3</color>
     <color name="switch_track_tint">#171717</color>
     <color name="switch_thumb_tint">#bdbdbd</color>
@@ -33,9 +36,6 @@
     <color name="tip_dot_color">#81C995</color>
     <color name="tip_dot_line_color">#000000</color>
 
-    <color name="selected_check_color">#000000</color>
-    <color name="selected_check_background_color">#81C995</color>
-
     <color name="toolbar_icon_color">@color/text_color_light</color>
 
     <color name="divider_color">@color/white_14_alpha</color>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 82d02b0..d5291c0 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -33,6 +33,8 @@
     <color name="theme_preview_icon_color">@color/google_grey700</color>
     <color name="theme_preview_workspace_shadow_color_dark">#B0000000</color>
     <color name="theme_preview_workspace_shadow_color_transparent">@android:color/transparent</color>
+    <color name="theme_preview_color_icons_background">@color/material_white_100</color>
+    <color name="theme_preview_color_icons_title_color">@color/black_87_alpha</color>
 
     <color name="text_color_dark">#2d2d2d</color>
     <color name="text_color_light">@color/material_white_text</color>
@@ -50,9 +52,6 @@
     <color name="tip_dot_color">#34A853</color>
     <color name="tip_dot_line_color">#FFFFFF</color>
 
-    <color name="selected_check_color">#FFFFFF</color>
-    <color name="selected_check_background_color">#1E8E3E</color>
-
     <color name="toolbar_icon_color">@color/text_color_dark</color>
 
     <color name="divider_color">@color/black_14_alpha</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 4f78920..1c6242e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -76,10 +76,10 @@
     <dimen name="preview_theme_topbar_container_margin_horizontal">16dp</dimen>
     <dimen name="preview_theme_color_icons_container_margin_horizontal">10dp</dimen>
     <dimen name="preview_theme_qsb_container_margin_horizontal">14dp</dimen>
-    <dimen name="preview_theme_smart_space_date_size">16sp</dimen>
+    <dimen name="preview_theme_smart_space_date_size">18sp</dimen>
     <dimen name="preview_theme_app_icon_size">64dp</dimen>
     <dimen name="preview_theme_app_icon_shape_text_margin_top">8dp</dimen>
-    <dimen name="preview_theme_app_icon_shape_text_size">14sp</dimen>
+    <dimen name="preview_theme_app_icon_shape_text_size">16sp</dimen>
     <dimen name="preview_theme_color_icons_padding_top">12dp</dimen>
     <dimen name="preview_theme_color_icons_padding_bottom">20dp</dimen>
     <dimen name="preview_theme_color_icons_padding_horizontal">18dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d80f74d..569600e 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -46,6 +46,12 @@
         [CHAR LIMIT=20] -->
     <string name="apply_btn">Apply</string>
 
+    <!-- Content description of theme preview card. [CHAR_LIMIT=30]-->
+    <string name="theme_preview_card_content_description">Style preview</string>
+
+    <!-- Content description of grid preview card. [CHAR_LIMIT=30]-->
+    <string name="grid_preview_card_content_description">Grid preview</string>
+
     <!-- Content description indicating that the selected option is currently applied to the device. [CHAR_LIMIT=NONE] -->
     <string name="option_applied_description"><xliff:g name="style_name">%1$s</xliff:g>, currently applied</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0b61fe4..dd0f2a3 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -51,7 +51,7 @@
         <item name="itemTextAppearanceActive">@style/BottomNavTextAppearanceActive</item>
         <item name="itemTextAppearanceInactive">@style/BottomNavTextAppearance</item>
         <item name="itemBackground">?android:attr/selectableItemBackgroundBorderless</item>
-        <item name="android:background">?android:colorPrimary</item>
+        <item name="android:background">@color/bottom_bar_background_color</item>
     </style>
 
     <style name="BottomNavTextAppearance" parent="TitleTextAppearance">
diff --git a/src/com/android/customization/model/grid/GridOptionsManager.java b/src/com/android/customization/model/grid/GridOptionsManager.java
index 84f5373..a0ae04c 100644
--- a/src/com/android/customization/model/grid/GridOptionsManager.java
+++ b/src/com/android/customization/model/grid/GridOptionsManager.java
@@ -61,11 +61,6 @@
         new FetchTask(mProvider, callback, reload).execute();
     }
 
-    /** See if using surface view to render grid options */
-    public boolean usesSurfaceView() {
-        return mProvider.usesSurfaceView();
-    }
-
     /** Call through content provider API to render preview */
     public Bundle renderPreview(Bundle bundle, String gridName) {
         return mProvider.renderPreview(gridName, bundle);
diff --git a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
index 6a47f95..175f71a 100644
--- a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
+++ b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
@@ -21,7 +21,6 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.util.Pair;
 import android.view.SurfaceView;
 
@@ -71,11 +70,6 @@
         return mPreviewUtils.supportsPreview();
     }
 
-    boolean usesSurfaceView() {
-        // If no version code is returned, fall back to V1.
-        return TextUtils.equals(mVersion, "V2");
-    }
-
     /**
      * Retrieve the available grids.
      * @param reload whether to reload grid options if they're cached.
diff --git a/src/com/android/customization/model/theme/DefaultThemeProvider.java b/src/com/android/customization/model/theme/DefaultThemeProvider.java
index dc93770..ddadc7d 100644
--- a/src/com/android/customization/model/theme/DefaultThemeProvider.java
+++ b/src/com/android/customization/model/theme/DefaultThemeProvider.java
@@ -109,9 +109,11 @@
     }
 
     private void loadAll() {
-        // Add "Custom" option at the first.
-        mThemes.add(new CustomTheme(CustomTheme.newId(), mContext.getString(
-                R.string.custom_theme), new HashMap<>(), null));
+        // Add "Custom" option at the beginning.
+        mThemes.add(new CustomTheme.Builder()
+                .setId(CustomTheme.newId())
+                .setTitle(mContext.getString(R.string.custom_theme))
+                .build(mContext));
 
         addDefaultTheme();
 
@@ -314,7 +316,13 @@
                 JSONArray customThemes = new JSONArray(serializedThemes);
                 for (int i = 0; i < customThemes.length(); i++) {
                     JSONObject jsonTheme = customThemes.getJSONObject(i);
-                    ThemeBundle.Builder builder = convertJsonToBuilder(jsonTheme);
+                    CustomTheme.Builder builder = new CustomTheme.Builder();
+                    try {
+                        convertJsonToBuilder(jsonTheme, builder);
+                    } catch (NameNotFoundException | NotFoundException e) {
+                        Log.i(TAG, "Couldn't parse serialized custom theme", e);
+                        builder = null;
+                    }
                     if (builder != null) {
                         if (TextUtils.isEmpty(builder.getTitle())) {
                             builder.setTitle(mContext.getString(R.string.custom_theme_title,
@@ -323,17 +331,21 @@
                         mThemes.add(builder.build(mContext));
                     } else {
                         Log.w(TAG, "Couldn't read stored custom theme, resetting");
-                        mThemes.add(new CustomTheme(CustomTheme.newId(),
-                                mContext.getString(R.string.custom_theme_title,
-                                customThemesCount + 1), new HashMap<>(), null));
+                        mThemes.add(new CustomTheme.Builder()
+                                .setId(CustomTheme.newId())
+                                .setTitle(mContext.getString(
+                                        R.string.custom_theme_title, customThemesCount + 1))
+                                .build(mContext));
                     }
                     customThemesCount++;
                 }
             } catch (JSONException e) {
                 Log.w(TAG, "Couldn't read stored custom theme, resetting", e);
-                mThemes.add(new CustomTheme(CustomTheme.newId(), mContext.getString(
-                        R.string.custom_theme_title, customThemesCount + 1),
-                        new HashMap<>(), null));
+                mThemes.add(new CustomTheme.Builder()
+                        .setId(CustomTheme.newId())
+                        .setTitle(mContext.getString(
+                                R.string.custom_theme_title, customThemesCount + 1))
+                        .build(mContext));
             }
         }
     }
@@ -341,49 +353,10 @@
     @Nullable
     @Override
     public ThemeBundle.Builder parseThemeBundle(String serializedTheme) throws JSONException {
-        return parseCustomTheme(serializedTheme);
-    }
-
-    @Nullable
-    @Override
-    public CustomTheme.Builder parseCustomTheme(String serializedTheme) throws JSONException {
         JSONObject theme = new JSONObject(serializedTheme);
-        return convertJsonToBuilder(theme);
-    }
-
-    @Nullable
-    private CustomTheme.Builder convertJsonToBuilder(JSONObject theme) throws JSONException {
         try {
-            Map<String, String> customPackages = new HashMap<>();
-            Iterator<String> keysIterator = theme.keys();
-
-            while (keysIterator.hasNext()) {
-                String category = keysIterator.next();
-                customPackages.put(category, theme.getString(category));
-            }
-            CustomTheme.Builder builder = new CustomTheme.Builder();
-            mOverlayProvider.addShapeOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_SHAPE));
-            mOverlayProvider.addFontOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_FONT));
-            mOverlayProvider.addColorOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_COLOR));
-            mOverlayProvider.addAndroidIconOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_ICON_ANDROID));
-            mOverlayProvider.addSysUiIconOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_ICON_SYSUI));
-            mOverlayProvider.addNoPreviewIconOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_ICON_SETTINGS));
-            mOverlayProvider.addNoPreviewIconOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_ICON_LAUNCHER));
-            mOverlayProvider.addNoPreviewIconOverlay(builder,
-                    customPackages.get(OVERLAY_CATEGORY_ICON_THEMEPICKER));
-            if (theme.has(THEME_TITLE_FIELD)) {
-                builder.setTitle(theme.getString(THEME_TITLE_FIELD));
-            }
-            if (theme.has(THEME_ID_FIELD)) {
-                builder.setId(theme.getString(THEME_ID_FIELD));
-            }
+            ThemeBundle.Builder builder = new ThemeBundle.Builder();
+            convertJsonToBuilder(theme, builder);
             return builder;
         } catch (NameNotFoundException | NotFoundException e) {
             Log.i(TAG, "Couldn't parse serialized custom theme", e);
@@ -391,6 +364,52 @@
         }
     }
 
+    @Nullable
+    @Override
+    public CustomTheme.Builder parseCustomTheme(String serializedTheme) throws JSONException {
+        JSONObject theme = new JSONObject(serializedTheme);
+        try {
+            CustomTheme.Builder builder = new CustomTheme.Builder();
+            convertJsonToBuilder(theme, builder);
+            return builder;
+        } catch (NameNotFoundException | NotFoundException e) {
+            Log.i(TAG, "Couldn't parse serialized custom theme", e);
+            return null;
+        }
+    }
+
+    private void convertJsonToBuilder(JSONObject theme, ThemeBundle.Builder builder)
+            throws JSONException, NameNotFoundException, NotFoundException {
+        Map<String, String> customPackages = new HashMap<>();
+        Iterator<String> keysIterator = theme.keys();
+
+        while (keysIterator.hasNext()) {
+            String category = keysIterator.next();
+            customPackages.put(category, theme.getString(category));
+        }
+        mOverlayProvider.addShapeOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_SHAPE));
+        mOverlayProvider.addFontOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_FONT));
+        mOverlayProvider.addColorOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_COLOR));
+        mOverlayProvider.addAndroidIconOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_ICON_ANDROID));
+        mOverlayProvider.addSysUiIconOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_ICON_SYSUI));
+        mOverlayProvider.addNoPreviewIconOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_ICON_SETTINGS));
+        mOverlayProvider.addNoPreviewIconOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_ICON_LAUNCHER));
+        mOverlayProvider.addNoPreviewIconOverlay(builder,
+                customPackages.get(OVERLAY_CATEGORY_ICON_THEMEPICKER));
+        if (theme.has(THEME_TITLE_FIELD)) {
+            builder.setTitle(theme.getString(THEME_TITLE_FIELD));
+        }
+        if (builder instanceof CustomTheme.Builder && theme.has(THEME_ID_FIELD)) {
+            ((CustomTheme.Builder) builder).setId(theme.getString(THEME_ID_FIELD));
+        }
+    }
 
     @Override
     public ThemeBundle findEquivalent(ThemeBundle other) {
diff --git a/src/com/android/customization/model/theme/custom/CustomTheme.java b/src/com/android/customization/model/theme/custom/CustomTheme.java
index 9c14f01..a1ee106 100644
--- a/src/com/android/customization/model/theme/custom/CustomTheme.java
+++ b/src/com/android/customization/model/theme/custom/CustomTheme.java
@@ -39,7 +39,7 @@
      */
     private final String mId;
 
-    public CustomTheme(@NonNull String id, String title, Map<String, String> overlayPackages,
+    private CustomTheme(@NonNull String id, String title, Map<String, String> overlayPackages,
             @Nullable PreviewInfo previewInfo) {
         super(title, overlayPackages, false, previewInfo);
         mId = id;
@@ -80,6 +80,11 @@
         return isDefined() && super.isActive(manager);
     }
 
+    @Override
+    public boolean isEquivalent(ThemeBundle other) {
+        return isDefined() && super.isEquivalent(other);
+    }
+
     public boolean isDefined() {
         return getPreviewInfo() != null;
     }
@@ -89,7 +94,8 @@
 
         @Override
         public CustomTheme build(Context context) {
-            return new CustomTheme(mId, mTitle, mPackages, createPreviewInfo(context));
+            return new CustomTheme(mId, mTitle, mPackages,
+                    mPackages.isEmpty() ? null : createPreviewInfo(context));
         }
 
         public Builder setId(String id) {
diff --git a/src/com/android/customization/model/theme/custom/ThemeComponentOption.java b/src/com/android/customization/model/theme/custom/ThemeComponentOption.java
index b3d9d15..178098c 100644
--- a/src/com/android/customization/model/theme/custom/ThemeComponentOption.java
+++ b/src/com/android/customization/model/theme/custom/ThemeComponentOption.java
@@ -35,6 +35,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.StateListDrawable;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -315,8 +316,21 @@
         @Override
         public void bindThumbnailTile(View view) {
             @ColorInt int color = resolveColor(view.getResources());
-            ((ImageView) view.findViewById(R.id.option_tile)).setImageTintList(
+            LayerDrawable selectedOption = (LayerDrawable) view.getResources().getDrawable(
+                    R.drawable.color_chip_hollow, view.getContext().getTheme());
+            Drawable unselectedOption = view.getResources().getDrawable(
+                    R.drawable.color_chip_filled, view.getContext().getTheme());
+
+            selectedOption.findDrawableByLayerId(R.id.center_fill).setTintList(
                     ColorStateList.valueOf(color));
+            unselectedOption.setTintList(ColorStateList.valueOf(color));
+
+            StateListDrawable stateListDrawable = new StateListDrawable();
+            stateListDrawable.addState(new int[] {android.R.attr.state_activated}, selectedOption);
+            stateListDrawable.addState(
+                    new int[] {-android.R.attr.state_activated}, unselectedOption);
+
+            ((ImageView) view.findViewById(R.id.option_tile)).setImageDrawable(stateListDrawable);
             view.setContentDescription(mLabel);
         }
 
diff --git a/src/com/android/customization/module/DefaultCustomizationInjector.java b/src/com/android/customization/module/DefaultCustomizationInjector.java
index 7358d8f..e18cb2d 100644
--- a/src/com/android/customization/module/DefaultCustomizationInjector.java
+++ b/src/com/android/customization/module/DefaultCustomizationInjector.java
@@ -89,8 +89,9 @@
             Context context,
             WallpaperInfo wallpaperInfo,
             int mode,
+            boolean viewAsHome,
             boolean testingModeEnabled) {
-        return PreviewFragment.newInstance(wallpaperInfo, mode, testingModeEnabled);
+        return PreviewFragment.newInstance(wallpaperInfo, mode, viewAsHome, testingModeEnabled);
     }
 
     @Override
diff --git a/src/com/android/customization/picker/CustomizationPickerActivity.java b/src/com/android/customization/picker/CustomizationPickerActivity.java
index 11bcbdf..2ee114b 100644
--- a/src/com/android/customization/picker/CustomizationPickerActivity.java
+++ b/src/com/android/customization/picker/CustomizationPickerActivity.java
@@ -145,13 +145,8 @@
         }
 
         mBottomActionBar = findViewById(R.id.bottom_actionbar);
-        mBottomActionBar.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
-            // Only update the visibility of mBottomNav when mBottomActionBar visibility changes.
-            // Since the listener will be triggered by mBottomActionBar and its child views.
-            if (mBottomActionBar.getVisibility() == mBottomNav.getVisibility()) {
-                mBottomNav.setVisibility(mBottomActionBar.isVisible() ? View.GONE : View.VISIBLE);
-            }
-        });
+        mBottomActionBar.addVisibilityChangeListener(
+                isVisible -> mBottomNav.setVisibility(isVisible ? View.GONE : View.VISIBLE));
     }
 
     @Override
@@ -357,8 +352,13 @@
     }
 
     @Override
-    public void showViewOnlyPreview(WallpaperInfo wallpaperInfo) {
-        mDelegate.showViewOnlyPreview(wallpaperInfo);
+    public void showViewOnlyPreview(WallpaperInfo wallpaperInfo, boolean isViewAsHome) {
+        mDelegate.showViewOnlyPreview(wallpaperInfo, isViewAsHome);
+    }
+
+    @Override
+    public void show(String collectionId) {
+        mDelegate.show(collectionId);
     }
 
     @Override
diff --git a/src/com/android/customization/picker/WallpaperPreviewer.java b/src/com/android/customization/picker/WallpaperPreviewer.java
index 8f69d59..03e7031 100644
--- a/src/com/android/customization/picker/WallpaperPreviewer.java
+++ b/src/com/android/customization/picker/WallpaperPreviewer.java
@@ -89,6 +89,15 @@
         }
     }
 
+    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+    @MainThread
+    public void onStop() {
+        if (mWallpaperConnection != null) {
+            mWallpaperConnection.disconnect();
+            mWallpaperConnection = null;
+        }
+    }
+
     @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
     @MainThread
     public void onDestroy() {
@@ -164,10 +173,7 @@
 
         mWallpaperConnection = new WallpaperConnection(
                 getWallpaperIntent(homeWallpaper.getWallpaperComponent()), mActivity,
-                new WallpaperConnection.WallpaperConnectionListener() {
-                    @Override
-                    public void onEngineShown() {}
-                }, mPreviewGlobalRect);
+                /* listener= */ null, mPreviewGlobalRect);
 
         LiveTileOverlay.INSTANCE.update(new RectF(mPreviewLocalRect),
                 ((CardView) mHomePreview.getParent()).getRadius());
diff --git a/src/com/android/customization/picker/grid/GridFragment.java b/src/com/android/customization/picker/grid/GridFragment.java
index 05f535c..b6a749e 100644
--- a/src/com/android/customization/picker/grid/GridFragment.java
+++ b/src/com/android/customization/picker/grid/GridFragment.java
@@ -19,7 +19,6 @@
 
 import static com.android.customization.picker.ViewOnlyFullPreviewActivity.SECTION_GRID;
 import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_GRID_OPTION;
-import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_GRID_USES_SURFACE_VIEW;
 import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_WALLPAPER_INFO;
 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
 
@@ -31,7 +30,6 @@
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ImageView;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
@@ -89,12 +87,10 @@
     private GridOptionsManager mGridManager;
     private GridOption mSelectedOption;
     private ContentLoadingProgressBar mLoading;
-    private ViewGroup mGridPreviewContainer;
     private View mContent;
     private View mError;
     private BottomActionBar mBottomActionBar;
     private ThemesUserEventLogger mEventLogger;
-    private boolean mReloadOptionsAfterApplying;
 
     private GridOptionPreviewer mGridOptionPreviewer;
 
@@ -130,7 +126,6 @@
         View view = inflater.inflate(
                 R.layout.fragment_grid_picker, container, /* attachToRoot */ false);
         setUpToolbar(view);
-        mGridPreviewContainer = view.findViewById(R.id.grid_preview_container);
         mContent = view.findViewById(R.id.content_section);
         mOptionsContainer = view.findViewById(R.id.options_container);
         mLoading = view.findViewById(R.id.loading_indicator);
@@ -140,12 +135,9 @@
         Glide.get(getContext()).clearMemory();
         setUpOptions(savedInstanceState);
 
-        ImageView wallpaperPreviewImage = view.findViewById(R.id.wallpaper_preview_image);
-        wallpaperPreviewImage.setOnClickListener(v -> showFullPreview());
         SurfaceView wallpaperSurface = view.findViewById(R.id.wallpaper_preview_surface);
-        WallpaperPreviewer wallpaperPreviewer = new WallpaperPreviewer(
-                getLifecycle(), getActivity(), wallpaperPreviewImage, wallpaperSurface);
-
+        WallpaperPreviewer wallpaperPreviewer = new WallpaperPreviewer(getLifecycle(),
+                getActivity(), view.findViewById(R.id.wallpaper_preview_image), wallpaperSurface);
         // Loads current Wallpaper.
         CurrentWallpaperInfoFactory factory = InjectorProvider.getInjector()
                 .getCurrentWallpaperFactory(getContext().getApplicationContext());
@@ -154,6 +146,9 @@
             wallpaperPreviewer.setWallpaper(mHomeWallpaper);
         }, false);
 
+        mGridOptionPreviewer = new GridOptionPreviewer(mGridManager,
+                view.findViewById(R.id.grid_preview_container));
+
         view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
             @Override
             public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -162,6 +157,8 @@
                 view.removeOnLayoutChangeListener(this);
             }
         });
+
+        view.findViewById(R.id.grid_preview_card).setOnClickListener(v -> showFullPreview());
         return view;
     }
 
@@ -206,18 +203,6 @@
         mGridManager.apply(gridOption, mApplyGridCallback);
     }
 
-    private void updatePreview() {
-        if (mGridOptionPreviewer != null) {
-            mGridOptionPreviewer.release();
-        }
-        if (getContext() == null) {
-            return;
-        }
-        mGridOptionPreviewer = new GridOptionPreviewer(
-                getContext(), mGridManager, mGridPreviewContainer);
-        mGridOptionPreviewer.setGridOption(mSelectedOption, mGridManager.usesSurfaceView());
-    }
-
     private void setUpOptions(@Nullable Bundle savedInstanceState) {
         hideError();
         mLoading.show();
@@ -228,13 +213,9 @@
                 mOptionsController = new OptionSelectorController<>(mOptionsContainer, options);
                 mOptionsController.addListener(selected -> {
                     mSelectedOption = (GridOption) selected;
-                    if (mReloadOptionsAfterApplying) {
-                        mReloadOptionsAfterApplying = false;
-                        return;
-                    }
                     mBottomActionBar.show();
                     mEventLogger.logGridSelected(mSelectedOption);
-                    updatePreview();
+                    mGridOptionPreviewer.setGridOption(mSelectedOption);
                 });
                 mOptionsController.initOptions(mGridManager);
 
@@ -246,6 +227,7 @@
                 mSelectedOption = previouslySelectedOption != null
                         ? previouslySelectedOption
                         : getActiveOption(options);
+                // Will trigger selected listener.
                 mOptionsController.setSelectedOption(mSelectedOption);
                 boolean bottomActionBarVisibility = savedInstanceState != null
                         && savedInstanceState.getBoolean(KEY_STATE_BOTTOM_ACTION_BAR_VISIBILITY);
@@ -254,7 +236,6 @@
                 } else {
                     mBottomActionBar.hide();
                 }
-                updatePreview();
             }
 
             @Override
@@ -298,7 +279,6 @@
         Bundle bundle = new Bundle();
         bundle.putParcelable(EXTRA_WALLPAPER_INFO, mHomeWallpaper);
         bundle.putParcelable(EXTRA_GRID_OPTION, mSelectedOption);
-        bundle.putBoolean(EXTRA_GRID_USES_SURFACE_VIEW, mGridManager.usesSurfaceView());
         Intent intent = ViewOnlyFullPreviewActivity.newIntent(getContext(), SECTION_GRID, bundle);
         startActivityForResult(intent, FULL_PREVIEW_REQUEST_CODE);
     }
diff --git a/src/com/android/customization/picker/grid/GridFullPreviewFragment.java b/src/com/android/customization/picker/grid/GridFullPreviewFragment.java
index 2be77d6..27293d6 100644
--- a/src/com/android/customization/picker/grid/GridFullPreviewFragment.java
+++ b/src/com/android/customization/picker/grid/GridFullPreviewFragment.java
@@ -51,11 +51,9 @@
 
     static final String EXTRA_WALLPAPER_INFO = "wallpaper_info";
     static final String EXTRA_GRID_OPTION = "grid_option";
-    static final String EXTRA_GRID_USES_SURFACE_VIEW = "uses_surface_view";
 
     private WallpaperInfo mWallpaper;
     private GridOption mGridOption;
-    private boolean mUsesSurfaceView;
 
     private WallpaperPreviewer mWallpaperPreviewer;
     private GridOptionPreviewer mGridOptionPreviewer;
@@ -78,7 +76,6 @@
         super.onCreate(savedInstanceState);
         mWallpaper = getArguments().getParcelable(EXTRA_WALLPAPER_INFO);
         mGridOption = getArguments().getParcelable(EXTRA_GRID_OPTION);
-        mUsesSurfaceView = getArguments().getBoolean(EXTRA_GRID_USES_SURFACE_VIEW);
     }
 
     @Nullable
@@ -105,9 +102,8 @@
                         getString(R.string.grid_control_metadata_name)),
                 eventLogger);
 
-        ViewGroup gridPreviewContainer = view.findViewById(R.id.grid_preview_container);
-        mGridOptionPreviewer = new GridOptionPreviewer(
-                getContext(), gridManager, gridPreviewContainer);
+        mGridOptionPreviewer = new GridOptionPreviewer(gridManager,
+                view.findViewById(R.id.grid_preview_container));
 
         view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
             @Override
@@ -124,7 +120,7 @@
     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mWallpaperPreviewer.setWallpaper(mWallpaper);
-        mGridOptionPreviewer.setGridOption(mGridOption, mUsesSurfaceView);
+        mGridOptionPreviewer.setGridOption(mGridOption);
     }
 
     @Override
diff --git a/src/com/android/customization/picker/grid/GridOptionPreviewer.java b/src/com/android/customization/picker/grid/GridOptionPreviewer.java
index 6d31689..47303e9 100644
--- a/src/com/android/customization/picker/grid/GridOptionPreviewer.java
+++ b/src/com/android/customization/picker/grid/GridOptionPreviewer.java
@@ -17,128 +17,88 @@
 
 import android.content.Context;
 import android.os.Bundle;
-import android.os.Message;
-import android.os.RemoteException;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
-import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ImageView;
 
 import com.android.customization.model.grid.GridOption;
 import com.android.customization.model.grid.GridOptionsManager;
-import com.android.wallpaper.asset.Asset;
-import com.android.wallpaper.asset.ContentUriAsset;
+import com.android.wallpaper.picker.WorkspaceSurfaceHolderCallback;
 import com.android.wallpaper.util.SurfaceViewUtils;
 
-import com.bumptech.glide.request.RequestOptions;
-
 /** A class to load the {@link GridOption} preview to the view. */
 class GridOptionPreviewer {
 
-    private static final int PREVIEW_FADE_DURATION_MS = 100;
-
-    private final Context mContext;
     private final GridOptionsManager mGridManager;
     private final ViewGroup mPreviewContainer;
 
     private SurfaceView mGridOptionSurface;
     private GridOption mGridOption;
+    private GridOptionSurfaceHolderCallback mSurfaceCallback;
 
-    GridOptionPreviewer(Context context, GridOptionsManager gridManager,
-                        ViewGroup previewContainer) {
-        mContext = context;
+    GridOptionPreviewer(GridOptionsManager gridManager, ViewGroup previewContainer) {
         mGridManager = gridManager;
         mPreviewContainer = previewContainer;
     }
 
     /** Loads the Grid option into the container view. */
-    public void setGridOption(GridOption gridOption, boolean usesSurfaceView) {
+    public void setGridOption(GridOption gridOption) {
         mGridOption = gridOption;
-        updateWorkspacePreview(usesSurfaceView);
+        if (mGridOption != null) {
+            updateWorkspacePreview();
+        }
     }
 
     /** Releases the view resource. */
     public void release() {
         if (mGridOptionSurface != null) {
+            mSurfaceCallback.cleanUp();
             mGridOptionSurface.getHolder().removeCallback(mSurfaceCallback);
             Surface surface = mGridOptionSurface.getHolder().getSurface();
             if (surface != null) {
                 surface.release();
             }
+            mGridOptionSurface = null;
         }
         mPreviewContainer.removeAllViews();
     }
 
-    private void updateWorkspacePreview(boolean usesSurfaceView) {
-        if (mGridOption == null) {
-            return;
-        }
+    private void updateWorkspacePreview() {
+        // Reattach SurfaceView to trigger #surfaceCreated to update preview for different option.
         mPreviewContainer.removeAllViews();
-
-        if (usesSurfaceView) {
-            mGridOptionSurface = new SurfaceView(mContext);
-            setUpView(mGridOptionSurface);
+        if (mSurfaceCallback != null) {
+            mSurfaceCallback.resetLastSurface();
+        }
+        if (mGridOptionSurface == null) {
+            mGridOptionSurface = new SurfaceView(mPreviewContainer.getContext());
+            mGridOptionSurface.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
             mGridOptionSurface.setZOrderMediaOverlay(true);
+            mSurfaceCallback = new GridOptionSurfaceHolderCallback(mGridOptionSurface,
+                    mGridOptionSurface.getContext());
             mGridOptionSurface.getHolder().addCallback(mSurfaceCallback);
-        } else {
-            final ImageView previewImage = new ImageView(mContext);
-            setUpView(previewImage);
-            final Asset previewAsset = new ContentUriAsset(
-                    mContext,
-                    mGridOption.previewImageUri,
-                    RequestOptions.fitCenterTransform());
-            previewAsset.loadDrawableWithTransition(mContext,
-                    previewImage /* imageView */,
-                    PREVIEW_FADE_DURATION_MS /* duration */,
-                    null /* drawableLoadedListener */,
-                    mContext.getResources().getColor(android.R.color.transparent,
-                            null) /* placeHolderColorJ */);
         }
+        mPreviewContainer.addView(mGridOptionSurface);
     }
 
-    private void setUpView(View view) {
-        view.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        mPreviewContainer.addView(view);
-    }
-
-    private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
-        private Surface mLastSurface;
-        private Message mCallback;
+    private class GridOptionSurfaceHolderCallback extends WorkspaceSurfaceHolderCallback {
+        private GridOptionSurfaceHolderCallback(SurfaceView workspaceSurface, Context context) {
+            super(workspaceSurface, context);
+        }
 
         @Override
         public void surfaceCreated(SurfaceHolder holder) {
-            if (mLastSurface != holder.getSurface() && mGridOption != null) {
-                mLastSurface = holder.getSurface();
-                Bundle result = mGridManager.renderPreview(
-                        SurfaceViewUtils.createSurfaceViewRequest(mGridOptionSurface),
-                        mGridOption.name);
-                if (result != null) {
-                    mGridOptionSurface.setChildSurfacePackage(
-                            SurfaceViewUtils.getSurfacePackage(result));
-                    mCallback = SurfaceViewUtils.getCallback(result);
-                }
+            if (mGridOption != null) {
+                super.surfaceCreated(holder);
             }
         }
 
         @Override
-        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
-
-        @Override
-        public void surfaceDestroyed(SurfaceHolder holder) {
-            if (mCallback != null) {
-                try {
-                    mCallback.replyTo.send(mCallback);
-                } catch (RemoteException e) {
-                    e.printStackTrace();
-                } finally {
-                    mCallback.recycle();
-                    mCallback = null;
-                }
-            }
+        protected Bundle renderPreview(SurfaceView workspaceSurface) {
+            return mGridManager.renderPreview(
+                    SurfaceViewUtils.createSurfaceViewRequest(workspaceSurface),
+                    mGridOption.name);
         }
-    };
+    }
 }
diff --git a/src/com/android/customization/picker/theme/CustomThemeActivity.java b/src/com/android/customization/picker/theme/CustomThemeActivity.java
index fc56337..a91faeb 100644
--- a/src/com/android/customization/picker/theme/CustomThemeActivity.java
+++ b/src/com/android/customization/picker/theme/CustomThemeActivity.java
@@ -64,7 +64,6 @@
     public static final String EXTRA_THEME_ID = "CustomThemeActivity.ThemeId";
     public static final String EXTRA_THEME_TITLE = "CustomThemeActivity.ThemeTitle";
     public static final String EXTRA_THEME_PACKAGES = "CustomThemeActivity.ThemePackages";
-    public static final String CREATE_NEW_THEME = "CustomThemeActivity.NewTheme";
     public static final int REQUEST_CODE_CUSTOM_THEME = 1;
     public static final int RESULT_THEME_DELETED = 10;
     public static final int RESULT_THEME_APPLIED = 20;
@@ -79,7 +78,6 @@
     private ThemeManager mThemeManager;
     private TextView mNextButton;
     private TextView mPreviousButton;
-    private boolean mIsDefinedTheme = true;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -91,7 +89,6 @@
         CustomTheme customTheme = null;
         if (intent != null && intent.hasExtra(EXTRA_THEME_PACKAGES)
                 && intent.hasExtra(EXTRA_THEME_TITLE) && intent.hasExtra(EXTRA_THEME_ID)) {
-            mIsDefinedTheme = intent.getBooleanExtra(CREATE_NEW_THEME, true);
             try {
                 CustomTheme.Builder themeBuilder = themeProvider.parseCustomTheme(
                         intent.getStringExtra(EXTRA_THEME_PACKAGES));
@@ -392,8 +389,7 @@
             return CustomThemeNameFragment.newInstance(
                     title,
                     position,
-                    titleResId,
-                    mIsDefinedTheme);
+                    titleResId);
         }
     }
 }
diff --git a/src/com/android/customization/picker/theme/CustomThemeNameFragment.java b/src/com/android/customization/picker/theme/CustomThemeNameFragment.java
index 3411542..f4a1106 100644
--- a/src/com/android/customization/picker/theme/CustomThemeNameFragment.java
+++ b/src/com/android/customization/picker/theme/CustomThemeNameFragment.java
@@ -20,6 +20,7 @@
 import static com.android.customization.picker.theme.ThemeFullPreviewFragment.EXTRA_THEME_OPTION_TITLE;
 import static com.android.customization.picker.theme.ThemeFullPreviewFragment.EXTRA_WALLPAPER_INFO;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.text.TextUtils;
@@ -53,15 +54,13 @@
 public class CustomThemeNameFragment extends CustomThemeStepFragment {
 
     private static final String TAG = "CustomThemeNameFragment";
-    private static final String ARG_IS_DEFINED_THEME = "CustomThemeNameFragment.new_theme";
 
     public static CustomThemeNameFragment newInstance(CharSequence toolbarTitle, int position,
-            int titleResId, boolean mIsDefinedTheme) {
+            int titleResId) {
         CustomThemeNameFragment fragment = new CustomThemeNameFragment();
         Bundle arguments = AppbarFragment.createArguments(toolbarTitle);
         arguments.putInt(ARG_KEY_POSITION, position);
         arguments.putInt(ARG_KEY_TITLE_RES_ID, titleResId);
-        arguments.putBoolean(ARG_IS_DEFINED_THEME, mIsDefinedTheme);
         fragment.setArguments(arguments);
         return fragment;
     }
@@ -84,6 +83,14 @@
         CustomizationInjector injector = (CustomizationInjector) InjectorProvider.getInjector();
         mCustomizationPreferences = injector.getCustomizationPreferences(getContext());
 
+        // Set theme option.
+        ViewGroup previewContainer = view.findViewById(R.id.theme_preview_container);
+        previewContainer.setOnClickListener(v -> showFullPreview());
+        mThemeOptionPreviewer = new ThemeOptionPreviewer(getLifecycle(), getContext(),
+                previewContainer);
+        PreviewInfo previewInfo = mCustomThemeManager.buildCustomThemePreviewInfo(getContext());
+        mThemeOptionPreviewer.setPreviewInfo(previewInfo);
+
         // Set wallpaper background.
         mWallpaperImage = view.findViewById(R.id.wallpaper_preview_image);
         final WallpaperPreviewer wallpaperPreviewer = new WallpaperPreviewer(
@@ -95,48 +102,33 @@
                 (homeWallpaper, lockWallpaper, presentationMode) -> {
                     mCurrentHomeWallpaper = homeWallpaper;
                     wallpaperPreviewer.setWallpaper(homeWallpaper);
-                    updateThemePreviewColorPerWallpaper();
+                    Context context =  getContext();
+                    if (context != null) {
+                        WallpaperColorsLoader.getWallpaperColors(
+                                context,
+                                mCurrentHomeWallpaper.getThumbAsset(context),
+                                mThemeOptionPreviewer::updateColorForLauncherWidgets);
+                    }
                 }, false);
 
-        // Set theme option.
-        ViewGroup previewContainer = view.findViewById(R.id.theme_preview_container);
-        previewContainer.setOnClickListener(v -> showFullPreview());
-        mThemeOptionPreviewer = new ThemeOptionPreviewer(getLifecycle(), getContext(),
-                previewContainer);
-        PreviewInfo previewInfo = mCustomThemeManager.buildCustomThemePreviewInfo(getContext());
-        mThemeOptionPreviewer.setPreviewInfo(previewInfo);
-
         // Set theme default name.
         mNameEditor = view.findViewById(R.id.custom_theme_name);
-        mNameEditor.setText(
-                getCustomThemeDefaultName(getArguments().getBoolean(ARG_IS_DEFINED_THEME, true)));
+        mNameEditor.setText(getOriginalThemeName());
 
         view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
             @Override
             public void onLayoutChange(View v, int left, int top, int right, int bottom,
                                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
                 wallpaperPreviewer.updatePreviewCardRadius();
-                updateThemePreviewColorPerWallpaper();
                 view.removeOnLayoutChangeListener(this);
             }
         });
         return view;
     }
 
-    private void updateThemePreviewColorPerWallpaper() {
-        if (mCurrentHomeWallpaper != null && mWallpaperImage.getMeasuredWidth() > 0
-                && mWallpaperImage.getMeasuredHeight() > 0) {
-            WallpaperColorsLoader.getWallpaperColors(
-                    getContext(),
-                    mCurrentHomeWallpaper.getThumbAsset(getContext()),
-                    mWallpaperImage.getMeasuredWidth(),
-                    mWallpaperImage.getMeasuredHeight(),
-                    mThemeOptionPreviewer::updateColorForLauncherWidgets);
-        }
-    }
-
-    private String getCustomThemeDefaultName(boolean mIsDefinedTheme) {
-        if (mIsDefinedTheme) {
+    private String getOriginalThemeName() {
+        CustomTheme originalTheme = mCustomThemeManager.getOriginalTheme();
+        if (originalTheme == null || !originalTheme.isDefined()) {
             // For new custom theme. use custom themes amount plus 1 as default naming.
             String serializedThemes = mCustomizationPreferences.getSerializedCustomThemes();
             int customThemesCount = 0;
@@ -152,9 +144,8 @@
                     R.string.custom_theme_title, customThemesCount + 1);
         } else {
             // For existing custom theme, keep its name as default naming.
-            return mCustomThemeManager.getOriginalTheme().getTitle();
+            return originalTheme.getTitle();
         }
-
     }
 
     @Override
diff --git a/src/com/android/customization/picker/theme/ThemeFragment.java b/src/com/android/customization/picker/theme/ThemeFragment.java
index 5c5dcdd..18cc3b4 100644
--- a/src/com/android/customization/picker/theme/ThemeFragment.java
+++ b/src/com/android/customization/picker/theme/ThemeFragment.java
@@ -123,6 +123,11 @@
                 .getCurrentWallpaperFactory(getActivity().getApplicationContext());
         mOptionsContainer = view.findViewById(R.id.options_container);
 
+        mThemeOptionPreviewer = new ThemeOptionPreviewer(
+                getLifecycle(),
+                getContext(),
+                view.findViewById(R.id.theme_preview_container));
+
         // Set Wallpaper background.
         mWallpaperImage = view.findViewById(R.id.wallpaper_preview_image);
         mWallpaperPreviewer = new WallpaperPreviewer(
@@ -134,25 +139,25 @@
                 (homeWallpaper, lockWallpaper, presentationMode) -> {
                     mCurrentHomeWallpaper = homeWallpaper;
                     mWallpaperPreviewer.setWallpaper(mCurrentHomeWallpaper);
-                    updateThemePreviewColorPerWallpaper();
+                    Context context = getContext();
+                    if (context != null) {
+                        WallpaperColorsLoader.getWallpaperColors(
+                                context,
+                                mCurrentHomeWallpaper.getThumbAsset(context),
+                                mThemeOptionPreviewer::updateColorForLauncherWidgets);
+                    }
                 }, false);
 
-        ViewGroup previewContainer = view.findViewById(R.id.theme_preview_container);
-        previewContainer.setOnClickListener(v -> showFullPreview());
-        mThemeOptionPreviewer = new ThemeOptionPreviewer(
-                getLifecycle(),
-                getContext(),
-                previewContainer);
-
         view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
             @Override
             public void onLayoutChange(View v, int left, int top, int right, int bottom,
                                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
                 mWallpaperPreviewer.updatePreviewCardRadius();
-                updateThemePreviewColorPerWallpaper();
                 view.removeOnLayoutChangeListener(this);
             }
         });
+
+        view.findViewById(R.id.theme_preview_card).setOnClickListener(v -> showFullPreview());
         return view;
     }
 
@@ -178,21 +183,6 @@
         setUpOptions(savedInstanceState);
     }
 
-    private void updateThemePreviewColorPerWallpaper() {
-        if (getContext() == null) {
-            return;
-        }
-        if (mCurrentHomeWallpaper != null && mWallpaperImage.getMeasuredWidth() > 0
-                && mWallpaperImage.getMeasuredHeight() > 0) {
-            WallpaperColorsLoader.getWallpaperColors(
-                    getContext(),
-                    mCurrentHomeWallpaper.getThumbAsset(getContext()),
-                    mWallpaperImage.getMeasuredWidth(),
-                    mWallpaperImage.getMeasuredHeight(),
-                    mThemeOptionPreviewer::updateColorForLauncherWidgets);
-        }
-    }
-
     private void applyTheme() {
         mThemeManager.apply(mSelectedTheme, new Callback() {
             @Override
@@ -376,7 +366,6 @@
         intent.putExtra(CustomThemeActivity.EXTRA_THEME_ID, themeToEdit.getId());
         intent.putExtra(CustomThemeActivity.EXTRA_THEME_PACKAGES,
                 themeToEdit.getSerializedPackages());
-        intent.putExtra(CustomThemeActivity.CREATE_NEW_THEME, !themeToEdit.isDefined());
         startActivityForResult(intent, CustomThemeActivity.REQUEST_CODE_CUSTOM_THEME);
     }
 
diff --git a/src/com/android/customization/picker/theme/ThemeFullPreviewFragment.java b/src/com/android/customization/picker/theme/ThemeFullPreviewFragment.java
index 253720e..1821f84 100644
--- a/src/com/android/customization/picker/theme/ThemeFullPreviewFragment.java
+++ b/src/com/android/customization/picker/theme/ThemeFullPreviewFragment.java
@@ -21,6 +21,7 @@
 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
@@ -125,13 +126,13 @@
             public void onLayoutChange(View v, int left, int top, int right, int bottom,
                                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
                 wallpaperPreviewer.updatePreviewCardRadius();
-                // Let's use half size of full preview card to reduce memory and loading time.
-                WallpaperColorsLoader.getWallpaperColors(
-                        getContext(),
-                        mWallpaper.getThumbAsset(getContext()),
-                        wallpaperImageView.getMeasuredWidth() / 2,
-                        wallpaperImageView.getMeasuredHeight() / 2,
-                        themeOptionPreviewer::updateColorForLauncherWidgets);
+                Context context = getContext();
+                if (context != null) {
+                    WallpaperColorsLoader.getWallpaperColors(
+                            context,
+                            mWallpaper.getThumbAsset(context),
+                            themeOptionPreviewer::updateColorForLauncherWidgets);
+                }
                 view.removeOnLayoutChangeListener(this);
             }
         });
diff --git a/src/com/android/customization/picker/theme/ThemeOptionPreviewer.java b/src/com/android/customization/picker/theme/ThemeOptionPreviewer.java
index f24cf64..ec98601 100644
--- a/src/com/android/customization/picker/theme/ThemeOptionPreviewer.java
+++ b/src/com/android/customization/picker/theme/ThemeOptionPreviewer.java
@@ -38,6 +38,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.MainThread;
+import androidx.annotation.Nullable;
 import androidx.cardview.widget.CardView;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleObserver;
@@ -159,6 +160,7 @@
     /** Loads the Theme option preview into the container view. */
     public void setPreviewInfo(PreviewInfo previewInfo) {
         setHeadlineFont(previewInfo.headlineFontFamily);
+        setBodyFont(previewInfo.bodyFontFamily);
         setTopBarIcons(previewInfo.icons);
         setAppIconShape(previewInfo.shapeAppIcons);
         setColorAndIconsSection(previewInfo.icons, previewInfo.shapeDrawable,
@@ -172,10 +174,13 @@
     /**
      * Updates the color of widgets in launcher (like top status bar, smart space, and app name
      * text) which will change its content color according to different wallpapers.
+     *
+     * @param colors the {@link WallpaperColors} of the wallpaper, or {@code null} to use light
+     *               color as default
      */
-    public void updateColorForLauncherWidgets(WallpaperColors colors) {
-        boolean useLightTextColor =
-                (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0;
+    public void updateColorForLauncherWidgets(@Nullable WallpaperColors colors) {
+        boolean useLightTextColor = colors == null
+                || (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0;
         int textColor = mContext.getColor(useLightTextColor
                 ? R.color.text_color_light
                 : R.color.text_color_dark);
@@ -248,17 +253,19 @@
         mStatusBarClock.setTypeface(headlineFont);
         mSmartSpaceDate.setTypeface(headlineFont);
 
-        // Update font of app names.
-        for (int id : mShapeIconAppNameIds) {
-            TextView appName = mContentView.findViewById(id);
-            appName.setTypeface(headlineFont);
-        }
-
         // Update font of color/icons section title.
         TextView colorIconsSectionTitle = mContentView.findViewById(R.id.color_icons_section_title);
         colorIconsSectionTitle.setTypeface(headlineFont);
     }
 
+    private void setBodyFont(Typeface bodyFont) {
+        // Update font of app names.
+        for (int id : mShapeIconAppNameIds) {
+            TextView appName = mContentView.findViewById(id);
+            appName.setTypeface(bodyFont);
+        }
+    }
+
     private void setTopBarIcons(List<Drawable> icons) {
         ViewGroup iconsContainer = mContentView.findViewById(R.id.theme_preview_top_bar_icons);
         for (int i = 0; i < iconsContainer.getChildCount(); i++) {
diff --git a/src/com/android/customization/widget/OptionSelectorController.java b/src/com/android/customization/widget/OptionSelectorController.java
index 5b76b36..a532e40 100644
--- a/src/com/android/customization/widget/OptionSelectorController.java
+++ b/src/com/android/customization/widget/OptionSelectorController.java
@@ -160,6 +160,11 @@
                 return mOptions.get(position).getLayoutResId();
             }
 
+            @Override
+            public long getItemId(int position) {
+                return position;
+            }
+
             @NonNull
             @Override
             public TileViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@@ -185,7 +190,8 @@
 
                 if (mShowCheckmark && option.equals(mAppliedOption)) {
                     Resources res = mContainer.getContext().getResources();
-                    Drawable checkmark = res.getDrawable(R.drawable.ic_check_circle_filled_24px);
+                    Drawable checkmark = res.getDrawable(R.drawable.check_circle_accent_24dp,
+                            mContainer.getContext().getTheme());
                     Drawable frame = holder.tileView.getForeground();
                     Drawable[] layers = {frame, checkmark};
                     if (frame == null) {
@@ -225,6 +231,11 @@
         mContainer.setLayoutManager(new LinearLayoutManager(mContainer.getContext(),
                 LinearLayoutManager.HORIZONTAL, false));
         Resources res = mContainer.getContext().getResources();
+
+        // A workaround from b/37088814, fix TalkBack will lose focus when receive notify*Changed()
+        mAdapter.setHasStableIds(true);
+        mContainer.setItemAnimator(null);
+
         mContainer.setAdapter(mAdapter);
 
         // Measure RecyclerView to get to the total amount of space used by all options.
diff --git a/src_override/com/android/wallpaper/module/WallpapersInjector.java b/src_override/com/android/wallpaper/module/WallpapersInjector.java
index a2bcd4d..b9a6952 100755
--- a/src_override/com/android/wallpaper/module/WallpapersInjector.java
+++ b/src_override/com/android/wallpaper/module/WallpapersInjector.java
@@ -65,11 +65,13 @@
 
     @Override
     public Fragment getPreviewFragment(
-        Context context,
-        WallpaperInfo wallpaperInfo,
-        int mode,
-        boolean testingModeEnabled) {
-        return ImagePreviewFragment.newInstance(wallpaperInfo, mode, testingModeEnabled);
+            Context context,
+            WallpaperInfo wallpaperInfo,
+            int mode,
+            boolean viewAsHome,
+            boolean testingModeEnabled) {
+        return ImagePreviewFragment.newInstance(wallpaperInfo, mode, viewAsHome,
+                testingModeEnabled);
     }
 
     @Override