diff options
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java | 143 | ||||
| -rw-r--r-- | packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java | 55 |
2 files changed, 134 insertions, 64 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index d8d388c4be08..d0a434f8857f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.phone; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.app.AlarmManager; import android.app.WallpaperManager; @@ -362,7 +361,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, * * The expansion fraction is tied to the scrim opacity. * - * @param fraction From 0 to 1 where 0 means collapse and 1 expanded. + * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded. */ public void setPanelExpansion(float fraction) { if (mExpansionFraction != fraction) { @@ -381,8 +380,25 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, if (mPinnedHeadsUpCount != 0) { updateHeadsUpScrim(false); } - updateScrim(false /* animate */, mScrimInFront, mCurrentInFrontAlpha); - updateScrim(false /* animate */, mScrimBehind, mCurrentBehindAlpha); + + setOrAdaptCurrentAnimation(mScrimBehind); + setOrAdaptCurrentAnimation(mScrimInFront); + } + } + + private void setOrAdaptCurrentAnimation(View scrim) { + if (!isAnimating(scrim)) { + updateScrimColor(scrim, getCurrentScrimAlpha(scrim), getCurrentScrimTint(scrim)); + } else { + ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM); + float alpha = getCurrentScrimAlpha(scrim); + float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA); + float previousStartValue = (Float) scrim.getTag(TAG_START_ALPHA); + float relativeDiff = alpha - previousEndValue; + float newStartValue = previousStartValue + relativeDiff; + scrim.setTag(TAG_START_ALPHA, newStartValue); + scrim.setTag(TAG_END_ALPHA, alpha); + previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); } } @@ -523,14 +539,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, setScrimAlpha(mScrimInFront, alpha); } - private void setScrimAlpha(View scrim, float alpha) { + private void setScrimAlpha(ScrimView scrim, float alpha) { if (alpha == 0f) { scrim.setClickable(false); } else { // Eat touch events (unless dozing). scrim.setClickable(!(mState == ScrimState.AOD)); } - updateScrim(mAnimateChange, scrim, alpha); + updateScrim(scrim, alpha); } private void updateScrimColor(View scrim, float alpha, int tint) { @@ -554,21 +570,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, dispatchScrimsVisible(); } - private int getCurrentScrimTint(View scrim) { - return scrim == mScrimInFront ? mCurrentInFrontTint : mCurrentBehindTint; - } - private void startScrimAnimation(final View scrim, float current) { ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() : Color.TRANSPARENT; anim.addUpdateListener(animation -> { + final float startAlpha = (Float) scrim.getTag(TAG_START_ALPHA); final float animAmount = (float) animation.getAnimatedValue(); - final int finalScrimTint = scrim == mScrimInFront ? - mCurrentInFrontTint : mCurrentBehindTint; - float finalScrimAlpha = scrim == mScrimInFront ? - mCurrentInFrontAlpha : mCurrentBehindAlpha; - float alpha = MathUtils.lerp(current, finalScrimAlpha, animAmount); + final int finalScrimTint = getCurrentScrimTint(scrim); + final float finalScrimAlpha = getCurrentScrimAlpha(scrim); + float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount); + alpha = MathUtils.constrain(alpha, 0f, 1f); int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount); updateScrimColor(scrim, alpha, tint); dispatchScrimsVisible(); @@ -579,12 +591,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - final int finalScrimTint = scrim == mScrimInFront ? - mCurrentInFrontTint : mCurrentBehindTint; - float finalScrimAlpha = scrim == mScrimInFront ? - mCurrentInFrontAlpha : mCurrentBehindAlpha; - updateScrimColor(scrim, finalScrimAlpha, finalScrimTint); - if (mKeyguardFadingOutInProgress) { mKeyguardFadeoutAnimation = null; mKeyguardFadingOutInProgress = false; @@ -600,12 +606,42 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } } }); - anim.start(); if (mAnimateKeyguardFadingOut) { mKeyguardFadingOutInProgress = true; mKeyguardFadeoutAnimation = anim; } + + // Cache alpha values because we might want to update this animator in the future if + // the user expands the panel while the animation is still running. + scrim.setTag(TAG_START_ALPHA, current); + scrim.setTag(TAG_END_ALPHA, getCurrentScrimAlpha(scrim)); + scrim.setTag(TAG_KEY_ANIM, anim); + anim.start(); + } + + private float getCurrentScrimAlpha(View scrim) { + if (scrim == mScrimInFront) { + return mCurrentInFrontAlpha; + } else if (scrim == mScrimBehind) { + return mCurrentBehindAlpha; + } else if (scrim == mHeadsUpScrim) { + return calculateHeadsUpAlpha(); + } else { + throw new IllegalArgumentException("Unknown scrim view"); + } + } + + private int getCurrentScrimTint(View scrim) { + if (scrim == mScrimInFront) { + return mCurrentInFrontTint; + } else if (scrim == mScrimBehind) { + return mCurrentBehindTint; + } else if (scrim == mHeadsUpScrim) { + return Color.TRANSPARENT; + } else { + throw new IllegalArgumentException("Unknown scrim view"); + } } protected Interpolator getInterpolator() { @@ -693,7 +729,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } private void updateHeadsUpScrim(boolean animate) { - updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha()); + if (animate) { + mAnimationDuration = ANIMATION_DURATION; + cancelAnimator((ValueAnimator) mHeadsUpScrim.getTag(TAG_KEY_ANIM)); + startScrimAnimation(mHeadsUpScrim, mHeadsUpScrim.getAlpha()); + } else { + setOrAdaptCurrentAnimation(mHeadsUpScrim); + } } @VisibleForTesting @@ -701,32 +743,28 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mOnAnimationFinished = onAnimationFinished; } - private void updateScrim(boolean animate, View scrim, float alpha) { - final float currentAlpha = scrim instanceof ScrimView ? ((ScrimView) scrim).getViewAlpha() - : scrim.getAlpha(); + private void updateScrim(ScrimView scrim, float alpha) { + final float currentAlpha = scrim.getViewAlpha(); ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM); - float animEndValue = -1; if (previousAnimator != null) { - if (animate || alpha == currentAlpha) { + if (mAnimateChange) { // We are not done yet! Defer calling the finished listener. - if (animate) { - mDeferFinishedListener = true; - } - cancelAnimator(previousAnimator); - mDeferFinishedListener = false; - } else { - animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA); + mDeferFinishedListener = true; } + // Previous animators should always be cancelled. Not doing so would cause + // overlap, especially on states that don't animate, leading to flickering, + // and in the worst case, an internal state that doesn't represent what + // transitionTo requested. + cancelAnimator(previousAnimator); + mDeferFinishedListener = false; } if (mPendingFrameCallback != null) { // Display is off and we're waiting. - cancelAnimator(previousAnimator); return; } else if (mBlankScreen) { // Need to blank the display before continuing. - cancelAnimator(previousAnimator); blankDisplay(); return; } else if (!mScreenBlankingCallbackCalled) { @@ -744,36 +782,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } final ScrimView scrimView = scrim instanceof ScrimView ? (ScrimView) scrim : null; - final boolean wantsAlphaUpdate = alpha != currentAlpha && alpha != animEndValue; + final boolean wantsAlphaUpdate = alpha != currentAlpha; final boolean wantsTintUpdate = scrimView != null && scrimView.getTint() != getCurrentScrimTint(scrimView); if (wantsAlphaUpdate || wantsTintUpdate) { - if (animate) { - final float fromAlpha = scrimView == null ? scrim.getAlpha() - : scrimView.getViewAlpha(); - startScrimAnimation(scrim, fromAlpha); - scrim.setTag(TAG_START_ALPHA, currentAlpha); - scrim.setTag(TAG_END_ALPHA, alpha); + if (mAnimateChange) { + startScrimAnimation(scrim, currentAlpha); } else { - if (previousAnimator != null) { - float previousStartValue = ViewState.getChildTag(scrim, TAG_START_ALPHA); - float previousEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA); - // we need to increase all animation keyframes of the previous animator by the - // relative change to the end value - PropertyValuesHolder[] values = previousAnimator.getValues(); - float relativeDiff = alpha - previousEndValue; - float newStartValue = previousStartValue + relativeDiff; - newStartValue = Math.max(0, Math.min(1.0f, newStartValue)); - values[0].setFloatValues(newStartValue, alpha); - scrim.setTag(TAG_START_ALPHA, newStartValue); - scrim.setTag(TAG_END_ALPHA, alpha); - previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); - } else { - // update the alpha directly - updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim)); - onFinished(); - } + // update the alpha directly + updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim)); + onFinished(); } } else { onFinished(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 168d8d36290d..3c9cca2da91d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -77,7 +77,7 @@ public class ScrimControllerTest extends SysuiTestCase { mLightBarController = mock(LightBarController.class); mScrimBehind = new ScrimView(getContext()); mScrimInFront = new ScrimView(getContext()); - mHeadsUpScrim = mock(View.class); + mHeadsUpScrim = new View(getContext()); mWakeLock = mock(WakeLock.class); mAlarmManager = mock(AlarmManager.class); mAlwaysOnEnabled = true; @@ -384,6 +384,56 @@ public class ScrimControllerTest extends SysuiTestCase { testConservesNotificationDensity(3 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY); } + @Test + public void testHeadsUpScrimOpacity() { + mScrimController.setPanelExpansion(0f); + mScrimController.onHeadsUpPinned(null /* row */); + mScrimController.finishAnimationsImmediately(); + + Assert.assertNotEquals("Heads-up scrim should be visible", 0f, + mHeadsUpScrim.getAlpha(), 0.01f); + + mScrimController.onHeadsUpUnPinned(null /* row */); + mScrimController.finishAnimationsImmediately(); + + Assert.assertEquals("Heads-up scrim should have disappeared", 0f, + mHeadsUpScrim.getAlpha(), 0.01f); + } + + @Test + public void testHeadsUpScrimCounting() { + mScrimController.setPanelExpansion(0f); + mScrimController.onHeadsUpPinned(null /* row */); + mScrimController.onHeadsUpPinned(null /* row */); + mScrimController.onHeadsUpPinned(null /* row */); + mScrimController.finishAnimationsImmediately(); + + Assert.assertNotEquals("Heads-up scrim should be visible", 0f, + mHeadsUpScrim.getAlpha(), 0.01f); + + mScrimController.onHeadsUpUnPinned(null /* row */); + mScrimController.finishAnimationsImmediately(); + + Assert.assertEquals("Heads-up scrim should only disappear when counter reaches 0", 1f, + mHeadsUpScrim.getAlpha(), 0.01f); + + mScrimController.onHeadsUpUnPinned(null /* row */); + mScrimController.onHeadsUpUnPinned(null /* row */); + mScrimController.finishAnimationsImmediately(); + Assert.assertEquals("Heads-up scrim should have disappeared", 0f, + mHeadsUpScrim.getAlpha(), 0.01f); + } + + @Test + public void testNoHeadsUpScrimExpanded() { + mScrimController.setPanelExpansion(1f); + mScrimController.onHeadsUpPinned(null /* row */); + mScrimController.finishAnimationsImmediately(); + + Assert.assertEquals("Heads-up scrim should not be visible when shade is expanded", 0f, + mHeadsUpScrim.getAlpha(), 0.01f); + } + /** * Conserves old notification density after leaving state and coming back. * @@ -458,6 +508,7 @@ public class ScrimControllerTest extends SysuiTestCase { // Force finish all animations. endAnimation(mScrimBehind, TAG_KEY_ANIM); endAnimation(mScrimInFront, TAG_KEY_ANIM); + endAnimation(mHeadsUpScrim, TAG_KEY_ANIM); if (!animationFinished[0]) { throw new IllegalStateException("Animation never finished"); @@ -470,7 +521,7 @@ public class ScrimControllerTest extends SysuiTestCase { return wasCancelled; } - private void endAnimation(ScrimView scrimView, int tag) { + private void endAnimation(View scrimView, int tag) { Animator animator = (Animator) scrimView.getTag(tag); if (animator != null) { animator.end(); |