blob: 31e5305410e85c849ba2de457d4dc286df59ef93 [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;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020032import android.view.View;
33import android.view.ViewTreeObserver;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020034import android.view.animation.DecelerateInterpolator;
35import android.view.animation.Interpolator;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070036
Lucas Dupin9e3fa102017-11-08 17:16:55 -080037import com.android.internal.annotations.VisibleForTesting;
Lucas Dupine2292a92017-07-06 14:35:30 -070038import com.android.internal.colorextraction.ColorExtractor;
39import com.android.internal.colorextraction.ColorExtractor.GradientColors;
40import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
Lucas Dupin9324aa92017-07-26 20:29:38 -070041import com.android.internal.graphics.ColorUtils;
Yohei Yukawa795f0102018-04-13 14:55:30 -070042import com.android.internal.util.function.TriConsumer;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070043import com.android.keyguard.KeyguardUpdateMonitor;
Lucas Dupinf8463ee2018-06-11 16:18:15 -070044import com.android.keyguard.KeyguardUpdateMonitorCallback;
Lucas Dupin314d41f2017-05-08 15:52:58 -070045import com.android.systemui.Dependency;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080046import com.android.systemui.Dumpable;
John Spurlockbf370992014-06-17 13:58:31 -040047import com.android.systemui.R;
Lucas Dupin1ead7fc2017-05-24 14:14:44 -070048import com.android.systemui.colorextraction.SysuiColorExtractor;
Selim Cineka0fad3b2014-09-19 17:20:05 +020049import com.android.systemui.statusbar.ScrimView;
Selim Cinek0cfbef42016-11-09 19:06:36 -080050import com.android.systemui.statusbar.stack.ViewState;
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;
Adrian Roosa5c63222017-07-27 16:33:39 +020057import java.util.function.Consumer;
58
Jorim Jaggiecc798e2014-05-26 18:14:37 +020059/**
60 * Controls both the scrim behind the notifications and in front of the notifications (when a
61 * security method gets shown).
62 */
Selim Cinek99e9adf2018-03-15 09:17:47 -070063public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
64 Dumpable {
Lucas Dupin9e3fa102017-11-08 17:16:55 -080065
66 private static final String TAG = "ScrimController";
67 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
68
Lucas Dupin4749f1b2018-04-04 15:09:06 -070069 /**
70 * General scrim animation duration.
71 */
John Spurlock8b12f222014-09-09 11:54:11 -040072 public static final long ANIMATION_DURATION = 220;
Lucas Dupin4749f1b2018-04-04 15:09:06 -070073 /**
74 * Longer duration, currently only used when going to AOD.
75 */
76 public static final long ANIMATION_DURATION_LONG = 1000;
Lucas Dupin82aa1632017-12-13 00:13:57 -080077 /**
78 * When both scrims have 0 alpha.
79 */
80 public static final int VISIBILITY_FULLY_TRANSPARENT = 0;
81 /**
82 * When scrims aren't transparent (alpha 0) but also not opaque (alpha 1.)
83 */
84 public static final int VISIBILITY_SEMI_TRANSPARENT = 1;
85 /**
86 * When at least 1 scrim is fully opaque (alpha set to 1.)
87 */
88 public static final int VISIBILITY_FULLY_OPAQUE = 2;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080089 /**
90 * Default alpha value for most scrims.
91 */
Lucas Dupin932f3b92018-05-01 15:43:06 -070092 public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080093 /**
94 * A scrim varies its opacity based on a busyness factor, for example
95 * how many notifications are currently visible.
96 */
Lucas Dupin16446262017-06-26 14:21:16 -070097 public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080098 /**
99 * The most common scrim, the one under the keyguard.
100 */
Lucas Dupina0bf8512017-05-24 17:04:47 -0700101 protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800102
103 static final int TAG_KEY_ANIM = R.id.scrim;
Selim Cinek5104a6d2015-12-18 18:38:31 -0800104 private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
105 private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
Selim Cinek511f2702017-04-10 19:53:01 -0700106 private static final float NOT_INITIALIZED = -1;
John Spurlockbf370992014-06-17 13:58:31 -0400107
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800108 private ScrimState mState = ScrimState.UNINITIALIZED;
109 private final Context mContext;
Xiaohui Chen5da71352016-02-22 10:04:41 -0800110 protected final ScrimView mScrimBehind;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700111 protected final ScrimView mScrimInFront;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800112 private final UnlockMethodCache mUnlockMethodCache;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700113 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800114 private final DozeParameters mDozeParameters;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800115 private final AlarmTimeout mTimeTicker;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200116
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700117 private final SysuiColorExtractor mColorExtractor;
Lucas Dupine2292a92017-07-06 14:35:30 -0700118 private GradientColors mLockColors;
119 private GradientColors mSystemColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700120 private boolean mNeedsDrawableColorUpdate;
121
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800122 protected float mScrimBehindAlpha;
Lucas Dupin9324aa92017-07-26 20:29:38 -0700123 protected float mScrimBehindAlphaResValue;
Evan Rosky9a895012016-04-21 11:26:15 -0700124 protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
Xiaohui Chen4dab4b52016-03-07 12:31:14 -0800125
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800126 // Assuming the shade is expanded during initialization
127 private float mExpansionFraction = 1f;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200128
129 private boolean mDarkenWhileDragging;
Lucas Dupin67f02632018-03-12 11:08:31 -0700130 private boolean mExpansionAffectsAlpha = true;
Evan Rosky9a895012016-04-21 11:26:15 -0700131 protected boolean mAnimateChange;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200132 private boolean mUpdatePending;
Jorim Jaggie93698b2016-11-11 18:24:38 -0800133 private boolean mTracking;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800134 protected long mAnimationDuration = -1;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200135 private long mAnimationDelay;
136 private Runnable mOnAnimationFinished;
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200137 private boolean mDeferFinishedListener;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200138 private final Interpolator mInterpolator = new DecelerateInterpolator();
Selim Cinek511f2702017-04-10 19:53:01 -0700139 private float mCurrentInFrontAlpha = NOT_INITIALIZED;
140 private float mCurrentBehindAlpha = NOT_INITIALIZED;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800141 private int mCurrentInFrontTint;
142 private int mCurrentBehindTint;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800143 private boolean mWallpaperVisibilityTimedOut;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800144 private int mScrimsVisibility;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700145 private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800146 private final Consumer<Integer> mScrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800147 private boolean mBlankScreen;
148 private boolean mScreenBlankingCallbackCalled;
149 private Callback mCallback;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800150 private boolean mWallpaperSupportsAmbientMode;
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800151 private boolean mScreenOn;
Lucas Dupinb380c882018-02-25 21:57:17 -0800152 private float mNotificationDensity;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800153
154 // Scrim blanking callbacks
Lucas Dupin0791d972018-03-26 13:32:16 -0700155 private Runnable mPendingFrameCallback;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800156 private Runnable mBlankingTransitionRunnable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800157
158 private final WakeLock mWakeLock;
159 private boolean mWakeLockHeld;
Lucas Dupind5107302018-03-19 15:30:29 -0700160 private boolean mKeyguardOccluded;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200161
shawnlin317db372018-04-09 19:49:48 +0800162 public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
Yohei Yukawa795f0102018-04-13 14:55:30 -0700163 TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
shawnlin317db372018-04-09 19:49:48 +0800164 Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
165 AlarmManager alarmManager) {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200166 mScrimBehind = scrimBehind;
167 mScrimInFront = scrimInFront;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700168 mScrimStateListener = scrimStateListener;
Adrian Roosa5c63222017-07-27 16:33:39 +0200169 mScrimVisibleListener = scrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800170 mContext = scrimBehind.getContext();
171 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800172 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800173 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800174 mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
Lucas Dupin82aa1632017-12-13 00:13:57 -0800175 mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
176 "hide_aod_wallpaper", new Handler());
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800177 mWakeLock = createWakeLock();
Lucas Dupin9324aa92017-07-26 20:29:38 -0700178 // Scrim alpha is initially set to the value on the resource but might be changed
179 // to make sure that text on top of it is legible.
180 mScrimBehindAlpha = mScrimBehindAlphaResValue;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800181 mDozeParameters = dozeParameters;
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800182
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700183 mColorExtractor = Dependency.get(SysuiColorExtractor.class);
Lucas Dupin314d41f2017-05-08 15:52:58 -0700184 mColorExtractor.addOnColorsChangedListener(this);
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700185 mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700186 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin5266ad12017-06-17 20:57:28 -0700187 mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700188 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700189 mNeedsDrawableColorUpdate = true;
190
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800191 final ScrimState[] states = ScrimState.values();
192 for (int i = 0; i < states.length; i++) {
193 states[i].init(mScrimInFront, mScrimBehind, mDozeParameters);
194 states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
195 }
196 mState = ScrimState.UNINITIALIZED;
197
Lucas Dupin373356b2018-04-07 10:50:25 -0700198 mScrimBehind.setDefaultFocusHighlightEnabled(false);
199 mScrimInFront.setDefaultFocusHighlightEnabled(false);
200
Selim Cinek511f2702017-04-10 19:53:01 -0700201 updateScrims();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200202 }
203
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800204 public void transitionTo(ScrimState state) {
205 transitionTo(state, null);
206 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700207
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800208 public void transitionTo(ScrimState state, Callback callback) {
209 if (state == mState) {
Lucas Dupin19aba8e2017-12-11 12:42:26 -0800210 // Call the callback anyway, unless it's already enqueued
211 if (callback != null && mCallback != callback) {
212 callback.onFinished();
213 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800214 return;
215 } else if (DEBUG) {
216 Log.d(TAG, "State changed to: " + state);
217 }
218
219 if (state == ScrimState.UNINITIALIZED) {
220 throw new IllegalArgumentException("Cannot change to UNINITIALIZED.");
221 }
222
Lucas Dupin8635c442017-12-08 10:36:28 -0800223 final ScrimState oldState = mState;
224 mState = state;
Lucas Dupin5866aaf2018-02-02 14:45:31 -0800225 Trace.traceCounter(Trace.TRACE_TAG_APP, "scrim_state", mState.getIndex());
Lucas Dupin8635c442017-12-08 10:36:28 -0800226
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800227 if (mCallback != null) {
228 mCallback.onCancelled();
229 }
230 mCallback = callback;
231
Lucas Dupin8635c442017-12-08 10:36:28 -0800232 state.prepare(oldState);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800233 mScreenBlankingCallbackCalled = false;
234 mAnimationDelay = 0;
235 mBlankScreen = state.getBlanksScreen();
236 mAnimateChange = state.getAnimateChange();
237 mAnimationDuration = state.getAnimationDuration();
238 mCurrentInFrontTint = state.getFrontTint();
239 mCurrentBehindTint = state.getBehindTint();
240 mCurrentInFrontAlpha = state.getFrontAlpha();
Lucas Dupinb380c882018-02-25 21:57:17 -0800241 mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800242 applyExpansionToAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800243
Lucas Dupin38962d72018-03-14 12:41:39 -0700244 // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
245 // We need to disable focus otherwise AOD would end up with a gray overlay.
246 mScrimInFront.setFocusable(!state.isLowPowerState());
247 mScrimBehind.setFocusable(!state.isLowPowerState());
248
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800249 // Cancel blanking transitions that were pending before we requested a new state
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800250 if (mPendingFrameCallback != null) {
Lucas Dupin0791d972018-03-26 13:32:16 -0700251 mScrimBehind.removeCallbacks(mPendingFrameCallback);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800252 mPendingFrameCallback = null;
253 }
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800254 if (getHandler().hasCallbacks(mBlankingTransitionRunnable)) {
255 getHandler().removeCallbacks(mBlankingTransitionRunnable);
256 mBlankingTransitionRunnable = null;
257 }
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800258
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800259 // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
260 // to do the same when you're just showing the brightness mirror.
261 mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
262
Lucas Dupineea53b32017-12-18 13:47:14 -0800263 // The device might sleep if it's entering AOD, we need to make sure that
264 // the animation plays properly until the last frame.
265 // It's important to avoid holding the wakelock unless necessary because
266 // WakeLock#aqcuire will trigger an IPC and will cause jank.
Lucas Dupin38962d72018-03-14 12:41:39 -0700267 if (mState.isLowPowerState()) {
Lucas Dupineea53b32017-12-18 13:47:14 -0800268 holdWakeLock();
269 }
Lucas Dupin82aa1632017-12-13 00:13:57 -0800270
271 // AOD wallpapers should fade away after a while
272 if (mWallpaperSupportsAmbientMode && mDozeParameters.getAlwaysOn()
Lucas Dupin6680b262018-03-19 12:38:05 -0700273 && mState == ScrimState.AOD) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800274 if (!mWallpaperVisibilityTimedOut) {
275 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
276 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800277 }
Lucas Dupin6680b262018-03-19 12:38:05 -0700278 // Do not re-schedule timeout when pulsing, let's save some extra battery.
279 } else if (mState != ScrimState.PULSING) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800280 mTimeTicker.cancel();
281 mWallpaperVisibilityTimedOut = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800282 }
283
Lucas Dupinff307d52018-02-05 21:16:39 -0800284 if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800285 // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
286 // with too many things at this case, in order to not skip the initial frames.
287 mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
288 mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
Lucas Dupin0791d972018-03-26 13:32:16 -0700289 } else if ((!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD)
Lucas Dupin16cfe452018-02-08 13:14:50 -0800290 || (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
291 // Scheduling a frame isn't enough when:
292 // • Leaving doze and we need to modify scrim color immediately
293 // • ColorFade will not kick-in and scrim cannot wait for pre-draw.
Lucas Dupinff307d52018-02-05 21:16:39 -0800294 onPreDraw();
295 } else {
296 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800297 }
Yohei Yukawa795f0102018-04-13 14:55:30 -0700298
299 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800300 }
301
302 public ScrimState getState() {
303 return mState;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200304 }
305
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800306 protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700307 mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800308 ScrimState[] states = ScrimState.values();
309 for (int i = 0; i < states.length; i++) {
310 states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
311 }
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700312 scheduleUpdate();
313 }
314
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200315 public void onTrackingStarted() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800316 mTracking = true;
Selim Cineke8bae622015-07-15 13:24:06 -0700317 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200318 }
319
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200320 public void onExpandingFinished() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800321 mTracking = false;
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200322 }
323
Lucas Dupin82aa1632017-12-13 00:13:57 -0800324 @VisibleForTesting
325 protected void onHideWallpaperTimeout() {
Lucas Dupin6680b262018-03-19 12:38:05 -0700326 if (mState != ScrimState.AOD) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800327 return;
328 }
329
330 holdWakeLock();
331 mWallpaperVisibilityTimedOut = true;
332 mAnimateChange = true;
333 mAnimationDuration = mDozeParameters.getWallpaperFadeOutDuration();
334 scheduleUpdate();
335 }
336
337 private void holdWakeLock() {
338 if (!mWakeLockHeld) {
339 if (mWakeLock != null) {
340 mWakeLockHeld = true;
341 mWakeLock.acquire();
342 } else {
343 Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
344 }
345 }
346 }
347
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800348 /**
349 * Current state of the shade expansion when pulling it from the top.
350 * This value is 1 when on top of the keyguard and goes to 0 as the user drags up.
351 *
352 * The expansion fraction is tied to the scrim opacity.
353 *
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800354 * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800355 */
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200356 public void setPanelExpansion(float fraction) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800357 if (mExpansionFraction != fraction) {
358 mExpansionFraction = fraction;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800359
Lucas Dupin067136c2018-03-27 18:03:25 -0700360 final boolean keyguardOrUnlocked = mState == ScrimState.UNLOCKED
361 || mState == ScrimState.KEYGUARD;
362 if (!keyguardOrUnlocked || !mExpansionAffectsAlpha) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800363 return;
364 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800365
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800366 applyExpansionToAlpha();
367
368 if (mUpdatePending) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800369 return;
370 }
371
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800372 setOrAdaptCurrentAnimation(mScrimBehind);
373 setOrAdaptCurrentAnimation(mScrimInFront);
shawnlin317db372018-04-09 19:49:48 +0800374
Yohei Yukawa795f0102018-04-13 14:55:30 -0700375 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800376 }
377 }
378
379 private void setOrAdaptCurrentAnimation(View scrim) {
380 if (!isAnimating(scrim)) {
381 updateScrimColor(scrim, getCurrentScrimAlpha(scrim), getCurrentScrimTint(scrim));
382 } else {
383 ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
384 float alpha = getCurrentScrimAlpha(scrim);
385 float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
386 float previousStartValue = (Float) scrim.getTag(TAG_START_ALPHA);
387 float relativeDiff = alpha - previousEndValue;
388 float newStartValue = previousStartValue + relativeDiff;
389 scrim.setTag(TAG_START_ALPHA, newStartValue);
390 scrim.setTag(TAG_END_ALPHA, alpha);
391 previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
Jorim Jaggi93439da2014-06-30 23:53:39 +0200392 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200393 }
394
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800395 private void applyExpansionToAlpha() {
Lucas Dupin67f02632018-03-12 11:08:31 -0700396 if (!mExpansionAffectsAlpha) {
397 return;
398 }
399
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800400 if (mState == ScrimState.UNLOCKED) {
401 // Darken scrim as you pull down the shade when unlocked
402 float behindFraction = getInterpolatedFraction();
403 behindFraction = (float) Math.pow(behindFraction, 0.8f);
Lucas Dupind7c44eb2018-04-05 10:00:31 -0700404 mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800405 mCurrentInFrontAlpha = 0;
406 } else if (mState == ScrimState.KEYGUARD) {
407 // Either darken of make the scrim transparent when you
408 // pull down the shade
409 float interpolatedFract = getInterpolatedFraction();
Lucas Dupinb380c882018-02-25 21:57:17 -0800410 float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800411 if (mDarkenWhileDragging) {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800412 mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
Lucas Dupinb380c882018-02-25 21:57:17 -0800413 interpolatedFract);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800414 mCurrentInFrontAlpha = 0;
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800415 } else {
Lucas Dupinb380c882018-02-25 21:57:17 -0800416 mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800417 interpolatedFract);
418 mCurrentInFrontAlpha = 0;
419 }
420 }
421 }
422
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800423 /**
424 * Keyguard and shade scrim opacity varies according to how many notifications are visible.
425 * @param notificationCount Number of visible notifications.
426 */
Lucas Dupina0bf8512017-05-24 17:04:47 -0700427 public void setNotificationCount(int notificationCount) {
428 final float maxNotificationDensity = 3;
429 float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
Lucas Dupinb380c882018-02-25 21:57:17 -0800430 if (mNotificationDensity == notificationDensity) {
431 return;
432 }
433 mNotificationDensity = notificationDensity;
Lucas Dupina0bf8512017-05-24 17:04:47 -0700434
Lucas Dupinb380c882018-02-25 21:57:17 -0800435 if (mState == ScrimState.KEYGUARD) {
436 applyExpansionToAlpha();
437 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800438 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700439 }
Selim Cinek359c48c2016-07-11 16:59:03 -0700440
Anthony Chene658cc22017-04-27 11:17:35 -0700441 /**
442 * Sets the given drawable as the background of the scrim that shows up behind the
443 * notifications.
444 */
445 public void setScrimBehindDrawable(Drawable drawable) {
446 mScrimBehind.setDrawable(drawable);
447 }
448
Michael Wrightcae88752018-04-16 23:13:54 +0100449 /**
Lucas Dupin69bda602018-05-18 17:24:52 -0700450 * Sets the front scrim opacity in AOD so it's not as bright.
451 * <p>
452 * Displays usually don't support multiple dimming settings when in low power mode.
453 * The workaround is to modify the front scrim opacity when in AOD, so it's not as
454 * bright when you're at the movies or lying down on bed.
455 * <p>
456 * This value will be lost during transitions and only updated again after the the
457 * device is dozing when the light sensor is on.
Michael Wrightcae88752018-04-16 23:13:54 +0100458 */
459 public void setAodFrontScrimAlpha(float alpha) {
Lucas Dupin69bda602018-05-18 17:24:52 -0700460 if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()
461 && mCurrentInFrontAlpha != alpha) {
Michael Wrightcae88752018-04-16 23:13:54 +0100462 mCurrentInFrontAlpha = alpha;
463 scheduleUpdate();
464 }
465
466 mState.AOD.setAodFrontScrimAlpha(alpha);
467 }
468
Evan Rosky9a895012016-04-21 11:26:15 -0700469 protected void scheduleUpdate() {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200470 if (mUpdatePending) return;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200471
472 // Make sure that a frame gets scheduled.
473 mScrimBehind.invalidate();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200474 mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
475 mUpdatePending = true;
476 }
477
Xiaohui Chen5da71352016-02-22 10:04:41 -0800478 protected void updateScrims() {
Lucas Dupin9324aa92017-07-26 20:29:38 -0700479 // Make sure we have the right gradients and their opacities will satisfy GAR.
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700480 if (mNeedsDrawableColorUpdate) {
481 mNeedsDrawableColorUpdate = false;
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700482 boolean isKeyguard = mKeyguardUpdateMonitor.isKeyguardVisible() && !mKeyguardOccluded;
483 GradientColors currentScrimColors = isKeyguard ? mLockColors : mSystemColors;
484 // Only animate scrim color if the scrim view is actually visible
485 boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen;
486 boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
487 mScrimInFront.setColors(currentScrimColors, animateScrimInFront);
488 mScrimBehind.setColors(currentScrimColors, animateScrimBehind);
Lucas Dupin9324aa92017-07-26 20:29:38 -0700489
490 // Calculate minimum scrim opacity for white or black text.
491 int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
492 int mainColor = currentScrimColors.getMainColor();
493 float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
494 4.5f /* minimumContrast */) / 255f;
495 mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
Yohei Yukawa795f0102018-04-13 14:55:30 -0700496 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700497 }
498
Lucas Dupind5107302018-03-19 15:30:29 -0700499 // We want to override the back scrim opacity for the AOD state
Lucas Dupin82aa1632017-12-13 00:13:57 -0800500 // when it's time to fade the wallpaper away.
Lucas Dupind5107302018-03-19 15:30:29 -0700501 boolean aodWallpaperTimeout = mState == ScrimState.AOD && mWallpaperVisibilityTimedOut;
502 // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
503 boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
504 && mKeyguardOccluded;
505 if (aodWallpaperTimeout || occludedKeyguard) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800506 mCurrentBehindAlpha = 1;
507 }
508
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800509 setScrimInFrontAlpha(mCurrentInFrontAlpha);
510 setScrimBehindAlpha(mCurrentBehindAlpha);
511
Adrian Roosa5c63222017-07-27 16:33:39 +0200512 dispatchScrimsVisible();
513 }
514
Yohei Yukawa795f0102018-04-13 14:55:30 -0700515 private void dispatchScrimState(float alpha) {
516 mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
517 }
518
Adrian Roosa5c63222017-07-27 16:33:39 +0200519 private void dispatchScrimsVisible() {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800520 final int currentScrimVisibility;
521 if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
522 currentScrimVisibility = VISIBILITY_FULLY_OPAQUE;
523 } else if (mScrimInFront.getViewAlpha() == 0 && mScrimBehind.getViewAlpha() == 0) {
524 currentScrimVisibility = VISIBILITY_FULLY_TRANSPARENT;
525 } else {
526 currentScrimVisibility = VISIBILITY_SEMI_TRANSPARENT;
527 }
Adrian Roosa5c63222017-07-27 16:33:39 +0200528
Lucas Dupin82aa1632017-12-13 00:13:57 -0800529 if (mScrimsVisibility != currentScrimVisibility) {
530 mScrimsVisibility = currentScrimVisibility;
531 mScrimVisibleListener.accept(currentScrimVisibility);
Adrian Roosa5c63222017-07-27 16:33:39 +0200532 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200533 }
534
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800535 private float getInterpolatedFraction() {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800536 float frac = mExpansionFraction;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200537 // let's start this 20% of the way down the screen
538 frac = frac * 1.2f - 0.2f;
539 if (frac <= 0) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800540 return 0;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200541 } else {
542 // woo, special effects
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800543 return (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200544 }
545 }
546
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700547 private void setScrimBehindAlpha(float alpha) {
548 setScrimAlpha(mScrimBehind, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200549 }
550
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700551 private void setScrimInFrontAlpha(float alpha) {
552 setScrimAlpha(mScrimInFront, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200553 }
554
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800555 private void setScrimAlpha(ScrimView scrim, float alpha) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800556 if (alpha == 0f) {
557 scrim.setClickable(false);
Selim Cinekaac93252015-04-14 20:04:12 -0700558 } else {
Lucas Dupin78949b82018-04-03 18:54:39 -0700559 // Eat touch events (unless dozing or pulsing).
560 scrim.setClickable(mState != ScrimState.AOD && mState != ScrimState.PULSING);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200561 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800562 updateScrim(scrim, alpha);
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100563 }
564
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800565 private void updateScrimColor(View scrim, float alpha, int tint) {
566 alpha = Math.max(0, Math.min(1.0f, alpha));
Selim Cinekaac93252015-04-14 20:04:12 -0700567 if (scrim instanceof ScrimView) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700568 ScrimView scrimView = (ScrimView) scrim;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700569
Adrian Roosa5c63222017-07-27 16:33:39 +0200570 Trace.traceCounter(Trace.TRACE_TAG_APP,
571 scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
572 (int) (alpha * 255));
573
Adrian Roosa5c63222017-07-27 16:33:39 +0200574 Trace.traceCounter(Trace.TRACE_TAG_APP,
575 scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800576 Color.alpha(tint));
Adrian Roosa5c63222017-07-27 16:33:39 +0200577
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800578 scrimView.setTint(tint);
579 scrimView.setViewAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700580 } else {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800581 scrim.setAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700582 }
Selim Cinek8cd80402017-08-01 10:44:29 -0700583 dispatchScrimsVisible();
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100584 }
585
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800586 private void startScrimAnimation(final View scrim, float current) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800587 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
588 final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() :
589 Color.TRANSPARENT;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700590 anim.addUpdateListener(animation -> {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800591 final float startAlpha = (Float) scrim.getTag(TAG_START_ALPHA);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800592 final float animAmount = (float) animation.getAnimatedValue();
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800593 final int finalScrimTint = getCurrentScrimTint(scrim);
594 final float finalScrimAlpha = getCurrentScrimAlpha(scrim);
595 float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount);
596 alpha = MathUtils.constrain(alpha, 0f, 1f);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800597 int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
598 updateScrimColor(scrim, alpha, tint);
Adrian Roosa5c63222017-07-27 16:33:39 +0200599 dispatchScrimsVisible();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200600 });
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800601 anim.setInterpolator(mInterpolator);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200602 anim.setStartDelay(mAnimationDelay);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800603 anim.setDuration(mAnimationDuration);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200604 anim.addListener(new AnimatorListenerAdapter() {
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200605 @Override
606 public void onAnimationEnd(Animator animation) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800607 onFinished();
608
609 scrim.setTag(TAG_KEY_ANIM, null);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800610 dispatchScrimsVisible();
611
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200612 if (!mDeferFinishedListener && mOnAnimationFinished != null) {
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200613 mOnAnimationFinished.run();
614 mOnAnimationFinished = null;
615 }
616 }
617 });
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800618
619 // Cache alpha values because we might want to update this animator in the future if
620 // the user expands the panel while the animation is still running.
621 scrim.setTag(TAG_START_ALPHA, current);
622 scrim.setTag(TAG_END_ALPHA, getCurrentScrimAlpha(scrim));
623
John Spurlockbf370992014-06-17 13:58:31 -0400624 scrim.setTag(TAG_KEY_ANIM, anim);
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800625 anim.start();
626 }
627
628 private float getCurrentScrimAlpha(View scrim) {
629 if (scrim == mScrimInFront) {
630 return mCurrentInFrontAlpha;
631 } else if (scrim == mScrimBehind) {
632 return mCurrentBehindAlpha;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800633 } else {
634 throw new IllegalArgumentException("Unknown scrim view");
635 }
636 }
637
638 private int getCurrentScrimTint(View scrim) {
639 if (scrim == mScrimInFront) {
640 return mCurrentInFrontTint;
641 } else if (scrim == mScrimBehind) {
642 return mCurrentBehindTint;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800643 } else {
644 throw new IllegalArgumentException("Unknown scrim view");
645 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200646 }
647
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200648 @Override
649 public boolean onPreDraw() {
650 mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
651 mUpdatePending = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800652 if (mCallback != null) {
653 mCallback.onStart();
Selim Cinek372d1bd2015-08-14 13:19:37 -0700654 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200655 updateScrims();
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800656 if (mOnAnimationFinished != null && !isAnimating(mScrimInFront)
657 && !isAnimating(mScrimBehind)) {
658 mOnAnimationFinished.run();
659 mOnAnimationFinished = null;
660 }
Selim Cinekedd32b82015-06-23 22:05:58 -0400661 return true;
662 }
663
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800664 private void onFinished() {
665 if (mWakeLockHeld) {
666 mWakeLock.release();
667 mWakeLockHeld = false;
668 }
669 if (mCallback != null) {
670 mCallback.onFinished();
671 mCallback = null;
672 }
673 // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
674 // At the end of the animation we need to remove the tint.
675 if (mState == ScrimState.UNLOCKED) {
676 mCurrentInFrontTint = Color.TRANSPARENT;
677 mCurrentBehindTint = Color.TRANSPARENT;
678 }
679 }
680
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700681 private boolean isAnimating(View scrim) {
682 return scrim.getTag(TAG_KEY_ANIM) != null;
683 }
684
Selim Cinek25503252016-03-03 15:31:43 -0800685 public void setDrawBehindAsSrc(boolean asSrc) {
Selim Cineka0fad3b2014-09-19 17:20:05 +0200686 mScrimBehind.setDrawAsSrc(asSrc);
687 }
Selim Cinekaac93252015-04-14 20:04:12 -0700688
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800689 @VisibleForTesting
690 void setOnAnimationFinished(Runnable onAnimationFinished) {
691 mOnAnimationFinished = onAnimationFinished;
692 }
Adrian Roos5f72c922016-03-08 15:54:26 -0800693
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800694 private void updateScrim(ScrimView scrim, float alpha) {
695 final float currentAlpha = scrim.getViewAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800696
697 ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM);
Selim Cinekaac93252015-04-14 20:04:12 -0700698 if (previousAnimator != null) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800699 if (mAnimateChange) {
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200700 // We are not done yet! Defer calling the finished listener.
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800701 mDeferFinishedListener = true;
Selim Cinekaac93252015-04-14 20:04:12 -0700702 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800703 // Previous animators should always be cancelled. Not doing so would cause
704 // overlap, especially on states that don't animate, leading to flickering,
705 // and in the worst case, an internal state that doesn't represent what
706 // transitionTo requested.
707 cancelAnimator(previousAnimator);
708 mDeferFinishedListener = false;
Selim Cinekaac93252015-04-14 20:04:12 -0700709 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800710
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800711 if (mPendingFrameCallback != null) {
712 // Display is off and we're waiting.
713 return;
714 } else if (mBlankScreen) {
715 // Need to blank the display before continuing.
716 blankDisplay();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800717 return;
718 } else if (!mScreenBlankingCallbackCalled) {
719 // Not blanking the screen. Letting the callback know that we're ready
720 // to replace what was on the screen before.
721 if (mCallback != null) {
722 mCallback.onDisplayBlanked();
723 mScreenBlankingCallbackCalled = true;
724 }
725 }
726
Lucas Dupin6afae372017-11-30 13:09:22 -0500727 if (scrim == mScrimBehind) {
Yohei Yukawa795f0102018-04-13 14:55:30 -0700728 dispatchScrimState(alpha);
Lucas Dupin6afae372017-11-30 13:09:22 -0500729 }
730
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800731 final boolean wantsAlphaUpdate = alpha != currentAlpha;
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800732 final boolean wantsTintUpdate = scrim.getTint() != getCurrentScrimTint(scrim);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800733
734 if (wantsAlphaUpdate || wantsTintUpdate) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800735 if (mAnimateChange) {
736 startScrimAnimation(scrim, currentAlpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700737 } else {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800738 // update the alpha directly
739 updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
740 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700741 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800742 } else {
743 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700744 }
745 }
746
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800747 @VisibleForTesting
748 protected void cancelAnimator(ValueAnimator previousAnimator) {
749 if (previousAnimator != null) {
750 previousAnimator.cancel();
751 }
752 }
753
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800754 private void blankDisplay() {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800755 updateScrimColor(mScrimInFront, 1, Color.BLACK);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800756
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800757 // Notify callback that the screen is completely black and we're
758 // ready to change the display power mode
Lucas Dupin0791d972018-03-26 13:32:16 -0700759 mPendingFrameCallback = () -> {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800760 if (mCallback != null) {
761 mCallback.onDisplayBlanked();
762 mScreenBlankingCallbackCalled = true;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800763 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800764
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800765 mBlankingTransitionRunnable = () -> {
766 mBlankingTransitionRunnable = null;
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800767 mPendingFrameCallback = null;
768 mBlankScreen = false;
769 // Try again.
770 updateScrims();
771 };
772
773 // Setting power states can happen after we push out the frame. Make sure we
774 // stay fully opaque until the power state request reaches the lower levels.
Lucas Dupin0791d972018-03-26 13:32:16 -0700775 final int delay = mScreenOn ? 32 : 500;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800776 if (DEBUG) {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800777 Log.d(TAG, "Fading out scrims with delay: " + delay);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800778 }
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800779 getHandler().postDelayed(mBlankingTransitionRunnable, delay);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800780 };
781 doOnTheNextFrame(mPendingFrameCallback);
782 }
783
Lucas Dupin0791d972018-03-26 13:32:16 -0700784 /**
785 * Executes a callback after the frame has hit the display.
786 * @param callback What to run.
787 */
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800788 @VisibleForTesting
Lucas Dupin0791d972018-03-26 13:32:16 -0700789 protected void doOnTheNextFrame(Runnable callback) {
790 // Just calling View#postOnAnimation isn't enough because the frame might not have reached
791 // the display yet. A timeout is the safest solution.
792 mScrimBehind.postOnAnimationDelayed(callback, 32 /* delayMillis */);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800793 }
794
795 @VisibleForTesting
796 protected Handler getHandler() {
797 return Handler.getMain();
798 }
799
Selim Cinek6811d722016-01-19 17:53:12 -0800800 public void setExcludedBackgroundArea(Rect area) {
801 mScrimBehind.setExcludedArea(area);
802 }
Selim Cinekd35c2792016-01-21 13:20:57 -0800803
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700804 public int getBackgroundColor() {
805 int color = mLockColors.getMainColor();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800806 return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700807 Color.red(color), Color.green(color), Color.blue(color));
Selim Cinekd35c2792016-01-21 13:20:57 -0800808 }
809
810 public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
811 mScrimBehind.setChangeRunnable(changeRunnable);
812 }
Selim Cineke803491c2016-04-09 21:24:45 -0700813
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700814 public void setCurrentUser(int currentUser) {
815 // Don't care in the base class.
816 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700817
818 @Override
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700819 public void onColorsChanged(ColorExtractor colorExtractor, int which) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700820 if ((which & WallpaperManager.FLAG_LOCK) != 0) {
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700821 mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700822 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700823 mNeedsDrawableColorUpdate = true;
824 scheduleUpdate();
825 }
826 if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700827 mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800828 ColorExtractor.TYPE_DARK, mState != ScrimState.UNLOCKED);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700829 mNeedsDrawableColorUpdate = true;
830 scheduleUpdate();
831 }
832 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200833
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800834 @VisibleForTesting
835 protected WakeLock createWakeLock() {
836 return new DelayedWakeLock(getHandler(),
Lucas Dupine03081f2018-04-03 11:31:27 -0700837 WakeLock.createPartial(mContext, "Scrims"));
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800838 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200839
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800840 @Override
841 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800842 pw.println(" ScrimController: ");
843 pw.print(" state: "); pw.println(mState);
844 pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200845 pw.print(" alpha="); pw.print(mCurrentInFrontAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200846 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint()));
847
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800848 pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200849 pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200850 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
851
Adrian Roosba7ca592017-08-15 17:48:05 +0200852 pw.print(" mTracking="); pw.println(mTracking);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800853 }
854
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700855 public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800856 mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
857 ScrimState[] states = ScrimState.values();
858 for (int i = 0; i < states.length; i++) {
859 states[i].setWallpaperSupportsAmbientMode(wallpaperSupportsAmbientMode);
860 }
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700861 }
862
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800863 /**
864 * Interrupts blanking transitions once the display notifies that it's already on.
865 */
866 public void onScreenTurnedOn() {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800867 mScreenOn = true;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800868 final Handler handler = getHandler();
869 if (handler.hasCallbacks(mBlankingTransitionRunnable)) {
870 if (DEBUG) {
871 Log.d(TAG, "Shorter blanking because screen turned on. All good.");
872 }
873 handler.removeCallbacks(mBlankingTransitionRunnable);
874 mBlankingTransitionRunnable.run();
875 }
876 }
877
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800878 public void onScreenTurnedOff() {
879 mScreenOn = false;
880 }
881
Lucas Dupin67f02632018-03-12 11:08:31 -0700882 public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
883 mExpansionAffectsAlpha = expansionAffectsAlpha;
884 }
885
Lucas Dupind5107302018-03-19 15:30:29 -0700886 public void setKeyguardOccluded(boolean keyguardOccluded) {
887 mKeyguardOccluded = keyguardOccluded;
Lucas Dupin63d72172018-06-06 11:42:55 -0700888 updateScrims();
Lucas Dupind5107302018-03-19 15:30:29 -0700889 }
890
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700891 public void setHasBackdrop(boolean hasBackdrop) {
Lucas Dupin193677c2018-06-11 19:16:03 -0700892 for (ScrimState state : ScrimState.values()) {
893 state.setHasBackdrop(hasBackdrop);
894 }
Lucas Dupin218a0cb2018-07-09 14:32:53 -0700895
896 // Backdrop event may arrive after state was already applied,
897 // in this case, back-scrim needs to be re-evaluated
898 if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
899 float newBehindAlpha = mState.getBehindAlpha(mNotificationDensity);
900 if (mCurrentBehindAlpha != newBehindAlpha) {
901 mCurrentBehindAlpha = newBehindAlpha;
902 updateScrims();
903 }
904 }
Lucas Dupin193677c2018-06-11 19:16:03 -0700905 }
906
907 public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
908 for (ScrimState state : ScrimState.values()) {
909 state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700910 }
911 }
912
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800913 public interface Callback {
914 default void onStart() {
915 }
916 default void onDisplayBlanked() {
917 }
918 default void onFinished() {
919 }
920 default void onCancelled() {
921 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200922 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200923}