Merge "Color Picker Section (1/3)" into tm-qpr-dev am: 13a16340b4
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/ThemePicker/+/20806327
Change-Id: I5c1394e5994dfe9233b9b5fb590bd678082a4831
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/res/color/keyguard_quick_affordance_slot_tab_text_color.xml b/res/color/picker_fragment_tab_text_color.xml
similarity index 100%
rename from res/color/keyguard_quick_affordance_slot_tab_text_color.xml
rename to res/color/picker_fragment_tab_text_color.xml
diff --git a/res/drawable/color_option_section_selected.xml b/res/drawable/color_option_section_selected.xml
new file mode 100644
index 0000000..13451a5
--- /dev/null
+++ b/res/drawable/color_option_section_selected.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright (C) 2023 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
+ android:height="@dimen/component_color_selected_small_diameter_default"
+ android:width="@dimen/component_color_selected_small_diameter_default"
+ android:gravity="center">
+ <shape
+ android:shape="ring"
+ android:innerRadius="@dimen/component_color_overflow_small_radius_default"
+ android:thickness="2dp"
+ android:useLevel="false">
+ <solid android:color="@color/text_color_primary"/>
+ </shape>
+ </item>
+ <item
+ android:height="@dimen/component_color_selected_small_diameter_default"
+ android:width="@dimen/component_color_selected_small_diameter_default"
+ android:gravity="center">
+ <shape
+ android:shape="ring"
+ android:innerRadius="@dimen/component_color_overflow_small_radius_default"
+ android:thickness="-3dp"
+ android:useLevel="false">
+ <solid android:color="@color/color_surface"/>
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/color_overflow.xml b/res/drawable/color_overflow.xml
new file mode 100644
index 0000000..90c2684
--- /dev/null
+++ b/res/drawable/color_overflow.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright (C) 2023 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
+ android:height="@dimen/component_color_overflow_small_diameter_default"
+ android:width="@dimen/component_color_overflow_small_diameter_default"
+ android:gravity="center">
+ <shape
+ android:shape="ring"
+ android:innerRadius="@dimen/component_color_overflow_small_radius_default"
+ android:thickness="-1dp"
+ android:useLevel="false">
+ <solid android:color="@color/color_surface_variant"/>
+ </shape>
+ </item>
+ <item
+ android:drawable="@drawable/ic_more_horiz"
+ android:gravity="center"/>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/color_section_background.xml b/res/drawable/color_section_background.xml
new file mode 100644
index 0000000..f96824b
--- /dev/null
+++ b/res/drawable/color_section_background.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 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.
+ ~
+ -->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+
+ <solid android:color="@color/color_surface" />
+
+ <corners
+ android:topLeftRadius="32dp"
+ android:topRightRadius="32dp"
+ android:bottomLeftRadius="8dp"
+ android:bottomRightRadius="8dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/ic_more_horiz.xml b/res/drawable/ic_more_horiz.xml
new file mode 100644
index 0000000..7c17df2
--- /dev/null
+++ b/res/drawable/ic_more_horiz.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2023 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:tint="?attr/colorControlNormal"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <path
+ android:fillColor="@color/text_color_primary"
+ android:pathData="M6,14Q5.175,14 4.588,13.412Q4,12.825 4,12Q4,11.175 4.588,10.587Q5.175,10 6,10Q6.825,10 7.412,10.587Q8,11.175 8,12Q8,12.825 7.412,13.412Q6.825,14 6,14ZM12,14Q11.175,14 10.588,13.412Q10,12.825 10,12Q10,11.175 10.588,10.587Q11.175,10 12,10Q12.825,10 13.413,10.587Q14,11.175 14,12Q14,12.825 13.413,13.412Q12.825,14 12,14ZM18,14Q17.175,14 16.587,13.412Q16,12.825 16,12Q16,11.175 16.587,10.587Q17.175,10 18,10Q18.825,10 19.413,10.587Q20,11.175 20,12Q20,12.825 19.413,13.412Q18.825,14 18,14Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/keyguard_quick_affordance_picker_background.xml b/res/drawable/picker_fragment_background.xml
similarity index 100%
rename from res/drawable/keyguard_quick_affordance_picker_background.xml
rename to res/drawable/picker_fragment_background.xml
diff --git a/res/drawable/keyguard_quick_affordance_slot_tab_background.xml b/res/drawable/picker_fragment_tab_background.xml
similarity index 100%
rename from res/drawable/keyguard_quick_affordance_slot_tab_background.xml
rename to res/drawable/picker_fragment_tab_background.xml
diff --git a/res/layout/color_option_section.xml b/res/layout/color_option_section.xml
new file mode 100644
index 0000000..d10f8e5
--- /dev/null
+++ b/res/layout/color_option_section.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2023 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.
+-->
+<!--
+ This displays the selection outline. It is dynamically sized, constrained remain square and
+ have a maximum size, and be centered within its parent. Defines a layout_weight of 1, and should
+ be used with a Linear Layout parent where weightSum is defined.
+ -->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:clipChildren="false"
+ android:gravity="center"
+ android:padding="@dimen/option_tile_grid_tile_padding_min"
+ android:layout_weight="1"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintWidth_max="@dimen/component_color_chip_small_diameter_default">
+ <!--
+ This is the color wheel itself, constrained to a maximum size and centered. The
+ constraint percentage is sized to leave a padding for the outer selection outline,
+ proportionate to 2dp for a 40dp color wheel
+ -->
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/option_tile"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_gravity="center"
+ android:gravity="center"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_percent="0.909">
+
+ <ImageView
+ android:id="@+id/color_preview_0"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:adjustViewBounds="true"
+ android:src="@drawable/color_chip_seed_filled0"
+ app:layout_constraintHeight_percent=".50"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_percent=".50" />
+
+ <ImageView
+ android:id="@+id/color_preview_1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:adjustViewBounds="true"
+ android:src="@drawable/color_chip_seed_filled2"
+ app:layout_constraintHeight_percent=".50"
+ app:layout_constraintLeft_toRightOf="@id/color_preview_0"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_percent=".50" />
+
+ <ImageView
+ android:id="@+id/color_preview_2"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:adjustViewBounds="true"
+ android:src="@drawable/color_chip_seed_filled1"
+ app:layout_constraintHeight_percent=".50"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/color_preview_0"
+ app:layout_constraintWidth_percent=".50" />
+
+ <ImageView
+ android:id="@+id/color_preview_3"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:adjustViewBounds="true"
+ android:src="@drawable/color_chip_seed_filled3"
+ app:layout_constraintHeight_percent=".50"
+ app:layout_constraintLeft_toRightOf="@id/color_preview_2"
+ app:layout_constraintTop_toBottomOf="@id/color_preview_1"
+ app:layout_constraintWidth_percent=".50" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <ImageView
+ android:id="@+id/option_selected"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:adjustViewBounds="true"
+ android:src="@drawable/color_option_section_selected"
+ android:visibility="gone"/>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/res/layout/color_option_section_overflow.xml b/res/layout/color_option_section_overflow.xml
new file mode 100644
index 0000000..fb25c35
--- /dev/null
+++ b/res/layout/color_option_section_overflow.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2023 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.
+-->
+<!--
+ This is added to keep sizing consistent with the color section options. For the color
+ section options, this displays the selection outline.
+ -->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:clipChildren="false"
+ android:gravity="center"
+ android:padding="@dimen/option_tile_grid_tile_padding_min"
+ android:layout_weight="1"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintWidth_max="@dimen/component_color_chip_small_diameter_default">
+
+ <!--
+ This is added to keep sizing consistent with the color section options. For the color
+ section options, this is the color wheel itself.
+ -->
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/option_tile"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_gravity="center"
+ android:gravity="center"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_percent="0.909"
+ android:clipChildren="false">
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:adjustViewBounds="true"
+ android:src="@drawable/color_overflow" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/res/layout/color_section_view2.xml b/res/layout/color_section_view2.xml
new file mode 100644
index 0000000..9ad140b
--- /dev/null
+++ b/res/layout/color_section_view2.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+-->
+<com.android.customization.picker.color.ColorSectionView2
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/section_bottom_padding"
+ android:paddingHorizontal="@dimen/section_horizontal_padding"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/color_section_option_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:background="@drawable/color_section_background"
+ android:paddingVertical="24dp"
+ android:paddingHorizontal="24dp"
+ android:weightSum="@integer/color_section_num_columns">
+
+ <!--
+ This is just an invisible placeholder put in place so that the parent keeps its height
+ stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the
+ layout logic to keep the size of the preview container stable as well, which bodes well
+ for setting up the SurfaceView for remote rendering without changing its size after the
+ content is loaded into the RecyclerView.
+
+ It's critical for any TextViews inside the included layout to have text.
+ -->
+ <include
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ layout="@layout/color_option_section_overflow"
+ android:visibility="invisible"
+ android:layout_weight="1"/>
+ </LinearLayout>
+</com.android.customization.picker.color.ColorSectionView2>
diff --git a/res/layout/fragment_color_picker.xml b/res/layout/fragment_color_picker.xml
new file mode 100644
index 0000000..d91ac5e
--- /dev/null
+++ b/res/layout/fragment_color_picker.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 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"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/section_header_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <include layout="@layout/section_header" />
+
+ </FrameLayout>
+
+ <com.android.wallpaper.picker.DisplayAspectRatioFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:paddingTop="36dp"
+ android:paddingBottom="40dp">
+
+ <include
+ android:id="@+id/preview"
+ layout="@layout/wallpaper_preview_card"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"/>
+
+ </com.android.wallpaper.picker.DisplayAspectRatioFrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginHorizontal="24dp"
+ android:layout_marginBottom="28dp"
+ android:background="@drawable/picker_fragment_background"
+ android:paddingTop="22dp"
+ android:paddingBottom="62dp">
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/color_type_tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingHorizontal="16dp" />
+
+ <!--
+ This is just an invisible placeholder put in place so that the parent keeps its height
+ stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the
+ layout logic to keep the size of the preview container stable as well, which bodes well
+ for setting up the SurfaceView for remote rendering without changing its size after the
+ content is loaded into the RecyclerView.
+
+ It's critical for any TextViews inside the included layout to have text.
+ -->
+ <include
+ layout="@layout/picker_fragment_tab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible" />
+
+ </FrameLayout>
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="22dp" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <androidx.viewpager2.widget.ViewPager2
+ android:id="@+id/color_section_view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/color_options_container_top_margin"
+ android:clipChildren="false"
+ android:clipToPadding="false"/>
+
+ <!--
+ This is just an invisible placeholder put in place so that the parent keeps its height
+ stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the
+ layout logic to keep the size of the preview container stable as well, which bodes well
+ for setting up the SurfaceView for remote rendering without changing its size after the
+ content is loaded into the RecyclerView.
+
+ It's critical for any TextViews inside the included layout to have text.
+ -->
+ <include
+ layout="@layout/color_option"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible" />
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/fragment_lock_screen_quick_affordances.xml b/res/layout/fragment_lock_screen_quick_affordances.xml
index 331d501..3fc7275 100644
--- a/res/layout/fragment_lock_screen_quick_affordances.xml
+++ b/res/layout/fragment_lock_screen_quick_affordances.xml
@@ -51,7 +51,7 @@
android:orientation="vertical"
android:layout_marginHorizontal="24dp"
android:layout_marginBottom="28dp"
- android:background="@drawable/keyguard_quick_affordance_picker_background"
+ android:background="@drawable/picker_fragment_background"
android:paddingTop="22dp"
android:paddingBottom="62dp">
@@ -77,7 +77,7 @@
It's critical for any TextViews inside the included layout to have text.
-->
<include
- layout="@layout/keyguard_quick_affordance_slot_tab"
+ layout="@layout/picker_fragment_tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible" />
diff --git a/res/layout/keyguard_quick_affordance_enablement_dialog.xml b/res/layout/keyguard_quick_affordance_enablement_dialog.xml
index d6ba105..f3d4d8c 100644
--- a/res/layout/keyguard_quick_affordance_enablement_dialog.xml
+++ b/res/layout/keyguard_quick_affordance_enablement_dialog.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@drawable/keyguard_quick_affordance_picker_background"
+ android:background="@drawable/picker_fragment_background"
android:orientation="vertical"
android:padding="24dp">
diff --git a/res/layout/keyguard_quick_affordance_slot_tab.xml b/res/layout/picker_fragment_tab.xml
similarity index 87%
rename from res/layout/keyguard_quick_affordance_slot_tab.xml
rename to res/layout/picker_fragment_tab.xml
index c4934d8..cd04758 100644
--- a/res/layout/keyguard_quick_affordance_slot_tab.xml
+++ b/res/layout/picker_fragment_tab.xml
@@ -21,12 +21,12 @@
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textColor="@color/keyguard_quick_affordance_slot_tab_text_color"
+ android:textColor="@color/picker_fragment_tab_text_color"
android:paddingVertical="8dp"
android:paddingHorizontal="16dp"
android:minWidth="48dp"
android:minHeight="48dp"
android:gravity="center"
- android:background="@drawable/keyguard_quick_affordance_slot_tab_background"
+ android:background="@drawable/picker_fragment_tab_background"
android:text="Placeholder for stable size calculation, please do not remove."
tools:ignore="HardcodedText" />
diff --git a/res/values-w800dp/integers.xml b/res/values-w800dp/integers.xml
index 23fa48a..cef5c90 100644
--- a/res/values-w800dp/integers.xml
+++ b/res/values-w800dp/integers.xml
@@ -16,4 +16,5 @@
-->
<resources>
<integer name="options_grid_num_columns">6</integer>
+ <integer name="color_section_num_columns">5</integer>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 64d9941..9099c93 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -133,6 +133,11 @@
<!-- For the color option section -->
<dimen name="color_options_container_top_margin">24dp</dimen>
+ <dimen name="component_color_overflow_small_radius_default">20dp</dimen>
+ <dimen name="component_color_overflow_small_diameter_default">40dp</dimen>
+ <dimen name="component_color_selected_small_radius_default">22dp</dimen>
+ <dimen name="component_color_selected_small_diameter_default">44dp</dimen>
+
<!-- For the color page. -->
<dimen name="color_page_indicator_margin_top">16dp</dimen>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index 6e2db17..2129ccd 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -16,4 +16,5 @@
-->
<resources>
<integer name="options_grid_num_columns">4</integer>
+ <integer name="color_section_num_columns">6</integer>
</resources>
diff --git a/src/com/android/customization/model/color/ColorSectionController2.java b/src/com/android/customization/model/color/ColorSectionController2.java
new file mode 100644
index 0000000..257bb94
--- /dev/null
+++ b/src/com/android/customization/model/color/ColorSectionController2.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2023 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.color;
+
+import static com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_HOME;
+import static com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_LOCK;
+import static com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_PRESET;
+
+import android.app.Activity;
+import android.app.WallpaperColors;
+import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.stats.style.StyleEnums;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.customization.model.CustomizationManager;
+import com.android.customization.model.theme.OverlayManagerCompat;
+import com.android.customization.module.CustomizationInjector;
+import com.android.customization.module.ThemesUserEventLogger;
+import com.android.customization.picker.color.ColorPickerFragment;
+import com.android.customization.picker.color.ColorSectionView2;
+import com.android.wallpaper.R;
+import com.android.wallpaper.model.CustomizationSectionController;
+import com.android.wallpaper.model.WallpaperColorsViewModel;
+import com.android.wallpaper.module.InjectorProvider;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Color section view's controller for the logic of color customization.
+ */
+public class ColorSectionController2 implements CustomizationSectionController<ColorSectionView2> {
+
+ private static final String TAG = "ColorSectionController";
+ private static final long MIN_COLOR_APPLY_PERIOD = 500L;
+
+ private final ThemesUserEventLogger mEventLogger;
+ private final ColorCustomizationManager mColorManager;
+ private final WallpaperColorsViewModel mWallpaperColorsViewModel;
+ private final LifecycleOwner mLifecycleOwner;
+ private final CustomizationSectionNavigationController mSectionNavigationController;
+
+ private List<ColorOption> mWallpaperColorOptions = new ArrayList<>();
+ private List<ColorOption> mPresetColorOptions = new ArrayList<>();
+ private ColorOption mSelectedColor;
+ @Nullable private WallpaperColors mHomeWallpaperColors;
+ @Nullable private WallpaperColors mLockWallpaperColors;
+ // Uses a boolean value to indicate whether wallpaper color is ready because WallpaperColors
+ // maybe be null when it's ready.
+ private boolean mHomeWallpaperColorsReady;
+ private boolean mLockWallpaperColorsReady;
+ private long mLastColorApplyingTime = 0L;
+ private ColorSectionView2 mColorSectionView;
+
+ public ColorSectionController2(Activity activity, WallpaperColorsViewModel viewModel,
+ LifecycleOwner lifecycleOwner,
+ CustomizationSectionNavigationController sectionNavigationController) {
+ CustomizationInjector injector = (CustomizationInjector) InjectorProvider.getInjector();
+ mEventLogger = (ThemesUserEventLogger) injector.getUserEventLogger(activity);
+ mColorManager = ColorCustomizationManager.getInstance(activity,
+ new OverlayManagerCompat(activity));
+ mWallpaperColorsViewModel = viewModel;
+ mLifecycleOwner = lifecycleOwner;
+ mSectionNavigationController = sectionNavigationController;
+ }
+
+ @Override
+ public boolean isAvailable(@Nullable Context context) {
+ return context != null && ColorUtils.isMonetEnabled(context) && mColorManager.isAvailable();
+ }
+
+ @Override
+ public ColorSectionView2 createView(Context context) {
+ mColorSectionView = (ColorSectionView2) LayoutInflater.from(context).inflate(
+ R.layout.color_section_view2, /* root= */ null);
+
+ mWallpaperColorsViewModel.getHomeWallpaperColors().observe(mLifecycleOwner,
+ homeColors -> {
+ mHomeWallpaperColors = homeColors;
+ mHomeWallpaperColorsReady = true;
+ maybeLoadColors();
+ });
+ mWallpaperColorsViewModel.getLockWallpaperColors().observe(mLifecycleOwner,
+ lockColors -> {
+ mLockWallpaperColors = lockColors;
+ mLockWallpaperColorsReady = true;
+ maybeLoadColors();
+ });
+ return mColorSectionView;
+ }
+
+ private void maybeLoadColors() {
+ if (mHomeWallpaperColorsReady && mLockWallpaperColorsReady) {
+ mColorManager.setWallpaperColors(mHomeWallpaperColors, mLockWallpaperColors);
+ loadColorOptions(/* reload= */ false);
+ }
+ }
+
+ private void loadColorOptions(boolean reload) {
+ mColorManager.fetchOptions(new CustomizationManager.OptionsFetchedListener<ColorOption>() {
+ @Override
+ public void onOptionsLoaded(List<ColorOption> options) {
+ List<ColorOption> wallpaperColorOptions = new ArrayList<>();
+ List<ColorOption> presetColorOptions = new ArrayList<>();
+ for (ColorOption option : options) {
+ if (option instanceof ColorSeedOption) {
+ wallpaperColorOptions.add(option);
+ } else if (option instanceof ColorBundle) {
+ presetColorOptions.add(option);
+ }
+ }
+ mWallpaperColorOptions = wallpaperColorOptions;
+ mPresetColorOptions = presetColorOptions;
+ mSelectedColor = findActiveColorOption(mWallpaperColorOptions,
+ mPresetColorOptions);
+
+ mColorSectionView.post(() -> setUpColorSectionView(mWallpaperColorOptions,
+ mPresetColorOptions));
+ }
+
+ @Override
+ public void onError(@Nullable Throwable throwable) {
+ if (throwable != null) {
+ Log.e(TAG, "Error loading theme bundles", throwable);
+ }
+ }
+ }, reload);
+ }
+
+ private void setUpColorSectionView(List<ColorOption> wallpaperColorOptions,
+ List<ColorOption> presetColorOptions) {
+ int wallpaperOptionSize = wallpaperColorOptions.size();
+
+ List<ColorOption> subOptions = wallpaperColorOptions.subList(0,
+ Math.min(5, wallpaperOptionSize));
+ // add additional options based on preset colors if there are less than 5 wallpaper colors
+ List<ColorOption> additionalSubOptions = presetColorOptions.subList(0,
+ Math.min(Math.max(0, 5 - wallpaperOptionSize), presetColorOptions.size()));
+ subOptions.addAll(additionalSubOptions);
+
+ mColorSectionView.setOverflowOnClick(() -> {
+ mSectionNavigationController.navigateTo(new ColorPickerFragment());
+ return null;
+ });
+ mColorSectionView.setColorOptionOnClick(selectedOption -> {
+ if (mSelectedColor.equals(selectedOption)) {
+ return null;
+ }
+ mSelectedColor = (ColorOption) selectedOption;
+ // Post with delay for color option to run ripple.
+ new Handler().postDelayed(()-> applyColor(mSelectedColor), /* delayMillis= */ 100);
+ return null;
+ });
+ mColorSectionView.setItems(subOptions, mColorManager);
+ }
+
+ private ColorOption findActiveColorOption(List<ColorOption> wallpaperColorOptions,
+ List<ColorOption> presetColorOptions) {
+ ColorOption activeColorOption = null;
+ for (ColorOption colorOption : Lists.newArrayList(
+ Iterables.concat(wallpaperColorOptions, presetColorOptions))) {
+ if (colorOption.isActive(mColorManager)) {
+ activeColorOption = colorOption;
+ break;
+ }
+ }
+ // Use the first one option by default. This should not happen as above should have an
+ // active option found.
+ if (activeColorOption == null) {
+ activeColorOption = wallpaperColorOptions.isEmpty()
+ ? presetColorOptions.get(0)
+ : wallpaperColorOptions.get(0);
+ }
+ return activeColorOption;
+ }
+
+ private void applyColor(ColorOption colorOption) {
+ if (SystemClock.elapsedRealtime() - mLastColorApplyingTime < MIN_COLOR_APPLY_PERIOD) {
+ return;
+ }
+ mLastColorApplyingTime = SystemClock.elapsedRealtime();
+ mColorManager.apply(colorOption, new CustomizationManager.Callback() {
+ @Override
+ public void onSuccess() {
+ mColorSectionView.announceForAccessibility(
+ mColorSectionView.getContext().getString(R.string.color_changed));
+ mEventLogger.logColorApplied(getColorAction(colorOption), colorOption);
+ }
+
+ @Override
+ public void onError(@Nullable Throwable throwable) {
+ Log.w(TAG, "Apply theme with error: " + throwable);
+ }
+ });
+ }
+
+ private int getColorAction(ColorOption colorOption) {
+ int action = StyleEnums.DEFAULT_ACTION;
+ boolean isForBoth = mLockWallpaperColors == null || mLockWallpaperColors.equals(
+ mHomeWallpaperColors);
+
+ if (TextUtils.equals(colorOption.getSource(), COLOR_SOURCE_PRESET)) {
+ action = StyleEnums.COLOR_PRESET_APPLIED;
+ } else if (isForBoth) {
+ action = StyleEnums.COLOR_WALLPAPER_HOME_LOCK_APPLIED;
+ } else {
+ switch (colorOption.getSource()) {
+ case COLOR_SOURCE_HOME:
+ action = StyleEnums.COLOR_WALLPAPER_HOME_APPLIED;
+ break;
+ case COLOR_SOURCE_LOCK:
+ action = StyleEnums.COLOR_WALLPAPER_LOCK_APPLIED;
+ break;
+ }
+ }
+ return action;
+ }
+}
diff --git a/src/com/android/customization/module/DefaultCustomizationSections.java b/src/com/android/customization/module/DefaultCustomizationSections.java
index 2fb530a..c5affd1 100644
--- a/src/com/android/customization/module/DefaultCustomizationSections.java
+++ b/src/com/android/customization/module/DefaultCustomizationSections.java
@@ -8,6 +8,7 @@
import androidx.lifecycle.ViewModelProvider;
import com.android.customization.model.color.ColorSectionController;
+import com.android.customization.model.color.ColorSectionController2;
import com.android.customization.model.grid.GridOptionsManager;
import com.android.customization.model.grid.GridSectionController;
import com.android.customization.model.mode.DarkModeSectionController;
@@ -50,7 +51,7 @@
}
@Override
- public List<CustomizationSectionController<?>> getSectionControllersForScreen(
+ public List<CustomizationSectionController<?>> getRevampedUISectionControllersForScreen(
Screen screen,
FragmentActivity activity,
LifecycleOwner lifecycleOwner,
@@ -76,8 +77,8 @@
displayUtils));
// Theme color section.
- sectionControllers.add(new ColorSectionController(
- activity, wallpaperColorsViewModel, lifecycleOwner, savedInstanceState));
+ sectionControllers.add(new ColorSectionController2(
+ activity, wallpaperColorsViewModel, lifecycleOwner, sectionNavigationController));
// Wallpaper quick switch section.
sectionControllers.add(
diff --git a/src/com/android/customization/picker/color/ColorPickerFragment.kt b/src/com/android/customization/picker/color/ColorPickerFragment.kt
new file mode 100644
index 0000000..c8ecb7f
--- /dev/null
+++ b/src/com/android/customization/picker/color/ColorPickerFragment.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 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.color
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.android.wallpaper.R
+import com.android.wallpaper.picker.AppbarFragment
+
+// TODO (b/262924623): Color Picker Fragment
+class ColorPickerFragment : AppbarFragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ val view =
+ inflater.inflate(
+ R.layout.fragment_color_picker,
+ container,
+ false,
+ )
+ setUpToolbar(view)
+ return view
+ }
+}
diff --git a/src/com/android/customization/picker/color/ColorSectionView2.kt b/src/com/android/customization/picker/color/ColorSectionView2.kt
new file mode 100644
index 0000000..3e4e4bc
--- /dev/null
+++ b/src/com/android/customization/picker/color/ColorSectionView2.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 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.color
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.ImageView
+import android.widget.LinearLayout
+import com.android.customization.model.color.ColorCustomizationManager
+import com.android.customization.model.color.ColorOption
+import com.android.wallpaper.R
+import com.android.wallpaper.picker.SectionView
+
+/**
+ * The class inherits from {@link SectionView} as the view representing the color section of the
+ * customization picker. It displays a list of color options and an overflow option.
+ */
+class ColorSectionView2(context: Context, attrs: AttributeSet?) : SectionView(context, attrs) {
+
+ private val items = mutableListOf<ColorOption>()
+ private var onClick: ((ColorOption) -> Unit)? = null
+ private var overflowOnClick: (() -> Unit)? = null
+
+ // TODO (b/262924623): make adjustments for large screen
+ fun setItems(items: List<ColorOption>, manager: ColorCustomizationManager) {
+ this.items.clear()
+ this.items.addAll(items)
+ val optionContainer = findViewById<LinearLayout>(R.id.color_section_option_container)
+ optionContainer.removeAllViews()
+ // Last color option is either the last index of the items list, or the second last index
+ // of column count. Save the last column of the option container for the overflow option
+ val lastOptionIndex = minOf(optionContainer.weightSum.toInt() - 2, items.size - 1)
+ if (items.isNotEmpty()) {
+ for (position in 0..lastOptionIndex) {
+ val item = items[position]
+ val itemView =
+ LayoutInflater.from(context)
+ .inflate(R.layout.color_option_section, optionContainer, false)
+ item.bindThumbnailTile(itemView.findViewById(R.id.option_tile))
+ if (item.isActive(manager)) {
+ val optionSelectedView = itemView.findViewById<ImageView>(R.id.option_selected)
+ optionSelectedView.visibility = VISIBLE
+ }
+ itemView.setOnClickListener { onClick?.invoke(item) }
+ optionContainer.addView(itemView)
+ }
+ }
+ // add overflow option
+ val itemView =
+ LayoutInflater.from(context)
+ .inflate(R.layout.color_option_section_overflow, optionContainer, false)
+ itemView.setOnClickListener { overflowOnClick?.invoke() }
+ optionContainer.addView(itemView)
+ }
+
+ /** Sets the on click callback for a color option. */
+ fun setColorOptionOnClick(onClick: (ColorOption) -> Unit) {
+ this.onClick = onClick
+ if (items.isNotEmpty()) {
+ val optionContainer = findViewById<LinearLayout>(R.id.color_section_option_container)
+ val lastOptionIndex = minOf(optionContainer.childCount - 2, items.size - 1)
+ for (position in 0..lastOptionIndex) {
+ val item = items[position]
+ val itemView = optionContainer.getChildAt(position)
+ itemView.setOnClickListener { onClick.invoke(item) }
+ }
+ }
+ }
+
+ /** Sets the on click callback for the overflow option. */
+ fun setOverflowOnClick(onClick: () -> Unit) {
+ this.overflowOnClick = onClick
+ val optionContainer = findViewById<LinearLayout>(R.id.color_section_option_container)
+ if (optionContainer.childCount > 0) {
+ val itemView = optionContainer.getChildAt(optionContainer.childCount - 1)
+ itemView.setOnClickListener { onClick.invoke() }
+ }
+ }
+}
diff --git a/src/com/android/customization/picker/quickaffordance/ui/adapter/SlotTabAdapter.kt b/src/com/android/customization/picker/quickaffordance/ui/adapter/SlotTabAdapter.kt
index acafef4..5203ed3 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/adapter/SlotTabAdapter.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/adapter/SlotTabAdapter.kt
@@ -44,7 +44,7 @@
return ViewHolder(
LayoutInflater.from(parent.context)
.inflate(
- R.layout.keyguard_quick_affordance_slot_tab,
+ R.layout.picker_fragment_tab,
parent,
false,
)
diff --git a/src/com/android/customization/widget/OptionSelectorController.java b/src/com/android/customization/widget/OptionSelectorController.java
index 8805caf..fc665b9 100644
--- a/src/com/android/customization/widget/OptionSelectorController.java
+++ b/src/com/android/customization/widget/OptionSelectorController.java
@@ -183,6 +183,16 @@
@Override
public TileViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
+ // Provide width constraint when a grid layout manager is not use and width is set
+ // to match parent
+ if (!mUseGrid
+ && v.getLayoutParams().width == RecyclerView.LayoutParams.MATCH_PARENT) {
+ Resources res = mContainer.getContext().getResources();
+ RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(
+ res.getDimensionPixelSize(R.dimen.option_tile_width),
+ RecyclerView.LayoutParams.WRAP_CONTENT);
+ v.setLayoutParams(layoutParams);
+ }
return new TileViewHolder(v);
}