blob: 279ede914fa72cc2a044a02527f3b5bcab79eafd [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 Dupin82aa1632017-12-13 00:13:57 -080022import android.app.AlarmManager;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070023import android.app.WallpaperManager;
John Spurlockd06aa572014-09-10 10:40:49 -040024import android.content.Context;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070025import android.graphics.Color;
Selim Cinek6811d722016-01-19 17:53:12 -080026import android.graphics.Rect;
Anthony Chene658cc22017-04-27 11:17:35 -070027import android.graphics.drawable.Drawable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080028import android.os.Handler;
Adrian Roosa5c63222017-07-27 16:33:39 +020029import android.os.Trace;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080030import android.util.Log;
Lucas Dupina0bf8512017-05-24 17:04:47 -070031import android.util.MathUtils;
Lucas Dupin8c7cb022018-02-05 10:49:03 -080032import android.view.Choreographer;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020033import android.view.View;
Selim Cineke803491c2016-04-09 21:24:45 -070034import android.view.ViewGroup;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020035import android.view.ViewTreeObserver;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020036import android.view.animation.DecelerateInterpolator;
37import android.view.animation.Interpolator;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070038
Lucas Dupin9e3fa102017-11-08 17:16:55 -080039import com.android.internal.annotations.VisibleForTesting;
Lucas Dupine2292a92017-07-06 14:35:30 -070040import com.android.internal.colorextraction.ColorExtractor;
41import com.android.internal.colorextraction.ColorExtractor.GradientColors;
42import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
Lucas Dupin9324aa92017-07-26 20:29:38 -070043import com.android.internal.graphics.ColorUtils;
Yohei Yukawa795f0102018-04-13 14:55:30 -070044import com.android.internal.util.function.TriConsumer;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070045import com.android.keyguard.KeyguardUpdateMonitor;
Lucas Dupin314d41f2017-05-08 15:52:58 -070046import com.android.systemui.Dependency;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080047import com.android.systemui.Dumpable;
John Spurlockbf370992014-06-17 13:58:31 -040048import com.android.systemui.R;
Lucas Dupin1ead7fc2017-05-24 14:14:44 -070049import com.android.systemui.colorextraction.SysuiColorExtractor;
Selim Cinekaac93252015-04-14 20:04:12 -070050import com.android.systemui.statusbar.ExpandableNotificationRow;
51import com.android.systemui.statusbar.NotificationData;
Selim Cineka0fad3b2014-09-19 17:20:05 +020052import com.android.systemui.statusbar.ScrimView;
Selim Cinek0cfbef42016-11-09 19:06:36 -080053import com.android.systemui.statusbar.stack.ViewState;
Lucas Dupin82aa1632017-12-13 00:13:57 -080054import com.android.systemui.util.AlarmTimeout;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080055import com.android.systemui.util.wakelock.DelayedWakeLock;
56import com.android.systemui.util.wakelock.WakeLock;
John Spurlockbf370992014-06-17 13:58:31 -040057
Lucas Dupin9e3fa102017-11-08 17:16:55 -080058import java.io.FileDescriptor;
Adrian Roosba7ca592017-08-15 17:48:05 +020059import java.io.PrintWriter;
Adrian Roosa5c63222017-07-27 16:33:39 +020060import java.util.function.Consumer;
61
Jorim Jaggiecc798e2014-05-26 18:14:37 +020062/**
63 * Controls both the scrim behind the notifications and in front of the notifications (when a
64 * security method gets shown).
65 */
Selim Cinek99e9adf2018-03-15 09:17:47 -070066public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
67 Dumpable {
Lucas Dupin9e3fa102017-11-08 17:16:55 -080068
69 private static final String TAG = "ScrimController";
70 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
71
Lucas Dupin4749f1b2018-04-04 15:09:06 -070072 /**
73 * General scrim animation duration.
74 */
John Spurlock8b12f222014-09-09 11:54:11 -040075 public static final long ANIMATION_DURATION = 220;
Lucas Dupin4749f1b2018-04-04 15:09:06 -070076 /**
77 * Longer duration, currently only used when going to AOD.
78 */
79 public static final long ANIMATION_DURATION_LONG = 1000;
Lucas Dupin82aa1632017-12-13 00:13:57 -080080 /**
81 * When both scrims have 0 alpha.
82 */
83 public static final int VISIBILITY_FULLY_TRANSPARENT = 0;
84 /**
85 * When scrims aren't transparent (alpha 0) but also not opaque (alpha 1.)
86 */
87 public static final int VISIBILITY_SEMI_TRANSPARENT = 1;
88 /**
89 * When at least 1 scrim is fully opaque (alpha set to 1.)
90 */
91 public static final int VISIBILITY_FULLY_OPAQUE = 2;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080092 /**
93 * Default alpha value for most scrims.
94 */
Lucas Dupin932f3b92018-05-01 15:43:06 -070095 public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080096 /**
97 * A scrim varies its opacity based on a busyness factor, for example
98 * how many notifications are currently visible.
99 */
Lucas Dupin16446262017-06-26 14:21:16 -0700100 public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800101 /**
102 * The most common scrim, the one under the keyguard.
103 */
Lucas Dupina0bf8512017-05-24 17:04:47 -0700104 protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800105
106 static final int TAG_KEY_ANIM = R.id.scrim;
Selim Cinek5104a6d2015-12-18 18:38:31 -0800107 private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
108 private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
Selim Cinek511f2702017-04-10 19:53:01 -0700109 private static final float NOT_INITIALIZED = -1;
John Spurlockbf370992014-06-17 13:58:31 -0400110
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800111 private ScrimState mState = ScrimState.UNINITIALIZED;
112 private final Context mContext;
Xiaohui Chen5da71352016-02-22 10:04:41 -0800113 protected final ScrimView mScrimBehind;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700114 protected final ScrimView mScrimInFront;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800115 private final UnlockMethodCache mUnlockMethodCache;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700116 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800117 private final DozeParameters mDozeParameters;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800118 private final AlarmTimeout mTimeTicker;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200119
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700120 private final SysuiColorExtractor mColorExtractor;
Lucas Dupine2292a92017-07-06 14:35:30 -0700121 private GradientColors mLockColors;
122 private GradientColors mSystemColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700123 private boolean mNeedsDrawableColorUpdate;
124
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800125 protected float mScrimBehindAlpha;
Lucas Dupin9324aa92017-07-26 20:29:38 -0700126 protected float mScrimBehindAlphaResValue;
Evan Rosky9a895012016-04-21 11:26:15 -0700127 protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
Xiaohui Chen4dab4b52016-03-07 12:31:14 -0800128
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800129 // Assuming the shade is expanded during initialization
130 private float mExpansionFraction = 1f;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200131
132 private boolean mDarkenWhileDragging;
Lucas Dupin67f02632018-03-12 11:08:31 -0700133 private boolean mExpansionAffectsAlpha = true;
Evan Rosky9a895012016-04-21 11:26:15 -0700134 protected boolean mAnimateChange;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200135 private boolean mUpdatePending;
Jorim Jaggie93698b2016-11-11 18:24:38 -0800136 private boolean mTracking;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800137 protected long mAnimationDuration = -1;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200138 private long mAnimationDelay;
139 private Runnable mOnAnimationFinished;
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200140 private boolean mDeferFinishedListener;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200141 private final Interpolator mInterpolator = new DecelerateInterpolator();
Selim Cinek511f2702017-04-10 19:53:01 -0700142 private float mCurrentInFrontAlpha = NOT_INITIALIZED;
143 private float mCurrentBehindAlpha = NOT_INITIALIZED;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800144 private int mCurrentInFrontTint;
145 private int mCurrentBehindTint;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800146 private boolean mWallpaperVisibilityTimedOut;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800147 private int mScrimsVisibility;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700148 private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800149 private final Consumer<Integer> mScrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800150 private boolean mBlankScreen;
151 private boolean mScreenBlankingCallbackCalled;
152 private Callback mCallback;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800153 private boolean mWallpaperSupportsAmbientMode;
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800154 private boolean mScreenOn;
Lucas Dupinb380c882018-02-25 21:57:17 -0800155 private float mNotificationDensity;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800156
157 // Scrim blanking callbacks
Lucas Dupin0791d972018-03-26 13:32:16 -0700158 private Runnable mPendingFrameCallback;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800159 private Runnable mBlankingTransitionRunnable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800160
161 private final WakeLock mWakeLock;
162 private boolean mWakeLockHeld;
Lucas Dupind5107302018-03-19 15:30:29 -0700163 private boolean mKeyguardOccluded;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200164
shawnlin317db372018-04-09 19:49:48 +0800165 public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
Yohei Yukawa795f0102018-04-13 14:55:30 -0700166 TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
shawnlin317db372018-04-09 19:49:48 +0800167 Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
168 AlarmManager alarmManager) {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200169 mScrimBehind = scrimBehind;
170 mScrimInFront = scrimInFront;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700171 mScrimStateListener = scrimStateListener;
Adrian Roosa5c63222017-07-27 16:33:39 +0200172 mScrimVisibleListener = scrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800173 mContext = scrimBehind.getContext();
174 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800175 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800176 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800177 mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
Lucas Dupin82aa1632017-12-13 00:13:57 -0800178 mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
179 "hide_aod_wallpaper", new Handler());
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800180 mWakeLock = createWakeLock();
Lucas Dupin9324aa92017-07-26 20:29:38 -0700181 // Scrim alpha is initially set to the value on the resource but might be changed
182 // to make sure that text on top of it is legible.
183 mScrimBehindAlpha = mScrimBehindAlphaResValue;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800184 mDozeParameters = dozeParameters;
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800185
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700186 mColorExtractor = Dependency.get(SysuiColorExtractor.class);
Lucas Dupin314d41f2017-05-08 15:52:58 -0700187 mColorExtractor.addOnColorsChangedListener(this);
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700188 mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700189 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin5266ad12017-06-17 20:57:28 -0700190 mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700191 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700192 mNeedsDrawableColorUpdate = true;
193
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800194 final ScrimState[] states = ScrimState.values();
195 for (int i = 0; i < states.length; i++) {
196 states[i].init(mScrimInFront, mScrimBehind, mDozeParameters);
197 states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
198 }
199 mState = ScrimState.UNINITIALIZED;
200
Lucas Dupin373356b2018-04-07 10:50:25 -0700201 mScrimBehind.setDefaultFocusHighlightEnabled(false);
202 mScrimInFront.setDefaultFocusHighlightEnabled(false);
203
Selim Cinek511f2702017-04-10 19:53:01 -0700204 updateScrims();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200205 }
206
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800207 public void transitionTo(ScrimState state) {
208 transitionTo(state, null);
209 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700210
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800211 public void transitionTo(ScrimState state, Callback callback) {
212 if (state == mState) {
Lucas Dupin19aba8e2017-12-11 12:42:26 -0800213 // Call the callback anyway, unless it's already enqueued
214 if (callback != null && mCallback != callback) {
215 callback.onFinished();
216 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800217 return;
218 } else if (DEBUG) {
219 Log.d(TAG, "State changed to: " + state);
220 }
221
222 if (state == ScrimState.UNINITIALIZED) {
223 throw new IllegalArgumentException("Cannot change to UNINITIALIZED.");
224 }
225
Lucas Dupin8635c442017-12-08 10:36:28 -0800226 final ScrimState oldState = mState;
227 mState = state;
Lucas Dupin5866aaf2018-02-02 14:45:31 -0800228 Trace.traceCounter(Trace.TRACE_TAG_APP, "scrim_state", mState.getIndex());
Lucas Dupin8635c442017-12-08 10:36:28 -0800229
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800230 if (mCallback != null) {
231 mCallback.onCancelled();
232 }
233 mCallback = callback;
234
Lucas Dupin8635c442017-12-08 10:36:28 -0800235 state.prepare(oldState);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800236 mScreenBlankingCallbackCalled = false;
237 mAnimationDelay = 0;
238 mBlankScreen = state.getBlanksScreen();
239 mAnimateChange = state.getAnimateChange();
240 mAnimationDuration = state.getAnimationDuration();
241 mCurrentInFrontTint = state.getFrontTint();
242 mCurrentBehindTint = state.getBehindTint();
243 mCurrentInFrontAlpha = state.getFrontAlpha();
Lucas Dupinb380c882018-02-25 21:57:17 -0800244 mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800245 applyExpansionToAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800246
Lucas Dupin38962d72018-03-14 12:41:39 -0700247 // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
248 // We need to disable focus otherwise AOD would end up with a gray overlay.
249 mScrimInFront.setFocusable(!state.isLowPowerState());
250 mScrimBehind.setFocusable(!state.isLowPowerState());
251
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800252 // Cancel blanking transitions that were pending before we requested a new state
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800253 if (mPendingFrameCallback != null) {
Lucas Dupin0791d972018-03-26 13:32:16 -0700254 mScrimBehind.removeCallbacks(mPendingFrameCallback);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800255 mPendingFrameCallback = null;
256 }
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800257 if (getHandler().hasCallbacks(mBlankingTransitionRunnable)) {
258 getHandler().removeCallbacks(mBlankingTransitionRunnable);
259 mBlankingTransitionRunnable = null;
260 }
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800261
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800262 // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
263 // to do the same when you're just showing the brightness mirror.
264 mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
265
Lucas Dupineea53b32017-12-18 13:47:14 -0800266 // The device might sleep if it's entering AOD, we need to make sure that
267 // the animation plays properly until the last frame.
268 // It's important to avoid holding the wakelock unless necessary because
269 // WakeLock#aqcuire will trigger an IPC and will cause jank.
Lucas Dupin38962d72018-03-14 12:41:39 -0700270 if (mState.isLowPowerState()) {
Lucas Dupineea53b32017-12-18 13:47:14 -0800271 holdWakeLock();
272 }
Lucas Dupin82aa1632017-12-13 00:13:57 -0800273
274 // AOD wallpapers should fade away after a while
275 if (mWallpaperSupportsAmbientMode && mDozeParameters.getAlwaysOn()
Lucas Dupin6680b262018-03-19 12:38:05 -0700276 && mState == ScrimState.AOD) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800277 if (!mWallpaperVisibilityTimedOut) {
278 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
279 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800280 }
Lucas Dupin6680b262018-03-19 12:38:05 -0700281 // Do not re-schedule timeout when pulsing, let's save some extra battery.
282 } else if (mState != ScrimState.PULSING) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800283 mTimeTicker.cancel();
284 mWallpaperVisibilityTimedOut = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800285 }
286
Lucas Dupinff307d52018-02-05 21:16:39 -0800287 if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800288 // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
289 // with too many things at this case, in order to not skip the initial frames.
290 mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
291 mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
Lucas Dupin0791d972018-03-26 13:32:16 -0700292 } else if ((!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD)
Lucas Dupin16cfe452018-02-08 13:14:50 -0800293 || (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
294 // Scheduling a frame isn't enough when:
295 // • Leaving doze and we need to modify scrim color immediately
296 // • ColorFade will not kick-in and scrim cannot wait for pre-draw.
Lucas Dupinff307d52018-02-05 21:16:39 -0800297 onPreDraw();
298 } else {
299 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800300 }
Yohei Yukawa795f0102018-04-13 14:55:30 -0700301
302 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800303 }
304
305 public ScrimState getState() {
306 return mState;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200307 }
308
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800309 protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700310 mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800311 ScrimState[] states = ScrimState.values();
312 for (int i = 0; i < states.length; i++) {
313 states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
314 }
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700315 scheduleUpdate();
316 }
317
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200318 public void onTrackingStarted() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800319 mTracking = true;
Selim Cineke8bae622015-07-15 13:24:06 -0700320 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200321 }
322
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200323 public void onExpandingFinished() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800324 mTracking = false;
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200325 }
326
Lucas Dupin82aa1632017-12-13 00:13:57 -0800327 @VisibleForTesting
328 protected void onHideWallpaperTimeout() {
Lucas Dupin6680b262018-03-19 12:38:05 -0700329 if (mState != ScrimState.AOD) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800330 return;
331 }
332
333 holdWakeLock();
334 mWallpaperVisibilityTimedOut = true;
335 mAnimateChange = true;
336 mAnimationDuration = mDozeParameters.getWallpaperFadeOutDuration();
337 scheduleUpdate();
338 }
339
340 private void holdWakeLock() {
341 if (!mWakeLockHeld) {
342 if (mWakeLock != null) {
343 mWakeLockHeld = true;
344 mWakeLock.acquire();
345 } else {
346 Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
347 }
348 }
349 }
350
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800351 /**
352 * Current state of the shade expansion when pulling it from the top.
353 * This value is 1 when on top of the keyguard and goes to 0 as the user drags up.
354 *
355 * The expansion fraction is tied to the scrim opacity.
356 *
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800357 * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800358 */
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200359 public void setPanelExpansion(float fraction) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800360 if (mExpansionFraction != fraction) {
361 mExpansionFraction = fraction;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800362
Lucas Dupin067136c2018-03-27 18:03:25 -0700363 final boolean keyguardOrUnlocked = mState == ScrimState.UNLOCKED
364 || mState == ScrimState.KEYGUARD;
365 if (!keyguardOrUnlocked || !mExpansionAffectsAlpha) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800366 return;
367 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800368
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800369 applyExpansionToAlpha();
370
371 if (mUpdatePending) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800372 return;
373 }
374
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800375 setOrAdaptCurrentAnimation(mScrimBehind);
376 setOrAdaptCurrentAnimation(mScrimInFront);
shawnlin317db372018-04-09 19:49:48 +0800377
Yohei Yukawa795f0102018-04-13 14:55:30 -0700378 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800379 }
380 }
381
382 private void setOrAdaptCurrentAnimation(View scrim) {
383 if (!isAnimating(scrim)) {
384 updateScrimColor(scrim, getCurrentScrimAlpha(scrim), getCurrentScrimTint(scrim));
385 } else {
386 ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
387 float alpha = getCurrentScrimAlpha(scrim);
388 float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
389 float previousStartValue = (Float) scrim.getTag(TAG_START_ALPHA);
390 float relativeDiff = alpha - previousEndValue;
391 float newStartValue = previousStartValue + relativeDiff;
392 scrim.setTag(TAG_START_ALPHA, newStartValue);
393 scrim.setTag(TAG_END_ALPHA, alpha);
394 previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
Jorim Jaggi93439da2014-06-30 23:53:39 +0200395 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200396 }
397
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800398 private void applyExpansionToAlpha() {
Lucas Dupin67f02632018-03-12 11:08:31 -0700399 if (!mExpansionAffectsAlpha) {
400 return;
401 }
402
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800403 if (mState == ScrimState.UNLOCKED) {
404 // Darken scrim as you pull down the shade when unlocked
405 float behindFraction = getInterpolatedFraction();
406 behindFraction = (float) Math.pow(behindFraction, 0.8f);
Lucas Dupind7c44eb2018-04-05 10:00:31 -0700407 mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800408 mCurrentInFrontAlpha = 0;
409 } else if (mState == ScrimState.KEYGUARD) {
410 // Either darken of make the scrim transparent when you
411 // pull down the shade
412 float interpolatedFract = getInterpolatedFraction();
Lucas Dupinb380c882018-02-25 21:57:17 -0800413 float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800414 if (mDarkenWhileDragging) {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800415 mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
Lucas Dupinb380c882018-02-25 21:57:17 -0800416 interpolatedFract);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800417 mCurrentInFrontAlpha = 0;
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800418 } else {
Lucas Dupinb380c882018-02-25 21:57:17 -0800419 mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800420 interpolatedFract);
421 mCurrentInFrontAlpha = 0;
422 }
423 }
424 }
425
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800426 /**
427 * Keyguard and shade scrim opacity varies according to how many notifications are visible.
428 * @param notificationCount Number of visible notifications.
429 */
Lucas Dupina0bf8512017-05-24 17:04:47 -0700430 public void setNotificationCount(int notificationCount) {
431 final float maxNotificationDensity = 3;
432 float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
Lucas Dupinb380c882018-02-25 21:57:17 -0800433 if (mNotificationDensity == notificationDensity) {
434 return;
435 }
436 mNotificationDensity = notificationDensity;
Lucas Dupina0bf8512017-05-24 17:04:47 -0700437
Lucas Dupinb380c882018-02-25 21:57:17 -0800438 if (mState == ScrimState.KEYGUARD) {
439 applyExpansionToAlpha();
440 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800441 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700442 }
Selim Cinek359c48c2016-07-11 16:59:03 -0700443
Anthony Chene658cc22017-04-27 11:17:35 -0700444 /**
445 * Sets the given drawable as the background of the scrim that shows up behind the
446 * notifications.
447 */
448 public void setScrimBehindDrawable(Drawable drawable) {
449 mScrimBehind.setDrawable(drawable);
450 }
451
Michael Wrightcae88752018-04-16 23:13:54 +0100452 /**
Lucas Dupin69bda602018-05-18 17:24:52 -0700453 * Sets the front scrim opacity in AOD so it's not as bright.
454 * <p>
455 * Displays usually don't support multiple dimming settings when in low power mode.
456 * The workaround is to modify the front scrim opacity when in AOD, so it's not as
457 * bright when you're at the movies or lying down on bed.
458 * <p>
459 * This value will be lost during transitions and only updated again after the the
460 * device is dozing when the light sensor is on.
Michael Wrightcae88752018-04-16 23:13:54 +0100461 */
462 public void setAodFrontScrimAlpha(float alpha) {
Lucas Dupin69bda602018-05-18 17:24:52 -0700463 if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()
464 && mCurrentInFrontAlpha != alpha) {
Michael Wrightcae88752018-04-16 23:13:54 +0100465 mCurrentInFrontAlpha = alpha;
466 scheduleUpdate();
467 }
468
469 mState.AOD.setAodFrontScrimAlpha(alpha);
470 }
471
Evan Rosky9a895012016-04-21 11:26:15 -0700472 protected void scheduleUpdate() {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200473 if (mUpdatePending) return;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200474
475 // Make sure that a frame gets scheduled.
476 mScrimBehind.invalidate();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200477 mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
478 mUpdatePending = true;
479 }
480
Xiaohui Chen5da71352016-02-22 10:04:41 -0800481 protected void updateScrims() {
Lucas Dupin9324aa92017-07-26 20:29:38 -0700482 // Make sure we have the right gradients and their opacities will satisfy GAR.
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700483 if (mNeedsDrawableColorUpdate) {
484 mNeedsDrawableColorUpdate = false;
Lucas Dupin9324aa92017-07-26 20:29:38 -0700485 final GradientColors currentScrimColors;
Lucas Dupin05726cd2018-03-13 14:00:24 -0700486 if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_SCRIMMED
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800487 || mState == ScrimState.BOUNCER) {
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700488 // Always animate color changes if we're seeing the keyguard
Lucas Dupin75ec3792017-06-29 14:07:18 -0700489 mScrimInFront.setColors(mLockColors, true /* animated */);
490 mScrimBehind.setColors(mLockColors, true /* animated */);
Lucas Dupin9324aa92017-07-26 20:29:38 -0700491 currentScrimColors = mLockColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700492 } else {
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700493 // Only animate scrim color if the scrim view is actually visible
494 boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
495 boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0;
Lucas Dupin5266ad12017-06-17 20:57:28 -0700496 mScrimInFront.setColors(mSystemColors, animateScrimInFront);
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700497 mScrimBehind.setColors(mSystemColors, animateScrimBehind);
Lucas Dupin9324aa92017-07-26 20:29:38 -0700498 currentScrimColors = mSystemColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700499 }
Lucas Dupin9324aa92017-07-26 20:29:38 -0700500
501 // Calculate minimum scrim opacity for white or black text.
502 int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
503 int mainColor = currentScrimColors.getMainColor();
504 float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
505 4.5f /* minimumContrast */) / 255f;
506 mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
Yohei Yukawa795f0102018-04-13 14:55:30 -0700507 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700508 }
509
Lucas Dupind5107302018-03-19 15:30:29 -0700510 // We want to override the back scrim opacity for the AOD state
Lucas Dupin82aa1632017-12-13 00:13:57 -0800511 // when it's time to fade the wallpaper away.
Lucas Dupind5107302018-03-19 15:30:29 -0700512 boolean aodWallpaperTimeout = mState == ScrimState.AOD && mWallpaperVisibilityTimedOut;
513 // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
514 boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
515 && mKeyguardOccluded;
516 if (aodWallpaperTimeout || occludedKeyguard) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800517 mCurrentBehindAlpha = 1;
518 }
519
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800520 setScrimInFrontAlpha(mCurrentInFrontAlpha);
521 setScrimBehindAlpha(mCurrentBehindAlpha);
522
Adrian Roosa5c63222017-07-27 16:33:39 +0200523 dispatchScrimsVisible();
524 }
525
Yohei Yukawa795f0102018-04-13 14:55:30 -0700526 private void dispatchScrimState(float alpha) {
527 mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
528 }
529
Adrian Roosa5c63222017-07-27 16:33:39 +0200530 private void dispatchScrimsVisible() {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800531 final int currentScrimVisibility;
532 if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
533 currentScrimVisibility = VISIBILITY_FULLY_OPAQUE;
534 } else if (mScrimInFront.getViewAlpha() == 0 && mScrimBehind.getViewAlpha() == 0) {
535 currentScrimVisibility = VISIBILITY_FULLY_TRANSPARENT;
536 } else {
537 currentScrimVisibility = VISIBILITY_SEMI_TRANSPARENT;
538 }
Adrian Roosa5c63222017-07-27 16:33:39 +0200539
Lucas Dupin82aa1632017-12-13 00:13:57 -0800540 if (mScrimsVisibility != currentScrimVisibility) {
541 mScrimsVisibility = currentScrimVisibility;
542 mScrimVisibleListener.accept(currentScrimVisibility);
Adrian Roosa5c63222017-07-27 16:33:39 +0200543 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200544 }
545
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800546 private float getInterpolatedFraction() {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800547 float frac = mExpansionFraction;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200548 // let's start this 20% of the way down the screen
549 frac = frac * 1.2f - 0.2f;
550 if (frac <= 0) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800551 return 0;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200552 } else {
553 // woo, special effects
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800554 return (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200555 }
556 }
557
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700558 private void setScrimBehindAlpha(float alpha) {
559 setScrimAlpha(mScrimBehind, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200560 }
561
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700562 private void setScrimInFrontAlpha(float alpha) {
563 setScrimAlpha(mScrimInFront, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200564 }
565
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800566 private void setScrimAlpha(ScrimView scrim, float alpha) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800567 if (alpha == 0f) {
568 scrim.setClickable(false);
Selim Cinekaac93252015-04-14 20:04:12 -0700569 } else {
Lucas Dupin78949b82018-04-03 18:54:39 -0700570 // Eat touch events (unless dozing or pulsing).
571 scrim.setClickable(mState != ScrimState.AOD && mState != ScrimState.PULSING);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200572 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800573 updateScrim(scrim, alpha);
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100574 }
575
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800576 private void updateScrimColor(View scrim, float alpha, int tint) {
577 alpha = Math.max(0, Math.min(1.0f, alpha));
Selim Cinekaac93252015-04-14 20:04:12 -0700578 if (scrim instanceof ScrimView) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700579 ScrimView scrimView = (ScrimView) scrim;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700580
Adrian Roosa5c63222017-07-27 16:33:39 +0200581 Trace.traceCounter(Trace.TRACE_TAG_APP,
582 scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
583 (int) (alpha * 255));
584
Adrian Roosa5c63222017-07-27 16:33:39 +0200585 Trace.traceCounter(Trace.TRACE_TAG_APP,
586 scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800587 Color.alpha(tint));
Adrian Roosa5c63222017-07-27 16:33:39 +0200588
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800589 scrimView.setTint(tint);
590 scrimView.setViewAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700591 } else {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800592 scrim.setAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700593 }
Selim Cinek8cd80402017-08-01 10:44:29 -0700594 dispatchScrimsVisible();
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100595 }
596
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800597 private void startScrimAnimation(final View scrim, float current) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800598 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
599 final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() :
600 Color.TRANSPARENT;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700601 anim.addUpdateListener(animation -> {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800602 final float startAlpha = (Float) scrim.getTag(TAG_START_ALPHA);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800603 final float animAmount = (float) animation.getAnimatedValue();
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800604 final int finalScrimTint = getCurrentScrimTint(scrim);
605 final float finalScrimAlpha = getCurrentScrimAlpha(scrim);
606 float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount);
607 alpha = MathUtils.constrain(alpha, 0f, 1f);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800608 int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
609 updateScrimColor(scrim, alpha, tint);
Adrian Roosa5c63222017-07-27 16:33:39 +0200610 dispatchScrimsVisible();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200611 });
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800612 anim.setInterpolator(mInterpolator);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200613 anim.setStartDelay(mAnimationDelay);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800614 anim.setDuration(mAnimationDuration);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200615 anim.addListener(new AnimatorListenerAdapter() {
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200616 @Override
617 public void onAnimationEnd(Animator animation) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800618 onFinished();
619
620 scrim.setTag(TAG_KEY_ANIM, null);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800621 dispatchScrimsVisible();
622
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200623 if (!mDeferFinishedListener && mOnAnimationFinished != null) {
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200624 mOnAnimationFinished.run();
625 mOnAnimationFinished = null;
626 }
627 }
628 });
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800629
630 // Cache alpha values because we might want to update this animator in the future if
631 // the user expands the panel while the animation is still running.
632 scrim.setTag(TAG_START_ALPHA, current);
633 scrim.setTag(TAG_END_ALPHA, getCurrentScrimAlpha(scrim));
634
John Spurlockbf370992014-06-17 13:58:31 -0400635 scrim.setTag(TAG_KEY_ANIM, anim);
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800636 anim.start();
637 }
638
639 private float getCurrentScrimAlpha(View scrim) {
640 if (scrim == mScrimInFront) {
641 return mCurrentInFrontAlpha;
642 } else if (scrim == mScrimBehind) {
643 return mCurrentBehindAlpha;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800644 } else {
645 throw new IllegalArgumentException("Unknown scrim view");
646 }
647 }
648
649 private int getCurrentScrimTint(View scrim) {
650 if (scrim == mScrimInFront) {
651 return mCurrentInFrontTint;
652 } else if (scrim == mScrimBehind) {
653 return mCurrentBehindTint;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800654 } else {
655 throw new IllegalArgumentException("Unknown scrim view");
656 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200657 }
658
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200659 @Override
660 public boolean onPreDraw() {
661 mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
662 mUpdatePending = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800663 if (mCallback != null) {
664 mCallback.onStart();
Selim Cinek372d1bd2015-08-14 13:19:37 -0700665 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200666 updateScrims();
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800667 if (mOnAnimationFinished != null && !isAnimating(mScrimInFront)
668 && !isAnimating(mScrimBehind)) {
669 mOnAnimationFinished.run();
670 mOnAnimationFinished = null;
671 }
Selim Cinekedd32b82015-06-23 22:05:58 -0400672 return true;
673 }
674
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800675 private void onFinished() {
676 if (mWakeLockHeld) {
677 mWakeLock.release();
678 mWakeLockHeld = false;
679 }
680 if (mCallback != null) {
681 mCallback.onFinished();
682 mCallback = null;
683 }
684 // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
685 // At the end of the animation we need to remove the tint.
686 if (mState == ScrimState.UNLOCKED) {
687 mCurrentInFrontTint = Color.TRANSPARENT;
688 mCurrentBehindTint = Color.TRANSPARENT;
689 }
690 }
691
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700692 private boolean isAnimating(View scrim) {
693 return scrim.getTag(TAG_KEY_ANIM) != null;
694 }
695
Selim Cinek25503252016-03-03 15:31:43 -0800696 public void setDrawBehindAsSrc(boolean asSrc) {
Selim Cineka0fad3b2014-09-19 17:20:05 +0200697 mScrimBehind.setDrawAsSrc(asSrc);
698 }
Selim Cinekaac93252015-04-14 20:04:12 -0700699
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800700 @VisibleForTesting
701 void setOnAnimationFinished(Runnable onAnimationFinished) {
702 mOnAnimationFinished = onAnimationFinished;
703 }
Adrian Roos5f72c922016-03-08 15:54:26 -0800704
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800705 private void updateScrim(ScrimView scrim, float alpha) {
706 final float currentAlpha = scrim.getViewAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800707
708 ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM);
Selim Cinekaac93252015-04-14 20:04:12 -0700709 if (previousAnimator != null) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800710 if (mAnimateChange) {
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200711 // We are not done yet! Defer calling the finished listener.
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800712 mDeferFinishedListener = true;
Selim Cinekaac93252015-04-14 20:04:12 -0700713 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800714 // Previous animators should always be cancelled. Not doing so would cause
715 // overlap, especially on states that don't animate, leading to flickering,
716 // and in the worst case, an internal state that doesn't represent what
717 // transitionTo requested.
718 cancelAnimator(previousAnimator);
719 mDeferFinishedListener = false;
Selim Cinekaac93252015-04-14 20:04:12 -0700720 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800721
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800722 if (mPendingFrameCallback != null) {
723 // Display is off and we're waiting.
724 return;
725 } else if (mBlankScreen) {
726 // Need to blank the display before continuing.
727 blankDisplay();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800728 return;
729 } else if (!mScreenBlankingCallbackCalled) {
730 // Not blanking the screen. Letting the callback know that we're ready
731 // to replace what was on the screen before.
732 if (mCallback != null) {
733 mCallback.onDisplayBlanked();
734 mScreenBlankingCallbackCalled = true;
735 }
736 }
737
Lucas Dupin6afae372017-11-30 13:09:22 -0500738 if (scrim == mScrimBehind) {
Yohei Yukawa795f0102018-04-13 14:55:30 -0700739 dispatchScrimState(alpha);
Lucas Dupin6afae372017-11-30 13:09:22 -0500740 }
741
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800742 final boolean wantsAlphaUpdate = alpha != currentAlpha;
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800743 final boolean wantsTintUpdate = scrim.getTint() != getCurrentScrimTint(scrim);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800744
745 if (wantsAlphaUpdate || wantsTintUpdate) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800746 if (mAnimateChange) {
747 startScrimAnimation(scrim, currentAlpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700748 } else {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800749 // update the alpha directly
750 updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
751 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700752 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800753 } else {
754 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700755 }
756 }
757
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800758 @VisibleForTesting
759 protected void cancelAnimator(ValueAnimator previousAnimator) {
760 if (previousAnimator != null) {
761 previousAnimator.cancel();
762 }
763 }
764
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800765 private void blankDisplay() {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800766 updateScrimColor(mScrimInFront, 1, Color.BLACK);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800767
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800768 // Notify callback that the screen is completely black and we're
769 // ready to change the display power mode
Lucas Dupin0791d972018-03-26 13:32:16 -0700770 mPendingFrameCallback = () -> {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800771 if (mCallback != null) {
772 mCallback.onDisplayBlanked();
773 mScreenBlankingCallbackCalled = true;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800774 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800775
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800776 mBlankingTransitionRunnable = () -> {
777 mBlankingTransitionRunnable = null;
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800778 mPendingFrameCallback = null;
779 mBlankScreen = false;
780 // Try again.
781 updateScrims();
782 };
783
784 // Setting power states can happen after we push out the frame. Make sure we
785 // stay fully opaque until the power state request reaches the lower levels.
Lucas Dupin0791d972018-03-26 13:32:16 -0700786 final int delay = mScreenOn ? 32 : 500;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800787 if (DEBUG) {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800788 Log.d(TAG, "Fading out scrims with delay: " + delay);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800789 }
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800790 getHandler().postDelayed(mBlankingTransitionRunnable, delay);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800791 };
792 doOnTheNextFrame(mPendingFrameCallback);
793 }
794
Lucas Dupin0791d972018-03-26 13:32:16 -0700795 /**
796 * Executes a callback after the frame has hit the display.
797 * @param callback What to run.
798 */
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800799 @VisibleForTesting
Lucas Dupin0791d972018-03-26 13:32:16 -0700800 protected void doOnTheNextFrame(Runnable callback) {
801 // Just calling View#postOnAnimation isn't enough because the frame might not have reached
802 // the display yet. A timeout is the safest solution.
803 mScrimBehind.postOnAnimationDelayed(callback, 32 /* delayMillis */);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800804 }
805
806 @VisibleForTesting
807 protected Handler getHandler() {
808 return Handler.getMain();
809 }
810
Selim Cinek6811d722016-01-19 17:53:12 -0800811 public void setExcludedBackgroundArea(Rect area) {
812 mScrimBehind.setExcludedArea(area);
813 }
Selim Cinekd35c2792016-01-21 13:20:57 -0800814
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700815 public int getBackgroundColor() {
816 int color = mLockColors.getMainColor();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800817 return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700818 Color.red(color), Color.green(color), Color.blue(color));
Selim Cinekd35c2792016-01-21 13:20:57 -0800819 }
820
821 public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
822 mScrimBehind.setChangeRunnable(changeRunnable);
823 }
Selim Cineke803491c2016-04-09 21:24:45 -0700824
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700825 public void setCurrentUser(int currentUser) {
826 // Don't care in the base class.
827 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700828
829 @Override
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700830 public void onColorsChanged(ColorExtractor colorExtractor, int which) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700831 if ((which & WallpaperManager.FLAG_LOCK) != 0) {
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700832 mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700833 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700834 mNeedsDrawableColorUpdate = true;
835 scheduleUpdate();
836 }
837 if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700838 mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800839 ColorExtractor.TYPE_DARK, mState != ScrimState.UNLOCKED);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700840 mNeedsDrawableColorUpdate = true;
841 scheduleUpdate();
842 }
843 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200844
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800845 @VisibleForTesting
846 protected WakeLock createWakeLock() {
847 return new DelayedWakeLock(getHandler(),
Lucas Dupine03081f2018-04-03 11:31:27 -0700848 WakeLock.createPartial(mContext, "Scrims"));
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800849 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200850
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800851 @Override
852 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800853 pw.println(" ScrimController: ");
854 pw.print(" state: "); pw.println(mState);
855 pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200856 pw.print(" alpha="); pw.print(mCurrentInFrontAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200857 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint()));
858
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800859 pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200860 pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200861 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
862
Adrian Roosba7ca592017-08-15 17:48:05 +0200863 pw.print(" mTracking="); pw.println(mTracking);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800864 }
865
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700866 public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800867 mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
868 ScrimState[] states = ScrimState.values();
869 for (int i = 0; i < states.length; i++) {
870 states[i].setWallpaperSupportsAmbientMode(wallpaperSupportsAmbientMode);
871 }
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700872 }
873
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800874 /**
875 * Interrupts blanking transitions once the display notifies that it's already on.
876 */
877 public void onScreenTurnedOn() {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800878 mScreenOn = true;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800879 final Handler handler = getHandler();
880 if (handler.hasCallbacks(mBlankingTransitionRunnable)) {
881 if (DEBUG) {
882 Log.d(TAG, "Shorter blanking because screen turned on. All good.");
883 }
884 handler.removeCallbacks(mBlankingTransitionRunnable);
885 mBlankingTransitionRunnable.run();
886 }
887 }
888
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800889 public void onScreenTurnedOff() {
890 mScreenOn = false;
891 }
892
Lucas Dupin67f02632018-03-12 11:08:31 -0700893 public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
894 mExpansionAffectsAlpha = expansionAffectsAlpha;
895 }
896
Lucas Dupind5107302018-03-19 15:30:29 -0700897 public void setKeyguardOccluded(boolean keyguardOccluded) {
898 mKeyguardOccluded = keyguardOccluded;
Lucas Dupin63d72172018-06-06 11:42:55 -0700899 updateScrims();
Lucas Dupind5107302018-03-19 15:30:29 -0700900 }
901
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800902 public interface Callback {
903 default void onStart() {
904 }
905 default void onDisplayBlanked() {
906 }
907 default void onFinished() {
908 }
909 default void onCancelled() {
910 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200911 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200912}