From ee50d90e9d41c877bed65fdfd39240c8693f57b4 Mon Sep 17 00:00:00 2001 From: Stanley Wang Date: Tue, 25 May 2021 20:09:05 +0800 Subject: 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 --- .../SettingsLib/IllustrationPreference/Android.bp | 2 +- .../res/drawable/protection_background.xml | 6 +- .../res/layout/illustration_preference.xml | 29 ++++- .../IllustrationPreference/res/values/colors.xml | 42 ++++++ .../IllustrationPreference/res/values/dimens.xml | 2 +- .../com/android/settingslib/widget/ColorUtils.java | 141 +++++++++++++++++++++ .../settingslib/widget/IllustrationPreference.java | 57 ++++++++- .../widget/IllustrationPreferenceTest.java | 31 ++++- 8 files changed, 295 insertions(+), 15 deletions(-) create mode 100644 packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/ColorUtils.java diff --git a/packages/SettingsLib/IllustrationPreference/Android.bp b/packages/SettingsLib/IllustrationPreference/Android.bp index f8dd3849c2a1..5904589ed22e 100644 --- a/packages/SettingsLib/IllustrationPreference/Android.bp +++ b/packages/SettingsLib/IllustrationPreference/Android.bp @@ -19,5 +19,5 @@ android_library { ], 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 dd2fa5e0f214..0734aca2ab90 100644 --- a/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml +++ b/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml @@ -16,11 +16,7 @@ --> - + diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml index 7d65aaea2512..54731f51248b 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"> - + + + + + android:visibility="gone"/> @android:color/white + + + #1a73e8 + #669df6 + #8ab4f8 + #d2e3fc + #e8f0fe + #1e8e3e + #5bb974 + #ceead6 + #e6f4ea + #d93025 + #ee675c + #fad2cf + #fce8e6 + #f9ab00 + #fcc934 + #feefc3 + #fef7e0 + #202124 + #3c4043 + #5f6368 + #80868b + #bdc1c6 + #dadce0 + #e8eaed + #e8710a + #fa903e + #fcad70 + #fedfc8 + #e52592 + #ff63b8 + #ff8bcb + #fdcfe8 + #9334e6 + #af5cf7 + #c58af9 + #e9d2fd + #12b5c8 + #4ecde6 + #78d9ec + #cbf0f8 diff --git a/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml index 79562b962ad1..5e540d3740f9 100644 --- a/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml +++ b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml @@ -17,5 +17,5 @@ - 16dp + 12dp 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 000000000000..cd2ddebe6367 --- /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 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> sFixedColors; + static { + sFixedColors = new HashMap<>(); + sFixedColors.put(".blue600", new Pair( + R.color.settingslib_color_blue600, R.color.settingslib_color_blue400)); + sFixedColors.put(".green600", new Pair( + R.color.settingslib_color_green600, R.color.settingslib_color_green400)); + sFixedColors.put(".red600", new Pair( + R.color.settingslib_color_red600, R.color.settingslib_color_red400)); + sFixedColors.put(".yellow600", new Pair( + R.color.settingslib_color_yellow600, R.color.settingslib_color_yellow400)); + sFixedColors.put(".blue400", new Pair( + R.color.settingslib_color_blue400, R.color.settingslib_color_blue100)); + sFixedColors.put(".green400", new Pair( + R.color.settingslib_color_green400, R.color.settingslib_color_green100)); + sFixedColors.put(".red400", new Pair( + R.color.settingslib_color_red400, R.color.settingslib_color_red100)); + sFixedColors.put(".yellow400", new Pair( + R.color.settingslib_color_yellow400, R.color.settingslib_color_yellow100)); + sFixedColors.put(".blue300", new Pair( + R.color.settingslib_color_blue300, R.color.settingslib_color_blue50)); + sFixedColors.put(".blue50", new Pair( + R.color.settingslib_color_blue50, R.color.settingslib_color_grey900)); + sFixedColors.put(".green50", new Pair( + R.color.settingslib_color_green50, R.color.settingslib_color_grey900)); + sFixedColors.put(".red50", new Pair( + R.color.settingslib_color_red50, R.color.settingslib_color_grey900)); + sFixedColors.put(".yellow50", new Pair( + R.color.settingslib_color_yellow50, R.color.settingslib_color_grey900)); + // Secondary colors + sFixedColors.put(".orange600", new Pair( + R.color.settingslib_color_orange600, R.color.settingslib_color_orange300)); + sFixedColors.put(".pink600", new Pair( + R.color.settingslib_color_pink600, R.color.settingslib_color_pink300)); + sFixedColors.put(".purple600", new Pair( + R.color.settingslib_color_purple600, R.color.settingslib_color_purple300)); + sFixedColors.put(".cyan600", new Pair( + R.color.settingslib_color_cyan600, R.color.settingslib_color_cyan300)); + sFixedColors.put(".orange400", new Pair( + R.color.settingslib_color_orange400, R.color.settingslib_color_orange100)); + sFixedColors.put(".pink400", new Pair( + R.color.settingslib_color_pink400, R.color.settingslib_color_pink100)); + sFixedColors.put(".purple400", new Pair( + R.color.settingslib_color_purple400, R.color.settingslib_color_purple100)); + sFixedColors.put(".cyan400", new Pair( + R.color.settingslib_color_cyan400, R.color.settingslib_color_cyan100)); + sFixedColors.put(".gery400", new Pair( + R.color.settingslib_color_grey400, R.color.settingslib_color_grey700)); + sFixedColors.put(".gery300", new Pair( + R.color.settingslib_color_grey300, R.color.settingslib_color_grey600)); + sFixedColors.put(".gery200", new Pair( + 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() { + @Override + public ColorFilter getValue(LottieFrameInfo frameInfo) { + return new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN); + } + } + ); + } + for (String key : sFixedColors.keySet()) { + final Pair fixedColorPair = sFixedColors.get(key); + final int color = isDarkMode(context) ? fixedColorPair.second : fixedColorPair.first; + animationView.addValueCallback( + new KeyPath("**", key, "**"), + LottieProperty.COLOR_FILTER, + new SimpleLottieValueCallback() { + @Override + public ColorFilter getValue(LottieFrameInfo 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 90b8a3210a42..7b2a0af269a6 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.os.Parcelable; 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 @@ import com.airbnb.lottie.LottieAnimationView; 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 @@ public class IllustrationPreference extends Preference implements OnPreferenceCl 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 @@ public class IllustrationPreference extends Preference implements OnPreferenceCl 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 4a14403b7ea3..f197cbb2ac70 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 static org.mockito.Mockito.when; 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 @@ public class IllustrationPreferenceTest { @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 @@ public class IllustrationPreferenceTest { 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); + } } -- cgit v1.2.3-59-g8ed1b