Make undefined ThemeBundle propagatable and buildable

- We won't need to pass the boolean value of ThemeBundle#isDefined.
- This also fix the problem of wrong custom theme suggestion: https://screenshot.googleplex.com/zEEX5WaaNgZ.png
Because the Custom button and Default theme are with empty packges set, and Custom button is in front of Default in the list. So add #isDefined to #isEquivalent to ensure Custom button has no equivalent.
Fix screenshot: https://screenshot.googleplex.com/SvUNccCWjYD.png

Test: Manually
Fixes: 157723282
Change-Id: I6a5f75840edd2153f2b197468762dda80fb13e8c
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/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 9bc6772..f4a1106 100644
--- a/src/com/android/customization/picker/theme/CustomThemeNameFragment.java
+++ b/src/com/android/customization/picker/theme/CustomThemeNameFragment.java
@@ -54,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;
     }
@@ -115,8 +113,7 @@
 
         // 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
@@ -129,8 +126,9 @@
         return view;
     }
 
-    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;
@@ -146,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 fa9d533..090158b 100644
--- a/src/com/android/customization/picker/theme/ThemeFragment.java
+++ b/src/com/android/customization/picker/theme/ThemeFragment.java
@@ -366,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);
     }