Custom Theme 1/n: initial structure

This CL is just laying out the groundwork, adding a new Activity and
CustomTheme class as well as a few layouts and strings needed on the UI

Bug: 124796742

Change-Id: I458995b208863a9201dd0ef6e935c8ff030587ed
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 129f5b9..990f043 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.wallpaper">
+          package="com.android.wallpaper">
 
     <uses-sdk android:targetSdkVersion="Q" android:minSdkVersion="28"/>
 
@@ -12,19 +12,24 @@
         android:hardwareAccelerated="true"
         android:icon="@mipmap/product_logo_wallpapers_launcher_color_48"
         android:label="@string/app_name"
-        android:theme="@style/CustomizationTheme"
         android:requiredForAllUsers="true"
         android:restoreAnyVersion="true"
-        android:supportsRtl="true">
-
-        <activity android:name="com.android.customization.picker.CustomizationPickerActivity"
+        android:supportsRtl="true"
+        android:theme="@style/CustomizationTheme">
+        <activity
+            android:name="com.android.customization.picker.CustomizationPickerActivity"
             android:label="@string/app_name"
-            android:theme="@style/CustomizationTheme.NoActionBar"
-            android:resizeableActivity="true">
+            android:resizeableActivity="true"
+            android:theme="@style/CustomizationTheme.NoActionBar">
             <intent-filter>
                 <action android:name="android.intent.action.SET_WALLPAPER"/>
+
                 <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
+        <activity android:name="com.android.customization.picker.theme.CustomThemeActivity"
+                  android:resizeableActivity="true"
+                  android:theme="@style/CustomizationTheme.NoActionBar"/>
     </application>
+
 </manifest>
diff --git a/res/layout/activity_custom_theme.xml b/res/layout/activity_custom_theme.xml
new file mode 100644
index 0000000..d69d9d7
--- /dev/null
+++ b/res/layout/activity_custom_theme.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context="com.android.customization.picker.theme.CustomThemeActivity">
+
+    <FrameLayout
+        android:id="@+id/fragment_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginBottom="@dimen/custom_theme_nav_height"/>
+
+    <FrameLayout
+        android:id="@+id/custom_theme_nav"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/custom_theme_nav_height">
+        <Button
+            android:id="@+id/next_button"
+            style="@style/ActionPrimaryButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end|center_vertical"
+            android:text="@string/custom_theme_next"/>
+    </FrameLayout>
+</FrameLayout>
diff --git a/res/layout/custom_theme_option.xml b/res/layout/custom_theme_option.xml
new file mode 100644
index 0000000..b249555
--- /dev/null
+++ b/res/layout/custom_theme_option.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/option_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginBottom="@dimen/theme_option_label_margin"
+        android:textAppearance="@style/OptionTitleTextAppearance"/>
+    <FrameLayout
+        android:id="@+id/option_tile"
+        android:layout_width="@dimen/option_tile_width"
+        android:layout_height="@dimen/option_tile_width"
+        android:layout_gravity="center_horizontal"
+        android:paddingHorizontal="@dimen/option_tile_padding_horizontal"
+        android:paddingVertical="@dimen/option_tile_padding_vertical"
+        android:background="@drawable/option_border">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:textSize="@dimen/theme_option_add_size"
+            android:textAlignment="center"
+            android:textColor="?android:colorAccent"
+            android:text="@string/add_custom_theme"/>
+    </FrameLayout>
+</LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1070deb..5487661 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -37,6 +37,8 @@
     <dimen name="theme_option_sample_height">23dp</dimen>
     <dimen name="theme_option_sample_width">23dp</dimen>
     <dimen name="theme_option_sample_padding">2dp</dimen>
+    <!-- Note, using dp instead of sp as this is just the "+" symbol, not text -->
+    <dimen name="theme_option_add_size">32dp</dimen>
     <dimen name="option_tile_padding_vertical">12dp</dimen>
     <dimen name="option_tile_padding_horizontal">10dp</dimen>
     <!-- Note, using dp instead of sp as this text is more like a "snapshot" of the font -->
@@ -56,4 +58,6 @@
 
     <dimen name="shape_preview_image_width">236dp</dimen>
     <dimen name="shape_preview_image_height">153dp</dimen>
+
+    <dimen name="custom_theme_nav_height">56dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e451795..dc5f7f5 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -56,6 +56,9 @@
     <!-- Sample text used to show a preview of a selected font [CHAR LIMIT=3] -->
     <string name="theme_font_example">ABC</string>
 
+    <!-- Plus sign used to indicate that the user can add a custom theme -->
+    <string name="add_custom_theme" translatable="false">+</string>
+
     <!-- Name for the Android Theme that comes preset with the device [CHAR LIMIT=10]-->
     <string name="default_theme_title">Default</string>
 
@@ -89,4 +92,12 @@
     <!-- Message shown when a theme couldn't be applied in the system because of an error
         [CHAR LIMIT=NONE] -->
     <string name="apply_theme_error_msg">There was a problem applying the style</string>
+
+    <!-- Label for a button that takes the user to the next step when configuring a custom theme.
+        [CHAR LIMIT=20] -->
+    <string name="custom_theme_next">Next</string>
+
+    <!-- Title for a system Style/Theme (combination of fonts/colors/icons) that is defined and
+        customized by the user [CHAR LIMIT=15] -->
+    <string name="custom_theme_title">Custom</string>
 </resources>
diff --git a/src/com/android/customization/model/theme/CustomTheme.java b/src/com/android/customization/model/theme/CustomTheme.java
new file mode 100644
index 0000000..289e3e4
--- /dev/null
+++ b/src/com/android/customization/model/theme/CustomTheme.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+package com.android.customization.model.theme;
+
+import android.view.View;
+
+import com.android.wallpaper.R;
+
+import java.util.Map;
+
+public class CustomTheme extends ThemeBundle {
+
+    public CustomTheme(String title, Map<String, String> overlayPackages,
+            PreviewInfo previewInfo) {
+        super(title, overlayPackages, false, null, previewInfo);
+    }
+
+    @Override
+    public void bindThumbnailTile(View view) {
+        if (isDefined()) {
+            super.bindThumbnailTile(view);
+        }
+    }
+
+    @Override
+    public int getLayoutResId() {
+        return isDefined() ? R.layout.theme_option : R.layout.custom_theme_option;
+    }
+
+    @Override
+    public boolean shouldUseThemeWallpaper() {
+        return false;
+    }
+
+    public boolean isDefined() {
+        return getPreviewInfo() != null;
+    }
+}
diff --git a/src/com/android/customization/model/theme/DefaultThemeProvider.java b/src/com/android/customization/model/theme/DefaultThemeProvider.java
index a2cb95c..3dcb90e 100644
--- a/src/com/android/customization/model/theme/DefaultThemeProvider.java
+++ b/src/com/android/customization/model/theme/DefaultThemeProvider.java
@@ -225,6 +225,7 @@
                         e);
             }
         }
+        addCustomTheme();
     }
 
     /**
@@ -362,6 +363,11 @@
         mThemes.add(builder.build());
     }
 
+    private void addCustomTheme() {
+        mThemes.add(new CustomTheme(mContext.getString(R.string.custom_theme_title),
+                new HashMap<>(), null));
+    }
+
     private String getOverlayPackage(String prefix, String themeName) {
         return getItemStringFromStub(prefix, themeName);
     }
diff --git a/src/com/android/customization/model/theme/ThemeBundle.java b/src/com/android/customization/model/theme/ThemeBundle.java
index 3af25d4..f3ced93 100644
--- a/src/com/android/customization/model/theme/ThemeBundle.java
+++ b/src/com/android/customization/model/theme/ThemeBundle.java
@@ -64,14 +64,14 @@
     @Nullable private final WallpaperInfo mWallpaperInfo;
     private WallpaperInfo mOverrideWallpaper;
 
-    private ThemeBundle(String title, Map<String, String> overlayPackages,
+    protected ThemeBundle(String title, Map<String, String> overlayPackages,
             boolean isDefault, @Nullable WallpaperInfo wallpaperInfo,
             PreviewInfo previewInfo) {
         mTitle = title;
         mIsDefault = isDefault;
         mPreviewInfo = previewInfo;
         mWallpaperInfo = wallpaperInfo;
-        mPackagesByCategory = Collections.unmodifiableMap(overlayPackages);        
+        mPackagesByCategory = Collections.unmodifiableMap(overlayPackages);
     }
 
     @Override
@@ -127,7 +127,7 @@
         mOverrideWallpaper = homeWallpaper;
     }
 
-    public boolean useThemeWallpaper() {
+    public boolean shouldUseThemeWallpaper() {
         return mOverrideWallpaper == null && mWallpaperInfo != null;
     }
 
diff --git a/src/com/android/customization/model/theme/ThemeManager.java b/src/com/android/customization/model/theme/ThemeManager.java
index e56503b..31e76ca 100644
--- a/src/com/android/customization/model/theme/ThemeManager.java
+++ b/src/com/android/customization/model/theme/ThemeManager.java
@@ -91,7 +91,7 @@
     @Override
     public void apply(ThemeBundle theme, Callback callback) {
         // Set wallpaper
-        if (theme.useThemeWallpaper()) {
+        if (theme.shouldUseThemeWallpaper()) {
             applyWallpaper(theme, new SetWallpaperCallback() {
                 @Override
                 public void onSuccess() {
diff --git a/src/com/android/customization/picker/theme/CustomThemeActivity.java b/src/com/android/customization/picker/theme/CustomThemeActivity.java
new file mode 100644
index 0000000..9ed9f66
--- /dev/null
+++ b/src/com/android/customization/picker/theme/CustomThemeActivity.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+package com.android.customization.picker.theme;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.module.Injector;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.UserEventLogger;
+
+public class CustomThemeActivity extends FragmentActivity {
+
+    private UserEventLogger mUserEventLogger;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Injector injector = InjectorProvider.getInjector();
+        mUserEventLogger = injector.getUserEventLogger(this);
+        setContentView(R.layout.activity_custom_theme);
+
+        FragmentManager fm = getSupportFragmentManager();
+        Fragment fragment = fm.findFragmentById(R.id.fragment_container);
+
+        if (fragment == null) {
+            // Navigate to the first step
+            navigateToStep(0);
+        }
+    }
+
+    private void navigateToStep(int i) {
+        //TODO(santie): implement
+    }
+}
diff --git a/src/com/android/customization/picker/theme/ThemeFragment.java b/src/com/android/customization/picker/theme/ThemeFragment.java
index a1d81c3..669f21c 100644
--- a/src/com/android/customization/picker/theme/ThemeFragment.java
+++ b/src/com/android/customization/picker/theme/ThemeFragment.java
@@ -15,11 +15,10 @@
  */
 package com.android.customization.picker.theme;
 
-import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME;
-
 import android.app.Activity;
 import android.app.WallpaperColors;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -45,6 +44,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.customization.model.CustomizationManager.Callback;
+import com.android.customization.model.theme.CustomTheme;
 import com.android.customization.model.theme.ThemeBundle;
 import com.android.customization.model.theme.ThemeBundle.PreviewInfo;
 import com.android.customization.model.theme.ThemeManager;
@@ -184,9 +184,13 @@
             mOptionsController = new OptionSelectorController(mOptionsContainer, options);
 
             mOptionsController.addListener(selected -> {
-                mSelectedTheme = (ThemeBundle) selected;
-                mSelectedTheme.setOverrideThemeWallpaper(mCurrentHomeWallpaper);
-                createAdapter();
+                if (selected instanceof CustomTheme && !((CustomTheme) selected).isDefined()) {
+                    navigateToCustomTheme();
+                } else {
+                    mSelectedTheme = (ThemeBundle) selected;
+                    mSelectedTheme.setOverrideThemeWallpaper(mCurrentHomeWallpaper);
+                    createAdapter();
+                }
             });
             mOptionsController.initOptions(mThemeManager);
             String previouslySelected = savedInstanceState != null
@@ -198,6 +202,7 @@
                     mSelectedTheme = theme;
                 } else if (theme.isActive(mThemeManager)) {
                     mSelectedTheme = theme;
+                    break;
                 }
             }
             mOptionsController.setSelectedOption(mSelectedTheme);
@@ -205,6 +210,11 @@
         createAdapter();
     }
 
+    private void navigateToCustomTheme() {
+        Intent intent = new Intent(getActivity(), CustomThemeActivity.class);
+        startActivity(intent);
+    }
+
     private static abstract class ThemePreviewPage extends PreviewPage {
         @StringRes final int nameResId;
         @DrawableRes final int iconSrc;