Merge "Evenly space theme options." into ub-launcher3-qt-dev
am: 16020ba23f

Change-Id: Ifd4b0426145029b8b339e10dfa3319b567c6c82a
diff --git a/res/layout/theme_color_option.xml b/res/layout/theme_color_option.xml
index 0b7ca9e..72acd8b 100644
--- a/res/layout/theme_color_option.xml
+++ b/res/layout/theme_color_option.xml
@@ -15,10 +15,10 @@
      limitations under the License.
 -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
-    android:layout_marginHorizontal="6dp"
-    android:paddingHorizontal="4dp">
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:padding="4dp">
 
     <ImageView
         android:id="@+id/option_tile"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 465a926..30123ed 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -57,7 +57,6 @@
     <dimen name="theme_option_title_font_text_size">12sp</dimen>
 
     <dimen name="option_tile_margin_horizontal">4dp</dimen>
-    <dimen name="option_tile_margin_horizontal_ends">10dp</dimen>
     <dimen name="theme_option_label_margin">4dp</dimen>
 
     <dimen name="preview_card_corner_radius">8dp</dimen>
diff --git a/res/values/integers.xml b/res/values/integers.xml
new file mode 100644
index 0000000..6e2db17
--- /dev/null
+++ b/res/values/integers.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<resources>
+    <integer name="options_grid_num_columns">4</integer>
+</resources>
diff --git a/src/com/android/customization/picker/theme/CustomThemeActivity.java b/src/com/android/customization/picker/theme/CustomThemeActivity.java
index df14c86..40d1fe8 100644
--- a/src/com/android/customization/picker/theme/CustomThemeActivity.java
+++ b/src/com/android/customization/picker/theme/CustomThemeActivity.java
@@ -339,7 +339,8 @@
             return CustomThemeComponentFragment.newInstance(
                     CustomThemeActivity.this.getString(R.string.custom_theme_fragment_title),
                     position,
-                    titleResId);
+                    titleResId,
+                    true);
         }
     }
 
diff --git a/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java b/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java
index f2088ae..cd2c067 100644
--- a/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java
+++ b/src/com/android/customization/picker/theme/CustomThemeComponentFragment.java
@@ -40,6 +40,7 @@
 public class CustomThemeComponentFragment extends ToolbarFragment {
     private static final String ARG_KEY_POSITION = "CustomThemeComponentFragment.position";
     private static final String ARG_KEY_TITLE_RES_ID = "CustomThemeComponentFragment.title_res";
+    private static final String ARG_USE_GRID_LAYOUT = "CustomThemeComponentFragment.use_grid";;
     private CustomThemeComponentFragmentHost mHost;
 
     public interface CustomThemeComponentFragmentHost {
@@ -55,10 +56,16 @@
 
     public static CustomThemeComponentFragment newInstance(CharSequence toolbarTitle, int position,
             int titleResId) {
+        return newInstance(toolbarTitle, position, titleResId, false);
+    }
+
+    public static CustomThemeComponentFragment newInstance(CharSequence toolbarTitle, int position,
+            int titleResId, boolean allowGridLayout) {
         CustomThemeComponentFragment fragment = new CustomThemeComponentFragment();
         Bundle arguments = ToolbarFragment.createArguments(toolbarTitle);
         arguments.putInt(ARG_KEY_POSITION, position);
         arguments.putInt(ARG_KEY_TITLE_RES_ID, titleResId);
+        arguments.putBoolean(ARG_USE_GRID_LAYOUT, allowGridLayout);
         fragment.setArguments(arguments);
         return fragment;
     }
@@ -67,6 +74,7 @@
     private CustomThemeManager mCustomThemeManager;
     private int mPosition;
     @StringRes private int mTitleResId;
+    private boolean mUseGridLayout;
 
     private RecyclerView mOptionsContainer;
     private OptionSelectorController<ThemeComponentOption> mOptionsController;
@@ -79,6 +87,7 @@
         super.onCreate(savedInstanceState);
         mPosition = getArguments().getInt(ARG_KEY_POSITION);
         mTitleResId = getArguments().getInt(ARG_KEY_TITLE_RES_ID);
+        mUseGridLayout = getArguments().getBoolean(ARG_USE_GRID_LAYOUT);
         mProvider = mHost.getComponentOptionProvider(mPosition);
         mCustomThemeManager = mHost.getCustomThemeManager();
     }
@@ -144,7 +153,8 @@
 
     private void setUpOptions() {
         mProvider.fetch(options -> {
-            mOptionsController = new OptionSelectorController(mOptionsContainer, options);
+            mOptionsController = new OptionSelectorController(
+                    mOptionsContainer, options, mUseGridLayout, false);
 
             mOptionsController.addListener(selected -> {
                 mSelectedOption = (ThemeComponentOption) selected;
diff --git a/src/com/android/customization/widget/HorizontalSpacerItemDecoration.java b/src/com/android/customization/widget/HorizontalSpacerItemDecoration.java
index f17d52f..df38e6e 100644
--- a/src/com/android/customization/widget/HorizontalSpacerItemDecoration.java
+++ b/src/com/android/customization/widget/HorizontalSpacerItemDecoration.java
@@ -11,24 +11,22 @@
 
 /**
  * RecyclerView ItemDecorator that adds a horizontal space of the given size between items
- * (except the first and last)
+ * and double that space on the ends.
  */
 public class HorizontalSpacerItemDecoration extends ItemDecoration {
 
     private final int mOffset;
-    private final int mEndOffset;
 
-    public HorizontalSpacerItemDecoration(@Dimension int offset, @Dimension int endOffset) {
+    public HorizontalSpacerItemDecoration(@Dimension int offset) {
         mOffset = offset;
-        mEndOffset = endOffset;
     }
 
     @Override
     public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
             @NonNull RecyclerView parent, @NonNull State state) {
         int position = parent.getChildAdapterPosition(view);
-        int left = position == 0 ? mEndOffset : mOffset;
-        int right = (position == parent.getAdapter().getItemCount() - 1) ? mEndOffset : mOffset;
+        int left = position == 0 ? mOffset * 2: mOffset;
+        int right = (position == parent.getAdapter().getItemCount() - 1) ? mOffset * 2 : mOffset;
         outRect.set(left, 0, right, 0);
     }
 }
diff --git a/src/com/android/customization/widget/OptionSelectorController.java b/src/com/android/customization/widget/OptionSelectorController.java
index 615d7d8..b311abe 100644
--- a/src/com/android/customization/widget/OptionSelectorController.java
+++ b/src/com/android/customization/widget/OptionSelectorController.java
@@ -18,18 +18,22 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.customization.model.CustomizationManager;
 import com.android.customization.model.CustomizationOption;
+import com.android.customization.model.theme.custom.ThemeComponentOption;
 import com.android.wallpaper.R;
 
 import java.util.HashSet;
@@ -49,6 +53,7 @@
      * Interface to be notified when an option is selected by the user.
      */
     public interface OptionSelectedListener {
+
         /**
          * Called when an option has been selected (and marked as such in the UI)
          */
@@ -57,6 +62,8 @@
 
     private final RecyclerView mContainer;
     private final List<T> mOptions;
+    private final boolean mUseGrid;
+    private final boolean mShowCheckmark;
 
     private final Set<OptionSelectedListener> mListeners = new HashSet<>();
     private RecyclerView.Adapter<TileViewHolder> mAdapter;
@@ -64,8 +71,15 @@
     private CustomizationOption mAppliedOption;
 
     public OptionSelectorController(RecyclerView container, List<T> options) {
+        this(container, options, false, true);
+    }
+
+    public OptionSelectorController(RecyclerView container, List<T> options,
+            boolean useGrid, boolean showCheckmark) {
         mContainer = container;
         mOptions = options;
+        mUseGrid = useGrid;
+        mShowCheckmark = showCheckmark;
     }
 
     public void addListener(OptionSelectedListener listener) {
@@ -140,7 +154,7 @@
                 holder.itemView.setActivated(option.equals(mSelectedOption));
                 holder.itemView.setOnClickListener(view -> setSelectedOption(option));
 
-                if (option.equals(mAppliedOption)) {
+                if (mShowCheckmark && option.equals(mAppliedOption)) {
                     Resources res = mContainer.getContext().getResources();
                     Drawable checkmark = res.getDrawable(R.drawable.ic_check_circle_filled_24px);
                     Drawable frame = holder.itemView.getForeground();
@@ -171,10 +185,38 @@
         mContainer.setLayoutManager(new LinearLayoutManager(mContainer.getContext(),
                 LinearLayoutManager.HORIZONTAL, false));
         Resources res = mContainer.getContext().getResources();
-        mContainer.addItemDecoration(new HorizontalSpacerItemDecoration(
-                res.getDimensionPixelOffset(R.dimen.option_tile_margin_horizontal),
-                res.getDimensionPixelOffset(R.dimen.option_tile_margin_horizontal_ends)));
         mContainer.setAdapter(mAdapter);
+
+        // Measure RecyclerView to get to the total amount of space used by all options.
+        mContainer.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        DisplayMetrics metrics = new DisplayMetrics();
+        // TODO: retrieve fixed container width for landscape
+        mContainer.getContext().getSystemService(WindowManager.class)
+                .getDefaultDisplay().getMetrics(metrics);
+        int totalWidth = mContainer.getMeasuredWidth();
+
+        if (mUseGrid) {
+            int numColumns = res.getInteger(R.integer.options_grid_num_columns);
+            int widthPerItem = totalWidth / mAdapter.getItemCount();
+            int extraSpace = metrics.widthPixels - widthPerItem * numColumns;
+            int containerSidePadding = extraSpace / (numColumns + 1);
+            mContainer.setLayoutManager(new GridLayoutManager(mContainer.getContext(), numColumns));
+            mContainer.setPaddingRelative(containerSidePadding, 0, containerSidePadding, 0);
+            mContainer.setOverScrollMode(View.OVER_SCROLL_NEVER);
+            return;
+        }
+
+        int extraSpace = metrics.widthPixels - totalWidth;
+        if (extraSpace >= 0) {
+            mContainer.setOverScrollMode(View.OVER_SCROLL_NEVER);
+        }
+        int itemSideMargin =  res.getDimensionPixelOffset(R.dimen.option_tile_margin_horizontal);
+        int defaultTotalPadding = itemSideMargin * (mAdapter.getItemCount() * 2 + 2);
+        if (extraSpace > defaultTotalPadding) {
+            int spaceBetweenItems = extraSpace / (mAdapter.getItemCount() + 1);
+            itemSideMargin = spaceBetweenItems / 2;
+        }
+        mContainer.addItemDecoration(new HorizontalSpacerItemDecoration(itemSideMargin));
     }
 
     public void resetOptions(List<T> options) {