fix: 首次提交

This commit is contained in:
2024-12-09 11:25:23 +08:00
parent d0c01071e9
commit 2c2109a5f3
4741 changed files with 290641 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_library {
name: "SettingsLibIllustrationPreference",
use_resource_processor: true,
defaults: [
"SettingsLintDefaults",
],
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
static_libs: [
"SettingsLibColor",
"androidx.preference_preference",
"lottie",
],
sdk_version: "system_current",
min_sdk_version: "28",
apex_available: [
"//apex_available:platform",
"com.android.permission",
],
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settingslib.widget.preference.illustration">
<uses-sdk android:minSdkVersion="28" />
</manifest>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_protection_color"/>
<corners android:radius="28dp"/>
<size android:width="@dimen/settingslib_illustration_width"
android:height="@dimen/settingslib_illustration_height"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:importantForAccessibility="noHideDescendants"
android:gravity="center"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/illustration_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:paddingHorizontal="@dimen/settingslib_illustration_padding"
android:orientation="vertical">
<ImageView
android:id="@+id/background_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:src="@drawable/protection_background"/>
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:maxWidth="@dimen/settingslib_illustration_width"
android:maxHeight="@dimen/settingslib_illustration_height"
android:adjustViewBounds="true"/>
<FrameLayout
android:id="@+id/middleground_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:layout_gravity="center"
android:visibility="gone"/>
</FrameLayout>
</FrameLayout>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<color name="settingslib_protection_color">@android:color/black</color>
</resources>

View File

@@ -0,0 +1,22 @@
<?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.
-->
<resources>
<declare-styleable name="IllustrationPreference">
<attr name="dynamicColor" format="boolean" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<color name="settingslib_protection_color">@android:color/white</color>
</resources>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<!-- Padding of illustration -->
<dimen name="settingslib_illustration_padding">16dp</dimen>
<dimen name="settingslib_illustration_width">412dp</dimen>
<dimen name="settingslib_illustration_height">300dp</dimen>
</resources>

View File

@@ -0,0 +1,123 @@
/*
* 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.android.settingslib.color.R;
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;
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 : 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

@@ -0,0 +1,444 @@
/*
* 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.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.RawRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieDrawable;
import java.io.FileNotFoundException;
import java.io.InputStream;
import com.android.settingslib.widget.preference.illustration.R;
/**
* IllustrationPreference is a preference that can play lottie format animation
*/
public class IllustrationPreference extends Preference {
private static final String TAG = "IllustrationPreference";
private static final boolean IS_ENABLED_LOTTIE_ADAPTIVE_COLOR = false;
private static final int SIZE_UNSPECIFIED = -1;
private int mMaxHeight = SIZE_UNSPECIFIED;
private int mImageResId;
private boolean mCacheComposition = true;
private boolean mIsAutoScale;
private Uri mImageUri;
private Drawable mImageDrawable;
private View mMiddleGroundView;
private OnBindListener mOnBindListener;
private boolean mLottieDynamicColor;
/**
* Interface to listen in on when {@link #onBindViewHolder(PreferenceViewHolder)} occurs.
*/
public interface OnBindListener {
/**
* Called when when {@link #onBindViewHolder(PreferenceViewHolder)} occurs.
* @param animationView the animation view for this preference.
*/
void onBind(LottieAnimationView animationView);
}
private final Animatable2.AnimationCallback mAnimationCallback =
new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
((Animatable) drawable).start();
}
};
private final Animatable2Compat.AnimationCallback mAnimationCallbackCompat =
new Animatable2Compat.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
((Animatable) drawable).start();
}
};
public IllustrationPreference(Context context) {
super(context);
init(context, /* attrs= */ null);
}
public IllustrationPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public IllustrationPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public IllustrationPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final ImageView backgroundView =
(ImageView) holder.findViewById(R.id.background_view);
final FrameLayout middleGroundLayout =
(FrameLayout) holder.findViewById(R.id.middleground_layout);
final LottieAnimationView illustrationView =
(LottieAnimationView) holder.findViewById(R.id.lottie_view);
// To solve the problem of non-compliant illustrations, we set the frame height
// to 300dp and set the length of the short side of the screen to
// the width of the frame.
final int screenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
final int screenHeight = getContext().getResources().getDisplayMetrics().heightPixels;
final FrameLayout illustrationFrame = (FrameLayout) holder.findViewById(
R.id.illustration_frame);
final LayoutParams lp = (LayoutParams) illustrationFrame.getLayoutParams();
lp.width = screenWidth < screenHeight ? screenWidth : screenHeight;
illustrationFrame.setLayoutParams(lp);
illustrationView.setCacheComposition(mCacheComposition);
handleImageWithAnimation(illustrationView);
handleImageFrameMaxHeight(backgroundView, illustrationView);
if (mIsAutoScale) {
illustrationView.setScaleType(mIsAutoScale
? ImageView.ScaleType.CENTER_CROP
: ImageView.ScaleType.CENTER_INSIDE);
}
handleMiddleGroundView(middleGroundLayout);
if (IS_ENABLED_LOTTIE_ADAPTIVE_COLOR) {
ColorUtils.applyDynamicColors(getContext(), illustrationView);
}
if (mLottieDynamicColor) {
LottieColorUtils.applyDynamicColors(getContext(), illustrationView);
}
if (mOnBindListener != null) {
mOnBindListener.onBind(illustrationView);
}
}
/**
* Sets a listener to be notified when the views are binded.
*/
public void setOnBindListener(OnBindListener listener) {
mOnBindListener = listener;
}
/**
* Sets the middle ground view to preference. The user
* can overlay a view on top of the animation.
*/
public void setMiddleGroundView(View view) {
if (view != mMiddleGroundView) {
mMiddleGroundView = view;
notifyChanged();
}
}
/**
* Removes the middle ground view of preference.
*/
public void removeMiddleGroundView() {
mMiddleGroundView = null;
notifyChanged();
}
/**
* Enables the auto scale feature of animation view.
*/
public void enableAnimationAutoScale(boolean enable) {
if (enable != mIsAutoScale) {
mIsAutoScale = enable;
notifyChanged();
}
}
/**
* Sets the lottie illustration resource id.
*/
public void setLottieAnimationResId(int resId) {
if (resId != mImageResId) {
resetImageResourceCache();
mImageResId = resId;
notifyChanged();
}
}
/**
* Gets the lottie illustration resource id.
*/
public int getLottieAnimationResId() {
return mImageResId;
}
/**
* Sets the image drawable to display image in {@link LottieAnimationView}.
*
* @param imageDrawable the drawable of an image
*/
public void setImageDrawable(Drawable imageDrawable) {
if (imageDrawable != mImageDrawable) {
resetImageResourceCache();
mImageDrawable = imageDrawable;
notifyChanged();
}
}
/**
* Gets the image drawable from display image in {@link LottieAnimationView}.
*
* @return the drawable of an image
*/
public Drawable getImageDrawable() {
return mImageDrawable;
}
/**
* Sets the image uri to display image in {@link LottieAnimationView}.
*
* @param imageUri the Uri of an image
*/
public void setImageUri(Uri imageUri) {
if (imageUri != mImageUri) {
resetImageResourceCache();
mImageUri = imageUri;
notifyChanged();
}
}
/**
* Gets the image uri from display image in {@link LottieAnimationView}.
*
* @return the Uri of an image
*/
public Uri getImageUri() {
return mImageUri;
}
/**
* Sets the maximum height of the views, still use the specific one if the maximum height was
* larger than the specific height from XML.
*
* @param maxHeight the maximum height of the frame views in terms of pixels.
*/
public void setMaxHeight(int maxHeight) {
if (maxHeight != mMaxHeight) {
mMaxHeight = maxHeight;
notifyChanged();
}
}
/**
* Sets the lottie illustration apply dynamic color.
*/
public void applyDynamicColor() {
mLottieDynamicColor = true;
notifyChanged();
}
/**
* Return if the lottie illustration apply dynamic color or not.
*/
public boolean isApplyDynamicColor() {
return mLottieDynamicColor;
}
private void resetImageResourceCache() {
mImageDrawable = null;
mImageUri = null;
mImageResId = 0;
}
private void handleMiddleGroundView(ViewGroup middleGroundLayout) {
middleGroundLayout.removeAllViews();
if (mMiddleGroundView != null) {
middleGroundLayout.addView(mMiddleGroundView);
middleGroundLayout.setVisibility(View.VISIBLE);
} else {
middleGroundLayout.setVisibility(View.GONE);
}
}
private void handleImageWithAnimation(LottieAnimationView illustrationView) {
if (mImageDrawable != null) {
resetAnimations(illustrationView);
illustrationView.setImageDrawable(mImageDrawable);
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
}
}
if (mImageUri != null) {
resetAnimations(illustrationView);
illustrationView.setImageURI(mImageUri);
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageUri);
}
}
if (mImageResId > 0) {
resetAnimations(illustrationView);
illustrationView.setImageResource(mImageResId);
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageResId);
}
}
}
private void handleImageFrameMaxHeight(ImageView backgroundView, ImageView illustrationView) {
if (mMaxHeight == SIZE_UNSPECIFIED) {
return;
}
final Resources res = backgroundView.getResources();
final int frameWidth = res.getDimensionPixelSize(R.dimen.settingslib_illustration_width);
final int frameHeight = res.getDimensionPixelSize(R.dimen.settingslib_illustration_height);
final int restrictedMaxHeight = Math.min(mMaxHeight, frameHeight);
backgroundView.setMaxHeight(restrictedMaxHeight);
illustrationView.setMaxHeight(restrictedMaxHeight);
// Ensures the illustration view size is smaller than or equal to the background view size.
final float aspectRatio = (float) frameWidth / frameHeight;
illustrationView.setMaxWidth((int) (restrictedMaxHeight * aspectRatio));
}
private void startAnimation(Drawable drawable) {
if (!(drawable instanceof Animatable)) {
return;
}
if (drawable instanceof Animatable2) {
((Animatable2) drawable).registerAnimationCallback(mAnimationCallback);
} else if (drawable instanceof Animatable2Compat) {
((Animatable2Compat) drawable).registerAnimationCallback(mAnimationCallbackCompat);
} else if (drawable instanceof AnimationDrawable) {
((AnimationDrawable) drawable).setOneShot(false);
}
((Animatable) drawable).start();
}
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
Uri imageUri) {
final InputStream inputStream =
getInputStreamFromUri(illustrationView.getContext(), imageUri);
illustrationView.setFailureListener(
result -> Log.w(TAG, "Invalid illustration image uri: " + imageUri, result));
illustrationView.setAnimation(inputStream, /* cacheKey= */ null);
illustrationView.setRepeatCount(LottieDrawable.INFINITE);
illustrationView.playAnimation();
}
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
@RawRes int rawRes) {
illustrationView.setFailureListener(
result -> Log.w(TAG, "Invalid illustration resource id: " + rawRes, result));
illustrationView.setAnimation(rawRes);
illustrationView.setRepeatCount(LottieDrawable.INFINITE);
illustrationView.playAnimation();
}
private static void resetAnimations(LottieAnimationView illustrationView) {
resetAnimation(illustrationView.getDrawable());
illustrationView.cancelAnimation();
}
private static void resetAnimation(Drawable drawable) {
if (!(drawable instanceof Animatable)) {
return;
}
if (drawable instanceof Animatable2) {
((Animatable2) drawable).clearAnimationCallbacks();
} else if (drawable instanceof Animatable2Compat) {
((Animatable2Compat) drawable).clearAnimationCallbacks();
}
((Animatable) drawable).stop();
}
private static InputStream getInputStreamFromUri(Context context, Uri uri) {
try {
return context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
Log.w(TAG, "Cannot find content uri: " + uri, e);
return null;
}
}
private void init(Context context, AttributeSet attrs) {
setLayoutResource(R.layout.illustration_preference);
mIsAutoScale = false;
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs,
com.airbnb.lottie.R.styleable.LottieAnimationView, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
mImageResId = a.getResourceId(com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes, 0);
mCacheComposition = a.getBoolean(
com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_cacheComposition, true);
a = context.obtainStyledAttributes(attrs,
R.styleable.IllustrationPreference, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
mLottieDynamicColor = a.getBoolean(R.styleable.IllustrationPreference_dynamicColor,
false);
a.recycle();
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2022 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.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import com.android.settingslib.color.R;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.model.KeyPath;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Util class which dynamically changes the color of tags in a lottie json file between Dark Theme
* (DT) and Light Theme (LT). This class assumes the json file is for Dark Theme.
*/
public class LottieColorUtils {
private static final Map<String, Integer> DARK_TO_LIGHT_THEME_COLOR_MAP;
static {
HashMap<String, Integer> map = new HashMap<>();
map.put(
".grey600",
R.color.settingslib_color_grey400);
map.put(
".grey800",
R.color.settingslib_color_grey300);
map.put(
".grey900",
R.color.settingslib_color_grey50);
map.put(
".red400",
R.color.settingslib_color_red600);
map.put(
".black",
android.R.color.white);
map.put(
".blue400",
R.color.settingslib_color_blue600);
map.put(
".green400",
R.color.settingslib_color_green600);
map.put(
".green200",
R.color.settingslib_color_green500);
map.put(
".red200",
R.color.settingslib_color_red500);
DARK_TO_LIGHT_THEME_COLOR_MAP = Collections.unmodifiableMap(map);
}
private LottieColorUtils() {
}
private static boolean isDarkMode(Context context) {
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
}
/** Applies dynamic colors based on DT vs. LT. The LottieAnimationView should be Dark Theme. */
public static void applyDynamicColors(Context context,
LottieAnimationView lottieAnimationView) {
// Assume the default for the lottie is dark mode
if (isDarkMode(context)) {
return;
}
for (String key : DARK_TO_LIGHT_THEME_COLOR_MAP.keySet()) {
final int color = context.getColor(DARK_TO_LIGHT_THEME_COLOR_MAP.get(key));
lottieAnimationView.addValueCallback(
new KeyPath("**", key, "**"),
LottieProperty.COLOR_FILTER,
frameInfo -> new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
}
}
}