Improve the features of IllustrationPreference.
- Support the dynamic color.
The colors of the illustration's labels can be changed.
We create a mapping table of colors and labels.
According to this mapping table, preference can
apply the corresponding colors to the illustration.
- Support the middle ground view.
User can overlay a view on top of the illustration.
- Support the auto scale of illustration.
- Update the layout to prevent the animation cropping.
Fix: 189199177
Test: rebotest and see the UI.
Change-Id: Ib02cbc5bb99ab8014d7ee7ed630a6721968a49ab
diff --git a/packages/SettingsLib/IllustrationPreference/Android.bp b/packages/SettingsLib/IllustrationPreference/Android.bp
index f8dd384..5904589 100644
--- a/packages/SettingsLib/IllustrationPreference/Android.bp
+++ b/packages/SettingsLib/IllustrationPreference/Android.bp
@@ -19,5 +19,5 @@
],
sdk_version: "system_current",
- min_sdk_version: "21",
+ min_sdk_version: "28",
}
diff --git a/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml b/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml
index dd2fa5e..0734aca 100644
--- a/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml
@@ -16,11 +16,7 @@
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:top="@dimen/settingslib_illustration_padding"
- android:left="@dimen/settingslib_illustration_padding"
- android:right="@dimen/settingslib_illustration_padding"
- android:bottom="@dimen/settingslib_illustration_padding">
+ <item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_protection_color"/>
<corners android:radius="28dp"/>
diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
index 7d65aae..54731f5 100644
--- a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
@@ -23,14 +23,33 @@
android:gravity="center"
android:orientation="horizontal">
- <com.airbnb.lottie.LottieAnimationView
- android:id="@+id/lottie_view"
- android:layout_width="412dp"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_gravity="center"
- android:clipToOutline="true"
- android:background="@drawable/protection_background"
- android:importantForAccessibility="no"/>
+ android:gravity="center_vertical"
+ android:padding="@dimen/settingslib_illustration_padding"
+ android:orientation="vertical">
+ <com.airbnb.lottie.LottieAnimationView
+ android:id="@+id/lottie_view"
+ android:adjustViewBounds="true"
+ android:maxWidth="412dp"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:clipToOutline="true"
+ android:background="@drawable/protection_background"
+ android:importantForAccessibility="no"/>
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/middleground_layout"
+ android:layout_width="412dp"
+ android:layout_height="300dp"
+ android:padding="@dimen/settingslib_illustration_padding"
+ android:background="@android:color/transparent"
+ android:layout_gravity="center"
+ android:visibility="gone"/>
<ImageView
android:id="@+id/video_play_button"
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
index e53a43e..ead5174 100644
--- a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
@@ -17,4 +17,46 @@
<resources>
<color name="settingslib_protection_color">@android:color/white</color>
+
+ <!-- Dynamic colors-->
+ <color name="settingslib_color_blue600">#1a73e8</color>
+ <color name="settingslib_color_blue400">#669df6</color>
+ <color name="settingslib_color_blue300">#8ab4f8</color>
+ <color name="settingslib_color_blue100">#d2e3fc</color>
+ <color name="settingslib_color_blue50">#e8f0fe</color>
+ <color name="settingslib_color_green600">#1e8e3e</color>
+ <color name="settingslib_color_green400">#5bb974</color>
+ <color name="settingslib_color_green100">#ceead6</color>
+ <color name="settingslib_color_green50">#e6f4ea</color>
+ <color name="settingslib_color_red600">#d93025</color>
+ <color name="settingslib_color_red400">#ee675c</color>
+ <color name="settingslib_color_red100">#fad2cf</color>
+ <color name="settingslib_color_red50">#fce8e6</color>
+ <color name="settingslib_color_yellow600">#f9ab00</color>
+ <color name="settingslib_color_yellow400">#fcc934</color>
+ <color name="settingslib_color_yellow100">#feefc3</color>
+ <color name="settingslib_color_yellow50">#fef7e0</color>
+ <color name="settingslib_color_grey900">#202124</color>
+ <color name="settingslib_color_grey800">#3c4043</color>
+ <color name="settingslib_color_grey700">#5f6368</color>
+ <color name="settingslib_color_grey600">#80868b</color>
+ <color name="settingslib_color_grey400">#bdc1c6</color>
+ <color name="settingslib_color_grey300">#dadce0</color>
+ <color name="settingslib_color_grey200">#e8eaed</color>
+ <color name="settingslib_color_orange600">#e8710a</color>
+ <color name="settingslib_color_orange400">#fa903e</color>
+ <color name="settingslib_color_orange300">#fcad70</color>
+ <color name="settingslib_color_orange100">#fedfc8</color>
+ <color name="settingslib_color_pink600">#e52592</color>
+ <color name="settingslib_color_pink400">#ff63b8</color>
+ <color name="settingslib_color_pink300">#ff8bcb</color>
+ <color name="settingslib_color_pink100">#fdcfe8</color>
+ <color name="settingslib_color_purple600">#9334e6</color>
+ <color name="settingslib_color_purple400">#af5cf7</color>
+ <color name="settingslib_color_purple300">#c58af9</color>
+ <color name="settingslib_color_purple100">#e9d2fd</color>
+ <color name="settingslib_color_cyan600">#12b5c8</color>
+ <color name="settingslib_color_cyan400">#4ecde6</color>
+ <color name="settingslib_color_cyan300">#78d9ec</color>
+ <color name="settingslib_color_cyan100">#cbf0f8</color>
</resources>
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
index 79562b9..5e540d3 100644
--- a/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
@@ -17,5 +17,5 @@
<resources>
<!-- Padding of illustration -->
- <dimen name="settingslib_illustration_padding">16dp</dimen>
+ <dimen name="settingslib_illustration_padding">12dp</dimen>
</resources>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/ColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/ColorUtils.java
new file mode 100644
index 0000000..cd2ddeb
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/ColorUtils.java
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.widget;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.util.Pair;
+
+import com.airbnb.lottie.LottieAnimationView;
+import com.airbnb.lottie.LottieProperty;
+import com.airbnb.lottie.model.KeyPath;
+import com.airbnb.lottie.value.LottieFrameInfo;
+import com.airbnb.lottie.value.SimpleLottieValueCallback;
+
+import java.util.HashMap;
+
+/**
+ * ColorUtils is a util class which help the lottie illustration
+ * changes the color of tags in the json file.
+ */
+
+public class ColorUtils {
+
+ private static HashMap<String, Integer> sSysColors;
+ static {
+ sSysColors = new HashMap<>();
+ sSysColors.put(".colorAccent", android.R.attr.colorAccent);
+ sSysColors.put(".colorPrimary", android.R.attr.colorPrimary);
+ sSysColors.put(".colorPrimaryDark", android.R.attr.colorPrimaryDark);
+ sSysColors.put(".colorSecondary", android.R.attr.colorSecondary);
+ }
+
+ private static HashMap<String, Pair<Integer, Integer>> sFixedColors;
+ static {
+ sFixedColors = new HashMap<>();
+ sFixedColors.put(".blue600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_blue600, R.color.settingslib_color_blue400));
+ sFixedColors.put(".green600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_green600, R.color.settingslib_color_green400));
+ sFixedColors.put(".red600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_red600, R.color.settingslib_color_red400));
+ sFixedColors.put(".yellow600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_yellow600, R.color.settingslib_color_yellow400));
+ sFixedColors.put(".blue400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_blue400, R.color.settingslib_color_blue100));
+ sFixedColors.put(".green400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_green400, R.color.settingslib_color_green100));
+ sFixedColors.put(".red400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_red400, R.color.settingslib_color_red100));
+ sFixedColors.put(".yellow400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_yellow400, R.color.settingslib_color_yellow100));
+ sFixedColors.put(".blue300", new Pair<Integer, Integer>(
+ R.color.settingslib_color_blue300, R.color.settingslib_color_blue50));
+ sFixedColors.put(".blue50", new Pair<Integer, Integer>(
+ R.color.settingslib_color_blue50, R.color.settingslib_color_grey900));
+ sFixedColors.put(".green50", new Pair<Integer, Integer>(
+ R.color.settingslib_color_green50, R.color.settingslib_color_grey900));
+ sFixedColors.put(".red50", new Pair<Integer, Integer>(
+ R.color.settingslib_color_red50, R.color.settingslib_color_grey900));
+ sFixedColors.put(".yellow50", new Pair<Integer, Integer>(
+ R.color.settingslib_color_yellow50, R.color.settingslib_color_grey900));
+ // Secondary colors
+ sFixedColors.put(".orange600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_orange600, R.color.settingslib_color_orange300));
+ sFixedColors.put(".pink600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_pink600, R.color.settingslib_color_pink300));
+ sFixedColors.put(".purple600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_purple600, R.color.settingslib_color_purple300));
+ sFixedColors.put(".cyan600", new Pair<Integer, Integer>(
+ R.color.settingslib_color_cyan600, R.color.settingslib_color_cyan300));
+ sFixedColors.put(".orange400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_orange400, R.color.settingslib_color_orange100));
+ sFixedColors.put(".pink400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_pink400, R.color.settingslib_color_pink100));
+ sFixedColors.put(".purple400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_purple400, R.color.settingslib_color_purple100));
+ sFixedColors.put(".cyan400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_cyan400, R.color.settingslib_color_cyan100));
+ sFixedColors.put(".gery400", new Pair<Integer, Integer>(
+ R.color.settingslib_color_grey400, R.color.settingslib_color_grey700));
+ sFixedColors.put(".gery300", new Pair<Integer, Integer>(
+ R.color.settingslib_color_grey300, R.color.settingslib_color_grey600));
+ sFixedColors.put(".gery200", new Pair<Integer, Integer>(
+ R.color.settingslib_color_grey200, R.color.settingslib_color_grey800));
+ }
+
+ private static boolean isDarkMode(Context context) {
+ return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ }
+
+ /**
+ * Apply the color of tags to the animation.
+ */
+ public static void applyDynamicColors(Context context, LottieAnimationView animationView) {
+ for (String key : sSysColors.keySet()) {
+ final int color = sSysColors.get(key);
+ animationView.addValueCallback(
+ new KeyPath("**", key, "**"),
+ LottieProperty.COLOR_FILTER,
+ new SimpleLottieValueCallback<ColorFilter>() {
+ @Override
+ public ColorFilter getValue(LottieFrameInfo<ColorFilter> frameInfo) {
+ return new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ }
+ );
+ }
+ for (String key : sFixedColors.keySet()) {
+ final Pair<Integer, Integer> fixedColorPair = sFixedColors.get(key);
+ final int color = isDarkMode(context) ? fixedColorPair.second : fixedColorPair.first;
+ animationView.addValueCallback(
+ new KeyPath("**", key, "**"),
+ LottieProperty.COLOR_FILTER,
+ new SimpleLottieValueCallback<ColorFilter>() {
+ @Override
+ public ColorFilter getValue(LottieFrameInfo<ColorFilter> frameInfo) {
+ return new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ }
+ );
+ }
+ }
+}
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index 90b8a32..7b2a0af 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -23,6 +23,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.VisibleForTesting;
@@ -38,10 +39,14 @@
public class IllustrationPreference extends Preference implements OnPreferenceClickListener {
static final String TAG = "IllustrationPreference";
+
private int mAnimationId;
private boolean mIsAnimating;
+ private boolean mIsAutoScale;
private ImageView mPlayButton;
private LottieAnimationView mIllustrationView;
+ private View mMiddleGroundView;
+ private FrameLayout mMiddleGroundLayout;
public IllustrationPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -66,13 +71,20 @@
Log.w(TAG, "Invalid illustration resource id.");
return;
}
+ mMiddleGroundLayout = (FrameLayout) holder.findViewById(R.id.middleground_layout);
mPlayButton = (ImageView) holder.findViewById(R.id.video_play_button);
mIllustrationView = (LottieAnimationView) holder.findViewById(R.id.lottie_view);
mIllustrationView.setAnimation(mAnimationId);
mIllustrationView.loop(true);
+ ColorUtils.applyDynamicColors(getContext(), mIllustrationView);
mIllustrationView.playAnimation();
updateAnimationStatus(mIsAnimating);
- setOnPreferenceClickListener(this);
+ if (mIsAutoScale) {
+ enableAnimationAutoScale(mIsAutoScale);
+ }
+ if (mMiddleGroundView != null) {
+ enableMiddleGroundView();
+ }
}
@Override
@@ -102,16 +114,59 @@
return mIllustrationView.isAnimating();
}
+ /**
+ * Set the middle ground view to preference. The user
+ * can overlay a view on top of the animation.
+ */
+ public void setMiddleGroundView(View view) {
+ mMiddleGroundView = view;
+ if (mMiddleGroundLayout == null) {
+ return;
+ }
+ enableMiddleGroundView();
+ }
+
+ /**
+ * Remove the middle ground view of preference.
+ */
+ public void removeMiddleGroundView() {
+ if (mMiddleGroundLayout == null) {
+ return;
+ }
+ mMiddleGroundLayout.removeAllViews();
+ mMiddleGroundLayout.setVisibility(View.GONE);
+ }
+
+ /**
+ * Enables the auto scale feature of animation view.
+ */
+ public void enableAnimationAutoScale(boolean enable) {
+ mIsAutoScale = enable;
+ if (mIllustrationView == null) {
+ return;
+ }
+ mIllustrationView.setScaleType(
+ mIsAutoScale ? ImageView.ScaleType.CENTER_CROP : ImageView.ScaleType.CENTER_INSIDE);
+ }
+
+ private void enableMiddleGroundView() {
+ mMiddleGroundLayout.removeAllViews();
+ mMiddleGroundLayout.addView(mMiddleGroundView);
+ mMiddleGroundLayout.setVisibility(View.VISIBLE);
+ }
+
private void init(Context context, AttributeSet attrs) {
setLayoutResource(R.layout.illustration_preference);
mIsAnimating = true;
+ mIsAutoScale = false;
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.LottieAnimationView, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
mAnimationId = a.getResourceId(R.styleable.LottieAnimationView_lottie_rawRes, 0);
a.recycle();
}
+ setOnPreferenceClickListener(this);
}
private void updateAnimationStatus(boolean playAnimation) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index 4a14403..f197cbb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -22,6 +22,9 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
import com.airbnb.lottie.LottieAnimationView;
@@ -41,14 +44,15 @@
@Mock
LottieAnimationView mAnimationView;
+ private Context mContext;
private IllustrationPreference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- final Context context = RuntimeEnvironment.application;
+ mContext = RuntimeEnvironment.application;
final AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
- mPreference = new IllustrationPreference(context, attributeSet);
+ mPreference = new IllustrationPreference(mContext, attributeSet);
ReflectionHelpers.setField(mPreference, "mIllustrationView", mAnimationView);
}
@@ -65,4 +69,27 @@
assertThat(mPreference.isAnimating()).isTrue();
}
+
+ @Test
+ public void setMiddleGroundView_middleGroundView_shouldVisible() {
+ final View view = new View(mContext);
+ final FrameLayout layout = new FrameLayout(mContext);
+ layout.setVisibility(View.GONE);
+ ReflectionHelpers.setField(mPreference, "mMiddleGroundView", view);
+ ReflectionHelpers.setField(mPreference, "mMiddleGroundLayout", layout);
+
+ mPreference.setMiddleGroundView(view);
+
+ assertThat(layout.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void enableAnimationAutoScale_shouldChangeScaleType() {
+ final LottieAnimationView animationView = new LottieAnimationView(mContext);
+ ReflectionHelpers.setField(mPreference, "mIllustrationView", animationView);
+
+ mPreference.enableAnimationAutoScale(true);
+
+ assertThat(animationView.getScaleType()).isEqualTo(ImageView.ScaleType.CENTER_CROP);
+ }
}