Merge "Improve the features of IllustrationPreference." into sc-dev

This commit is contained in:
Stanley Wang
2021-06-03 06:07:33 +00:00
committed by Android (Google) Code Review
8 changed files with 296 additions and 16 deletions

View File

@@ -19,5 +19,5 @@ android_library {
],
sdk_version: "system_current",
min_sdk_version: "21",
min_sdk_version: "28",
}

View File

@@ -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"/>

View File

@@ -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"

View File

@@ -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>

View File

@@ -17,5 +17,5 @@
<resources>
<!-- Padding of illustration -->
<dimen name="settingslib_illustration_padding">16dp</dimen>
<dimen name="settingslib_illustration_padding">12dp</dimen>
</resources>

View File

@@ -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);
}
}
);
}
}
}

View File

@@ -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) {

View File

@@ -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);
}
}