diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSIconView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSIconView.java index c268d325bd02f..0cdb509a5209c 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSIconView.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSIconView.java @@ -29,7 +29,7 @@ public abstract class QSIconView extends ViewGroup { super(context); } - public abstract void setIcon(State state); + public abstract void setIcon(State state, boolean allowAnimations); public abstract void disableAnimation(); public abstract View getIconView(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java index e7eefe8d5e560..376e6ae16cc8d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java @@ -43,9 +43,9 @@ public class CellTileView extends SignalTileView { R.dimen.qs_tile_icon_size)); } - protected void updateIcon(ImageView iv, State state) { + protected void updateIcon(ImageView iv, State state, boolean allowAnimations) { if (!(state.icon instanceof SignalIcon)) { - super.updateIcon(iv, state); + super.updateIcon(iv, state, allowAnimations); return; } else if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) { mSignalDrawable.setLevel(((SignalIcon) state.icon).getState()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java index d9583af65df63..ce90fc107b82d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java @@ -18,14 +18,13 @@ package com.android.systemui.qs; import android.animation.ValueAnimator; import android.content.Context; -import android.graphics.drawable.Drawable; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; +import com.android.systemui.plugins.qs.QSTile.State; import com.android.systemui.qs.tileimpl.QSIconViewImpl; import com.android.systemui.qs.tileimpl.SlashImageView; @@ -119,9 +118,9 @@ public class SignalTileView extends QSIconViewImpl { } @Override - public void setIcon(QSTile.State state) { + public void setIcon(State state, boolean allowAnimations) { final SignalState s = (SignalState) state; - setIcon(mSignal, s); + setIcon(mSignal, s, allowAnimations); if (s.overlayIconId > 0) { mOverlay.setVisibility(VISIBLE); @@ -134,9 +133,9 @@ public class SignalTileView extends QSIconViewImpl { } else { mSignal.setPaddingRelative(0, 0, 0, 0); } - final boolean shown = isShown(); - setVisibility(mIn, shown, s.activityIn); - setVisibility(mOut, shown, s.activityOut); + final boolean shouldAnimate = allowAnimations && isShown(); + setVisibility(mIn, shouldAnimate, s.activityIn); + setVisibility(mOut, shouldAnimate, s.activityOut); } private void setVisibility(View view, boolean shown, boolean visible) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java index e7e756f87c846..9dd5d8fbc776f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java @@ -84,16 +84,15 @@ public class QSIconViewImpl extends QSIconView { layout(mIcon, iconLeft, top); } - public void setIcon(QSTile.State state) { - setIcon((ImageView) mIcon, state); + public void setIcon(State state, boolean allowAnimations) { + setIcon((ImageView) mIcon, state, allowAnimations); } - protected void updateIcon(ImageView iv, State state) { + protected void updateIcon(ImageView iv, State state, boolean allowAnimations) { final QSTile.Icon icon = state.iconSupplier != null ? state.iconSupplier.get() : state.icon; if (!Objects.equals(icon, iv.getTag(R.id.qs_icon_tag)) || !Objects.equals(state.slash, iv.getTag(R.id.qs_slash_tag))) { - boolean shouldAnimate = iv.isShown() && mAnimationEnabled - && iv.getDrawable() != null; + boolean shouldAnimate = allowAnimations && shouldAnimate(iv); Drawable d = icon != null ? shouldAnimate ? icon.getDrawable(mContext) : icon.getInvisibleDrawable(mContext) : null; @@ -128,7 +127,11 @@ public class QSIconViewImpl extends QSIconView { } } - protected void setIcon(ImageView iv, QSTile.State state) { + private boolean shouldAnimate(ImageView iv) { + return mAnimationEnabled && iv.isShown() && iv.getDrawable() != null; + } + + protected void setIcon(ImageView iv, QSTile.State state, boolean allowAnimations) { if (state.disabledByPolicy) { iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color)); } else { @@ -137,8 +140,8 @@ public class QSIconViewImpl extends QSIconView { if (state.state != mState) { int color = getColor(state.state); mState = state.state; - if (iv.isShown() && mTint != 0) { - animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state)); + if (mTint != 0 && allowAnimations && shouldAnimate(iv)) { + animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations)); mTint = color; } else { if (iv instanceof AlphaControlledSlashImageView) { @@ -148,10 +151,10 @@ public class QSIconViewImpl extends QSIconView { setTint(iv, color); } mTint = color; - updateIcon(iv, state); + updateIcon(iv, state, allowAnimations); } } else { - updateIcon(iv, state); + updateIcon(iv, state, allowAnimations); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java index 91afef02a2465..d42127e749448 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java @@ -47,6 +47,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { private static final String TAG = "QSTileBaseView"; private final H mHandler = new H(); + private final int[] mLocInScreen = new int[2]; private final FrameLayout mIconFrame; protected QSIconView mIcon; protected RippleDrawable mRipple; @@ -178,8 +179,9 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { protected void handleStateChanged(QSTile.State state) { int circleColor = getCircleColor(state.state); + boolean allowAnimations = animationsEnabled(); if (circleColor != mCircleColor) { - if (mBg.isShown() && animationsEnabled()) { + if (allowAnimations) { ValueAnimator animator = ValueAnimator.ofArgb(mCircleColor, circleColor) .setDuration(QS_ANIM_LENGTH); animator.addUpdateListener(animation -> mBg.setImageTintList(ColorStateList.valueOf( @@ -192,7 +194,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { } setClickable(state.state != Tile.STATE_UNAVAILABLE); - mIcon.setIcon(state); + mIcon.setIcon(state, allowAnimations); setContentDescription(state.contentDescription); mAccessibilityClass = state.expandedAccessibilityClassName; @@ -205,8 +207,17 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { } } + /* The view should not be animated if it's not on screen and no part of it is visible. + */ protected boolean animationsEnabled() { - return true; + if (!isShown()) { + return false; + } + if (getAlpha() != 1f) { + return false; + } + getLocationOnScreen(mLocInScreen); + return mLocInScreen[1] >= -getHeight(); } private int getCircleColor(int state) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java index f9f4f497a2ecb..c5e404385f8bb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java @@ -59,14 +59,14 @@ public class QSIconViewImplTest extends SysuiTestCase { // No current icon, only the static drawable should be used. s.icon = mock(Icon.class); when(iv.getDrawable()).thenReturn(null); - mIconView.updateIcon(iv, s); + mIconView.updateIcon(iv, s, true); verify(s.icon, never()).getDrawable(any()); verify(s.icon).getInvisibleDrawable(any()); // Has icon, should use the standard (animated) form. s.icon = mock(Icon.class); when(iv.getDrawable()).thenReturn(mock(Drawable.class)); - mIconView.updateIcon(iv, s); + mIconView.updateIcon(iv, s, true); verify(s.icon).getDrawable(any()); verify(s.icon, never()).getInvisibleDrawable(any()); } @@ -79,7 +79,7 @@ public class QSIconViewImplTest extends SysuiTestCase { int desiredColor = mIconView.getColor(s.state); when(iv.isShown()).thenReturn(true); - mIconView.setIcon(iv, s); + mIconView.setIcon(iv, s, true); verify(iv).setImageTintList(argThat(stateList -> stateList.getColors()[0] == desiredColor)); } }