Merge "Replace the AnimatedImagePreference with IllustrationPreference." into sc-dev

This commit is contained in:
PETER LIANG
2021-06-30 00:38:20 +00:00
committed by Android (Google) Code Review
4 changed files with 7 additions and 389 deletions

View File

@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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"
android:layout_width="match_parent"
android:layout_height="@dimen/settingslib_illustration_height"
android:gravity="center"
android:padding="@dimen/settingslib_illustration_padding"
android:orientation="vertical"
android:importantForAccessibility="noHideDescendants">
<ImageView
android:id="@+id/animated_img"
android:maxWidth="@dimen/settingslib_illustration_width"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/protection_background"
android:scaleType="fitCenter"
android:adjustViewBounds="true"/>
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_view"
android:maxWidth="@dimen/settingslib_illustration_width"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/protection_background"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:clipToOutline="true"/>
</LinearLayout>

View File

@@ -1,181 +0,0 @@
/*
* Copyright (C) 2019 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.settings.accessibility;
import android.content.Context;
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.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieDrawable;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Objects;
/**
* A custom {@link ImageView} preference for showing animated or static image, such as <a
* href="https://developers.google.com/speed/webp/">animated webp</a> and static png.
*/
public class AnimatedImagePreference extends Preference {
private static final String TAG = "AnimatedImagePreference";
private Uri mImageUri;
private int mMaxHeight = -1;
private final Animatable2.AnimationCallback mAnimationCallback =
new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
((Animatable2) drawable).start();
}
};
AnimatedImagePreference(Context context) {
super(context);
setLayoutResource(R.layout.preference_animated_image);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final ImageView imageView = holder.itemView.findViewById(R.id.animated_img);
final LottieAnimationView lottieView = holder.itemView.findViewById(R.id.lottie_view);
if (imageView == null || lottieView == null) {
return;
}
if (mImageUri != null) {
resetAnimations(imageView, lottieView);
hideAllChildViews(holder.itemView);
imageView.setImageURI(mImageUri);
if (imageView.getDrawable() != null) {
startAnimationWith(imageView);
} else {
// The lottie image from the raw folder also returns null.
startLottieAnimationWith(lottieView);
}
}
if (mMaxHeight > -1) {
imageView.setMaxHeight(mMaxHeight);
lottieView.setMaxHeight(mMaxHeight);
}
}
/**
* Sets image uri to display image in {@link ImageView}
*
* @param imageUri the Uri of an image
*/
public void setImageUri(Uri imageUri) {
if (imageUri != null && !imageUri.equals(mImageUri)) {
mImageUri = imageUri;
notifyChanged();
}
}
/**
* Sets the maximum height of the view.
*
* @param maxHeight the maximum height of ImageView in terms of pixels.
*/
public void setMaxHeight(int maxHeight) {
if (maxHeight != mMaxHeight) {
mMaxHeight = maxHeight;
notifyChanged();
}
}
private void startAnimationWith(ImageView imageView) {
startAnimation(imageView.getDrawable());
imageView.setVisibility(View.VISIBLE);
}
private void startLottieAnimationWith(LottieAnimationView lottieView) {
final InputStream inputStream = getInputStreamFromUri(mImageUri);
Objects.requireNonNull(inputStream, "Invalid resource.");
lottieView.setAnimation(inputStream, /* cacheKey= */ null);
lottieView.setRepeatCount(LottieDrawable.INFINITE);
lottieView.playAnimation();
lottieView.setVisibility(View.VISIBLE);
}
private void startAnimation(Drawable drawable) {
if (!(drawable instanceof Animatable)) {
return;
}
if (drawable instanceof Animatable2) {
((Animatable2) drawable).registerAnimationCallback(mAnimationCallback);
} else if (drawable instanceof AnimationDrawable) {
((AnimationDrawable) drawable).setOneShot(false);
}
((Animatable) drawable).start();
}
private void resetAnimations(ImageView imageView, LottieAnimationView lottieView) {
resetAnimation(imageView.getDrawable());
lottieView.cancelAnimation();
}
private void resetAnimation(Drawable drawable) {
if (!(drawable instanceof Animatable)) {
return;
}
if (drawable instanceof Animatable2) {
((Animatable2) drawable).clearAnimationCallbacks();
}
((Animatable) drawable).stop();
}
private InputStream getInputStreamFromUri(Uri uri) {
try {
return getContext().getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
Log.w(TAG, "Cannot find content uri: " + uri, e);
return null;
}
}
private void hideAllChildViews(View itemView) {
final ViewGroup viewGroup = (ViewGroup) itemView;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
viewGroup.getChildAt(i).setVisibility(View.GONE);
}
}
}

View File

@@ -59,6 +59,7 @@ import com.android.settings.widget.SettingsMainSwitchBar;
import com.android.settings.widget.SettingsMainSwitchPreference;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.accessibility.AccessibilityUtils;
import com.android.settingslib.widget.IllustrationPreference;
import com.android.settingslib.widget.OnMainSwitchChangeListener;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -398,15 +399,13 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
return;
}
final int screenHalfHeight = AccessibilityUtil.getScreenHeightPixels(getPrefContext()) / 2;
final AnimatedImagePreference animatedImagePreference =
new AnimatedImagePreference(getPrefContext());
animatedImagePreference.setImageUri(mImageUri);
animatedImagePreference.setSelectable(false);
animatedImagePreference.setMaxHeight(screenHalfHeight);
animatedImagePreference.setKey(KEY_ANIMATED_IMAGE);
final IllustrationPreference illustrationPreference =
new IllustrationPreference(getPrefContext());
illustrationPreference.setImageUri(mImageUri);
illustrationPreference.setSelectable(false);
illustrationPreference.setKey(KEY_ANIMATED_IMAGE);
getPreferenceScreen().addPreference(animatedImagePreference);
getPreferenceScreen().addPreference(illustrationPreference);
}
private void initToggleServiceSwitchPreference() {

View File

@@ -1,155 +0,0 @@
/*
* Copyright (C) 2020 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.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.net.Uri;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.airbnb.lottie.LottieAnimationView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.io.InputStream;
/** Tests for {@link AnimatedImagePreference}. */
@RunWith(RobolectricTestRunner.class)
public class AnimatedImagePreferenceTest {
private final Context mContext = RuntimeEnvironment.application;
private Uri mImageUri;
private PreferenceViewHolder mViewHolder;
private AnimatedImagePreference mAnimatedImagePreference;
@Mock
private ViewGroup mRootView;
@Spy
private ImageView mImageView;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(mRootView));
doReturn(new LottieAnimationView(mContext)).when(mRootView).findViewById(R.id.lottie_view);
mImageView = spy(new ImageView(mContext));
mAnimatedImagePreference = new AnimatedImagePreference(mContext);
mImageUri = new Uri.Builder().build();
}
@Test
public void playAnimation_animatedImageDrawable_success() {
final AnimatedImageDrawable drawable = mock(AnimatedImageDrawable.class);
doReturn(mImageView).when(mRootView).findViewById(R.id.animated_img);
doReturn(drawable).when(mImageView).getDrawable();
mAnimatedImagePreference.setImageUri(mImageUri);
mAnimatedImagePreference.onBindViewHolder(mViewHolder);
verify(drawable).start();
}
@Test
public void playAnimation_animatedVectorDrawable_success() {
final AnimatedVectorDrawable drawable = mock(AnimatedVectorDrawable.class);
doReturn(mImageView).when(mRootView).findViewById(R.id.animated_img);
doReturn(drawable).when(mImageView).getDrawable();
mAnimatedImagePreference.setImageUri(mImageUri);
mAnimatedImagePreference.onBindViewHolder(mViewHolder);
verify(drawable).start();
}
@Test
public void playAnimation_animationDrawable_success() {
final AnimationDrawable drawable = mock(AnimationDrawable.class);
doReturn(mImageView).when(mRootView).findViewById(R.id.animated_img);
doReturn(drawable).when(mImageView).getDrawable();
mAnimatedImagePreference.setImageUri(mImageUri);
mAnimatedImagePreference.onBindViewHolder(mViewHolder);
verify(drawable).start();
}
@Test
public void setImageUri_viewNotExist_setFail() {
doReturn(null).when(mRootView).findViewById(R.id.animated_img);
mAnimatedImagePreference.setImageUri(mImageUri);
mAnimatedImagePreference.onBindViewHolder(mViewHolder);
verify(mImageView, never()).setImageURI(mImageUri);
}
@Test
public void setMaxHeight_success() {
final int maxHeight = 100;
doReturn(mImageView).when(mRootView).findViewById(R.id.animated_img);
mAnimatedImagePreference.setMaxHeight(maxHeight);
mAnimatedImagePreference.onBindViewHolder(mViewHolder);
assertThat(mImageView.getMaxHeight()).isEqualTo(maxHeight);
}
@Test
public void setImageUriAndRebindViewHolder_lottieImageFromRawFolder_setAnimation() {
final int fakeLottieResId = 111111;
final Uri lottieImageUri =
new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(mContext.getPackageName())
.appendPath(String.valueOf(fakeLottieResId))
.build();
final LottieAnimationView lottieView = spy(new LottieAnimationView(mContext));
doReturn(mImageView).when(mRootView).findViewById(R.id.animated_img);
doReturn(lottieView).when(mRootView).findViewById(R.id.lottie_view);
mAnimatedImagePreference.setImageUri(lottieImageUri);
mAnimatedImagePreference.onBindViewHolder(mViewHolder);
verify(lottieView).setAnimation(any(InputStream.class), eq(null));
}
}