Add alternative checkmark for currently selected option

Bug: 181111177
Test: manual
Change-Id: I990b7a50860093ed5031db1772ab35e2239748c5
diff --git a/res/drawable/check_circle_grey_large.xml b/res/drawable/check_circle_grey_large.xml
new file mode 100644
index 0000000..16c5d94
--- /dev/null
+++ b/res/drawable/check_circle_grey_large.xml
@@ -0,0 +1,31 @@
+<!--
+     Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <size android:width="@dimen/center_check_size"
+                android:height="@dimen/center_check_size" />
+            <solid android:color="@color/center_check_color" />
+        </shape>
+    </item>
+    <item>
+        <inset android:drawable="@drawable/ic_check_24dp"
+            android:insetTop="@dimen/center_check_padding"
+            android:insetRight="@dimen/center_check_padding"
+            android:insetBottom="@dimen/center_check_padding"
+            android:insetLeft="@dimen/center_check_padding"/>
+    </item>
+</layer-list>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 02b3472..1f1ee30 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -52,4 +52,6 @@
     <color name="divider_color">@color/black_14_alpha</color>
 
     <color name="cover_title_color">@color/black_87_alpha</color>
+
+    <color name="center_check_color">#EDF2EB</color>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 53b4e39..abc2c6a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -22,6 +22,8 @@
     <dimen name="tip_dot_line_width">2dp</dimen>
 
     <dimen name="check_size">16dp</dimen>
+    <dimen name="center_check_size">34dp</dimen>
+    <dimen name="center_check_padding">9dp</dimen>
     <dimen name="check_offset">4dp</dimen>
 
     <dimen name="component_preview_page_bottom_margin">16dp</dimen>
diff --git a/src/com/android/customization/module/CustomizationInjector.java b/src/com/android/customization/module/CustomizationInjector.java
index fe5a0aa..722ebb3 100644
--- a/src/com/android/customization/module/CustomizationInjector.java
+++ b/src/com/android/customization/module/CustomizationInjector.java
@@ -56,7 +56,7 @@
      *
      * @return {@code true} if the system supports customization extension, {@code false} otherwise.
      */
-    default boolean supportsCustomizationExtended() {
+    default boolean supportsCustomizationExtended(Context context) {
         return false;
     }
 }
diff --git a/src/com/android/customization/picker/CustomizationPickerActivity.java b/src/com/android/customization/picker/CustomizationPickerActivity.java
index 17b4fc7..b54d24c 100644
--- a/src/com/android/customization/picker/CustomizationPickerActivity.java
+++ b/src/com/android/customization/picker/CustomizationPickerActivity.java
@@ -241,7 +241,7 @@
 
     private boolean supportsCustomizationExtended() {
         CustomizationInjector injector = (CustomizationInjector) InjectorProvider.getInjector();
-        return injector.supportsCustomizationExtended();
+        return injector.supportsCustomizationExtended(this);
     }
 
     private void initSections() {
diff --git a/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java b/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java
index 5495e9a..a1e9967 100644
--- a/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java
+++ b/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java
@@ -27,6 +27,7 @@
 import com.android.customization.model.theme.custom.ThemeComponentOption;
 import com.android.customization.model.theme.custom.ThemeComponentOptionProvider;
 import com.android.customization.widget.OptionSelectorController;
+import com.android.customization.widget.OptionSelectorController.CheckmarkStyle;
 import com.android.wallpaper.R;
 import com.android.wallpaper.picker.AppbarFragment;
 
@@ -94,7 +95,7 @@
     private void setUpOptions() {
         mProvider.fetch(options -> {
             mOptionsController = new OptionSelectorController(
-                    mOptionsContainer, options, mUseGridLayout, false);
+                    mOptionsContainer, options, mUseGridLayout, CheckmarkStyle.NONE);
 
             mOptionsController.addListener(selected -> {
                 mSelectedOption = (ThemeComponentOption) selected;
diff --git a/src/com/android/customization/widget/OptionSelectorController.java b/src/com/android/customization/widget/OptionSelectorController.java
index 47b0aa7..1d1b658 100644
--- a/src/com/android/customization/widget/OptionSelectorController.java
+++ b/src/com/android/customization/widget/OptionSelectorController.java
@@ -29,6 +29,9 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.TextView;
 
+import androidx.annotation.ColorInt;
+import androidx.annotation.Dimension;
+import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.LinearLayoutManager;
@@ -63,10 +66,17 @@
         void onOptionSelected(CustomizationOption selected);
     }
 
+    @IntDef({CheckmarkStyle.NONE, CheckmarkStyle.CORNER, CheckmarkStyle.CENTER})
+    public @interface CheckmarkStyle {
+        int NONE = 0;
+        int CORNER = 1;
+        int CENTER = 2;
+    }
+
     private final RecyclerView mContainer;
     private final List<T> mOptions;
     private final boolean mUseGrid;
-    private final boolean mShowCheckmark;
+    @CheckmarkStyle private final int mCheckmarkStyle;
 
     private final Set<OptionSelectedListener> mListeners = new HashSet<>();
     private RecyclerView.Adapter<TileViewHolder> mAdapter;
@@ -74,15 +84,15 @@
     private CustomizationOption mAppliedOption;
 
     public OptionSelectorController(RecyclerView container, List<T> options) {
-        this(container, options, true, true);
+        this(container, options, true, CheckmarkStyle.CORNER);
     }
 
     public OptionSelectorController(RecyclerView container, List<T> options,
-            boolean useGrid, boolean showCheckmark) {
+            boolean useGrid, @CheckmarkStyle int checkmarkStyle) {
         mContainer = container;
         mOptions = options;
         mUseGrid = useGrid;
-        mShowCheckmark = showCheckmark;
+        mCheckmarkStyle = checkmarkStyle;
     }
 
     public void addListener(OptionSelectedListener listener) {
@@ -132,14 +142,14 @@
             if (holder instanceof TileViewHolder) {
                 TileViewHolder tileHolder = (TileViewHolder) holder;
                 if (isActivated) {
-                    if (option == mAppliedOption && mShowCheckmark) {
+                    if (option == mAppliedOption && mCheckmarkStyle != CheckmarkStyle.NONE) {
                         tileHolder.setContentDescription(mContainer.getContext(), option,
                             R.string.option_applied_previewed_description);
                     } else {
                         tileHolder.setContentDescription(mContainer.getContext(), option,
                             R.string.option_previewed_description);
                     }
-                } else if (option == mAppliedOption && mShowCheckmark) {
+                } else if (option == mAppliedOption && mCheckmarkStyle != CheckmarkStyle.NONE) {
                     tileHolder.setContentDescription(mContainer.getContext(), option,
                         R.string.option_applied_description);
                 } else {
@@ -195,40 +205,30 @@
                 if (holder.labelView != null) {
                     holder.labelView.setText(option.getTitle());
                 }
-                option.bindThumbnailTile(holder.tileView);
                 holder.itemView.setActivated(option.equals(mSelectedOption));
+                option.bindThumbnailTile(holder.tileView);
                 holder.itemView.setOnClickListener(view -> setSelectedOption(option));
 
-                if (mShowCheckmark && option.equals(mAppliedOption)) {
-                    Resources res = mContainer.getContext().getResources();
-                    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) {
-                        layers = new Drawable[]{checkmark};
-                    }
-                    LayerDrawable checkedFrame = new LayerDrawable(layers);
-
-                    // Position at lower right
-                    int idx = layers.length - 1;
-                    int checkSize = (int) res.getDimension(R.dimen.check_size);
-                    int checkOffset = (int) res.getDimensionPixelOffset(R.dimen.check_offset);
-                    checkedFrame.setLayerGravity(idx, Gravity.BOTTOM | Gravity.RIGHT);
-                    checkedFrame.setLayerWidth(idx, checkSize);
-                    checkedFrame.setLayerHeight(idx, checkSize);
-                    checkedFrame.setLayerInsetBottom(idx, checkOffset);
-                    checkedFrame.setLayerInsetRight(idx, checkOffset);
-                    holder.tileView.setForeground(checkedFrame);
-
-                    // Initialize the currently applied option
-                    holder.setContentDescription(mContainer.getContext(), option,
-                        R.string.option_applied_previewed_description);
+                Resources res = mContainer.getContext().getResources();
+                if (mCheckmarkStyle == CheckmarkStyle.CORNER && option.equals(mAppliedOption)) {
+                    drawCheckmark(option, holder,
+                            res.getDrawable(R.drawable.check_circle_accent_24dp,
+                                    mContainer.getContext().getTheme()),
+                            Gravity.BOTTOM | Gravity.RIGHT,
+                            res.getDimensionPixelSize(R.dimen.check_size),
+                            res.getDimensionPixelOffset(R.dimen.check_offset), 0);
+                } else if (mCheckmarkStyle == CheckmarkStyle.CENTER
+                        && option.equals(mAppliedOption)) {
+                    drawCheckmark(option, holder,
+                            res.getDrawable(R.drawable.check_circle_grey_large,
+                                    mContainer.getContext().getTheme()),
+                            Gravity.CENTER, res.getDimensionPixelSize(R.dimen.center_check_size),
+                            0, res.getColor(android.R.color.black));
                 } else if (option.equals(mAppliedOption)) {
                     // Initialize with "previewed" description if we don't show checkmark
                     holder.setContentDescription(mContainer.getContext(), option,
                         R.string.option_previewed_description);
-                } else if (mShowCheckmark) {
+                } else if (mCheckmarkStyle != CheckmarkStyle.NONE) {
                     holder.tileView.setForeground(null);
                 }
             }
@@ -237,6 +237,33 @@
             public int getItemCount() {
                 return mOptions.size();
             }
+
+            private void drawCheckmark(CustomizationOption<?> option, TileViewHolder holder,
+                    Drawable checkmark, int gravity, @Dimension int checkSize,
+                    @Dimension int checkOffset, @ColorInt int checkColor) {
+                if (checkColor != 0 && checkmark instanceof LayerDrawable) {
+                    ((LayerDrawable) checkmark).getDrawable(1).setTint(checkColor);
+                }
+                Drawable frame = holder.tileView.getForeground();
+                Drawable[] layers = {frame, checkmark};
+                if (frame == null) {
+                    layers = new Drawable[]{checkmark};
+                }
+                LayerDrawable checkedFrame = new LayerDrawable(layers);
+
+                // Position according to the given gravity and offset
+                int idx = layers.length - 1;
+                checkedFrame.setLayerGravity(idx, gravity);
+                checkedFrame.setLayerWidth(idx, checkSize);
+                checkedFrame.setLayerHeight(idx, checkSize);
+                checkedFrame.setLayerInsetBottom(idx, checkOffset);
+                checkedFrame.setLayerInsetRight(idx, checkOffset);
+                holder.tileView.setForeground(checkedFrame);
+
+                // Initialize the currently applied option
+                holder.setContentDescription(mContainer.getContext(), option,
+                        R.string.option_applied_previewed_description);
+            }
         };
 
         Resources res = mContainer.getContext().getResources();