blob: 945a9db7c836b81b756418306f6e812215343760 [file] [log] [blame]
Jorim Jaggiecc798e2014-05-26 18:14:37 +02001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070022import android.annotation.IntDef;
Lucas Dupin82aa1632017-12-13 00:13:57 -080023import android.app.AlarmManager;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070024import android.graphics.Color;
Anthony Chene658cc22017-04-27 11:17:35 -070025import android.graphics.drawable.Drawable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080026import android.os.Handler;
Adrian Roosa5c63222017-07-27 16:33:39 +020027import android.os.Trace;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080028import android.util.Log;
Lucas Dupina0bf8512017-05-24 17:04:47 -070029import android.util.MathUtils;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020030import android.view.View;
31import android.view.ViewTreeObserver;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020032import android.view.animation.DecelerateInterpolator;
33import android.view.animation.Interpolator;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070034
Lucas Dupin9e3fa102017-11-08 17:16:55 -080035import com.android.internal.annotations.VisibleForTesting;
Lucas Dupine2292a92017-07-06 14:35:30 -070036import com.android.internal.colorextraction.ColorExtractor;
37import com.android.internal.colorextraction.ColorExtractor.GradientColors;
38import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
Lucas Dupin9324aa92017-07-26 20:29:38 -070039import com.android.internal.graphics.ColorUtils;
Yohei Yukawa795f0102018-04-13 14:55:30 -070040import com.android.internal.util.function.TriConsumer;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070041import com.android.keyguard.KeyguardUpdateMonitor;
Lucas Dupinf8463ee2018-06-11 16:18:15 -070042import com.android.keyguard.KeyguardUpdateMonitorCallback;
Lucas Dupinfc6ba372019-10-01 15:21:16 -070043import com.android.systemui.DejankUtils;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080044import com.android.systemui.Dumpable;
John Spurlockbf370992014-06-17 13:58:31 -040045import com.android.systemui.R;
Lucas Dupin1ead7fc2017-05-24 14:14:44 -070046import com.android.systemui.colorextraction.SysuiColorExtractor;
Jerry Chang50c5da42019-10-16 17:21:07 +080047import com.android.systemui.dock.DockManager;
Selim Cineka0fad3b2014-09-19 17:20:05 +020048import com.android.systemui.statusbar.ScrimView;
Rohan Shah20790b82018-07-02 17:21:04 -070049import com.android.systemui.statusbar.notification.stack.ViewState;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040050import com.android.systemui.statusbar.policy.KeyguardStateController;
Lucas Dupin82aa1632017-12-13 00:13:57 -080051import com.android.systemui.util.AlarmTimeout;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080052import com.android.systemui.util.wakelock.DelayedWakeLock;
53import com.android.systemui.util.wakelock.WakeLock;
John Spurlockbf370992014-06-17 13:58:31 -040054
Lucas Dupin9e3fa102017-11-08 17:16:55 -080055import java.io.FileDescriptor;
Adrian Roosba7ca592017-08-15 17:48:05 +020056import java.io.PrintWriter;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070057import java.lang.annotation.Retention;
58import java.lang.annotation.RetentionPolicy;
Adrian Roosa5c63222017-07-27 16:33:39 +020059import java.util.function.Consumer;
60
Dave Mankoffa8749962019-10-18 10:44:07 -040061import javax.inject.Inject;
Dave Mankoff1193aa42019-10-28 17:51:26 -040062import javax.inject.Singleton;
Dave Mankoffa8749962019-10-18 10:44:07 -040063
Jorim Jaggiecc798e2014-05-26 18:14:37 +020064/**
65 * Controls both the scrim behind the notifications and in front of the notifications (when a
66 * security method gets shown).
67 */
Dave Mankoff1193aa42019-10-28 17:51:26 -040068@Singleton
Selim Cinek99e9adf2018-03-15 09:17:47 -070069public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
70 Dumpable {
Lucas Dupin9e3fa102017-11-08 17:16:55 -080071
Lucas Dupin55c6e802018-09-27 18:07:36 -070072 static final String TAG = "ScrimController";
Lucas Dupin9e3fa102017-11-08 17:16:55 -080073 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
74
Lucas Dupin4749f1b2018-04-04 15:09:06 -070075 /**
76 * General scrim animation duration.
77 */
John Spurlock8b12f222014-09-09 11:54:11 -040078 public static final long ANIMATION_DURATION = 220;
Lucas Dupin4749f1b2018-04-04 15:09:06 -070079 /**
80 * Longer duration, currently only used when going to AOD.
81 */
82 public static final long ANIMATION_DURATION_LONG = 1000;
Lucas Dupin82aa1632017-12-13 00:13:57 -080083 /**
84 * When both scrims have 0 alpha.
85 */
Lyn Hanbde48202019-05-29 19:18:29 -070086 public static final int TRANSPARENT = 0;
Lucas Dupin82aa1632017-12-13 00:13:57 -080087 /**
88 * When scrims aren't transparent (alpha 0) but also not opaque (alpha 1.)
89 */
Lyn Hanbde48202019-05-29 19:18:29 -070090 public static final int SEMI_TRANSPARENT = 1;
Lucas Dupin82aa1632017-12-13 00:13:57 -080091 /**
92 * When at least 1 scrim is fully opaque (alpha set to 1.)
93 */
Lyn Hanbde48202019-05-29 19:18:29 -070094 public static final int OPAQUE = 2;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070095
Lyn Hanbde48202019-05-29 19:18:29 -070096 @IntDef(prefix = {"VISIBILITY_"}, value = {
97 TRANSPARENT,
98 SEMI_TRANSPARENT,
99 OPAQUE
Lucas Dupincdbb1cb2019-05-16 19:48:30 -0700100 })
101 @Retention(RetentionPolicy.SOURCE)
Lyn Hanbde48202019-05-29 19:18:29 -0700102 public @interface ScrimVisibility {
103 }
Lucas Dupincdbb1cb2019-05-16 19:48:30 -0700104
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800105 /**
106 * Default alpha value for most scrims.
107 */
Lucas Dupin43d01242020-02-03 11:58:33 -0800108 public static final float SCRIM_ALPHA = 0.2f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800109 /**
Lucas Dupin3113db62019-03-08 18:21:27 -0800110 * Scrim opacity when the phone is about to wake-up.
111 */
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700112 public static final float WAKE_SENSOR_SCRIM_ALPHA = 0.6f;
Lucas Dupin3113db62019-03-08 18:21:27 -0800113 /**
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800114 * A scrim varies its opacity based on a busyness factor, for example
115 * how many notifications are currently visible.
116 */
Steve Elliottb0940382020-02-20 14:24:02 -0500117 public static final float BUSY_SCRIM_ALPHA = 0.75f;
Lucas Dupinde64ee02018-12-21 14:45:12 -0800118
Lucas Dupin55c6e802018-09-27 18:07:36 -0700119 /**
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800120 * The most common scrim, the one under the keyguard.
121 */
Lucas Dupin43d01242020-02-03 11:58:33 -0800122 protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = SCRIM_ALPHA;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800123
124 static final int TAG_KEY_ANIM = R.id.scrim;
Selim Cinek5104a6d2015-12-18 18:38:31 -0800125 private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
126 private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
Selim Cinek511f2702017-04-10 19:53:01 -0700127 private static final float NOT_INITIALIZED = -1;
John Spurlockbf370992014-06-17 13:58:31 -0400128
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800129 private ScrimState mState = ScrimState.UNINITIALIZED;
Lyn Hanbde48202019-05-29 19:18:29 -0700130
Dave Mankoffa8749962019-10-18 10:44:07 -0400131 private ScrimView mScrimInFront;
132 private ScrimView mScrimBehind;
133 private ScrimView mScrimForBubble;
Lyn Hanbde48202019-05-29 19:18:29 -0700134
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400135 private final KeyguardStateController mKeyguardStateController;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700136 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800137 private final DozeParameters mDozeParameters;
Jerry Chang50c5da42019-10-16 17:21:07 +0800138 private final DockManager mDockManager;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800139 private final AlarmTimeout mTimeTicker;
Lucas Dupin690c6f52018-07-10 15:28:57 -0700140 private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800141 private final Handler mHandler;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200142
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700143 private final SysuiColorExtractor mColorExtractor;
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700144 private GradientColors mColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700145 private boolean mNeedsDrawableColorUpdate;
146
Dave Mankoffa8749962019-10-18 10:44:07 -0400147 private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
Xiaohui Chen4dab4b52016-03-07 12:31:14 -0800148
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800149 // Assuming the shade is expanded during initialization
150 private float mExpansionFraction = 1f;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200151
152 private boolean mDarkenWhileDragging;
Lucas Dupin67f02632018-03-12 11:08:31 -0700153 private boolean mExpansionAffectsAlpha = true;
Dave Mankoffa8749962019-10-18 10:44:07 -0400154 private boolean mAnimateChange;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200155 private boolean mUpdatePending;
Jorim Jaggie93698b2016-11-11 18:24:38 -0800156 private boolean mTracking;
Dave Mankoffa8749962019-10-18 10:44:07 -0400157 private long mAnimationDuration = -1;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200158 private long mAnimationDelay;
Dave Mankoffa8749962019-10-18 10:44:07 -0400159 private Animator.AnimatorListener mAnimatorListener;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200160 private final Interpolator mInterpolator = new DecelerateInterpolator();
Lyn Hanbde48202019-05-29 19:18:29 -0700161
162 private float mInFrontAlpha = NOT_INITIALIZED;
163 private float mBehindAlpha = NOT_INITIALIZED;
164 private float mBubbleAlpha = NOT_INITIALIZED;
165
166 private int mInFrontTint;
167 private int mBehindTint;
168 private int mBubbleTint;
169
Lucas Dupin82aa1632017-12-13 00:13:57 -0800170 private boolean mWallpaperVisibilityTimedOut;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800171 private int mScrimsVisibility;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700172 private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
Dave Mankoffa8749962019-10-18 10:44:07 -0400173 private Consumer<Integer> mScrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800174 private boolean mBlankScreen;
175 private boolean mScreenBlankingCallbackCalled;
176 private Callback mCallback;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800177 private boolean mWallpaperSupportsAmbientMode;
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800178 private boolean mScreenOn;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800179
180 // Scrim blanking callbacks
Lucas Dupin0791d972018-03-26 13:32:16 -0700181 private Runnable mPendingFrameCallback;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800182 private Runnable mBlankingTransitionRunnable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800183
184 private final WakeLock mWakeLock;
185 private boolean mWakeLockHeld;
Lucas Dupind5107302018-03-19 15:30:29 -0700186 private boolean mKeyguardOccluded;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200187
Dave Mankoffa8749962019-10-18 10:44:07 -0400188 @Inject
189 public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
190 AlarmManager alarmManager, KeyguardStateController keyguardStateController,
Dave Mankoffa8749962019-10-18 10:44:07 -0400191 DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
Jerry Chang50c5da42019-10-16 17:21:07 +0800192 KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
193 DockManager dockManager) {
Lyn Hanbde48202019-05-29 19:18:29 -0700194
Dave Mankoffa8749962019-10-18 10:44:07 -0400195 mScrimStateListener = lightBarController::setScrimState;
Lyn Hanbde48202019-05-29 19:18:29 -0700196
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400197 mKeyguardStateController = keyguardStateController;
198 mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
Dave Mankoffa8749962019-10-18 10:44:07 -0400199 mKeyguardUpdateMonitor = keyguardUpdateMonitor;
Lucas Dupin690c6f52018-07-10 15:28:57 -0700200 mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
Dave Mankoffa8749962019-10-18 10:44:07 -0400201 mHandler = handler;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800202 mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800203 "hide_aod_wallpaper", mHandler);
Dave Mankoffa8749962019-10-18 10:44:07 -0400204 mWakeLock = delayedWakeLockBuilder.setHandler(mHandler).setTag("Scrims").build();
Lucas Dupin9324aa92017-07-26 20:29:38 -0700205 // Scrim alpha is initially set to the value on the resource but might be changed
206 // to make sure that text on top of it is legible.
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800207 mDozeParameters = dozeParameters;
Jerry Chang50c5da42019-10-16 17:21:07 +0800208 mDockManager = dockManager;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400209 keyguardStateController.addCallback(new KeyguardStateController.Callback() {
Selim Cinek72cd9a72019-08-09 17:19:57 -0700210 @Override
211 public void onKeyguardFadingAwayChanged() {
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400212 setKeyguardFadingAway(keyguardStateController.isKeyguardFadingAway(),
213 keyguardStateController.getKeyguardFadingAwayDuration());
Selim Cinek72cd9a72019-08-09 17:19:57 -0700214 }
215 });
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800216
Dave Mankoffa8749962019-10-18 10:44:07 -0400217 mColorExtractor = sysuiColorExtractor;
Lucas Dupin314d41f2017-05-08 15:52:58 -0700218 mColorExtractor.addOnColorsChangedListener(this);
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700219 mColors = mColorExtractor.getNeutralColors();
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700220 mNeedsDrawableColorUpdate = true;
Dave Mankoffa8749962019-10-18 10:44:07 -0400221 }
222
223 /**
224 * Attach the controller to the supplied views.
225 */
226 public void attachViews(
227 ScrimView scrimBehind, ScrimView scrimInFront, ScrimView scrimForBubble) {
228 mScrimBehind = scrimBehind;
229 mScrimInFront = scrimInFront;
230 mScrimForBubble = scrimForBubble;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700231
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800232 final ScrimState[] states = ScrimState.values();
233 for (int i = 0; i < states.length; i++) {
Jerry Chang50c5da42019-10-16 17:21:07 +0800234 states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
235 mDockManager);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800236 states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
237 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800238
Lucas Dupin373356b2018-04-07 10:50:25 -0700239 mScrimBehind.setDefaultFocusHighlightEnabled(false);
240 mScrimInFront.setDefaultFocusHighlightEnabled(false);
Lyn Hanbde48202019-05-29 19:18:29 -0700241 mScrimForBubble.setDefaultFocusHighlightEnabled(false);
Selim Cinek511f2702017-04-10 19:53:01 -0700242 updateScrims();
Dave Mankoffa8749962019-10-18 10:44:07 -0400243 mKeyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
244 }
245
246 void setScrimVisibleListener(Consumer<Integer> listener) {
247 mScrimVisibleListener = listener;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200248 }
249
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800250 public void transitionTo(ScrimState state) {
251 transitionTo(state, null);
252 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700253
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800254 public void transitionTo(ScrimState state, Callback callback) {
255 if (state == mState) {
Lucas Dupin19aba8e2017-12-11 12:42:26 -0800256 // Call the callback anyway, unless it's already enqueued
257 if (callback != null && mCallback != callback) {
258 callback.onFinished();
259 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800260 return;
261 } else if (DEBUG) {
262 Log.d(TAG, "State changed to: " + state);
263 }
264
265 if (state == ScrimState.UNINITIALIZED) {
266 throw new IllegalArgumentException("Cannot change to UNINITIALIZED.");
267 }
268
Lucas Dupin8635c442017-12-08 10:36:28 -0800269 final ScrimState oldState = mState;
270 mState = state;
Lucas Dupinedbe45b2019-10-14 15:43:03 -0700271 Trace.traceCounter(Trace.TRACE_TAG_APP, "scrim_state", mState.ordinal());
Lucas Dupin8635c442017-12-08 10:36:28 -0800272
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800273 if (mCallback != null) {
274 mCallback.onCancelled();
275 }
276 mCallback = callback;
277
Lucas Dupin8635c442017-12-08 10:36:28 -0800278 state.prepare(oldState);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800279 mScreenBlankingCallbackCalled = false;
280 mAnimationDelay = 0;
281 mBlankScreen = state.getBlanksScreen();
282 mAnimateChange = state.getAnimateChange();
283 mAnimationDuration = state.getAnimationDuration();
Lyn Hanbde48202019-05-29 19:18:29 -0700284
285 mInFrontTint = state.getFrontTint();
286 mBehindTint = state.getBehindTint();
287 mBubbleTint = state.getBubbleTint();
288
289 mInFrontAlpha = state.getFrontAlpha();
290 mBehindAlpha = state.getBehindAlpha();
291 mBubbleAlpha = state.getBubbleAlpha();
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800292 applyExpansionToAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800293
Lucas Dupin38962d72018-03-14 12:41:39 -0700294 // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
295 // We need to disable focus otherwise AOD would end up with a gray overlay.
296 mScrimInFront.setFocusable(!state.isLowPowerState());
297 mScrimBehind.setFocusable(!state.isLowPowerState());
298
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800299 // Cancel blanking transitions that were pending before we requested a new state
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800300 if (mPendingFrameCallback != null) {
Lucas Dupin0791d972018-03-26 13:32:16 -0700301 mScrimBehind.removeCallbacks(mPendingFrameCallback);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800302 mPendingFrameCallback = null;
303 }
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800304 if (mHandler.hasCallbacks(mBlankingTransitionRunnable)) {
305 mHandler.removeCallbacks(mBlankingTransitionRunnable);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800306 mBlankingTransitionRunnable = null;
307 }
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800308
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800309 // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
310 // to do the same when you're just showing the brightness mirror.
311 mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
312
Lucas Dupineea53b32017-12-18 13:47:14 -0800313 // The device might sleep if it's entering AOD, we need to make sure that
314 // the animation plays properly until the last frame.
315 // It's important to avoid holding the wakelock unless necessary because
316 // WakeLock#aqcuire will trigger an IPC and will cause jank.
Lucas Dupin38962d72018-03-14 12:41:39 -0700317 if (mState.isLowPowerState()) {
Lucas Dupineea53b32017-12-18 13:47:14 -0800318 holdWakeLock();
319 }
Lucas Dupin82aa1632017-12-13 00:13:57 -0800320
TYM Tsaia71c8922019-01-07 15:57:53 +0800321 // AOD wallpapers should fade away after a while.
322 // Docking pulses may take a long time, wallpapers should also fade away after a while.
Jerry Changbde4c0c2019-06-13 16:58:41 +0800323 mWallpaperVisibilityTimedOut = false;
324 if (shouldFadeAwayWallpaper()) {
Lucas Dupinfc6ba372019-10-01 15:21:16 -0700325 DejankUtils.postAfterTraversal(() -> {
326 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
327 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
328 });
Lucas Dupinc7804042018-12-21 12:26:33 -0800329 } else {
Lucas Dupinfc6ba372019-10-01 15:21:16 -0700330 DejankUtils.postAfterTraversal(mTimeTicker::cancel);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800331 }
332
Lucas Dupinff307d52018-02-05 21:16:39 -0800333 if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800334 // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
335 // with too many things at this case, in order to not skip the initial frames.
336 mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
337 mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
Lucas Dupin0791d972018-03-26 13:32:16 -0700338 } else if ((!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD)
Lucas Dupin16cfe452018-02-08 13:14:50 -0800339 || (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
340 // Scheduling a frame isn't enough when:
341 // • Leaving doze and we need to modify scrim color immediately
342 // • ColorFade will not kick-in and scrim cannot wait for pre-draw.
Lucas Dupinff307d52018-02-05 21:16:39 -0800343 onPreDraw();
344 } else {
345 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800346 }
Yohei Yukawa795f0102018-04-13 14:55:30 -0700347
348 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800349 }
350
Jerry Changbde4c0c2019-06-13 16:58:41 +0800351 private boolean shouldFadeAwayWallpaper() {
352 if (!mWallpaperSupportsAmbientMode) {
353 return false;
354 }
355
Jerry Changc12e4602019-12-16 15:17:13 +0800356 if (mState == ScrimState.AOD
357 && (mDozeParameters.getAlwaysOn() || mDockManager.isDocked())) {
Jerry Changbde4c0c2019-06-13 16:58:41 +0800358 return true;
359 }
360
Jerry Changbde4c0c2019-06-13 16:58:41 +0800361 return false;
362 }
363
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800364 public ScrimState getState() {
365 return mState;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200366 }
367
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800368 protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700369 mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800370 ScrimState[] states = ScrimState.values();
371 for (int i = 0; i < states.length; i++) {
372 states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
373 }
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700374 scheduleUpdate();
375 }
376
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200377 public void onTrackingStarted() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800378 mTracking = true;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400379 mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200380 }
381
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200382 public void onExpandingFinished() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800383 mTracking = false;
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200384 }
385
Lucas Dupin82aa1632017-12-13 00:13:57 -0800386 @VisibleForTesting
387 protected void onHideWallpaperTimeout() {
TYM Tsaia71c8922019-01-07 15:57:53 +0800388 if (mState != ScrimState.AOD && mState != ScrimState.PULSING) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800389 return;
390 }
391
392 holdWakeLock();
393 mWallpaperVisibilityTimedOut = true;
394 mAnimateChange = true;
395 mAnimationDuration = mDozeParameters.getWallpaperFadeOutDuration();
396 scheduleUpdate();
397 }
398
399 private void holdWakeLock() {
400 if (!mWakeLockHeld) {
401 if (mWakeLock != null) {
402 mWakeLockHeld = true;
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800403 mWakeLock.acquire(TAG);
Lucas Dupin82aa1632017-12-13 00:13:57 -0800404 } else {
405 Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
406 }
407 }
408 }
409
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800410 /**
411 * Current state of the shade expansion when pulling it from the top.
412 * This value is 1 when on top of the keyguard and goes to 0 as the user drags up.
413 *
414 * The expansion fraction is tied to the scrim opacity.
415 *
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800416 * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800417 */
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200418 public void setPanelExpansion(float fraction) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800419 if (mExpansionFraction != fraction) {
420 mExpansionFraction = fraction;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800421
Lyn Hanbde48202019-05-29 19:18:29 -0700422 boolean relevantState = (mState == ScrimState.UNLOCKED
423 || mState == ScrimState.KEYGUARD
424 || mState == ScrimState.PULSING
425 || mState == ScrimState.BUBBLE_EXPANDED);
426 if (!(relevantState && mExpansionAffectsAlpha)) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800427 return;
428 }
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800429 applyExpansionToAlpha();
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800430 if (mUpdatePending) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800431 return;
432 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800433 setOrAdaptCurrentAnimation(mScrimBehind);
434 setOrAdaptCurrentAnimation(mScrimInFront);
Lyn Hanbde48202019-05-29 19:18:29 -0700435 setOrAdaptCurrentAnimation(mScrimForBubble);
Yohei Yukawa795f0102018-04-13 14:55:30 -0700436 dispatchScrimState(mScrimBehind.getViewAlpha());
Jerry Changbde4c0c2019-06-13 16:58:41 +0800437
438 // Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
439 // and docking.
440 if (mWallpaperVisibilityTimedOut) {
441 mWallpaperVisibilityTimedOut = false;
Lucas Dupinfc6ba372019-10-01 15:21:16 -0700442 DejankUtils.postAfterTraversal(() -> {
443 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
444 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
445 });
Jerry Changbde4c0c2019-06-13 16:58:41 +0800446 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800447 }
448 }
449
450 private void setOrAdaptCurrentAnimation(View scrim) {
Lyn Hanbde48202019-05-29 19:18:29 -0700451 float alpha = getCurrentScrimAlpha(scrim);
452 if (isAnimating(scrim)) {
453 // Adapt current animation.
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800454 ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800455 float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
456 float previousStartValue = (Float) scrim.getTag(TAG_START_ALPHA);
457 float relativeDiff = alpha - previousEndValue;
458 float newStartValue = previousStartValue + relativeDiff;
459 scrim.setTag(TAG_START_ALPHA, newStartValue);
460 scrim.setTag(TAG_END_ALPHA, alpha);
461 previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
Lyn Hanbde48202019-05-29 19:18:29 -0700462 } else {
463 // Set animation.
464 updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
Jorim Jaggi93439da2014-06-30 23:53:39 +0200465 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200466 }
467
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800468 private void applyExpansionToAlpha() {
Lucas Dupin67f02632018-03-12 11:08:31 -0700469 if (!mExpansionAffectsAlpha) {
470 return;
471 }
472
Lyn Hanbde48202019-05-29 19:18:29 -0700473 if (mState == ScrimState.UNLOCKED || mState == ScrimState.BUBBLE_EXPANDED) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800474 // Darken scrim as you pull down the shade when unlocked
475 float behindFraction = getInterpolatedFraction();
476 behindFraction = (float) Math.pow(behindFraction, 0.8f);
Lucas Dupin43d01242020-02-03 11:58:33 -0800477 mBehindAlpha = behindFraction * BUSY_SCRIM_ALPHA;
Lyn Hanbde48202019-05-29 19:18:29 -0700478 mInFrontAlpha = 0;
Lucas Dupin1c327432019-01-03 13:37:53 -0800479 } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800480 // Either darken of make the scrim transparent when you
481 // pull down the shade
482 float interpolatedFract = getInterpolatedFraction();
Lucas Dupin3d36dd82019-01-02 14:38:35 -0800483 float alphaBehind = mState.getBehindAlpha();
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800484 if (mDarkenWhileDragging) {
Lucas Dupin43d01242020-02-03 11:58:33 -0800485 mBehindAlpha = MathUtils.lerp(BUSY_SCRIM_ALPHA, alphaBehind,
Lucas Dupinb380c882018-02-25 21:57:17 -0800486 interpolatedFract);
Chris.CC Leed424e202019-09-16 12:17:19 +0800487 mInFrontAlpha = mState.getFrontAlpha();
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800488 } else {
Lyn Hanbde48202019-05-29 19:18:29 -0700489 mBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800490 interpolatedFract);
Chris.CC Leed424e202019-09-16 12:17:19 +0800491 mInFrontAlpha = mState.getFrontAlpha();
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800492 }
Lyn Hanbde48202019-05-29 19:18:29 -0700493 mBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
Lucas Dupin4cf01062019-03-08 17:07:49 -0800494 mState.getBehindTint(), interpolatedFract);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800495 }
496 }
497
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800498 /**
Anthony Chene658cc22017-04-27 11:17:35 -0700499 * Sets the given drawable as the background of the scrim that shows up behind the
500 * notifications.
501 */
502 public void setScrimBehindDrawable(Drawable drawable) {
503 mScrimBehind.setDrawable(drawable);
504 }
505
Michael Wrightcae88752018-04-16 23:13:54 +0100506 /**
Lucas Dupin69bda602018-05-18 17:24:52 -0700507 * Sets the front scrim opacity in AOD so it's not as bright.
508 * <p>
509 * Displays usually don't support multiple dimming settings when in low power mode.
510 * The workaround is to modify the front scrim opacity when in AOD, so it's not as
511 * bright when you're at the movies or lying down on bed.
512 * <p>
513 * This value will be lost during transitions and only updated again after the the
514 * device is dozing when the light sensor is on.
Michael Wrightcae88752018-04-16 23:13:54 +0100515 */
516 public void setAodFrontScrimAlpha(float alpha) {
Jerry Chang50c5da42019-10-16 17:21:07 +0800517 if (mInFrontAlpha != alpha && shouldUpdateFrontScrimAlpha()) {
Lyn Hanbde48202019-05-29 19:18:29 -0700518 mInFrontAlpha = alpha;
Lucas Dupin8523d132018-05-31 17:34:32 -0700519 updateScrims();
Michael Wrightcae88752018-04-16 23:13:54 +0100520 }
521
522 mState.AOD.setAodFrontScrimAlpha(alpha);
Chris.CC Leed424e202019-09-16 12:17:19 +0800523 mState.PULSING.setAodFrontScrimAlpha(alpha);
Michael Wrightcae88752018-04-16 23:13:54 +0100524 }
525
Jerry Chang50c5da42019-10-16 17:21:07 +0800526 private boolean shouldUpdateFrontScrimAlpha() {
527 if (mState == ScrimState.AOD
528 && (mDozeParameters.getAlwaysOn() || mDockManager.isDocked())) {
529 return true;
530 }
531
532 if (mState == ScrimState.PULSING) {
533 return true;
534 }
535
536 return false;
537 }
538
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700539 /**
540 * If the lock screen sensor is active.
541 */
542 public void setWakeLockScreenSensorActive(boolean active) {
543 for (ScrimState state : ScrimState.values()) {
544 state.setWakeLockScreenSensorActive(active);
545 }
546
547 if (mState == ScrimState.PULSING) {
548 float newBehindAlpha = mState.getBehindAlpha();
Lyn Hanbde48202019-05-29 19:18:29 -0700549 if (mBehindAlpha != newBehindAlpha) {
550 mBehindAlpha = newBehindAlpha;
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700551 updateScrims();
552 }
553 }
554 }
555
Evan Rosky9a895012016-04-21 11:26:15 -0700556 protected void scheduleUpdate() {
Lucas Dupin54c821e2019-12-17 11:53:04 -0800557 if (mUpdatePending || mScrimBehind == null) return;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200558
559 // Make sure that a frame gets scheduled.
560 mScrimBehind.invalidate();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200561 mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
562 mUpdatePending = true;
563 }
564
Xiaohui Chen5da71352016-02-22 10:04:41 -0800565 protected void updateScrims() {
Lucas Dupin9324aa92017-07-26 20:29:38 -0700566 // Make sure we have the right gradients and their opacities will satisfy GAR.
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700567 if (mNeedsDrawableColorUpdate) {
568 mNeedsDrawableColorUpdate = false;
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700569 // Only animate scrim color if the scrim view is actually visible
570 boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen;
571 boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
Lyn Hanbde48202019-05-29 19:18:29 -0700572 boolean animateScrimForBubble = mScrimForBubble.getViewAlpha() != 0 && !mBlankScreen;
573
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700574 mScrimInFront.setColors(mColors, animateScrimInFront);
575 mScrimBehind.setColors(mColors, animateScrimBehind);
Lyn Hanbde48202019-05-29 19:18:29 -0700576 mScrimForBubble.setColors(mColors, animateScrimForBubble);
Lucas Dupin9324aa92017-07-26 20:29:38 -0700577
578 // Calculate minimum scrim opacity for white or black text.
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700579 int textColor = mColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
580 int mainColor = mColors.getMainColor();
Lucas Dupin9324aa92017-07-26 20:29:38 -0700581 float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
582 4.5f /* minimumContrast */) / 255f;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700583 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700584 }
585
Lucas Dupind5107302018-03-19 15:30:29 -0700586 // We want to override the back scrim opacity for the AOD state
Lucas Dupin82aa1632017-12-13 00:13:57 -0800587 // when it's time to fade the wallpaper away.
TYM Tsaia71c8922019-01-07 15:57:53 +0800588 boolean aodWallpaperTimeout = (mState == ScrimState.AOD || mState == ScrimState.PULSING)
589 && mWallpaperVisibilityTimedOut;
Lucas Dupind5107302018-03-19 15:30:29 -0700590 // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
591 boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
592 && mKeyguardOccluded;
593 if (aodWallpaperTimeout || occludedKeyguard) {
Lyn Hanbde48202019-05-29 19:18:29 -0700594 mBehindAlpha = 1;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800595 }
Lyn Hanbde48202019-05-29 19:18:29 -0700596 setScrimAlpha(mScrimInFront, mInFrontAlpha);
597 setScrimAlpha(mScrimBehind, mBehindAlpha);
598 setScrimAlpha(mScrimForBubble, mBubbleAlpha);
Selim Cinek9449cfc2019-10-14 12:00:36 -0700599 // The animation could have all already finished, let's call onFinished just in case
600 onFinished();
Adrian Roosa5c63222017-07-27 16:33:39 +0200601 dispatchScrimsVisible();
602 }
603
Yohei Yukawa795f0102018-04-13 14:55:30 -0700604 private void dispatchScrimState(float alpha) {
605 mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
606 }
607
Adrian Roosa5c63222017-07-27 16:33:39 +0200608 private void dispatchScrimsVisible() {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800609 final int currentScrimVisibility;
610 if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
Lyn Hanbde48202019-05-29 19:18:29 -0700611 currentScrimVisibility = OPAQUE;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800612 } else if (mScrimInFront.getViewAlpha() == 0 && mScrimBehind.getViewAlpha() == 0) {
Lyn Hanbde48202019-05-29 19:18:29 -0700613 currentScrimVisibility = TRANSPARENT;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800614 } else {
Lyn Hanbde48202019-05-29 19:18:29 -0700615 currentScrimVisibility = SEMI_TRANSPARENT;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800616 }
Adrian Roosa5c63222017-07-27 16:33:39 +0200617
Lucas Dupin82aa1632017-12-13 00:13:57 -0800618 if (mScrimsVisibility != currentScrimVisibility) {
619 mScrimsVisibility = currentScrimVisibility;
620 mScrimVisibleListener.accept(currentScrimVisibility);
Adrian Roosa5c63222017-07-27 16:33:39 +0200621 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200622 }
623
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800624 private float getInterpolatedFraction() {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800625 float frac = mExpansionFraction;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200626 // let's start this 20% of the way down the screen
627 frac = frac * 1.2f - 0.2f;
628 if (frac <= 0) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800629 return 0;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200630 } else {
631 // woo, special effects
Lyn Hanbde48202019-05-29 19:18:29 -0700632 return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * Math.pow(1f - frac, 2f))));
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200633 }
634 }
635
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800636 private void setScrimAlpha(ScrimView scrim, float alpha) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800637 if (alpha == 0f) {
638 scrim.setClickable(false);
Selim Cinekaac93252015-04-14 20:04:12 -0700639 } else {
Lucas Dupin1c327432019-01-03 13:37:53 -0800640 // Eat touch events (unless dozing).
641 scrim.setClickable(mState != ScrimState.AOD);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200642 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800643 updateScrim(scrim, alpha);
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100644 }
645
Lyn Hanbde48202019-05-29 19:18:29 -0700646 private String getScrimName(ScrimView scrim) {
647 if (scrim == mScrimInFront) {
648 return "front_scrim";
649 } else if (scrim == mScrimBehind) {
650 return "back_scrim";
651 } else if (scrim == mScrimForBubble) {
652 return "bubble_scrim";
653 }
654 return "unknown_scrim";
655 }
656
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800657 private void updateScrimColor(View scrim, float alpha, int tint) {
658 alpha = Math.max(0, Math.min(1.0f, alpha));
Selim Cinekaac93252015-04-14 20:04:12 -0700659 if (scrim instanceof ScrimView) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700660 ScrimView scrimView = (ScrimView) scrim;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700661
Lyn Hanbde48202019-05-29 19:18:29 -0700662 Trace.traceCounter(Trace.TRACE_TAG_APP, getScrimName(scrimView) + "_alpha",
Adrian Roosa5c63222017-07-27 16:33:39 +0200663 (int) (alpha * 255));
664
Lyn Hanbde48202019-05-29 19:18:29 -0700665 Trace.traceCounter(Trace.TRACE_TAG_APP, getScrimName(scrimView) + "_tint",
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800666 Color.alpha(tint));
Adrian Roosa5c63222017-07-27 16:33:39 +0200667
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800668 scrimView.setTint(tint);
669 scrimView.setViewAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700670 } else {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800671 scrim.setAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700672 }
Selim Cinek8cd80402017-08-01 10:44:29 -0700673 dispatchScrimsVisible();
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100674 }
675
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800676 private void startScrimAnimation(final View scrim, float current) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800677 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
Dave Mankoffa8749962019-10-18 10:44:07 -0400678 if (mAnimatorListener != null) {
679 anim.addListener(mAnimatorListener);
680 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800681 final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() :
682 Color.TRANSPARENT;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700683 anim.addUpdateListener(animation -> {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800684 final float startAlpha = (Float) scrim.getTag(TAG_START_ALPHA);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800685 final float animAmount = (float) animation.getAnimatedValue();
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800686 final int finalScrimTint = getCurrentScrimTint(scrim);
687 final float finalScrimAlpha = getCurrentScrimAlpha(scrim);
688 float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount);
689 alpha = MathUtils.constrain(alpha, 0f, 1f);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800690 int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
691 updateScrimColor(scrim, alpha, tint);
Adrian Roosa5c63222017-07-27 16:33:39 +0200692 dispatchScrimsVisible();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200693 });
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800694 anim.setInterpolator(mInterpolator);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200695 anim.setStartDelay(mAnimationDelay);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800696 anim.setDuration(mAnimationDuration);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200697 anim.addListener(new AnimatorListenerAdapter() {
Joanne Chunga393ad62019-01-16 21:41:31 +0800698 private Callback lastCallback = mCallback;
699
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200700 @Override
701 public void onAnimationEnd(Animator animation) {
Selim Cinek9449cfc2019-10-14 12:00:36 -0700702 scrim.setTag(TAG_KEY_ANIM, null);
Joanne Chunga393ad62019-01-16 21:41:31 +0800703 onFinished(lastCallback);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800704
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800705 dispatchScrimsVisible();
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200706 }
707 });
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800708
709 // Cache alpha values because we might want to update this animator in the future if
710 // the user expands the panel while the animation is still running.
711 scrim.setTag(TAG_START_ALPHA, current);
712 scrim.setTag(TAG_END_ALPHA, getCurrentScrimAlpha(scrim));
713
John Spurlockbf370992014-06-17 13:58:31 -0400714 scrim.setTag(TAG_KEY_ANIM, anim);
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800715 anim.start();
716 }
717
718 private float getCurrentScrimAlpha(View scrim) {
719 if (scrim == mScrimInFront) {
Lyn Hanbde48202019-05-29 19:18:29 -0700720 return mInFrontAlpha;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800721 } else if (scrim == mScrimBehind) {
Lyn Hanbde48202019-05-29 19:18:29 -0700722 return mBehindAlpha;
723 } else if (scrim == mScrimForBubble) {
724 return mBubbleAlpha;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800725 } else {
726 throw new IllegalArgumentException("Unknown scrim view");
727 }
728 }
729
730 private int getCurrentScrimTint(View scrim) {
731 if (scrim == mScrimInFront) {
Lyn Hanbde48202019-05-29 19:18:29 -0700732 return mInFrontTint;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800733 } else if (scrim == mScrimBehind) {
Lyn Hanbde48202019-05-29 19:18:29 -0700734 return mBehindTint;
735 } else if (scrim == mScrimForBubble) {
736 return mBubbleTint;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800737 } else {
738 throw new IllegalArgumentException("Unknown scrim view");
739 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200740 }
741
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200742 @Override
743 public boolean onPreDraw() {
744 mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
745 mUpdatePending = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800746 if (mCallback != null) {
747 mCallback.onStart();
Selim Cinek372d1bd2015-08-14 13:19:37 -0700748 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200749 updateScrims();
Selim Cinekedd32b82015-06-23 22:05:58 -0400750 return true;
751 }
752
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800753 private void onFinished() {
Joanne Chunga393ad62019-01-16 21:41:31 +0800754 onFinished(mCallback);
755 }
756
757 private void onFinished(Callback callback) {
Selim Cinek97139d12019-10-30 16:34:34 -0700758 if (mPendingFrameCallback != null) {
759 // No animations can finish while we're waiting on the blanking to finish
760 return;
761
762 }
Selim Cinek9449cfc2019-10-14 12:00:36 -0700763 if (isAnimating(mScrimBehind)
764 || isAnimating(mScrimInFront)
765 || isAnimating(mScrimForBubble)) {
Selim Cinek22fa9752019-09-26 16:53:31 -0700766 if (callback != null && callback != mCallback) {
767 // Since we only notify the callback that we're finished once everything has
768 // finished, we need to make sure that any changing callbacks are also invoked
769 callback.onFinished();
770 }
771 return;
772 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800773 if (mWakeLockHeld) {
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800774 mWakeLock.release(TAG);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800775 mWakeLockHeld = false;
776 }
Joanne Chunga393ad62019-01-16 21:41:31 +0800777
778 if (callback != null) {
779 callback.onFinished();
780
781 if (callback == mCallback) {
782 mCallback = null;
783 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800784 }
Joanne Chunga393ad62019-01-16 21:41:31 +0800785
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800786 // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
787 // At the end of the animation we need to remove the tint.
788 if (mState == ScrimState.UNLOCKED) {
Lyn Hanbde48202019-05-29 19:18:29 -0700789 mInFrontTint = Color.TRANSPARENT;
790 mBehindTint = Color.TRANSPARENT;
791 mBubbleTint = Color.TRANSPARENT;
Selim Cinek22fa9752019-09-26 16:53:31 -0700792 updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint);
793 updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint);
794 updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800795 }
796 }
797
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700798 private boolean isAnimating(View scrim) {
799 return scrim.getTag(TAG_KEY_ANIM) != null;
800 }
801
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800802 @VisibleForTesting
Dave Mankoffa8749962019-10-18 10:44:07 -0400803 void setAnimatorListener(Animator.AnimatorListener animatorListener) {
804 mAnimatorListener = animatorListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800805 }
Adrian Roos5f72c922016-03-08 15:54:26 -0800806
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800807 private void updateScrim(ScrimView scrim, float alpha) {
808 final float currentAlpha = scrim.getViewAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800809
810 ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM);
Selim Cinekaac93252015-04-14 20:04:12 -0700811 if (previousAnimator != null) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800812 // Previous animators should always be cancelled. Not doing so would cause
813 // overlap, especially on states that don't animate, leading to flickering,
814 // and in the worst case, an internal state that doesn't represent what
815 // transitionTo requested.
816 cancelAnimator(previousAnimator);
Selim Cinekaac93252015-04-14 20:04:12 -0700817 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800818
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800819 if (mPendingFrameCallback != null) {
820 // Display is off and we're waiting.
821 return;
822 } else if (mBlankScreen) {
823 // Need to blank the display before continuing.
824 blankDisplay();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800825 return;
826 } else if (!mScreenBlankingCallbackCalled) {
827 // Not blanking the screen. Letting the callback know that we're ready
828 // to replace what was on the screen before.
829 if (mCallback != null) {
830 mCallback.onDisplayBlanked();
831 mScreenBlankingCallbackCalled = true;
832 }
833 }
834
Lucas Dupin6afae372017-11-30 13:09:22 -0500835 if (scrim == mScrimBehind) {
Yohei Yukawa795f0102018-04-13 14:55:30 -0700836 dispatchScrimState(alpha);
Lucas Dupin6afae372017-11-30 13:09:22 -0500837 }
838
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800839 final boolean wantsAlphaUpdate = alpha != currentAlpha;
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800840 final boolean wantsTintUpdate = scrim.getTint() != getCurrentScrimTint(scrim);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800841
842 if (wantsAlphaUpdate || wantsTintUpdate) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800843 if (mAnimateChange) {
844 startScrimAnimation(scrim, currentAlpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700845 } else {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800846 // update the alpha directly
847 updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
Selim Cinekaac93252015-04-14 20:04:12 -0700848 }
849 }
850 }
851
Dave Mankoffa8749962019-10-18 10:44:07 -0400852 private void cancelAnimator(ValueAnimator previousAnimator) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800853 if (previousAnimator != null) {
854 previousAnimator.cancel();
855 }
856 }
857
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800858 private void blankDisplay() {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800859 updateScrimColor(mScrimInFront, 1, Color.BLACK);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800860
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800861 // Notify callback that the screen is completely black and we're
862 // ready to change the display power mode
Lucas Dupin0791d972018-03-26 13:32:16 -0700863 mPendingFrameCallback = () -> {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800864 if (mCallback != null) {
865 mCallback.onDisplayBlanked();
866 mScreenBlankingCallbackCalled = true;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800867 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800868
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800869 mBlankingTransitionRunnable = () -> {
870 mBlankingTransitionRunnable = null;
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800871 mPendingFrameCallback = null;
872 mBlankScreen = false;
873 // Try again.
874 updateScrims();
875 };
876
877 // Setting power states can happen after we push out the frame. Make sure we
878 // stay fully opaque until the power state request reaches the lower levels.
Lucas Dupin0791d972018-03-26 13:32:16 -0700879 final int delay = mScreenOn ? 32 : 500;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800880 if (DEBUG) {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800881 Log.d(TAG, "Fading out scrims with delay: " + delay);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800882 }
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800883 mHandler.postDelayed(mBlankingTransitionRunnable, delay);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800884 };
885 doOnTheNextFrame(mPendingFrameCallback);
886 }
887
Lucas Dupin0791d972018-03-26 13:32:16 -0700888 /**
889 * Executes a callback after the frame has hit the display.
Lyn Hanbde48202019-05-29 19:18:29 -0700890 *
Lucas Dupin0791d972018-03-26 13:32:16 -0700891 * @param callback What to run.
892 */
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800893 @VisibleForTesting
Lucas Dupin0791d972018-03-26 13:32:16 -0700894 protected void doOnTheNextFrame(Runnable callback) {
895 // Just calling View#postOnAnimation isn't enough because the frame might not have reached
896 // the display yet. A timeout is the safest solution.
897 mScrimBehind.postOnAnimationDelayed(callback, 32 /* delayMillis */);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800898 }
899
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700900 public int getBackgroundColor() {
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700901 int color = mColors.getMainColor();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800902 return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700903 Color.red(color), Color.green(color), Color.blue(color));
Selim Cinekd35c2792016-01-21 13:20:57 -0800904 }
905
906 public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
907 mScrimBehind.setChangeRunnable(changeRunnable);
908 }
Selim Cineke803491c2016-04-09 21:24:45 -0700909
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700910 public void setCurrentUser(int currentUser) {
911 // Don't care in the base class.
912 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700913
914 @Override
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700915 public void onColorsChanged(ColorExtractor colorExtractor, int which) {
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700916 mColors = mColorExtractor.getNeutralColors();
917 mNeedsDrawableColorUpdate = true;
918 scheduleUpdate();
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700919 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200920
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800921 @Override
922 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800923 pw.println(" ScrimController: ");
Lyn Hanbde48202019-05-29 19:18:29 -0700924 pw.print(" state: ");
925 pw.println(mState);
Adrian Roosba7ca592017-08-15 17:48:05 +0200926
Lyn Hanbde48202019-05-29 19:18:29 -0700927 pw.print(" frontScrim:");
928 pw.print(" viewAlpha=");
929 pw.print(mScrimInFront.getViewAlpha());
930 pw.print(" alpha=");
931 pw.print(mInFrontAlpha);
932 pw.print(" tint=0x");
933 pw.println(Integer.toHexString(mScrimInFront.getTint()));
Adrian Roosba7ca592017-08-15 17:48:05 +0200934
Lyn Hanbde48202019-05-29 19:18:29 -0700935 pw.print(" backScrim:");
936 pw.print(" viewAlpha=");
937 pw.print(mScrimBehind.getViewAlpha());
938 pw.print(" alpha=");
939 pw.print(mBehindAlpha);
940 pw.print(" tint=0x");
941 pw.println(Integer.toHexString(mScrimBehind.getTint()));
942
943 pw.print(" bubbleScrim:");
944 pw.print(" viewAlpha=");
945 pw.print(mScrimForBubble.getViewAlpha());
946 pw.print(" alpha=");
947 pw.print(mBubbleAlpha);
948 pw.print(" tint=0x");
949 pw.println(Integer.toHexString(mScrimForBubble.getTint()));
950
951 pw.print(" mTracking=");
952 pw.println(mTracking);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800953 }
954
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700955 public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800956 mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
957 ScrimState[] states = ScrimState.values();
958 for (int i = 0; i < states.length; i++) {
959 states[i].setWallpaperSupportsAmbientMode(wallpaperSupportsAmbientMode);
960 }
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700961 }
962
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800963 /**
964 * Interrupts blanking transitions once the display notifies that it's already on.
965 */
966 public void onScreenTurnedOn() {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800967 mScreenOn = true;
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800968 if (mHandler.hasCallbacks(mBlankingTransitionRunnable)) {
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800969 if (DEBUG) {
970 Log.d(TAG, "Shorter blanking because screen turned on. All good.");
971 }
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800972 mHandler.removeCallbacks(mBlankingTransitionRunnable);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800973 mBlankingTransitionRunnable.run();
974 }
975 }
976
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800977 public void onScreenTurnedOff() {
978 mScreenOn = false;
979 }
980
Lucas Dupin67f02632018-03-12 11:08:31 -0700981 public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
982 mExpansionAffectsAlpha = expansionAffectsAlpha;
983 }
984
Lucas Dupind5107302018-03-19 15:30:29 -0700985 public void setKeyguardOccluded(boolean keyguardOccluded) {
986 mKeyguardOccluded = keyguardOccluded;
Lucas Dupin63d72172018-06-06 11:42:55 -0700987 updateScrims();
Lucas Dupind5107302018-03-19 15:30:29 -0700988 }
989
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700990 public void setHasBackdrop(boolean hasBackdrop) {
Lucas Dupin193677c2018-06-11 19:16:03 -0700991 for (ScrimState state : ScrimState.values()) {
992 state.setHasBackdrop(hasBackdrop);
993 }
Lucas Dupin9bee5822018-07-09 14:32:53 -0700994
995 // Backdrop event may arrive after state was already applied,
996 // in this case, back-scrim needs to be re-evaluated
997 if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
Lucas Dupin3d36dd82019-01-02 14:38:35 -0800998 float newBehindAlpha = mState.getBehindAlpha();
Lyn Hanbde48202019-05-29 19:18:29 -0700999 if (mBehindAlpha != newBehindAlpha) {
1000 mBehindAlpha = newBehindAlpha;
Lucas Dupin9bee5822018-07-09 14:32:53 -07001001 updateScrims();
1002 }
1003 }
Lucas Dupin193677c2018-06-11 19:16:03 -07001004 }
1005
Selim Cinek72cd9a72019-08-09 17:19:57 -07001006 private void setKeyguardFadingAway(boolean fadingAway, long duration) {
Selim Cinek84b2acc2019-07-07 00:40:38 -07001007 for (ScrimState state : ScrimState.values()) {
Selim Cinek72cd9a72019-08-09 17:19:57 -07001008 state.setKeyguardFadingAway(fadingAway, duration);
Selim Cinek84b2acc2019-07-07 00:40:38 -07001009 }
1010 }
1011
Lucas Dupin193677c2018-06-11 19:16:03 -07001012 public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
1013 for (ScrimState state : ScrimState.values()) {
1014 state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
Lucas Dupinf8463ee2018-06-11 16:18:15 -07001015 }
1016 }
1017
Lucas Dupin9e3fa102017-11-08 17:16:55 -08001018 public interface Callback {
1019 default void onStart() {
1020 }
Lyn Hanbde48202019-05-29 19:18:29 -07001021
Lucas Dupin9e3fa102017-11-08 17:16:55 -08001022 default void onDisplayBlanked() {
1023 }
Lyn Hanbde48202019-05-29 19:18:29 -07001024
Lucas Dupin9e3fa102017-11-08 17:16:55 -08001025 default void onFinished() {
1026 }
Lyn Hanbde48202019-05-29 19:18:29 -07001027
Lucas Dupin9e3fa102017-11-08 17:16:55 -08001028 default void onCancelled() {
1029 }
Adrian Roosba7ca592017-08-15 17:48:05 +02001030 }
Lucas Dupin690c6f52018-07-10 15:28:57 -07001031
1032 /**
1033 * Simple keyguard callback that updates scrims when keyguard visibility changes.
1034 */
1035 private class KeyguardVisibilityCallback extends KeyguardUpdateMonitorCallback {
1036
1037 @Override
1038 public void onKeyguardVisibilityChanged(boolean showing) {
1039 mNeedsDrawableColorUpdate = true;
1040 scheduleUpdate();
1041 }
1042 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +02001043}