diff options
| author | 2017-11-28 23:16:12 +0000 | |
|---|---|---|
| committer | 2017-11-28 23:16:12 +0000 | |
| commit | 94de3518323afb32eacb5b69c081b184fa60e18d (patch) | |
| tree | 009db1a7696378d6c31ba08bfa770069d6c89f65 | |
| parent | d2b6b41095055ee385dc3f63fce6b8b5c0e55e26 (diff) | |
| parent | 9e3fa1033c1fb43c82abf93f231636a4b103c0e4 (diff) | |
Merge "Refactoring ScrimController"
19 files changed, 1131 insertions, 736 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3512793103bf..65a7ec643078 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1955,7 +1955,7 @@ <string name="config_dozeLongPressSensorType" translatable="false"></string> <!-- Control whether the always on display mode is available. This should only be enabled on - devices where the display has be tuned to be power efficient in DOZE and/or DOZE_SUSPEND + devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND states. --> <bool name="config_dozeAlwaysOnDisplayAvailable">false</bool> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index cf7923805f0f..8e065d1bf06b 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -250,10 +250,7 @@ <string name="doze_brightness_sensor_type" translatable="false"></string> <!-- Doze: pulse parameter - how long does it take to fade in? --> - <integer name="doze_pulse_duration_in">900</integer> - - <!-- Doze: pulse parameter - how long does it take to fade in after a pickup? --> - <integer name="doze_pulse_duration_in_pickup">130</integer> + <integer name="doze_pulse_duration_in">130</integer> <!-- Doze: pulse parameter - once faded in, how long does it stay visible? --> <integer name="doze_pulse_duration_visible">6000</integer> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index cfd95b41825a..884e18918fd6 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -47,6 +47,7 @@ <item type="id" name="qs_icon_tag"/> <item type="id" name="qs_slash_tag"/> <item type="id" name="scrim"/> + <item type="id" name="scrim_blanking"/> <item type="id" name="scrim_target"/> <item type="id" name="scrim_alpha_start"/> <item type="id" name="scrim_alpha_end"/> diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 0c067ff38295..526a8f464441 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -28,6 +28,7 @@ import com.android.systemui.Dependency.DependencyProvider; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.ScrimView; +import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LockIcon; @@ -86,10 +87,10 @@ public class SystemUIFactory { public ScrimController createScrimController(LightBarController lightBarController, ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim, - LockscreenWallpaper lockscreenWallpaper, - Consumer<Boolean> scrimVisibleListener) { + LockscreenWallpaper lockscreenWallpaper, Consumer<Boolean> scrimVisibleListener, + DozeParameters dozeParameters) { return new ScrimController(lightBarController, scrimBehind, scrimInFront, headsUpScrim, - scrimVisibleListener); + scrimVisibleListener, dozeParameters); } public NotificationIconAreaController createNotificationIconAreaController(Context context, diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index 7db118d7fb1c..2f607eee4f16 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -35,7 +35,6 @@ public interface DozeHost { boolean isBlockingDoze(); void startPendingIntentDismissingKeyguard(PendingIntent intent); - void abortPulsing(); void extendPulse(); void setAnimateWakeup(boolean animateWakeup); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index b99e76a28c6d..c92acd068745 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2028,12 +2028,9 @@ public class KeyguardViewMediator extends SystemUI { } public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar, - ViewGroup container, - ScrimController scrimController, - FingerprintUnlockController fingerprintUnlockController) { + ViewGroup container, FingerprintUnlockController fingerprintUnlockController) { mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, - scrimController, fingerprintUnlockController, - mDismissCallbackRegistry); + fingerprintUnlockController, mDismissCallbackRegistry); return mStatusBarKeyguardViewManager; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java index a53e348fd16c..fb9c037c236c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java @@ -252,6 +252,13 @@ public class ScrimView extends View implements ConfigurationController.Configura return false; } + /** + * It might look counterintuitive to have another method to set the alpha instead of + * only using {@link #setAlpha(float)}. In this case we're in a hardware layer + * optimizing blend modes, so it makes sense. + * + * @param alpha Gradient alpha from 0 to 1. + */ public void setViewAlpha(float alpha) { if (alpha != mViewAlpha) { mViewAlpha = alpha; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 6b7397b3f8ca..3f57c2f9384f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -46,10 +46,8 @@ public class DozeParameters { public void dump(PrintWriter pw) { pw.println(" DozeParameters:"); pw.print(" getDisplayStateSupported(): "); pw.println(getDisplayStateSupported()); - pw.print(" getPulseDuration(pickup=false): "); pw.println(getPulseDuration(false)); - pw.print(" getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true)); - pw.print(" getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false)); - pw.print(" getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true)); + pw.print(" getPulseDuration(): "); pw.println(getPulseDuration()); + pw.print(" getPulseInDuration(): "); pw.println(getPulseInDuration()); pw.print(" getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration()); pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration()); pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion()); @@ -81,14 +79,12 @@ public class DozeParameters { return mContext.getResources().getBoolean(R.bool.doze_suspend_display_state_supported); } - public int getPulseDuration(boolean pickup) { - return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration(); + public int getPulseDuration() { + return getPulseInDuration() + getPulseVisibleDuration() + getPulseOutDuration(); } - public int getPulseInDuration(boolean pickupOrDoubleTap) { - return pickupOrDoubleTap - ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup) - : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in); + public int getPulseInDuration() { + return getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in); } public int getPulseVisibleDuration() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index 8afb8490808e..1011383b72e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -16,16 +16,11 @@ package com.android.systemui.statusbar.phone; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; import android.annotation.NonNull; import android.content.Context; import android.os.Handler; import android.util.Log; -import android.view.animation.Interpolator; -import com.android.systemui.Interpolators; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; @@ -40,74 +35,59 @@ public class DozeScrimController { private final Handler mHandler = new Handler(); private final ScrimController mScrimController; - private final Context mContext; - private boolean mDozing; private DozeHost.PulseCallback mPulseCallback; private int mPulseReason; - private Animator mInFrontAnimator; - private Animator mBehindAnimator; - private float mInFrontTarget; - private float mBehindTarget; - private boolean mDozingAborted; - private boolean mWakeAndUnlocking; private boolean mFullyPulsing; - private float mAodFrontScrimOpacity = 0; - private Runnable mSetDozeInFrontAlphaDelayed; + private final ScrimController.Callback mScrimCallback = new ScrimController.Callback() { + @Override + public void onDisplayBlanked() { + if (DEBUG) { + Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason=" + + DozeLog.pulseReasonToString(mPulseReason)); + } + if (!mDozing) { + return; + } + + // Signal that the pulse is ready to turn the screen on and draw. + pulseStarted(); + } + + @Override + public void onFinished() { + if (DEBUG) { + Log.d(TAG, "Pulse in finished, mDozing=" + mDozing); + } + if (!mDozing) { + return; + } + mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); + mHandler.postDelayed(mPulseOutExtended, + mDozeParameters.getPulseVisibleDurationExtended()); + mFullyPulsing = true; + } + + /** + * Transition was aborted before it was over. + */ + @Override + public void onCancelled() { + pulseFinished(); + } + }; public DozeScrimController(ScrimController scrimController, Context context) { - mContext = context; mScrimController = scrimController; mDozeParameters = new DozeParameters(context); } - public void setDozing(boolean dozing, boolean animate) { + public void setDozing(boolean dozing) { if (mDozing == dozing) return; mDozing = dozing; - mWakeAndUnlocking = false; - if (mDozing) { - mDozingAborted = false; - abortAnimations(); - mScrimController.setDozeBehindAlpha(1f); - setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f); - } else { + if (!mDozing) { cancelPulsing(); - if (animate) { - startScrimAnimation(false /* inFront */, 0f /* target */, - NotificationPanelView.DOZE_ANIMATION_DURATION, - Interpolators.LINEAR_OUT_SLOW_IN); - startScrimAnimation(true /* inFront */, 0f /* target */, - NotificationPanelView.DOZE_ANIMATION_DURATION, - Interpolators.LINEAR_OUT_SLOW_IN); - } else { - abortAnimations(); - mScrimController.setDozeBehindAlpha(0f); - setDozeInFrontAlpha(0f); - } - } - } - - /** - * Set the opacity of the front scrim when showing AOD1 - * - * Used to emulate lower brightness values than the hardware supports natively. - */ - public void setAodDimmingScrim(float scrimOpacity) { - mAodFrontScrimOpacity = scrimOpacity; - if (mDozing && !isPulsing() && !mDozingAborted && !mWakeAndUnlocking - && mDozeParameters.getAlwaysOn()) { - setDozeInFrontAlpha(mAodFrontScrimOpacity); - } - } - - public void setWakeAndUnlocking() { - // Immediately abort the doze scrims in case of wake-and-unlock - // for pulsing so the Keyguard fade-out animation scrim can take over. - if (!mWakeAndUnlocking) { - mWakeAndUnlocking = true; - mScrimController.setDozeBehindAlpha(0f); - setDozeInFrontAlpha(0f); } } @@ -118,37 +98,21 @@ public class DozeScrimController { } if (!mDozing || mPulseCallback != null) { + if (DEBUG) { + Log.d(TAG, "Pulse supressed. Dozing: " + mDozeParameters + " had callback? " + + (mPulseCallback != null)); + } // Pulse suppressed. callback.onPulseFinished(); return; } - // Begin pulse. Note that it's very important that the pulse finished callback + // Begin pulse. Note that it's very important that the pulse finished callback // be invoked when we're done so that the caller can drop the pulse wakelock. mPulseCallback = callback; mPulseReason = reason; - setDozeInFrontAlpha(1f); - mHandler.post(mPulseIn); - } - - /** - * Aborts pulsing immediately. - */ - public void abortPulsing() { - cancelPulsing(); - if (mDozing && !mWakeAndUnlocking) { - mScrimController.setDozeBehindAlpha(1f); - setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() && !mDozingAborted - ? mAodFrontScrimOpacity : 1f); - } - } - /** - * Aborts dozing immediately. - */ - public void abortDoze() { - mDozingAborted = true; - abortPulsing(); + mScrimController.transitionTo(ScrimState.PULSING, mScrimCallback); } public void pulseOutNow() { @@ -157,17 +121,6 @@ public class DozeScrimController { } } - public void onScreenTurnedOn() { - if (isPulsing()) { - final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP - || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP; - startScrimAnimation(true /* inFront */, 0f, - mDozeParameters.getPulseInDuration(pickupOrDoubleTap), - pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT, - mPulseInFinished); - } - } - public boolean isPulsing() { return mPulseCallback != null; } @@ -181,11 +134,9 @@ public class DozeScrimController { } private void cancelPulsing() { - if (DEBUG) Log.d(TAG, "Cancel pulsing"); - if (mPulseCallback != null) { + if (DEBUG) Log.d(TAG, "Cancel pulsing"); mFullyPulsing = false; - mHandler.removeCallbacks(mPulseIn); mHandler.removeCallbacks(mPulseOut); mHandler.removeCallbacks(mPulseOutExtended); pulseFinished(); @@ -193,151 +144,20 @@ public class DozeScrimController { } private void pulseStarted() { + DozeLog.tracePulseStart(mPulseReason); if (mPulseCallback != null) { mPulseCallback.onPulseStarted(); } } private void pulseFinished() { + DozeLog.tracePulseFinish(); if (mPulseCallback != null) { mPulseCallback.onPulseFinished(); mPulseCallback = null; } } - private void abortAnimations() { - if (mInFrontAnimator != null) { - mInFrontAnimator.cancel(); - } - if (mBehindAnimator != null) { - mBehindAnimator.cancel(); - } - } - - private void startScrimAnimation(final boolean inFront, float target, long duration, - Interpolator interpolator) { - startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */); - } - - private void startScrimAnimation(final boolean inFront, float target, long duration, - Interpolator interpolator, final Runnable endRunnable) { - Animator current = getCurrentAnimator(inFront); - if (current != null) { - float currentTarget = getCurrentTarget(inFront); - if (currentTarget == target) { - return; - } - current.cancel(); - } - ValueAnimator anim = ValueAnimator.ofFloat(getDozeAlpha(inFront), target); - anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float value = (float) animation.getAnimatedValue(); - setDozeAlpha(inFront, value); - } - }); - anim.setInterpolator(interpolator); - anim.setDuration(duration); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - setCurrentAnimator(inFront, null); - if (endRunnable != null) { - endRunnable.run(); - } - } - }); - anim.start(); - setCurrentAnimator(inFront, anim); - setCurrentTarget(inFront, target); - } - - private float getCurrentTarget(boolean inFront) { - return inFront ? mInFrontTarget : mBehindTarget; - } - - private void setCurrentTarget(boolean inFront, float target) { - if (inFront) { - mInFrontTarget = target; - } else { - mBehindTarget = target; - } - } - - private Animator getCurrentAnimator(boolean inFront) { - return inFront ? mInFrontAnimator : mBehindAnimator; - } - - private void setCurrentAnimator(boolean inFront, Animator animator) { - if (inFront) { - mInFrontAnimator = animator; - } else { - mBehindAnimator = animator; - } - } - - private void setDozeAlpha(boolean inFront, float alpha) { - if (mWakeAndUnlocking) { - return; - } - if (inFront) { - mScrimController.setDozeInFrontAlpha(alpha); - } else { - mScrimController.setDozeBehindAlpha(alpha); - } - } - - private float getDozeAlpha(boolean inFront) { - return inFront - ? mScrimController.getDozeInFrontAlpha() - : mScrimController.getDozeBehindAlpha(); - } - - private void setDozeInFrontAlpha(float opacity) { - setDozeInFrontAlphaDelayed(opacity, 0 /* delay */); - - } - - private void setDozeInFrontAlphaDelayed(float opacity, long delayMs) { - if (mSetDozeInFrontAlphaDelayed != null) { - mHandler.removeCallbacks(mSetDozeInFrontAlphaDelayed); - mSetDozeInFrontAlphaDelayed = null; - } - if (delayMs <= 0) { - mScrimController.setDozeInFrontAlpha(opacity); - } else { - mHandler.postDelayed(mSetDozeInFrontAlphaDelayed = () -> { - setDozeInFrontAlpha(opacity); - }, delayMs); - } - } - - private final Runnable mPulseIn = new Runnable() { - @Override - public void run() { - if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason=" - + DozeLog.pulseReasonToString(mPulseReason)); - if (!mDozing) return; - DozeLog.tracePulseStart(mPulseReason); - - // Signal that the pulse is ready to turn the screen on and draw. - pulseStarted(); - } - }; - - private final Runnable mPulseInFinished = new Runnable() { - @Override - public void run() { - if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing); - if (!mDozing) return; - mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); - mHandler.postDelayed(mPulseOutExtended, - mDozeParameters.getPulseVisibleDurationExtended()); - mFullyPulsing = true; - } - }; - private final Runnable mPulseOutExtended = new Runnable() { @Override public void run() { @@ -354,38 +174,13 @@ public class DozeScrimController { mHandler.removeCallbacks(mPulseOutExtended); if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing); if (!mDozing) return; - startScrimAnimation(true /* inFront */, 1, - mDozeParameters.getPulseOutDuration(), - Interpolators.ALPHA_IN, mPulseOutFinishing); - } - }; - - private final Runnable mPulseOutFinishing = new Runnable() { - @Override - public void run() { - if (DEBUG) Log.d(TAG, "Pulse out finished"); - DozeLog.tracePulseFinish(); - if (mDozeParameters.getAlwaysOn() && mDozing) { - // Setting power states can block rendering. For AOD, delay finishing the pulse and - // setting the power state until the fully black scrim had time to hit the - // framebuffer. - mHandler.postDelayed(mPulseOutFinished, 30); - } else { - mPulseOutFinished.run(); - } - } - }; - - private final Runnable mPulseOutFinished = new Runnable() { - @Override - public void run() { - // Signal that the pulse is all finished so we can turn the screen off now. - DozeScrimController.this.pulseFinished(); - if (mDozeParameters.getAlwaysOn()) { - // Setting power states can happen after we push out the frame. Make sure we - // stay fully opaque until the power state request reaches the lower levels. - setDozeInFrontAlphaDelayed(mAodFrontScrimOpacity, 100); - } + mScrimController.transitionTo(ScrimState.AOD, + new ScrimController.Callback() { + @Override + public void onDisplayBlanked() { + pulseFinished(); + } + }); } }; -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java index 91369dbd5f89..80d4061b3864 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java @@ -181,9 +181,9 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { } private boolean pulsingOrAod() { - boolean pulsing = mDozeScrimController.isPulsing(); - boolean dozingWithScreenOn = mStatusBar.isDozing() && !mStatusBar.isScreenFullyOff(); - return pulsing || dozingWithScreenOn; + final ScrimState scrimState = mScrimController.getState(); + return scrimState == ScrimState.AOD + || scrimState == ScrimState.PULSING; } @Override @@ -246,15 +246,12 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { true /* allowEnterAnimation */); } else if (mMode == MODE_WAKE_AND_UNLOCK){ Trace.beginSection("MODE_WAKE_AND_UNLOCK"); - mDozeScrimController.abortDoze(); } else { Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM"); mUpdateMonitor.awakenFromDream(); } mStatusBarWindowManager.setStatusBarFocusable(false); mKeyguardViewMediator.onWakeAndUnlocking(); - mScrimController.setWakeAndUnlocking(); - mDozeScrimController.setWakeAndUnlocking(); if (mStatusBar.getNavigationBarView() != null) { mStatusBar.getNavigationBarView().setWakeAndUnlocking(true); } @@ -269,6 +266,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { } private void showBouncer() { + mScrimController.transitionTo(ScrimState.BOUNCER); mStatusBarKeyguardViewManager.animateCollapsePanels( FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR); mPendingShowBouncer = false; 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 702afa3a38b1..dfd4c1768268 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -25,7 +25,9 @@ import android.content.Context; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Handler; import android.os.Trace; +import android.util.Log; import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; @@ -34,12 +36,14 @@ import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener; import com.android.internal.graphics.ColorUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dependency; +import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.statusbar.ExpandableNotificationRow; @@ -47,7 +51,10 @@ import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.stack.ViewState; +import com.android.systemui.util.wakelock.DelayedWakeLock; +import com.android.systemui.util.wakelock.WakeLock; +import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.function.Consumer; @@ -56,33 +63,54 @@ import java.util.function.Consumer; * security method gets shown). */ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, - OnHeadsUpChangedListener, OnColorsChangedListener { + OnHeadsUpChangedListener, OnColorsChangedListener, Dumpable { + + private static final String TAG = "ScrimController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + public static final long ANIMATION_DURATION = 220; public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR = new PathInterpolator(0f, 0, 0.7f, 1f); public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED = new PathInterpolator(0.3f, 0f, 0.8f, 1f); - // Default alpha value for most scrims, if unsure use this constant + /** + * Default alpha value for most scrims. + */ public static final float GRADIENT_SCRIM_ALPHA = 0.45f; - // A scrim varies its opacity based on a busyness factor, for example - // how many notifications are currently visible. + /** + * A scrim varies its opacity based on a busyness factor, for example + * how many notifications are currently visible. + */ public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f; + /** + * The most common scrim, the one under the keyguard. + */ protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA; + /** + * We fade out the bottom scrim when the bouncer is visible. + */ protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f; - private static final float SCRIM_IN_FRONT_ALPHA = GRADIENT_SCRIM_ALPHA_BUSY; - private static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY; - private static final int TAG_KEY_ANIM = R.id.scrim; + /** + * Opacity of the scrim behind the bouncer (the one doing actual background protection.) + */ + protected static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY; + + static final int TAG_KEY_ANIM = R.id.scrim; + static final int TAG_KEY_ANIM_BLANK = R.id.scrim_blanking; private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target; private static final int TAG_START_ALPHA = R.id.scrim_alpha_start; private static final int TAG_END_ALPHA = R.id.scrim_alpha_end; private static final float NOT_INITIALIZED = -1; - private final LightBarController mLightBarController; + private ScrimState mState = ScrimState.UNINITIALIZED; + private final Context mContext; protected final ScrimView mScrimBehind; protected final ScrimView mScrimInFront; - private final UnlockMethodCache mUnlockMethodCache; private final View mHeadsUpScrim; + private final LightBarController mLightBarController; + private final UnlockMethodCache mUnlockMethodCache; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final DozeParameters mDozeParameters; private final SysuiColorExtractor mColorExtractor; private GradientColors mLockColors; @@ -94,61 +122,53 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD; protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING; - protected boolean mKeyguardShowing; private float mFraction; private boolean mDarkenWhileDragging; - protected boolean mBouncerShowing; - protected boolean mBouncerIsKeyguard = false; - private boolean mWakeAndUnlocking; protected boolean mAnimateChange; private boolean mUpdatePending; private boolean mTracking; private boolean mAnimateKeyguardFadingOut; - protected long mDurationOverride = -1; + protected long mAnimationDuration = -1; private long mAnimationDelay; private Runnable mOnAnimationFinished; private boolean mDeferFinishedListener; private final Interpolator mInterpolator = new DecelerateInterpolator(); - private boolean mDozing; - private float mDozeInFrontAlpha; - private float mDozeBehindAlpha; private float mCurrentInFrontAlpha = NOT_INITIALIZED; private float mCurrentBehindAlpha = NOT_INITIALIZED; - private float mCurrentHeadsUpAlpha = NOT_INITIALIZED; + private int mCurrentInFrontTint; + private int mCurrentBehindTint; private int mPinnedHeadsUpCount; private float mTopHeadsUpDragAmount; private View mDraggedHeadsUpView; - private boolean mForceHideScrims; - private boolean mSkipFirstFrame; - private boolean mDontAnimateBouncerChanges; private boolean mKeyguardFadingOutInProgress; - private boolean mAnimatingDozeUnlock; private ValueAnimator mKeyguardFadeoutAnimation; - /** Wake up from AOD transition is starting; need fully opaque front scrim */ - private boolean mWakingUpFromAodStarting; - /** Wake up from AOD transition is in progress; need black tint */ - private boolean mWakingUpFromAodInProgress; - /** Wake up from AOD transition is animating; need to reset when animation finishes */ - private boolean mWakingUpFromAodAnimationRunning; - private boolean mScrimsVisble; + private boolean mScrimsVisible; private final Consumer<Boolean> mScrimVisibleListener; + private boolean mBlankScreen; + private boolean mScreenBlankingCallbackCalled; + private Callback mCallback; + + private final WakeLock mWakeLock; + private boolean mWakeLockHeld; public ScrimController(LightBarController lightBarController, ScrimView scrimBehind, - ScrimView scrimInFront, View headsUpScrim, - Consumer<Boolean> scrimVisibleListener) { + ScrimView scrimInFront, View headsUpScrim, Consumer<Boolean> scrimVisibleListener, + DozeParameters dozeParameters) { mScrimBehind = scrimBehind; mScrimInFront = scrimInFront; mHeadsUpScrim = headsUpScrim; mScrimVisibleListener = scrimVisibleListener; - final Context context = scrimBehind.getContext(); - mUnlockMethodCache = UnlockMethodCache.getInstance(context); - mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context); + mContext = scrimBehind.getContext(); + mUnlockMethodCache = UnlockMethodCache.getInstance(mContext); + mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); mLightBarController = lightBarController; - mScrimBehindAlphaResValue = context.getResources().getFloat(R.dimen.scrim_behind_alpha); + mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha); + mWakeLock = createWakeLock(); // Scrim alpha is initially set to the value on the resource but might be changed // to make sure that text on top of it is legible. mScrimBehindAlpha = mScrimBehindAlphaResValue; + mDozeParameters = dozeParameters; mColorExtractor = Dependency.get(SysuiColorExtractor.class); mColorExtractor.addOnColorsChangedListener(this); @@ -158,159 +178,155 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, ColorExtractor.TYPE_DARK, true /* ignoreVisibility */); mNeedsDrawableColorUpdate = true; + final ScrimState[] states = ScrimState.values(); + for (int i = 0; i < states.length; i++) { + states[i].init(mScrimInFront, mScrimBehind, mDozeParameters); + states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard); + } + mState = ScrimState.UNINITIALIZED; + updateHeadsUpScrim(false); updateScrims(); } - public void setKeyguardShowing(boolean showing) { - mKeyguardShowing = showing; - - // Showing/hiding the keyguard means that scrim colors have to be switched - mNeedsDrawableColorUpdate = true; - scheduleUpdate(); - } - - protected void setScrimBehindValues(float scrimBehindAlphaKeyguard, - float scrimBehindAlphaUnlocking) { - mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard; - mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking; - scheduleUpdate(); - } - - public void onTrackingStarted() { - mTracking = true; - mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer(); - } - - public void onExpandingFinished() { - mTracking = false; + public void transitionTo(ScrimState state) { + transitionTo(state, null); } - public void setPanelExpansion(float fraction) { - if (mFraction != fraction) { - mFraction = fraction; - scheduleUpdate(); - if (mPinnedHeadsUpCount != 0) { - updateHeadsUpScrim(false); - } - if (mKeyguardFadeoutAnimation != null && mTracking) { - mKeyguardFadeoutAnimation.cancel(); - } + public void transitionTo(ScrimState state, Callback callback) { + if (state == mState) { + return; + } else if (DEBUG) { + Log.d(TAG, "State changed to: " + state); } - } - - public void setBouncerShowing(boolean showing) { - mBouncerShowing = showing; - mAnimateChange = !mTracking && !mDontAnimateBouncerChanges && !mKeyguardFadingOutInProgress; - scheduleUpdate(); - } - /** Prepares the wakeUpFromAod animation (while turning on screen); Forces black scrims. */ - public void prepareWakeUpFromAod() { - if (mWakingUpFromAodInProgress) { - return; + if (state == ScrimState.UNINITIALIZED) { + throw new IllegalArgumentException("Cannot change to UNINITIALIZED."); } - mWakingUpFromAodInProgress = true; - mWakingUpFromAodStarting = true; - mAnimateChange = false; - scheduleUpdate(); - onPreDraw(); - } - /** Starts the wakeUpFromAod animation (once screen is on); animate to transparent scrims. */ - public void wakeUpFromAod() { - if (mWakeAndUnlocking || mAnimateKeyguardFadingOut) { - // Wake and unlocking has a separate transition that must not be interfered with. - mWakingUpFromAodStarting = false; - mWakingUpFromAodInProgress = false; - return; + if (mCallback != null) { + mCallback.onCancelled(); } - if (mWakingUpFromAodStarting) { - mWakingUpFromAodInProgress = true; - mWakingUpFromAodStarting = false; - mAnimateChange = true; - scheduleUpdate(); + mCallback = callback; + + state.prepare(mState); + mScreenBlankingCallbackCalled = false; + mAnimationDelay = 0; + mBlankScreen = state.getBlanksScreen(); + mAnimateChange = state.getAnimateChange(); + mAnimationDuration = state.getAnimationDuration(); + mCurrentInFrontTint = state.getFrontTint(); + mCurrentBehindTint = state.getBehindTint(); + mCurrentInFrontAlpha = state.getFrontAlpha(); + mCurrentBehindAlpha = state.getBehindAlpha(); + + // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary + // to do the same when you're just showing the brightness mirror. + mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR; + + if (mKeyguardFadeoutAnimation != null) { + mKeyguardFadeoutAnimation.cancel(); } - } - public void setWakeAndUnlocking() { - mWakeAndUnlocking = true; - mAnimatingDozeUnlock = true; - mWakingUpFromAodStarting = false; - mWakingUpFromAodInProgress = false; - scheduleUpdate(); - } + mState = state; - public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished, - boolean skipFirstFrame) { - mWakeAndUnlocking = false; - mAnimateKeyguardFadingOut = true; - mDurationOverride = duration; - mAnimationDelay = delay; - mAnimateChange = true; - mSkipFirstFrame = skipFirstFrame; - mOnAnimationFinished = onAnimationFinished; + // Do not let the device sleep until we're done with all animations + if (!mWakeLockHeld) { + if (mWakeLock != null) { + mWakeLockHeld = true; + mWakeLock.acquire(); + } else { + Log.w(TAG, "Cannot hold wake lock, it has not been set yet"); + } + } if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) { scheduleUpdate(); - - // No need to wait for the next frame to be drawn for this case - onPreDraw will execute - // the changes we just scheduled. - onPreDraw(); } else { - // In case the user isn't unlocked, make sure to delay a bit because the system is hosed - // with too many things in this case, in order to not skip the initial frames. + // with too many things at this case, in order to not skip the initial frames. mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16); + mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY; } } - public void abortKeyguardFadingOut() { - if (mAnimateKeyguardFadingOut) { - endAnimateKeyguardFadingOut(true /* force */); - } + public ScrimState getState() { + return mState; } - public void animateKeyguardUnoccluding(long duration) { - mAnimateChange = false; - setScrimBehindAlpha(0f); - mAnimateChange = true; + protected void setScrimBehindValues(float scrimBehindAlphaKeyguard, + float scrimBehindAlphaUnlocking) { + mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard; + mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking; + ScrimState[] states = ScrimState.values(); + for (int i = 0; i < states.length; i++) { + states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard); + } scheduleUpdate(); - mDurationOverride = duration; } - public void animateGoingToFullShade(long delay, long duration) { - mDurationOverride = duration; - mAnimationDelay = delay; - mAnimateChange = true; - scheduleUpdate(); + public void onTrackingStarted() { + mTracking = true; + mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer(); } - public void setDozing(boolean dozing) { - if (mDozing != dozing) { - mDozing = dozing; - scheduleUpdate(); - } + public void onExpandingFinished() { + mTracking = false; } - public void setDozeInFrontAlpha(float alpha) { - mDozeInFrontAlpha = alpha; - updateScrimColor(mScrimInFront); - } + /** + * Current state of the shade expansion when pulling it from the top. + * This value is 1 when on top of the keyguard and goes to 0 as the user drags up. + * + * The expansion fraction is tied to the scrim opacity. + * + * @param fraction From 0 to 1 where 0 means collapse and 1 expanded. + */ + public void setPanelExpansion(float fraction) { + if (mFraction != fraction) { + mFraction = fraction; - public void setDozeBehindAlpha(float alpha) { - mDozeBehindAlpha = alpha; - updateScrimColor(mScrimBehind); - } + if (mState == ScrimState.UNLOCKED) { + // Darken scrim as you pull down the shade when unlocked + float behindFraction = getInterpolatedFraction(); + behindFraction = (float) Math.pow(behindFraction, 0.8f); + mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard; + mCurrentInFrontAlpha = 0; + } else if (mState == ScrimState.KEYGUARD) { + if (mUpdatePending) { + return; + } - public float getDozeBehindAlpha() { - return mDozeBehindAlpha; - } + // Either darken of make the scrim transparent when you + // pull down the shade + float interpolatedFract = getInterpolatedFraction(); + if (mDarkenWhileDragging) { + mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking, + mScrimBehindAlphaKeyguard, interpolatedFract); + mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED; + } else { + mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, mScrimBehindAlphaKeyguard, + interpolatedFract); + mCurrentInFrontAlpha = 0; + } + } else { + Log.w(TAG, "Invalid state, cannot set panel expansion when: " + mState); + return; + } + + if (mPinnedHeadsUpCount != 0) { + updateHeadsUpScrim(false); + } - public float getDozeInFrontAlpha() { - return mDozeInFrontAlpha; + updateScrim(false /* animate */, mScrimInFront, mCurrentInFrontAlpha); + updateScrim(false /* animate */, mScrimBehind, mCurrentBehindAlpha); + } } + /** + * Keyguard and shade scrim opacity varies according to how many notifications are visible. + * @param notificationCount Number of visible notifications. + */ public void setNotificationCount(int notificationCount) { final float maxNotificationDensity = 3; float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f); @@ -319,15 +335,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, notificationDensity); if (mScrimBehindAlphaKeyguard != newAlpha) { mScrimBehindAlphaKeyguard = newAlpha; - mAnimateChange = true; - scheduleUpdate(); - } - } - private float getScrimInFrontAlpha() { - return mKeyguardUpdateMonitor.needsSlowUnlockTransition() - ? SCRIM_IN_FRONT_ALPHA_LOCKED - : SCRIM_IN_FRONT_ALPHA; + if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) { + scheduleUpdate(); + } + } } /** @@ -352,7 +364,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, if (mNeedsDrawableColorUpdate) { mNeedsDrawableColorUpdate = false; final GradientColors currentScrimColors; - if (mKeyguardShowing) { + if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) { // Always animate color changes if we're seeing the keyguard mScrimInFront.setColors(mLockColors, true /* animated */); mScrimBehind.setColors(mLockColors, true /* animated */); @@ -375,77 +387,31 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mLightBarController.setScrimColor(mScrimInFront.getColors()); } - if (mAnimateKeyguardFadingOut || mForceHideScrims) { - setScrimInFrontAlpha(0f); - setScrimBehindAlpha(0f); - } else if (mWakeAndUnlocking) { - // During wake and unlock, we first hide everything behind a black scrim, which then - // gets faded out from animateKeyguardFadingOut. This must never be animated. - mAnimateChange = false; - if (mDozing) { - setScrimInFrontAlpha(0f); - setScrimBehindAlpha(1f); - } else { - setScrimInFrontAlpha(1f); - setScrimBehindAlpha(0f); - } - } else if (!mKeyguardShowing && !mBouncerShowing && !mWakingUpFromAodStarting) { - updateScrimNormal(); - setScrimInFrontAlpha(0); - } else { - updateScrimKeyguard(); - } - mAnimateChange = false; + setScrimInFrontAlpha(mCurrentInFrontAlpha); + setScrimBehindAlpha(mCurrentBehindAlpha); + dispatchScrimsVisible(); } private void dispatchScrimsVisible() { boolean scrimsVisible = mScrimBehind.getViewAlpha() > 0 || mScrimInFront.getViewAlpha() > 0; - if (mScrimsVisble != scrimsVisible) { - mScrimsVisble = scrimsVisible; + if (mScrimsVisible != scrimsVisible) { + mScrimsVisible = scrimsVisible; mScrimVisibleListener.accept(scrimsVisible); } } - private void updateScrimKeyguard() { - if (mTracking && mDarkenWhileDragging) { - float behindFraction = Math.max(0, Math.min(mFraction, 1)); - float fraction = 1 - behindFraction; - fraction = (float) Math.pow(fraction, 0.8f); - behindFraction = (float) Math.pow(behindFraction, 0.8f); - setScrimInFrontAlpha(fraction * getScrimInFrontAlpha()); - setScrimBehindAlpha(behindFraction * mScrimBehindAlphaKeyguard); - } else if (mBouncerShowing && !mBouncerIsKeyguard) { - setScrimInFrontAlpha(getScrimInFrontAlpha()); - updateScrimNormal(); - } else if (mBouncerShowing) { - setScrimInFrontAlpha(0f); - setScrimBehindAlpha(mScrimBehindAlpha); - } else { - float fraction = Math.max(0, Math.min(mFraction, 1)); - if (mWakingUpFromAodStarting) { - setScrimInFrontAlpha(1f); - } else { - setScrimInFrontAlpha(0f); - } - setScrimBehindAlpha(fraction - * (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking) - + mScrimBehindAlphaUnlocking); - } - } - - private void updateScrimNormal() { + private float getInterpolatedFraction() { float frac = mFraction; // let's start this 20% of the way down the screen frac = frac * 1.2f - 0.2f; if (frac <= 0) { - setScrimBehindAlpha(0); + return 0; } else { // woo, special effects - final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f)))); - setScrimBehindAlpha(k * mScrimBehindAlpha); + return (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f)))); } } @@ -455,102 +421,76 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private void setScrimInFrontAlpha(float alpha) { setScrimAlpha(mScrimInFront, alpha); - if (alpha == 0f) { - mScrimInFront.setClickable(false); - } else { - // Eat touch events (unless dozing). - mScrimInFront.setClickable(!mDozing); - } } private void setScrimAlpha(View scrim, float alpha) { - updateScrim(mAnimateChange, scrim, alpha, getCurrentScrimAlpha(scrim)); - } - - protected float getDozeAlpha(View scrim) { - return scrim == mScrimBehind ? mDozeBehindAlpha : mDozeInFrontAlpha; - } - - protected float getCurrentScrimAlpha(View scrim) { - return scrim == mScrimBehind ? mCurrentBehindAlpha - : scrim == mScrimInFront ? mCurrentInFrontAlpha - : mCurrentHeadsUpAlpha; - } - - private void setCurrentScrimAlpha(View scrim, float alpha) { - if (scrim == mScrimBehind) { - mCurrentBehindAlpha = alpha; - mLightBarController.setScrimAlpha(mCurrentBehindAlpha); - } else if (scrim == mScrimInFront) { - mCurrentInFrontAlpha = alpha; + if (alpha == 0f) { + scrim.setClickable(false); } else { - alpha = Math.max(0.0f, Math.min(1.0f, alpha)); - mCurrentHeadsUpAlpha = alpha; + // Eat touch events (unless dozing). + scrim.setClickable(!(mState == ScrimState.AOD)); } + updateScrim(mAnimateChange, scrim, alpha); } - private void updateScrimColor(View scrim) { - float alpha1 = getCurrentScrimAlpha(scrim); + private void updateScrimColor(View scrim, float alpha, int tint) { + alpha = Math.max(0, Math.min(1.0f, alpha)); if (scrim instanceof ScrimView) { ScrimView scrimView = (ScrimView) scrim; - float dozeAlpha = getDozeAlpha(scrim); - float alpha = 1 - (1 - alpha1) * (1 - dozeAlpha); - alpha = Math.max(0, Math.min(1.0f, alpha)); - scrimView.setViewAlpha(alpha); Trace.traceCounter(Trace.TRACE_TAG_APP, scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha", (int) (alpha * 255)); - int dozeTint = Color.TRANSPARENT; - - boolean dozing = mAnimatingDozeUnlock || mDozing; - boolean frontScrimDozing = mWakingUpFromAodInProgress; - if (dozing || frontScrimDozing && scrim == mScrimInFront) { - dozeTint = Color.BLACK; - } Trace.traceCounter(Trace.TRACE_TAG_APP, scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint", - dozeTint == Color.BLACK ? 1 : 0); + Color.alpha(tint)); - scrimView.setTint(dozeTint); + scrimView.setTint(tint); + scrimView.setViewAlpha(alpha); } else { - scrim.setAlpha(alpha1); + scrim.setAlpha(alpha); } dispatchScrimsVisible(); } - private void startScrimAnimation(final View scrim, float target) { - float current = getCurrentScrimAlpha(scrim); - ValueAnimator anim = ValueAnimator.ofFloat(current, target); + private int getCurrentScrimTint(View scrim) { + return scrim == mScrimInFront ? mCurrentInFrontTint : mCurrentBehindTint; + } + + private void startScrimAnimation(final View scrim, float current, float target) { + ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); + final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() : + Color.TRANSPARENT; anim.addUpdateListener(animation -> { - float alpha = (float) animation.getAnimatedValue(); - setCurrentScrimAlpha(scrim, alpha); - updateScrimColor(scrim); + final float animAmount = (float) animation.getAnimatedValue(); + final int finalScrimTint = scrim == mScrimInFront ? + mCurrentInFrontTint : mCurrentBehindTint; + float alpha = MathUtils.lerp(current, target, animAmount); + int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount); + updateScrimColor(scrim, alpha, tint); dispatchScrimsVisible(); }); anim.setInterpolator(getInterpolator()); anim.setStartDelay(mAnimationDelay); - anim.setDuration(mDurationOverride != -1 ? mDurationOverride : ANIMATION_DURATION); + anim.setDuration(mAnimationDuration); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (!mDeferFinishedListener && mOnAnimationFinished != null) { - mOnAnimationFinished.run(); - mOnAnimationFinished = null; - } if (mKeyguardFadingOutInProgress) { mKeyguardFadeoutAnimation = null; mKeyguardFadingOutInProgress = false; - mAnimatingDozeUnlock = false; - } - if (mWakingUpFromAodAnimationRunning && !mDeferFinishedListener) { - mWakingUpFromAodAnimationRunning = false; - mWakingUpFromAodInProgress = false; } + onFinished(); + scrim.setTag(TAG_KEY_ANIM, null); scrim.setTag(TAG_KEY_ANIM_TARGET, null); dispatchScrimsVisible(); + + if (!mDeferFinishedListener && mOnAnimationFinished != null) { + mOnAnimationFinished.run(); + mOnAnimationFinished = null; + } } }); anim.start(); @@ -558,12 +498,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mKeyguardFadingOutInProgress = true; mKeyguardFadeoutAnimation = anim; } - if (mWakingUpFromAodInProgress) { - mWakingUpFromAodAnimationRunning = true; - } - if (mSkipFirstFrame) { - anim.setCurrentPlayTime(16); - } scrim.setTag(TAG_KEY_ANIM, anim); scrim.setTag(TAG_KEY_ANIM_TARGET, target); } @@ -582,19 +516,33 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, public boolean onPreDraw() { mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this); mUpdatePending = false; - if (mDontAnimateBouncerChanges) { - mDontAnimateBouncerChanges = false; + if (mCallback != null) { + mCallback.onStart(); } updateScrims(); - mDurationOverride = -1; - mAnimationDelay = 0; - mSkipFirstFrame = false; // Make sure that we always call the listener even if we didn't start an animation. endAnimateKeyguardFadingOut(false /* force */); return true; } + private void onFinished() { + if (mWakeLockHeld) { + mWakeLock.release(); + mWakeLockHeld = false; + } + if (mCallback != null) { + mCallback.onFinished(); + mCallback = null; + } + // When unlocking with fingerprint, we'll fade the scrims from black to transparent. + // At the end of the animation we need to remove the tint. + if (mState == ScrimState.UNLOCKED) { + mCurrentInFrontTint = Color.TRANSPARENT; + mCurrentBehindTint = Color.TRANSPARENT; + } + } + private void endAnimateKeyguardFadingOut(boolean force) { mAnimateKeyguardFadingOut = false; if (force || (!isAnimating(mScrimInFront) && !isAnimating(mScrimBehind))) { @@ -603,8 +551,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mOnAnimationFinished = null; } mKeyguardFadingOutInProgress = false; - if (!mWakeAndUnlocking || force) - mAnimatingDozeUnlock = false; } } @@ -641,16 +587,19 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } private void updateHeadsUpScrim(boolean animate) { - updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha(), mCurrentHeadsUpAlpha); + updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha()); } - private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) { - if (mKeyguardFadingOutInProgress && mKeyguardFadeoutAnimation.getCurrentPlayTime() != 0) { - return; - } + @VisibleForTesting + void setOnAnimationFinished(Runnable onAnimationFinished) { + mOnAnimationFinished = onAnimationFinished; + } + + private void updateScrim(boolean animate, View scrim, float alpha) { + final float currentAlpha = scrim instanceof ScrimView ? ((ScrimView) scrim).getViewAlpha() + : scrim.getAlpha(); - ValueAnimator previousAnimator = ViewState.getChildTag(scrim, - TAG_KEY_ANIM); + ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM); float animEndValue = -1; if (previousAnimator != null) { if (animate || alpha == currentAlpha) { @@ -664,9 +613,32 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA); } } - if (alpha != currentAlpha && alpha != animEndValue) { + + final boolean blankingInProgress = mScrimInFront.getTag(TAG_KEY_ANIM_BLANK) != null; + if (mBlankScreen || blankingInProgress) { + if (!blankingInProgress) { + blankDisplay(); + } + return; + } else if (!mScreenBlankingCallbackCalled) { + // Not blanking the screen. Letting the callback know that we're ready + // to replace what was on the screen before. + if (mCallback != null) { + mCallback.onDisplayBlanked(); + mScreenBlankingCallbackCalled = true; + } + } + + final ScrimView scrimView = scrim instanceof ScrimView ? (ScrimView) scrim : null; + final boolean wantsAlphaUpdate = alpha != currentAlpha && alpha != animEndValue; + final boolean wantsTintUpdate = scrimView != null + && scrimView.getTint() != getCurrentScrimTint(scrimView); + + if (wantsAlphaUpdate || wantsTintUpdate) { if (animate) { - startScrimAnimation(scrim, alpha); + final float fromAlpha = scrimView == null ? scrim.getAlpha() + : scrimView.getViewAlpha(); + startScrimAnimation(scrim, fromAlpha, alpha); scrim.setTag(TAG_START_ALPHA, currentAlpha); scrim.setTag(TAG_END_ALPHA, alpha); } else { @@ -685,13 +657,62 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); } else { // update the alpha directly - setCurrentScrimAlpha(scrim, alpha); - updateScrimColor(scrim); + updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim)); + onFinished(); } } + } else { + onFinished(); } } + private void blankDisplay() { + final float initialAlpha = mScrimInFront.getViewAlpha(); + final int initialTint = mScrimInFront.getTint(); + ValueAnimator anim = ValueAnimator.ofFloat(0, 1); + anim.addUpdateListener(animation -> { + final float amount = (float) animation.getAnimatedValue(); + float animAlpha = MathUtils.lerp(initialAlpha, 1, amount); + int animTint = ColorUtils.blendARGB(initialTint, Color.BLACK, amount); + updateScrimColor(mScrimInFront, animAlpha, animTint); + dispatchScrimsVisible(); + }); + anim.setInterpolator(getInterpolator()); + anim.setDuration(mDozeParameters.getPulseInDuration()); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (mCallback != null) { + mCallback.onDisplayBlanked(); + mScreenBlankingCallbackCalled = true; + } + Runnable blankingCallback = () -> { + mScrimInFront.setTag(TAG_KEY_ANIM_BLANK, null); + mBlankScreen = false; + // Try again. + updateScrims(); + }; + + // Setting power states can happen after we push out the frame. Make sure we + // stay fully opaque until the power state request reaches the lower levels. + getHandler().postDelayed(blankingCallback, 100); + + } + }); + anim.start(); + mScrimInFront.setTag(TAG_KEY_ANIM_BLANK, anim); + + // Finish animation if we're already at its final state + if (initialAlpha == 1 && mScrimInFront.getTint() == Color.BLACK) { + anim.end(); + } + } + + @VisibleForTesting + protected Handler getHandler() { + return Handler.getMain(); + } + /** * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means * the heads up is in its resting space and 1 means it's fully dragged out. @@ -719,23 +740,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, return alpha * expandFactor; } - public void forceHideScrims(boolean hide, boolean animated) { - mForceHideScrims = hide; - mAnimateChange = animated; - scheduleUpdate(); - } - - public void dontAnimateBouncerChangesUntilNextFrame() { - mDontAnimateBouncerChanges = true; - } - public void setExcludedBackgroundArea(Rect area) { mScrimBehind.setExcludedArea(area); } public int getBackgroundColor() { int color = mLockColors.getMainColor(); - return Color.argb((int) (mScrimBehind.getAlpha() * Color.alpha(color)), + return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)), Color.red(color), Color.green(color), Color.blue(color)); } @@ -764,27 +775,41 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } if ((which & WallpaperManager.FLAG_SYSTEM) != 0) { mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, - ColorExtractor.TYPE_DARK, mKeyguardShowing); + ColorExtractor.TYPE_DARK, mState != ScrimState.UNLOCKED); mNeedsDrawableColorUpdate = true; scheduleUpdate(); } } - public void dump(PrintWriter pw) { - pw.println(" ScrimController:"); + @VisibleForTesting + protected WakeLock createWakeLock() { + return new DelayedWakeLock(getHandler(), + WakeLock.createPartial(mContext, "Doze")); + } + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(" ScrimController:"); + pw.print(" state:"); pw.println(mState); pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha()); pw.print(" alpha="); pw.print(mCurrentInFrontAlpha); - pw.print(" dozeAlpha="); pw.print(mDozeInFrontAlpha); pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint())); pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha()); pw.print(" alpha="); pw.print(mCurrentBehindAlpha); - pw.print(" dozeAlpha="); pw.print(mDozeBehindAlpha); pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint())); - pw.print(" mBouncerShowing="); pw.println(mBouncerShowing); pw.print(" mTracking="); pw.println(mTracking); - pw.print(" mForceHideScrims="); pw.println(mForceHideScrims); + } + + public interface Callback { + default void onStart() { + } + default void onDisplayBlanked() { + } + default void onFinished() { + } + default void onCancelled() { + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java new file mode 100644 index 000000000000..0db98f372561 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2017 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.systemui.statusbar.phone; + +import android.graphics.Color; +import android.os.Trace; + +import com.android.systemui.statusbar.ScrimView; + +/** + * Possible states of the ScrimController state machine. + */ +public enum ScrimState { + + /** + * Initial state. + */ + UNINITIALIZED, + + /** + * On the lock screen. + */ + KEYGUARD { + + @Override + public void prepare(ScrimState previousState) { + // DisplayPowerManager will blank the screen, we'll just + // set our scrim to black in this frame to avoid flickering and + // fade it out afterwards. + mBlankScreen = previousState == ScrimState.AOD; + if (previousState == ScrimState.AOD) { + updateScrimColor(mScrimInFront, 1, Color.BLACK); + } + mCurrentBehindAlpha = mScrimBehindAlphaKeyguard; + mCurrentInFrontAlpha = 0; + } + }, + + /** + * Showing password challenge. + */ + BOUNCER { + @Override + public void prepare(ScrimState previousState) { + mCurrentBehindAlpha = ScrimController.SCRIM_BEHIND_ALPHA_UNLOCKING; + mCurrentInFrontAlpha = ScrimController.SCRIM_IN_FRONT_ALPHA_LOCKED; + } + }, + + /** + * Changing screen brightness from quick settings. + */ + BRIGHTNESS_MIRROR { + @Override + public void prepare(ScrimState previousState) { + mCurrentBehindAlpha = 0; + mCurrentInFrontAlpha = 0; + } + }, + + /** + * Always on display or screen off. + */ + AOD { + @Override + public void prepare(ScrimState previousState) { + if (previousState == ScrimState.PULSING) { + updateScrimColor(mScrimInFront, 1, Color.BLACK); + } + final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn(); + mBlankScreen = previousState == ScrimState.PULSING; + mCurrentBehindAlpha = 1; + mCurrentInFrontAlpha = alwaysOnEnabled ? mAodFrontScrimAlpha : 1f; + mCurrentInFrontTint = Color.BLACK; + mCurrentBehindTint = Color.BLACK; + // DisplayPowerManager will blank the screen for us, we just need + // to set our state. + mAnimateChange = false; + } + }, + + /** + * When phone wakes up because you received a notification. + */ + PULSING { + @Override + public void prepare(ScrimState previousState) { + mCurrentBehindAlpha = 1; + mCurrentInFrontAlpha = 0; + mCurrentInFrontTint = Color.BLACK; + mCurrentBehindTint = Color.BLACK; + mBlankScreen = true; + updateScrimColor(mScrimInFront, 1, Color.BLACK); + } + }, + + /** + * Unlocked on top of an app (launcher or any other activity.) + */ + UNLOCKED { + @Override + public void prepare(ScrimState previousState) { + mCurrentBehindAlpha = 0; + mCurrentInFrontAlpha = 0; + mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION; + + if (previousState == ScrimState.AOD) { + // Fade from black to transparent when coming directly from AOD + updateScrimColor(mScrimInFront, 1, Color.BLACK); + updateScrimColor(mScrimBehind, 1, Color.BLACK); + // Scrims should still be black at the end of the transition. + mCurrentInFrontTint = Color.BLACK; + mCurrentBehindTint = Color.BLACK; + mBlankScreen = true; + } else { + // Scrims should still be black at the end of the transition. + mCurrentInFrontTint = Color.TRANSPARENT; + mCurrentBehindTint = Color.TRANSPARENT; + mBlankScreen = false; + } + } + }; + + boolean mBlankScreen = false; + long mAnimationDuration = ScrimController.ANIMATION_DURATION; + int mCurrentInFrontTint = Color.TRANSPARENT; + int mCurrentBehindTint = Color.TRANSPARENT; + boolean mAnimateChange = true; + float mCurrentInFrontAlpha; + float mCurrentBehindAlpha; + float mAodFrontScrimAlpha; + float mScrimBehindAlphaKeyguard; + ScrimView mScrimInFront; + ScrimView mScrimBehind; + DozeParameters mDozeParameters; + + public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters) { + mScrimInFront = scrimInFront; + mScrimBehind = scrimBehind; + mDozeParameters = dozeParameters; + } + + public void prepare(ScrimState previousState) { + } + + public float getFrontAlpha() { + return mCurrentInFrontAlpha; + } + + public float getBehindAlpha() { + return mCurrentBehindAlpha; + } + + public int getFrontTint() { + return mCurrentInFrontTint; + } + + public int getBehindTint() { + return mCurrentBehindTint; + } + + public long getAnimationDuration() { + return mAnimationDuration; + } + + public boolean getBlanksScreen() { + return mBlankScreen; + } + + public void updateScrimColor(ScrimView scrim, float alpha, int tint) { + Trace.traceCounter(Trace.TRACE_TAG_APP, + scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha", + (int) (alpha * 255)); + + Trace.traceCounter(Trace.TRACE_TAG_APP, + scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint", + Color.alpha(tint)); + + scrim.setTint(tint); + scrim.setViewAlpha(alpha); + } + + public boolean getAnimateChange() { + return mAnimateChange; + } + + public void setAodFrontScrimAlpha(float aodFrontScrimAlpha) { + mAodFrontScrimAlpha = aodFrontScrimAlpha; + } + + public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) { + mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard; + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 43cc0f771a97..a5609da78abb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -238,6 +238,7 @@ import com.android.systemui.statusbar.stack.NotificationStackScrollLayout .OnChildLocationsChangedListener; import com.android.systemui.util.NotificationChannels; import com.android.systemui.util.leak.LeakDetector; +import com.android.systemui.util.wakelock.WakeLock; import com.android.systemui.volume.VolumeComponent; import java.io.FileDescriptor; @@ -386,6 +387,7 @@ public class StatusBar extends SystemUI implements DemoMode, private VolumeComponent mVolumeComponent; private BrightnessMirrorController mBrightnessMirrorController; + private boolean mBrightnessMirrorVisible; protected FingerprintUnlockController mFingerprintUnlockController; private LightBarController mLightBarController; protected LockscreenWallpaper mLockscreenWallpaper; @@ -646,6 +648,31 @@ public class StatusBar extends SystemUI implements DemoMode, } }; + // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over, + // this animation is tied to the scrim for historic reasons. + // TODO: notify when keyguard has faded away instead of the scrim. + private final ScrimController.Callback mUnlockScrimCallback = new ScrimController + .Callback() { + @Override + public void onFinished() { + notifyKeyguardState(); + } + + @Override + public void onCancelled() { + notifyKeyguardState(); + } + + private void notifyKeyguardState() { + if (mStatusBarKeyguardViewManager == null) { + Log.w(TAG, "Tried to notify keyguard visibility when " + + "mStatusBarKeyguardViewManager was null"); + return; + } + mStatusBarKeyguardViewManager.onKeyguardFadedAway(); + } + }; + private NotificationMessagingUtil mMessagingUtil; private KeyguardUserSwitcher mKeyguardUserSwitcher; private UserSwitcherController mUserSwitcherController; @@ -1045,7 +1072,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (mStatusBarWindowManager != null) { mStatusBarWindowManager.setScrimsVisible(scrimsVisible); } - }); + }, new DozeParameters(mContext)); if (mScrimSrcModeEnabled) { Runnable runnable = () -> { boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; @@ -1081,7 +1108,10 @@ public class StatusBar extends SystemUI implements DemoMode, final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this, mIconController); mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow, - mScrimController); + (visible) -> { + mBrightnessMirrorVisible = visible; + updateScrimController(); + }); fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> { QS qs = (QS) f; if (qs instanceof QSFragment) { @@ -1457,8 +1487,7 @@ public class StatusBar extends SystemUI implements DemoMode, mDozeScrimController, keyguardViewMediator, mScrimController, this, UnlockMethodCache.getInstance(mContext)); mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, - getBouncerContainer(), mScrimController, - mFingerprintUnlockController); + getBouncerContainer(), mFingerprintUnlockController); mKeyguardIndicationController .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); @@ -2640,7 +2669,7 @@ public class StatusBar extends SystemUI implements DemoMode, } public boolean isPulsing() { - return mDozeScrimController.isPulsing(); + return mDozeScrimController != null && mDozeScrimController.isPulsing(); } @Override @@ -3348,7 +3377,7 @@ public class StatusBar extends SystemUI implements DemoMode, } if (mScrimController != null) { - mScrimController.dump(pw); + mScrimController.dump(fd, pw, args); } if (DUMPTRUCK) { @@ -4081,7 +4110,6 @@ public class StatusBar extends SystemUI implements DemoMode, releaseGestureWakeLock(); runLaunchTransitionEndRunnable(); mLaunchTransitionFadingAway = false; - mScrimController.forceHideScrims(false /* hide */, false /* animated */); updateMediaMetaData(true /* metaDataChanged */, true); } @@ -4114,7 +4142,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (beforeFading != null) { beforeFading.run(); } - mScrimController.forceHideScrims(true /* hide */, false /* animated */); + updateScrimController(); updateMediaMetaData(false, true); mNotificationPanel.setAlpha(1); mStackScroller.setParentNotFullyVisible(true); @@ -4145,6 +4173,13 @@ public class StatusBar extends SystemUI implements DemoMode, .setStartDelay(0) .setDuration(FADE_KEYGUARD_DURATION_PULSING) .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + hideKeyguard(); + mStatusBarKeyguardViewManager.onKeyguardFadedAway(); + } + }) .start(); } @@ -4152,7 +4187,6 @@ public class StatusBar extends SystemUI implements DemoMode, * Plays the animation when an activity that was occluding Keyguard goes away. */ public void animateKeyguardUnoccluding() { - mScrimController.animateKeyguardUnoccluding(500); mNotificationPanel.setExpandedFraction(0f); animateExpandNotificationsPanel(); } @@ -4340,11 +4374,6 @@ public class StatusBar extends SystemUI implements DemoMode, mAmbientIndicationContainer.setVisibility(View.INVISIBLE); } } - if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { - mScrimController.setKeyguardShowing(true); - } else { - mScrimController.setKeyguardShowing(false); - } mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); updateTheme(); updateDozingState(); @@ -4352,6 +4381,7 @@ public class StatusBar extends SystemUI implements DemoMode, updateStackScrollerState(goingToFullShade, fromShadeLocked); updateNotifications(); checkBarModes(); + updateScrimController(); updateMediaMetaData(false, mState != StatusBarState.KEYGUARD); mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), mUnlockMethodCache.isMethodSecure(), @@ -4415,11 +4445,10 @@ public class StatusBar extends SystemUI implements DemoMode, boolean animate = !mDozing && mDozeServiceHost.shouldAnimateWakeup(); mNotificationPanel.setDozing(mDozing, animate); mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); - mScrimController.setDozing(mDozing); + mDozeScrimController.setDozing(mDozing); mKeyguardIndicationController.setDozing(mDozing); mNotificationPanel.setDark(mDozing, animate); updateQsExpansionEnabled(); - mDozeScrimController.setDozing(mDozing, animate); updateRowStates(); Trace.endSection(); } @@ -4914,6 +4943,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing); updateHideIconsForBouncer(true /* animate */); recomputeDisableFlags(true /* animate */); + updateScrimController(); } public void cancelCurrentTouch() { @@ -4965,12 +4995,10 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller.setAnimationsEnabled(true); mVisualStabilityManager.setScreenOn(true); mNotificationPanel.setTouchDisabled(false); - - maybePrepareWakeUpFromAod(); - mDozeServiceHost.stopDozing(); updateVisibleToUser(); updateIsKeyguard(); + updateScrimController(); } }; @@ -4980,18 +5008,16 @@ public class StatusBar extends SystemUI implements DemoMode, mFalsingManager.onScreenTurningOn(); mNotificationPanel.onScreenTurningOn(); - maybePrepareWakeUpFromAod(); - if (mLaunchCameraOnScreenTurningOn) { mNotificationPanel.launchCamera(false, mLastCameraLaunchSource); mLaunchCameraOnScreenTurningOn = false; } + + updateScrimController(); } @Override public void onScreenTurnedOn() { - mScrimController.wakeUpFromAod(); - mDozeScrimController.onScreenTurnedOn(); } @Override @@ -5009,13 +5035,6 @@ public class StatusBar extends SystemUI implements DemoMode, return mWakefulnessLifecycle.getWakefulness(); } - private void maybePrepareWakeUpFromAod() { - int wakefulness = mWakefulnessLifecycle.getWakefulness(); - if (mDozing && wakefulness == WAKEFULNESS_WAKING && !isPulsing()) { - mScrimController.prepareWakeUpFromAod(); - } - } - private void vibrateForCameraGesture() { // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep. mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */); @@ -5098,12 +5117,12 @@ public class StatusBar extends SystemUI implements DemoMode, if (!mDeviceInteractive) { // Avoid flickering of the scrim when we instant launch the camera and the bouncer // comes on. - mScrimController.dontAnimateBouncerChangesUntilNextFrame(); mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); } if (isScreenTurningOnOrOn()) { if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera"); mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source); + updateScrimController(); } else { // We need to defer the camera launch until the screen comes on, since otherwise // we will dismiss us too early since we are waiting on an activity to be drawn and @@ -5145,15 +5164,16 @@ public class StatusBar extends SystemUI implements DemoMode, private void updateDozing() { Trace.beginSection("StatusBar#updateDozing"); // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked. - mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD + boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD || mFingerprintUnlockController.getMode() == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; // When in wake-and-unlock we may not have received a change to mState // but we still should not be dozing, manually set to false. if (mFingerprintUnlockController.getMode() == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) { - mDozing = false; + dozing = false; } + mDozing = dozing; mStatusBarWindowManager.setDozing(mDozing); mStatusBarKeyguardViewManager.setDozing(mDozing); if (mAmbientIndicationContainer instanceof DozeReceiver) { @@ -5163,6 +5183,24 @@ public class StatusBar extends SystemUI implements DemoMode, Trace.endSection(); } + public void updateScrimController() { + if (mBouncerShowing) { + mScrimController.transitionTo(ScrimState.BOUNCER); + } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) { + mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); + } else if (mBrightnessMirrorVisible) { + mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR); + } else if (isPulsing()) { + // Handled in DozeScrimController#setPulsing + } else if (mDozing) { + mScrimController.transitionTo(ScrimState.AOD); + } else if (mIsKeyguard) { + mScrimController.transitionTo(ScrimState.KEYGUARD); + } else { + mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); + } + } + public boolean isKeyguardShowing() { if (mStatusBarKeyguardViewManager == null) { Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true"); @@ -5222,7 +5260,6 @@ public class StatusBar extends SystemUI implements DemoMode, } mDozeScrimController.pulse(new PulseCallback() { - @Override public void onPulseStarted() { callback.onPulseStarted(); @@ -5307,11 +5344,6 @@ public class StatusBar extends SystemUI implements DemoMode, } @Override - public void abortPulsing() { - mDozeScrimController.abortPulsing(); - } - - @Override public void extendPulse() { mDozeScrimController.extendPulse(); } @@ -5347,7 +5379,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void setAodDimmingScrim(float scrimOpacity) { - mDozeScrimController.setAodDimmingScrim(scrimOpacity); + ScrimState.AOD.setAodFrontScrimAlpha(scrimOpacity); } public void dispatchDoubleTap(float viewX, float viewY) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index bcde556a5954..ef05bbb4fe3d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -24,7 +24,6 @@ import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Bundle; import android.os.SystemClock; -import android.os.Trace; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; @@ -71,17 +70,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb protected final Context mContext; private final StatusBarWindowManager mStatusBarWindowManager; - private final boolean mDisplayBlanksAfterDoze; protected LockPatternUtils mLockPatternUtils; protected ViewMediatorCallback mViewMediatorCallback; protected StatusBar mStatusBar; - private ScrimController mScrimController; private FingerprintUnlockController mFingerprintUnlockController; private ViewGroup mContainer; - private boolean mScreenTurnedOn; protected KeyguardBouncer mBouncer; protected boolean mShowing; protected boolean mOccluded; @@ -95,12 +91,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastBouncerDismissible; protected boolean mLastRemoteInputActive; private boolean mLastDozing; - private boolean mLastDeferScrimFadeOut; private int mLastFpMode; private OnDismissAction mAfterKeyguardGoneAction; private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>(); - private boolean mDeferScrimFadeOut; // Dismiss action to be launched when we stop dozing or the keyguard is gone. private DismissWithActionRequest mPendingWakeupAction; @@ -125,18 +119,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLockPatternUtils = lockPatternUtils; mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback); - mDisplayBlanksAfterDoze = context.getResources().getBoolean( - com.android.internal.R.bool.config_displayBlanksAfterDoze); } public void registerStatusBar(StatusBar statusBar, ViewGroup container, - ScrimController scrimController, FingerprintUnlockController fingerprintUnlockController, DismissCallbackRegistry dismissCallbackRegistry) { mStatusBar = statusBar; mContainer = container; - mScrimController = scrimController; mFingerprintUnlockController = fingerprintUnlockController; mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry); @@ -149,7 +139,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void show(Bundle options) { mShowing = true; mStatusBarWindowManager.setKeyguardShowing(true); - mScrimController.abortKeyguardFadingOut(); reset(true /* hideBouncerWhenShowing */); } @@ -253,15 +242,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } public void onScreenTurnedOn() { - Trace.beginSection("StatusBarKeyguardViewManager#onScreenTurnedOn"); - mScreenTurnedOn = true; - if (mDeferScrimFadeOut) { - mDeferScrimFadeOut = false; - animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS, - true /* skipFirstFrame */); - updateStates(); - } - Trace.endSection(); + // TODO: remove } @Override @@ -285,7 +266,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } public void onScreenTurnedOff() { - mScreenTurnedOn = false; + // TODO: remove } public void notifyDeviceWakeUpRequested() { @@ -374,10 +355,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBarWindowManager.setKeyguardFadingAway(true); hideBouncer(true /* destroyView */); updateStates(); - mScrimController.animateKeyguardFadingOut( - StatusBar.FADE_KEYGUARD_START_DELAY, - StatusBar.FADE_KEYGUARD_DURATION, null, - false /* skipFirstFrame */); } }, new Runnable() { @Override @@ -400,36 +377,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mFingerprintUnlockController.startKeyguardFadingAway(); hideBouncer(true /* destroyView */); if (wakeUnlockPulsing) { - mStatusBarWindowManager.setKeyguardFadingAway(true); mStatusBar.fadeKeyguardWhilePulsing(); - animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration, - mStatusBar::hideKeyguard, false /* skipFirstFrame */); + wakeAndUnlockDejank(); } else { mFingerprintUnlockController.startKeyguardFadingAway(); mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration); boolean staying = mStatusBar.hideKeyguard(); if (!staying) { mStatusBarWindowManager.setKeyguardFadingAway(true); - if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK) { - boolean turnedOnSinceAuth = - mFingerprintUnlockController.hasScreenTurnedOnSinceAuthenticating(); - if (!mScreenTurnedOn || mDisplayBlanksAfterDoze && !turnedOnSinceAuth) { - // Not ready to animate yet; either because the screen is not on yet, - // or it is on but will turn off before waking out of doze. - mDeferScrimFadeOut = true; - } else { - - // Screen is already on, don't defer with fading out. - animateScrimControllerKeyguardFadingOut(0, - WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS, - true /* skipFirstFrame */); - } - } else { - animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration, - false /* skipFirstFrame */); - } + wakeAndUnlockDejank(); } else { - mScrimController.animateGoingToFullShade(delay, fadeoutDuration); mStatusBar.finishKeyguardFadingAway(); mFingerprintUnlockController.finishKeyguardFadingAway(); } @@ -449,30 +406,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer.prepare(); } - private void animateScrimControllerKeyguardFadingOut(long delay, long duration, - boolean skipFirstFrame) { - animateScrimControllerKeyguardFadingOut(delay, duration, null /* endRunnable */, - skipFirstFrame); + public void onKeyguardFadedAway() { + mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false), + 100); + mStatusBar.finishKeyguardFadingAway(); + mFingerprintUnlockController.finishKeyguardFadingAway(); + WindowManagerGlobal.getInstance().trimMemory( + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); + } - private void animateScrimControllerKeyguardFadingOut(long delay, long duration, - final Runnable endRunnable, boolean skipFirstFrame) { - Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "Fading out", 0); - mScrimController.animateKeyguardFadingOut(delay, duration, new Runnable() { - @Override - public void run() { - if (endRunnable != null) { - endRunnable.run(); - } - mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false), - 100); - mStatusBar.finishKeyguardFadingAway(); - mFingerprintUnlockController.finishKeyguardFadingAway(); - WindowManagerGlobal.getInstance().trimMemory( - ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); - Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "Fading out", 0); - } - }, skipFirstFrame); + private void wakeAndUnlockDejank() { if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK && LatencyTracker.isEnabled(mContext)) { DejankUtils.postAfterTraversal(() -> @@ -593,7 +537,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { mStatusBarWindowManager.setBouncerShowing(bouncerShowing); mStatusBar.setBouncerShowing(bouncerShowing); - mScrimController.setBouncerShowing(bouncerShowing); } KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); @@ -611,7 +554,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastBouncerDismissible = bouncerDismissible; mLastRemoteInputActive = remoteInputActive; mLastDozing = mDozing; - mLastDeferScrimFadeOut = mDeferScrimFadeOut; mLastFpMode = mFingerprintUnlockController.getMode(); mStatusBar.onKeyguardViewManagerStatesUpdated(); } @@ -624,7 +566,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean keyguardShowing = mShowing && !mOccluded; boolean hideWhileDozing = mDozing && fpMode != MODE_WAKE_AND_UNLOCK_PULSING; return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing() - || mRemoteInputActive) && !mDeferScrimFadeOut; + || mRemoteInputActive); } /** @@ -634,7 +576,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean keyguardShowing = mLastShowing && !mLastOccluded; boolean hideWhileDozing = mLastDozing && mLastFpMode != MODE_WAKE_AND_UNLOCK_PULSING; return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing - || mLastRemoteInputActive) && !mLastDeferScrimFadeOut; + || mLastRemoteInputActive); } public boolean shouldDismissOnMenuPressed() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index b0553d72dd49..a011952f1476 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.policy; +import android.annotation.NonNull; import android.util.ArraySet; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; @@ -26,46 +27,47 @@ import android.widget.FrameLayout; import com.android.internal.util.Preconditions; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBarWindowView; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; +import java.util.function.Consumer; + /** * Controls showing and hiding of the brightness mirror. */ public class BrightnessMirrorController implements CallbackController<BrightnessMirrorController.BrightnessMirrorListener> { - private final NotificationStackScrollLayout mStackScroller; - public long TRANSITION_DURATION_OUT = 150; - public long TRANSITION_DURATION_IN = 200; + private final static long TRANSITION_DURATION_OUT = 150; + private final static long TRANSITION_DURATION_IN = 200; private final StatusBarWindowView mStatusBarWindow; - private final ScrimController mScrimController; + private final NotificationStackScrollLayout mStackScroller; + private final Consumer<Boolean> mVisibilityCallback; private final View mNotificationPanel; private final ArraySet<BrightnessMirrorListener> mBrightnessMirrorListeners = new ArraySet<>(); private final int[] mInt2Cache = new int[2]; private View mBrightnessMirror; public BrightnessMirrorController(StatusBarWindowView statusBarWindow, - ScrimController scrimController) { + @NonNull Consumer<Boolean> visibilityCallback) { mStatusBarWindow = statusBarWindow; mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror); mNotificationPanel = statusBarWindow.findViewById(R.id.notification_panel); mStackScroller = statusBarWindow.findViewById(R.id.notification_stack_scroller); - mScrimController = scrimController; + mVisibilityCallback = visibilityCallback; } public void showMirror() { mBrightnessMirror.setVisibility(View.VISIBLE); mStackScroller.setFadingOut(true); - mScrimController.forceHideScrims(true /* hide */, true /* animated */); + mVisibilityCallback.accept(true); outAnimation(mNotificationPanel.animate()) .withLayer(); } public void hideMirror() { - mScrimController.forceHideScrims(false /* hide */, true /* animated */); + mVisibilityCallback.accept(false); inAnimation(mNotificationPanel.animate()) .withLayer() .withEndAction(() -> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java index b0c9f32873ff..1c104cffc3c1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java @@ -19,12 +19,13 @@ package com.android.systemui.doze; import android.annotation.NonNull; import android.app.PendingIntent; +import com.android.systemui.util.wakelock.WakeLock; + /** * A rudimentary fake for DozeHost. */ class DozeHostFake implements DozeHost { Callback callback; - boolean pulseAborted; boolean pulseExtended; boolean animateWakeup; boolean dozing; @@ -92,11 +93,6 @@ class DozeHostFake implements DozeHost { } @Override - public void abortPulsing() { - pulseAborted = true; - } - - @Override public void extendPulse() { pulseExtended = true; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java index 4c3bf1081792..a4bcc69c0e10 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java @@ -86,9 +86,9 @@ public class ScrimViewTest extends LeakCheckedTest { @Test public void testSetViewAlpha_propagatesToDrawable() { - float alpha = 0.5f; + final float alpha = 0.5f; mView.setViewAlpha(alpha); - assertEquals(mView.getViewAlpha(), alpha); + assertEquals("View alpha did not propagate to drawable", alpha, mView.getViewAlpha()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java new file mode 100644 index 000000000000..ca2f713d2b6f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017 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.systemui.statusbar.phone; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.os.Debug; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.doze.DozeHost; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class DozeScrimControllerTest extends SysuiTestCase { + + private ScrimController mScrimController; + private DozeScrimController mDozeScrimController; + + @Before + public void setup() { + mScrimController = mock(ScrimController.class); + // Make sure callbacks will be invoked to complete the lifecycle. + doAnswer(invocationOnMock -> { + ScrimController.Callback callback = invocationOnMock.getArgument(1); + callback.onStart(); + callback.onDisplayBlanked(); + callback.onFinished(); + return null; + }).when(mScrimController).transitionTo(any(ScrimState.class), + any(ScrimController.Callback.class)); + + mDozeScrimController = new DozeScrimController(mScrimController, getContext()); + mDozeScrimController.setDozing(true); + } + + @Test + public void changesScrimControllerState() { + mDozeScrimController.pulse(mock(DozeHost.PulseCallback.class), 0); + verify(mScrimController).transitionTo(eq(ScrimState.PULSING), + any(ScrimController.Callback.class)); + } + + @Test + public void callsPulseCallback() { + DozeHost.PulseCallback callback = mock(DozeHost.PulseCallback.class); + mDozeScrimController.pulse(callback, 0); + + verify(callback).onPulseStarted(); + mDozeScrimController.pulseOutNow(); + verify(callback).onPulseFinished(); + } + + @Test + public void secondPulseIsSuppressed() { + DozeHost.PulseCallback callback1 = mock(DozeHost.PulseCallback.class); + DozeHost.PulseCallback callback2 = mock(DozeHost.PulseCallback.class); + mDozeScrimController.pulse(callback1, 0); + mDozeScrimController.pulse(callback2, 0); + + verify(callback1, never()).onPulseFinished(); + verify(callback2).onPulseFinished(); + } + + @Test + public void suppressesPulseIfNotDozing() { + mDozeScrimController.setDozing(false); + DozeHost.PulseCallback callback = mock(DozeHost.PulseCallback.class); + mDozeScrimController.pulse(callback, 0); + + verify(callback).onPulseFinished(); + } +} 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 new file mode 100644 index 000000000000..b9f695be90cf --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2017 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.systemui.statusbar.phone; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.animation.Animator; +import android.graphics.Color; +import android.os.Handler; +import android.os.Looper; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.View; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.ScrimView; +import com.android.systemui.util.wakelock.WakeLock; +import com.android.systemui.utils.os.FakeHandler; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.function.Consumer; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class ScrimControllerTest extends SysuiTestCase { + + private SynchronousScrimController mScrimController; + private ScrimView mScrimBehind; + private ScrimView mScrimInFront; + private View mHeadsUpScrim; + private Consumer<Boolean> mScrimVisibilityCallback; + private Boolean mScrimVisibile; + private LightBarController mLightBarController; + private DozeParameters mDozeParamenters; + private WakeLock mWakeLock; + private boolean mAlwaysOnEnabled; + + @Before + public void setup() { + mLightBarController = mock(LightBarController.class); + mScrimBehind = new ScrimView(getContext()); + mScrimInFront = new ScrimView(getContext()); + mHeadsUpScrim = mock(View.class); + mWakeLock = mock(WakeLock.class); + mAlwaysOnEnabled = true; + mScrimVisibilityCallback = (Boolean visible) -> mScrimVisibile = visible; + mDozeParamenters = mock(DozeParameters.class); + when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled); + mScrimController = new SynchronousScrimController(mLightBarController, mScrimBehind, + mScrimInFront, mHeadsUpScrim, mScrimVisibilityCallback, mDozeParamenters); + } + + @Test + public void initialState() { + Assert.assertEquals("ScrimController should start initialized", + mScrimController.getState(), ScrimState.UNINITIALIZED); + } + + @Test + public void transitionToKeyguard() { + mScrimController.transitionTo(ScrimState.KEYGUARD); + mScrimController.finishAnimationsImmediately(); + // Front scrim should be transparent + // Back scrim should be visible without tint + assertScrimVisibility(false /* front */, true /* behind */); + assertScrimTint(mScrimBehind, false /* tinted */); + } + + @Test + public void transitionToAod() { + mScrimController.transitionTo(ScrimState.AOD); + mScrimController.finishAnimationsImmediately(); + // Front scrim should be transparent + // Back scrim should be visible with tint + assertScrimVisibility(false /* front */, true /* behind */); + assertScrimTint(mScrimBehind, true /* tinted */); + assertScrimTint(mScrimInFront, true /* tinted */); + } + + @Test + public void transitionToPulsing() { + mScrimController.transitionTo(ScrimState.PULSING); + mScrimController.finishAnimationsImmediately(); + // Front scrim should be transparent + // Back scrim should be visible with tint + // Pulse callback should have been invoked + assertScrimVisibility(false /* front */, true /* behind */); + assertScrimTint(mScrimBehind, true /* tinted */); + } + + @Test + public void transitionToBouncer() { + mScrimController.transitionTo(ScrimState.BOUNCER); + mScrimController.finishAnimationsImmediately(); + // Front scrim should be transparent + // Back scrim should be visible without tint + assertScrimVisibility(true /* front */, true /* behind */); + assertScrimTint(mScrimBehind, false /* tinted */); + } + + @Test + public void transitionToUnlocked() { + mScrimController.transitionTo(ScrimState.UNLOCKED); + mScrimController.finishAnimationsImmediately(); + // Front scrim should be transparent + // Back scrim should be transparent + assertScrimVisibility(false /* front */, false /* behind */); + assertScrimTint(mScrimBehind, false /* tinted */); + assertScrimTint(mScrimInFront, false /* tinted */); + + // Back scrim should be visible after start dragging + mScrimController.setPanelExpansion(0.5f); + assertScrimVisibility(false /* front */, true /* behind */); + } + + @Test + public void transitionToUnlockedFromAod() { + // Simulate unlock with fingerprint + mScrimController.transitionTo(ScrimState.AOD); + mScrimController.finishAnimationsImmediately(); + mScrimController.transitionTo(ScrimState.UNLOCKED); + // Immediately tinted after the transition starts + assertScrimTint(mScrimInFront, true /* tinted */); + assertScrimTint(mScrimBehind, true /* tinted */); + mScrimController.finishAnimationsImmediately(); + // Front scrim should be transparent + // Back scrim should be transparent + // Neither scrims should be tinted anymore after the animation. + assertScrimVisibility(false /* front */, false /* behind */); + assertScrimTint(mScrimInFront, false /* tinted */); + assertScrimTint(mScrimBehind, false /* tinted */); + } + + @Test + public void scrimBlanksBeforeLeavingAoD() { + // Simulate unlock with fingerprint + mScrimController.transitionTo(ScrimState.AOD); + mScrimController.finishAnimationsImmediately(); + mScrimController.transitionTo(ScrimState.UNLOCKED, + new ScrimController.Callback() { + @Override + public void onDisplayBlanked() { + // Front scrim should be black in the middle of the transition + Assert.assertTrue("Scrim should be visible during transition. Alpha: " + + mScrimInFront.getViewAlpha(), mScrimInFront.getViewAlpha() > 0); + assertScrimTint(mScrimInFront, true /* tinted */); + Assert.assertTrue("Scrim should be visible during transition.", + mScrimVisibile); + } + }); + mScrimController.finishAnimationsImmediately(); + } + + @Test + public void testScrimCallback() { + int[] callOrder = {0, 0, 0}; + int[] currentCall = {0}; + mScrimController.transitionTo(ScrimState.AOD, new ScrimController.Callback() { + @Override + public void onStart() { + callOrder[0] = ++currentCall[0]; + } + + @Override + public void onDisplayBlanked() { + callOrder[1] = ++currentCall[0]; + } + + @Override + public void onFinished() { + callOrder[2] = ++currentCall[0]; + } + }); + mScrimController.finishAnimationsImmediately(); + Assert.assertEquals("onStart called in wrong order", 1, callOrder[0]); + Assert.assertEquals("onDisplayBlanked called in wrong order", 2, callOrder[1]); + Assert.assertEquals("onFinished called in wrong order", 3, callOrder[2]); + } + + @Test + public void testScrimCallbacksWithoutAmbientDisplay() { + mAlwaysOnEnabled = false; + testScrimCallback(); + } + + @Test + public void testScrimCallbackCancelled() { + boolean[] cancelledCalled = {false}; + mScrimController.transitionTo(ScrimState.AOD, new ScrimController.Callback() { + @Override + public void onCancelled() { + cancelledCalled[0] = true; + } + }); + mScrimController.transitionTo(ScrimState.PULSING); + Assert.assertTrue("onCancelled should have been called", cancelledCalled[0]); + } + + @Test + public void testHoldsWakeLock() { + mScrimController.transitionTo(ScrimState.AOD); + verify(mWakeLock, times(1)).acquire(); + verify(mWakeLock, never()).release(); + mScrimController.finishAnimationsImmediately(); + verify(mWakeLock, times(1)).release(); + } + + private void assertScrimTint(ScrimView scrimView, boolean tinted) { + final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT; + final String name = scrimView == mScrimInFront ? "front" : "back"; + Assert.assertEquals("Tint test failed at state " + mScrimController.getState() + +" with scrim: " + name + " and tint: " + Integer.toHexString(scrimView.getTint()), + tinted, viewIsTinted); + } + + private void assertScrimVisibility(boolean inFront, boolean behind) { + Assert.assertEquals("Unexpected front scrim visibility. Alpha is " + + mScrimInFront.getViewAlpha(), inFront, mScrimInFront.getViewAlpha() > 0); + Assert.assertEquals("Unexpected back scrim visibility. Alpha is " + + mScrimBehind.getViewAlpha(), behind, mScrimBehind.getViewAlpha() > 0); + Assert.assertEquals("Invalid visibility.", inFront || behind, mScrimVisibile); + } + + /** + * Special version of ScrimController where animations have 0 duration for test purposes. + */ + private class SynchronousScrimController extends ScrimController { + + private FakeHandler mHandler; + + public SynchronousScrimController(LightBarController lightBarController, + ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim, + Consumer<Boolean> scrimVisibleListener, DozeParameters dozeParameters) { + super(lightBarController, scrimBehind, scrimInFront, headsUpScrim, + scrimVisibleListener, dozeParameters); + mHandler = new FakeHandler(Looper.myLooper()); + } + + public void finishAnimationsImmediately() { + boolean[] animationFinished = {false}; + setOnAnimationFinished(()-> animationFinished[0] = true); + + // Execute code that will trigger animations. + onPreDraw(); + + // Force finish screen blanking. + endAnimation(mScrimInFront, TAG_KEY_ANIM_BLANK); + mHandler.dispatchQueuedMessages(); + // Force finish all animations. + endAnimation(mScrimBehind, TAG_KEY_ANIM); + endAnimation(mScrimInFront, TAG_KEY_ANIM); + + if (!animationFinished[0]) { + throw new IllegalStateException("Animation never finished"); + } + } + + private void endAnimation(ScrimView scrimView, int tag) { + Animator animator = (Animator) scrimView.getTag(tag); + if (animator != null) { + animator.end(); + } + } + + @Override + protected Handler getHandler() { + return mHandler; + } + + @Override + protected WakeLock createWakeLock() { + return mWakeLock; + } + } + +} |