Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bcad6e27 authored by Chris Antol's avatar Chris Antol
Browse files

Auto hide IllustrationPreference when lottie file is empty

Flag: com.android.settingslib.widget.flags.auto_hide_lottie_res
Bug: 337873972
Test: unit test
Test: manual: delete `lottie_adaptive_brightness.json` from overlay, navigate to Display > Adaptive Brightness -- verify no empty container
Change-Id: I873976d3e87b119a3ee690d95c68149f249fe7a9
parent a5b030c7
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ android_library {
        "SettingsLibColor",
        "androidx.preference_preference",
        "lottie",
        "settingslib_illustrationpreference_flags_lib",
    ],

    sdk_version: "system_current",
@@ -31,3 +32,24 @@ android_library {
        "com.android.permission",
    ],
}

aconfig_declarations {
    name: "settingslib_illustrationpreference_flags",
    package: "com.android.settingslib.widget.flags",
    container: "system",
    srcs: [
        "aconfig/illustrationpreference.aconfig",
    ],
}

java_aconfig_library {
    name: "settingslib_illustrationpreference_flags_lib",
    aconfig_declarations: "settingslib_illustrationpreference_flags",

    min_sdk_version: "30",

    apex_available: [
        "//apex_available:platform",
        "com.android.permission",
    ],
}
+12 −0
Original line number Diff line number Diff line
package: "com.android.settingslib.widget.flags"
container: "system"

flag {
    name: "auto_hide_empty_lottie_res"
    namespace: "android_settings"
    description: "Hides IllustrationPreference when Lottie resource is an empty file"
    bug: "337873972"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
 No newline at end of file
+24 −2
Original line number Diff line number Diff line
@@ -39,12 +39,14 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;

import com.android.settingslib.widget.flags.Flags;
import com.android.settingslib.widget.preference.illustration.R;

import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieDrawable;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

/**
@@ -142,7 +144,7 @@ public class IllustrationPreference extends Preference {
        illustrationFrame.setLayoutParams(lp);

        illustrationView.setCacheComposition(mCacheComposition);
        handleImageWithAnimation(illustrationView);
        handleImageWithAnimation(illustrationView, illustrationFrame);
        handleImageFrameMaxHeight(backgroundView, illustrationView);

        if (mIsAutoScale) {
@@ -332,7 +334,8 @@ public class IllustrationPreference extends Preference {
        }
    }

    private void handleImageWithAnimation(LottieAnimationView illustrationView) {
    private void handleImageWithAnimation(LottieAnimationView illustrationView,
            ViewGroup container) {
        if (mImageDrawable != null) {
            resetAnimations(illustrationView);
            illustrationView.setImageDrawable(mImageDrawable);
@@ -356,6 +359,25 @@ public class IllustrationPreference extends Preference {
        }

        if (mImageResId > 0) {
            if (Flags.autoHideEmptyLottieRes()) {
                // Check if resource is empty
                try (InputStream is = illustrationView.getResources()
                        .openRawResource(mImageResId)) {
                    int check = is.read();
                    // -1 = end of stream. if first read is end of stream, then file is empty
                    if (check == -1) {
                        illustrationView.setVisibility(View.GONE);
                        container.setVisibility(View.GONE);
                        return;
                    }
                } catch (IOException e) {
                    Log.w(TAG, "Unable to open Lottie raw resource", e);
                }

                illustrationView.setVisibility(View.VISIBLE);
                container.setVisibility(View.VISIBLE);
            }

            resetAnimations(illustrationView);
            illustrationView.setImageResource(mImageResId);
            final Drawable drawable = illustrationView.getDrawable();
+1 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ android_robolectric_test {
        "androidx.core_core",
        "flag-junit",
        "settingslib_media_flags_lib",
        "settingslib_illustrationpreference_flags_lib",
        "testng", // TODO: remove once JUnit on Android provides assertThrows
    ],
    java_resource_dirs: ["config"],
+60 −3
Original line number Diff line number Diff line
@@ -26,10 +26,14 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.net.Uri;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -39,11 +43,13 @@ import android.widget.ImageView;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider;

import com.android.settingslib.widget.flags.Flags;
import com.android.settingslib.widget.preference.illustration.R;

import com.airbnb.lottie.LottieAnimationView;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -51,10 +57,14 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;

import java.io.ByteArrayInputStream;


@RunWith(RobolectricTestRunner.class)
public class IllustrationPreferenceTest {

    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Mock
    private ViewGroup mRootView;
    private Uri mImageUri;
@@ -66,6 +76,7 @@ public class IllustrationPreferenceTest {
    private final Context mContext = ApplicationProvider.getApplicationContext();
    private IllustrationPreference.OnBindListener mOnBindListener;
    private LottieAnimationView mOnBindListenerAnimationView;
    private FrameLayout mIllustrationFrame;

    @Before
    public void setUp() {
@@ -75,14 +86,14 @@ public class IllustrationPreferenceTest {
        mBackgroundView = new ImageView(mContext);
        mAnimationView = spy(new LottieAnimationView(mContext));
        mMiddleGroundLayout = new FrameLayout(mContext);
        final FrameLayout illustrationFrame = new FrameLayout(mContext);
        illustrationFrame.setLayoutParams(
        mIllustrationFrame = new FrameLayout(mContext);
        mIllustrationFrame.setLayoutParams(
                new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT));
        doReturn(mMiddleGroundLayout).when(mRootView).findViewById(R.id.middleground_layout);
        doReturn(mBackgroundView).when(mRootView).findViewById(R.id.background_view);
        doReturn(mAnimationView).when(mRootView).findViewById(R.id.lottie_view);
        doReturn(illustrationFrame).when(mRootView).findViewById(R.id.illustration_frame);
        doReturn(mIllustrationFrame).when(mRootView).findViewById(R.id.illustration_frame);
        mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(mRootView));

        final AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
@@ -158,11 +169,13 @@ public class IllustrationPreferenceTest {
    }

    @Test
    @DisableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES)
    public void playLottieAnimationWithResource_verifyFailureListener() {
        // fake the valid lottie image
        final int fakeValidResId = 111;
        doNothing().when(mAnimationView).setImageResource(fakeValidResId);
        doReturn(null).when(mAnimationView).getDrawable();
        doNothing().when(mAnimationView).setAnimation(fakeValidResId);

        mPreference.setLottieAnimationResId(fakeValidResId);
        mPreference.onBindViewHolder(mViewHolder);
@@ -170,6 +183,50 @@ public class IllustrationPreferenceTest {
        verify(mAnimationView).setFailureListener(any());
    }

    @Test
    @DisableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES)
    public void handleImageWithAnimation_emptyInputStreamDisabledFlag_verifyContainerVisible() {
        doNothing().when(mAnimationView).setImageResource(111);
        doReturn(null).when(mAnimationView).getDrawable();

        mPreference.setLottieAnimationResId(111);
        mPreference.onBindViewHolder(mViewHolder);

        assertThat(mAnimationView.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mIllustrationFrame.getVisibility()).isEqualTo(View.VISIBLE);
    }

    @Test
    @EnableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES)
    public void handleImageWithAnimation_emptyInputStreamEnabledFlag_verifyContainerHidden() {
        Resources res = spy(mContext.getResources());
        doReturn(res).when(mAnimationView).getResources();
        doReturn(new ByteArrayInputStream(new byte[] {})).when(res).openRawResource(111);

        mPreference.setLottieAnimationResId(111);
        mPreference.onBindViewHolder(mViewHolder);

        assertThat(mAnimationView.getVisibility()).isEqualTo(View.GONE);
        assertThat(mIllustrationFrame.getVisibility()).isEqualTo(View.GONE);
    }

    @Test
    @EnableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES)
    public void handleImageWithAnimation_nonEmptyInputStreamEnabledFlag_verifyContainerVisible() {
        Resources res = spy(mContext.getResources());
        doReturn(res).when(mAnimationView).getResources();
        doReturn(new ByteArrayInputStream(new byte[] { 1, 2, 3 })).when(res).openRawResource(111);
        doNothing().when(mAnimationView).setImageResource(111);
        doNothing().when(mAnimationView).setAnimation(111);
        doReturn(null).when(mAnimationView).getDrawable();

        mPreference.setLottieAnimationResId(111);
        mPreference.onBindViewHolder(mViewHolder);

        assertThat(mAnimationView.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mIllustrationFrame.getVisibility()).isEqualTo(View.VISIBLE);
    }

    @Test
    public void setMaxHeight_smallerThanRestrictedHeight_matchResult() {
        final int restrictedHeight =