blob: a7262cfcfefb335978404f34ebd1d0a1639e3139 [file] [log] [blame]
Jorim Jaggiecc798e2014-05-26 18:14:37 +02001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070022import android.annotation.IntDef;
Lucas Dupin82aa1632017-12-13 00:13:57 -080023import android.app.AlarmManager;
John Spurlockd06aa572014-09-10 10:40:49 -040024import android.content.Context;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070025import android.graphics.Color;
Anthony Chene658cc22017-04-27 11:17:35 -070026import android.graphics.drawable.Drawable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080027import android.os.Handler;
Adrian Roosa5c63222017-07-27 16:33:39 +020028import android.os.Trace;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080029import android.util.Log;
Lucas Dupina0bf8512017-05-24 17:04:47 -070030import android.util.MathUtils;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020031import android.view.View;
32import android.view.ViewTreeObserver;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020033import android.view.animation.DecelerateInterpolator;
34import android.view.animation.Interpolator;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070035
Lucas Dupin9e3fa102017-11-08 17:16:55 -080036import com.android.internal.annotations.VisibleForTesting;
Lucas Dupine2292a92017-07-06 14:35:30 -070037import com.android.internal.colorextraction.ColorExtractor;
38import com.android.internal.colorextraction.ColorExtractor.GradientColors;
39import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
Lucas Dupin9324aa92017-07-26 20:29:38 -070040import com.android.internal.graphics.ColorUtils;
Yohei Yukawa795f0102018-04-13 14:55:30 -070041import com.android.internal.util.function.TriConsumer;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070042import com.android.keyguard.KeyguardUpdateMonitor;
Lucas Dupinf8463ee2018-06-11 16:18:15 -070043import com.android.keyguard.KeyguardUpdateMonitorCallback;
Lucas Dupin314d41f2017-05-08 15:52:58 -070044import com.android.systemui.Dependency;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080045import com.android.systemui.Dumpable;
John Spurlockbf370992014-06-17 13:58:31 -040046import com.android.systemui.R;
Lucas Dupin1ead7fc2017-05-24 14:14:44 -070047import com.android.systemui.colorextraction.SysuiColorExtractor;
Selim Cineka0fad3b2014-09-19 17:20:05 +020048import com.android.systemui.statusbar.ScrimView;
Rohan Shah20790b82018-07-02 17:21:04 -070049import com.android.systemui.statusbar.notification.stack.ViewState;
Selim Cinek72cd9a72019-08-09 17:19:57 -070050import com.android.systemui.statusbar.policy.KeyguardMonitor;
Lucas Dupin82aa1632017-12-13 00:13:57 -080051import com.android.systemui.util.AlarmTimeout;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080052import com.android.systemui.util.wakelock.DelayedWakeLock;
53import com.android.systemui.util.wakelock.WakeLock;
John Spurlockbf370992014-06-17 13:58:31 -040054
Lucas Dupin9e3fa102017-11-08 17:16:55 -080055import java.io.FileDescriptor;
Adrian Roosba7ca592017-08-15 17:48:05 +020056import java.io.PrintWriter;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070057import java.lang.annotation.Retention;
58import java.lang.annotation.RetentionPolicy;
Adrian Roosa5c63222017-07-27 16:33:39 +020059import java.util.function.Consumer;
60
Jorim Jaggiecc798e2014-05-26 18:14:37 +020061/**
62 * Controls both the scrim behind the notifications and in front of the notifications (when a
63 * security method gets shown).
64 */
Selim Cinek99e9adf2018-03-15 09:17:47 -070065public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
66 Dumpable {
Lucas Dupin9e3fa102017-11-08 17:16:55 -080067
Lucas Dupin55c6e802018-09-27 18:07:36 -070068 static final String TAG = "ScrimController";
Lucas Dupin9e3fa102017-11-08 17:16:55 -080069 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
70
Lucas Dupin4749f1b2018-04-04 15:09:06 -070071 /**
72 * General scrim animation duration.
73 */
John Spurlock8b12f222014-09-09 11:54:11 -040074 public static final long ANIMATION_DURATION = 220;
Lucas Dupin4749f1b2018-04-04 15:09:06 -070075 /**
76 * Longer duration, currently only used when going to AOD.
77 */
78 public static final long ANIMATION_DURATION_LONG = 1000;
Lucas Dupin82aa1632017-12-13 00:13:57 -080079 /**
80 * When both scrims have 0 alpha.
81 */
82 public static final int VISIBILITY_FULLY_TRANSPARENT = 0;
83 /**
84 * When scrims aren't transparent (alpha 0) but also not opaque (alpha 1.)
85 */
86 public static final int VISIBILITY_SEMI_TRANSPARENT = 1;
87 /**
88 * When at least 1 scrim is fully opaque (alpha set to 1.)
89 */
90 public static final int VISIBILITY_FULLY_OPAQUE = 2;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070091
92 @IntDef(prefix = { "VISIBILITY_" }, value = {
93 VISIBILITY_FULLY_TRANSPARENT,
94 VISIBILITY_SEMI_TRANSPARENT,
95 VISIBILITY_FULLY_OPAQUE
96 })
97 @Retention(RetentionPolicy.SOURCE)
98 public @interface ScrimVisibility {}
99
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800100 /**
101 * Default alpha value for most scrims.
102 */
Lucas Dupin3d36dd82019-01-02 14:38:35 -0800103 public static final float GRADIENT_SCRIM_ALPHA = 0.2f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800104 /**
Lucas Dupin3113db62019-03-08 18:21:27 -0800105 * Scrim opacity when the phone is about to wake-up.
106 */
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700107 public static final float WAKE_SENSOR_SCRIM_ALPHA = 0.6f;
Lucas Dupin3113db62019-03-08 18:21:27 -0800108 /**
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800109 * A scrim varies its opacity based on a busyness factor, for example
110 * how many notifications are currently visible.
111 */
Lucas Dupinde64ee02018-12-21 14:45:12 -0800112 public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.7f;
Lucas Dupinde64ee02018-12-21 14:45:12 -0800113
Lucas Dupin55c6e802018-09-27 18:07:36 -0700114 /**
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800115 * The most common scrim, the one under the keyguard.
116 */
Lucas Dupina0bf8512017-05-24 17:04:47 -0700117 protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800118
119 static final int TAG_KEY_ANIM = R.id.scrim;
Selim Cinek5104a6d2015-12-18 18:38:31 -0800120 private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
121 private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
Selim Cinek511f2702017-04-10 19:53:01 -0700122 private static final float NOT_INITIALIZED = -1;
John Spurlockbf370992014-06-17 13:58:31 -0400123
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800124 private ScrimState mState = ScrimState.UNINITIALIZED;
125 private final Context mContext;
Xiaohui Chen5da71352016-02-22 10:04:41 -0800126 protected final ScrimView mScrimBehind;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700127 protected final ScrimView mScrimInFront;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800128 private final UnlockMethodCache mUnlockMethodCache;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700129 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800130 private final DozeParameters mDozeParameters;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800131 private final AlarmTimeout mTimeTicker;
Lucas Dupin690c6f52018-07-10 15:28:57 -0700132 private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800133 private final Handler mHandler;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200134
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700135 private final SysuiColorExtractor mColorExtractor;
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700136 private GradientColors mColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700137 private boolean mNeedsDrawableColorUpdate;
138
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800139 protected float mScrimBehindAlpha;
Lucas Dupin9324aa92017-07-26 20:29:38 -0700140 protected float mScrimBehindAlphaResValue;
Evan Rosky9a895012016-04-21 11:26:15 -0700141 protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
Xiaohui Chen4dab4b52016-03-07 12:31:14 -0800142
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800143 // Assuming the shade is expanded during initialization
144 private float mExpansionFraction = 1f;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200145
146 private boolean mDarkenWhileDragging;
Lucas Dupin67f02632018-03-12 11:08:31 -0700147 private boolean mExpansionAffectsAlpha = true;
Evan Rosky9a895012016-04-21 11:26:15 -0700148 protected boolean mAnimateChange;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200149 private boolean mUpdatePending;
Jorim Jaggie93698b2016-11-11 18:24:38 -0800150 private boolean mTracking;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800151 protected long mAnimationDuration = -1;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200152 private long mAnimationDelay;
153 private Runnable mOnAnimationFinished;
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200154 private boolean mDeferFinishedListener;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200155 private final Interpolator mInterpolator = new DecelerateInterpolator();
Selim Cinek511f2702017-04-10 19:53:01 -0700156 private float mCurrentInFrontAlpha = NOT_INITIALIZED;
157 private float mCurrentBehindAlpha = NOT_INITIALIZED;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800158 private int mCurrentInFrontTint;
159 private int mCurrentBehindTint;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800160 private boolean mWallpaperVisibilityTimedOut;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800161 private int mScrimsVisibility;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700162 private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800163 private final Consumer<Integer> mScrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800164 private boolean mBlankScreen;
165 private boolean mScreenBlankingCallbackCalled;
166 private Callback mCallback;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800167 private boolean mWallpaperSupportsAmbientMode;
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800168 private boolean mScreenOn;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800169
170 // Scrim blanking callbacks
Lucas Dupin0791d972018-03-26 13:32:16 -0700171 private Runnable mPendingFrameCallback;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800172 private Runnable mBlankingTransitionRunnable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800173
174 private final WakeLock mWakeLock;
175 private boolean mWakeLockHeld;
Lucas Dupind5107302018-03-19 15:30:29 -0700176 private boolean mKeyguardOccluded;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200177
shawnlin317db372018-04-09 19:49:48 +0800178 public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
Yohei Yukawa795f0102018-04-13 14:55:30 -0700179 TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
shawnlin317db372018-04-09 19:49:48 +0800180 Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
Selim Cinek72cd9a72019-08-09 17:19:57 -0700181 AlarmManager alarmManager, KeyguardMonitor keyguardMonitor) {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200182 mScrimBehind = scrimBehind;
183 mScrimInFront = scrimInFront;
Yohei Yukawa795f0102018-04-13 14:55:30 -0700184 mScrimStateListener = scrimStateListener;
Adrian Roosa5c63222017-07-27 16:33:39 +0200185 mScrimVisibleListener = scrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800186 mContext = scrimBehind.getContext();
187 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800188 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800189 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Lucas Dupin690c6f52018-07-10 15:28:57 -0700190 mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
191 mKeyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800192 mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800193 mHandler = getHandler();
Lucas Dupin82aa1632017-12-13 00:13:57 -0800194 mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800195 "hide_aod_wallpaper", mHandler);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800196 mWakeLock = createWakeLock();
Lucas Dupin9324aa92017-07-26 20:29:38 -0700197 // Scrim alpha is initially set to the value on the resource but might be changed
198 // to make sure that text on top of it is legible.
199 mScrimBehindAlpha = mScrimBehindAlphaResValue;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800200 mDozeParameters = dozeParameters;
Selim Cinek72cd9a72019-08-09 17:19:57 -0700201 keyguardMonitor.addCallback(new KeyguardMonitor.Callback() {
202 @Override
203 public void onKeyguardFadingAwayChanged() {
204 setKeyguardFadingAway(keyguardMonitor.isKeyguardFadingAway(),
205 keyguardMonitor.getKeyguardFadingAwayDuration());
206 }
207 });
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800208
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700209 mColorExtractor = Dependency.get(SysuiColorExtractor.class);
Lucas Dupin314d41f2017-05-08 15:52:58 -0700210 mColorExtractor.addOnColorsChangedListener(this);
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700211 mColors = mColorExtractor.getNeutralColors();
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700212 mNeedsDrawableColorUpdate = true;
213
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800214 final ScrimState[] states = ScrimState.values();
215 for (int i = 0; i < states.length; i++) {
216 states[i].init(mScrimInFront, mScrimBehind, mDozeParameters);
217 states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
218 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800219
Lucas Dupin373356b2018-04-07 10:50:25 -0700220 mScrimBehind.setDefaultFocusHighlightEnabled(false);
221 mScrimInFront.setDefaultFocusHighlightEnabled(false);
222
Selim Cinek511f2702017-04-10 19:53:01 -0700223 updateScrims();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200224 }
225
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800226 public void transitionTo(ScrimState state) {
227 transitionTo(state, null);
228 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700229
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800230 public void transitionTo(ScrimState state, Callback callback) {
231 if (state == mState) {
Lucas Dupin19aba8e2017-12-11 12:42:26 -0800232 // Call the callback anyway, unless it's already enqueued
233 if (callback != null && mCallback != callback) {
234 callback.onFinished();
235 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800236 return;
237 } else if (DEBUG) {
238 Log.d(TAG, "State changed to: " + state);
239 }
240
241 if (state == ScrimState.UNINITIALIZED) {
242 throw new IllegalArgumentException("Cannot change to UNINITIALIZED.");
243 }
244
Lucas Dupin8635c442017-12-08 10:36:28 -0800245 final ScrimState oldState = mState;
246 mState = state;
Lucas Dupin5866aaf2018-02-02 14:45:31 -0800247 Trace.traceCounter(Trace.TRACE_TAG_APP, "scrim_state", mState.getIndex());
Lucas Dupin8635c442017-12-08 10:36:28 -0800248
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800249 if (mCallback != null) {
250 mCallback.onCancelled();
251 }
252 mCallback = callback;
253
Lucas Dupin8635c442017-12-08 10:36:28 -0800254 state.prepare(oldState);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800255 mScreenBlankingCallbackCalled = false;
256 mAnimationDelay = 0;
257 mBlankScreen = state.getBlanksScreen();
258 mAnimateChange = state.getAnimateChange();
259 mAnimationDuration = state.getAnimationDuration();
260 mCurrentInFrontTint = state.getFrontTint();
261 mCurrentBehindTint = state.getBehindTint();
262 mCurrentInFrontAlpha = state.getFrontAlpha();
Lucas Dupin3d36dd82019-01-02 14:38:35 -0800263 mCurrentBehindAlpha = state.getBehindAlpha();
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800264 applyExpansionToAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800265
Lucas Dupin38962d72018-03-14 12:41:39 -0700266 // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
267 // We need to disable focus otherwise AOD would end up with a gray overlay.
268 mScrimInFront.setFocusable(!state.isLowPowerState());
269 mScrimBehind.setFocusable(!state.isLowPowerState());
270
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800271 // Cancel blanking transitions that were pending before we requested a new state
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800272 if (mPendingFrameCallback != null) {
Lucas Dupin0791d972018-03-26 13:32:16 -0700273 mScrimBehind.removeCallbacks(mPendingFrameCallback);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800274 mPendingFrameCallback = null;
275 }
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800276 if (mHandler.hasCallbacks(mBlankingTransitionRunnable)) {
277 mHandler.removeCallbacks(mBlankingTransitionRunnable);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800278 mBlankingTransitionRunnable = null;
279 }
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800280
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800281 // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
282 // to do the same when you're just showing the brightness mirror.
283 mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
284
Lucas Dupineea53b32017-12-18 13:47:14 -0800285 // The device might sleep if it's entering AOD, we need to make sure that
286 // the animation plays properly until the last frame.
287 // It's important to avoid holding the wakelock unless necessary because
288 // WakeLock#aqcuire will trigger an IPC and will cause jank.
Lucas Dupin38962d72018-03-14 12:41:39 -0700289 if (mState.isLowPowerState()) {
Lucas Dupineea53b32017-12-18 13:47:14 -0800290 holdWakeLock();
291 }
Lucas Dupin82aa1632017-12-13 00:13:57 -0800292
TYM Tsaia71c8922019-01-07 15:57:53 +0800293 // AOD wallpapers should fade away after a while.
294 // Docking pulses may take a long time, wallpapers should also fade away after a while.
Jerry Changbde4c0c2019-06-13 16:58:41 +0800295 mWallpaperVisibilityTimedOut = false;
296 if (shouldFadeAwayWallpaper()) {
297 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
298 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
Lucas Dupinc7804042018-12-21 12:26:33 -0800299 } else {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800300 mTimeTicker.cancel();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800301 }
302
Lucas Dupinff307d52018-02-05 21:16:39 -0800303 if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800304 // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
305 // with too many things at this case, in order to not skip the initial frames.
306 mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
307 mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
Lucas Dupin0791d972018-03-26 13:32:16 -0700308 } else if ((!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD)
Lucas Dupin16cfe452018-02-08 13:14:50 -0800309 || (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
310 // Scheduling a frame isn't enough when:
311 // • Leaving doze and we need to modify scrim color immediately
312 // • ColorFade will not kick-in and scrim cannot wait for pre-draw.
Lucas Dupinff307d52018-02-05 21:16:39 -0800313 onPreDraw();
314 } else {
315 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800316 }
Yohei Yukawa795f0102018-04-13 14:55:30 -0700317
318 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800319 }
320
Jerry Changbde4c0c2019-06-13 16:58:41 +0800321 private boolean shouldFadeAwayWallpaper() {
322 if (!mWallpaperSupportsAmbientMode) {
323 return false;
324 }
325
326 if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()) {
327 return true;
328 }
329
330 if (mState == ScrimState.PULSING
331 && mCallback != null && mCallback.shouldTimeoutWallpaper()) {
332 return true;
333 }
334
335 return false;
336 }
337
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800338 public ScrimState getState() {
339 return mState;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200340 }
341
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800342 protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700343 mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800344 ScrimState[] states = ScrimState.values();
345 for (int i = 0; i < states.length; i++) {
346 states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
347 }
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700348 scheduleUpdate();
349 }
350
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200351 public void onTrackingStarted() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800352 mTracking = true;
Selim Cineke8bae622015-07-15 13:24:06 -0700353 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200354 }
355
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200356 public void onExpandingFinished() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800357 mTracking = false;
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200358 }
359
Lucas Dupin82aa1632017-12-13 00:13:57 -0800360 @VisibleForTesting
361 protected void onHideWallpaperTimeout() {
TYM Tsaia71c8922019-01-07 15:57:53 +0800362 if (mState != ScrimState.AOD && mState != ScrimState.PULSING) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800363 return;
364 }
365
366 holdWakeLock();
367 mWallpaperVisibilityTimedOut = true;
368 mAnimateChange = true;
369 mAnimationDuration = mDozeParameters.getWallpaperFadeOutDuration();
370 scheduleUpdate();
371 }
372
373 private void holdWakeLock() {
374 if (!mWakeLockHeld) {
375 if (mWakeLock != null) {
376 mWakeLockHeld = true;
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800377 mWakeLock.acquire(TAG);
Lucas Dupin82aa1632017-12-13 00:13:57 -0800378 } else {
379 Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
380 }
381 }
382 }
383
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800384 /**
385 * Current state of the shade expansion when pulling it from the top.
386 * This value is 1 when on top of the keyguard and goes to 0 as the user drags up.
387 *
388 * The expansion fraction is tied to the scrim opacity.
389 *
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800390 * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800391 */
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200392 public void setPanelExpansion(float fraction) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800393 if (mExpansionFraction != fraction) {
394 mExpansionFraction = fraction;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800395
Lucas Dupin067136c2018-03-27 18:03:25 -0700396 final boolean keyguardOrUnlocked = mState == ScrimState.UNLOCKED
Lucas Dupin1c327432019-01-03 13:37:53 -0800397 || mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING;
Lucas Dupin067136c2018-03-27 18:03:25 -0700398 if (!keyguardOrUnlocked || !mExpansionAffectsAlpha) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800399 return;
400 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800401
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800402 applyExpansionToAlpha();
403
404 if (mUpdatePending) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800405 return;
406 }
407
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800408 setOrAdaptCurrentAnimation(mScrimBehind);
409 setOrAdaptCurrentAnimation(mScrimInFront);
shawnlin317db372018-04-09 19:49:48 +0800410
Yohei Yukawa795f0102018-04-13 14:55:30 -0700411 dispatchScrimState(mScrimBehind.getViewAlpha());
Jerry Changbde4c0c2019-06-13 16:58:41 +0800412
413 // Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
414 // and docking.
415 if (mWallpaperVisibilityTimedOut) {
416 mWallpaperVisibilityTimedOut = false;
417 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
418 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
419 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800420 }
421 }
422
423 private void setOrAdaptCurrentAnimation(View scrim) {
424 if (!isAnimating(scrim)) {
425 updateScrimColor(scrim, getCurrentScrimAlpha(scrim), getCurrentScrimTint(scrim));
426 } else {
427 ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
428 float alpha = getCurrentScrimAlpha(scrim);
429 float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
430 float previousStartValue = (Float) scrim.getTag(TAG_START_ALPHA);
431 float relativeDiff = alpha - previousEndValue;
432 float newStartValue = previousStartValue + relativeDiff;
433 scrim.setTag(TAG_START_ALPHA, newStartValue);
434 scrim.setTag(TAG_END_ALPHA, alpha);
435 previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
Jorim Jaggi93439da2014-06-30 23:53:39 +0200436 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200437 }
438
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800439 private void applyExpansionToAlpha() {
Lucas Dupin67f02632018-03-12 11:08:31 -0700440 if (!mExpansionAffectsAlpha) {
441 return;
442 }
443
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800444 if (mState == ScrimState.UNLOCKED) {
445 // Darken scrim as you pull down the shade when unlocked
446 float behindFraction = getInterpolatedFraction();
447 behindFraction = (float) Math.pow(behindFraction, 0.8f);
Lucas Dupind7c44eb2018-04-05 10:00:31 -0700448 mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800449 mCurrentInFrontAlpha = 0;
Lucas Dupin1c327432019-01-03 13:37:53 -0800450 } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800451 // Either darken of make the scrim transparent when you
452 // pull down the shade
453 float interpolatedFract = getInterpolatedFraction();
Lucas Dupin3d36dd82019-01-02 14:38:35 -0800454 float alphaBehind = mState.getBehindAlpha();
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800455 if (mDarkenWhileDragging) {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800456 mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
Lucas Dupinb380c882018-02-25 21:57:17 -0800457 interpolatedFract);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800458 mCurrentInFrontAlpha = 0;
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800459 } else {
Lucas Dupinb380c882018-02-25 21:57:17 -0800460 mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800461 interpolatedFract);
462 mCurrentInFrontAlpha = 0;
463 }
Lucas Dupin4cf01062019-03-08 17:07:49 -0800464 mCurrentBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
465 mState.getBehindTint(), interpolatedFract);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800466 }
467 }
468
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800469 /**
Anthony Chene658cc22017-04-27 11:17:35 -0700470 * Sets the given drawable as the background of the scrim that shows up behind the
471 * notifications.
472 */
473 public void setScrimBehindDrawable(Drawable drawable) {
474 mScrimBehind.setDrawable(drawable);
475 }
476
Michael Wrightcae88752018-04-16 23:13:54 +0100477 /**
Lucas Dupin69bda602018-05-18 17:24:52 -0700478 * Sets the front scrim opacity in AOD so it's not as bright.
479 * <p>
480 * Displays usually don't support multiple dimming settings when in low power mode.
481 * The workaround is to modify the front scrim opacity when in AOD, so it's not as
482 * bright when you're at the movies or lying down on bed.
483 * <p>
484 * This value will be lost during transitions and only updated again after the the
485 * device is dozing when the light sensor is on.
Michael Wrightcae88752018-04-16 23:13:54 +0100486 */
487 public void setAodFrontScrimAlpha(float alpha) {
Lucas Dupin69bda602018-05-18 17:24:52 -0700488 if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()
489 && mCurrentInFrontAlpha != alpha) {
Michael Wrightcae88752018-04-16 23:13:54 +0100490 mCurrentInFrontAlpha = alpha;
Lucas Dupin8523d132018-05-31 17:34:32 -0700491 updateScrims();
Michael Wrightcae88752018-04-16 23:13:54 +0100492 }
493
494 mState.AOD.setAodFrontScrimAlpha(alpha);
495 }
496
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700497 /**
Lucas Dupin34306c32019-07-16 11:56:53 -0700498 * Set front scrim to black, cancelling animations, in order to prepare to fade them
499 * away once the display turns on.
500 */
501 public void prepareForGentleWakeUp() {
Lucas Dupina7eacf92019-07-24 12:40:34 -0700502 if (mState == ScrimState.AOD) {
Lucas Dupin34306c32019-07-16 11:56:53 -0700503 mCurrentInFrontAlpha = 1f;
Lucas Dupina7eacf92019-07-24 12:40:34 -0700504 mCurrentInFrontTint = Color.BLACK;
505 mCurrentBehindTint = Color.BLACK;
Lucas Dupin34306c32019-07-16 11:56:53 -0700506 mAnimateChange = false;
507 updateScrims();
508 mAnimateChange = true;
509 mAnimationDuration = ANIMATION_DURATION_LONG;
510 }
511 }
512
513 /**
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700514 * If the lock screen sensor is active.
515 */
516 public void setWakeLockScreenSensorActive(boolean active) {
517 for (ScrimState state : ScrimState.values()) {
518 state.setWakeLockScreenSensorActive(active);
519 }
520
521 if (mState == ScrimState.PULSING) {
522 float newBehindAlpha = mState.getBehindAlpha();
523 if (mCurrentBehindAlpha != newBehindAlpha) {
524 mCurrentBehindAlpha = newBehindAlpha;
525 updateScrims();
526 }
527 }
528 }
529
Evan Rosky9a895012016-04-21 11:26:15 -0700530 protected void scheduleUpdate() {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200531 if (mUpdatePending) return;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200532
533 // Make sure that a frame gets scheduled.
534 mScrimBehind.invalidate();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200535 mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
536 mUpdatePending = true;
537 }
538
Xiaohui Chen5da71352016-02-22 10:04:41 -0800539 protected void updateScrims() {
Lucas Dupin9324aa92017-07-26 20:29:38 -0700540 // Make sure we have the right gradients and their opacities will satisfy GAR.
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700541 if (mNeedsDrawableColorUpdate) {
542 mNeedsDrawableColorUpdate = false;
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700543 // Only animate scrim color if the scrim view is actually visible
544 boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen;
545 boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700546 mScrimInFront.setColors(mColors, animateScrimInFront);
547 mScrimBehind.setColors(mColors, animateScrimBehind);
Lucas Dupin9324aa92017-07-26 20:29:38 -0700548
549 // Calculate minimum scrim opacity for white or black text.
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700550 int textColor = mColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
551 int mainColor = mColors.getMainColor();
Lucas Dupin9324aa92017-07-26 20:29:38 -0700552 float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
553 4.5f /* minimumContrast */) / 255f;
554 mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
Yohei Yukawa795f0102018-04-13 14:55:30 -0700555 dispatchScrimState(mScrimBehind.getViewAlpha());
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700556 }
557
Lucas Dupind5107302018-03-19 15:30:29 -0700558 // We want to override the back scrim opacity for the AOD state
Lucas Dupin82aa1632017-12-13 00:13:57 -0800559 // when it's time to fade the wallpaper away.
TYM Tsaia71c8922019-01-07 15:57:53 +0800560 boolean aodWallpaperTimeout = (mState == ScrimState.AOD || mState == ScrimState.PULSING)
561 && mWallpaperVisibilityTimedOut;
Lucas Dupind5107302018-03-19 15:30:29 -0700562 // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
563 boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
564 && mKeyguardOccluded;
565 if (aodWallpaperTimeout || occludedKeyguard) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800566 mCurrentBehindAlpha = 1;
567 }
568
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800569 setScrimInFrontAlpha(mCurrentInFrontAlpha);
570 setScrimBehindAlpha(mCurrentBehindAlpha);
571
Adrian Roosa5c63222017-07-27 16:33:39 +0200572 dispatchScrimsVisible();
573 }
574
Yohei Yukawa795f0102018-04-13 14:55:30 -0700575 private void dispatchScrimState(float alpha) {
576 mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
577 }
578
Adrian Roosa5c63222017-07-27 16:33:39 +0200579 private void dispatchScrimsVisible() {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800580 final int currentScrimVisibility;
581 if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
582 currentScrimVisibility = VISIBILITY_FULLY_OPAQUE;
583 } else if (mScrimInFront.getViewAlpha() == 0 && mScrimBehind.getViewAlpha() == 0) {
584 currentScrimVisibility = VISIBILITY_FULLY_TRANSPARENT;
585 } else {
586 currentScrimVisibility = VISIBILITY_SEMI_TRANSPARENT;
587 }
Adrian Roosa5c63222017-07-27 16:33:39 +0200588
Lucas Dupin82aa1632017-12-13 00:13:57 -0800589 if (mScrimsVisibility != currentScrimVisibility) {
590 mScrimsVisibility = currentScrimVisibility;
591 mScrimVisibleListener.accept(currentScrimVisibility);
Adrian Roosa5c63222017-07-27 16:33:39 +0200592 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200593 }
594
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800595 private float getInterpolatedFraction() {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800596 float frac = mExpansionFraction;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200597 // let's start this 20% of the way down the screen
598 frac = frac * 1.2f - 0.2f;
599 if (frac <= 0) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800600 return 0;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200601 } else {
602 // woo, special effects
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800603 return (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200604 }
605 }
606
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700607 private void setScrimBehindAlpha(float alpha) {
608 setScrimAlpha(mScrimBehind, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200609 }
610
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700611 private void setScrimInFrontAlpha(float alpha) {
612 setScrimAlpha(mScrimInFront, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200613 }
614
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800615 private void setScrimAlpha(ScrimView scrim, float alpha) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800616 if (alpha == 0f) {
617 scrim.setClickable(false);
Selim Cinekaac93252015-04-14 20:04:12 -0700618 } else {
Lucas Dupin1c327432019-01-03 13:37:53 -0800619 // Eat touch events (unless dozing).
620 scrim.setClickable(mState != ScrimState.AOD);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200621 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800622 updateScrim(scrim, alpha);
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100623 }
624
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800625 private void updateScrimColor(View scrim, float alpha, int tint) {
626 alpha = Math.max(0, Math.min(1.0f, alpha));
Selim Cinekaac93252015-04-14 20:04:12 -0700627 if (scrim instanceof ScrimView) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700628 ScrimView scrimView = (ScrimView) scrim;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700629
Adrian Roosa5c63222017-07-27 16:33:39 +0200630 Trace.traceCounter(Trace.TRACE_TAG_APP,
631 scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
632 (int) (alpha * 255));
633
Adrian Roosa5c63222017-07-27 16:33:39 +0200634 Trace.traceCounter(Trace.TRACE_TAG_APP,
635 scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800636 Color.alpha(tint));
Adrian Roosa5c63222017-07-27 16:33:39 +0200637
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800638 scrimView.setTint(tint);
639 scrimView.setViewAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700640 } else {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800641 scrim.setAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700642 }
Selim Cinek8cd80402017-08-01 10:44:29 -0700643 dispatchScrimsVisible();
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100644 }
645
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800646 private void startScrimAnimation(final View scrim, float current) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800647 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
648 final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() :
649 Color.TRANSPARENT;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700650 anim.addUpdateListener(animation -> {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800651 final float startAlpha = (Float) scrim.getTag(TAG_START_ALPHA);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800652 final float animAmount = (float) animation.getAnimatedValue();
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800653 final int finalScrimTint = getCurrentScrimTint(scrim);
654 final float finalScrimAlpha = getCurrentScrimAlpha(scrim);
655 float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount);
656 alpha = MathUtils.constrain(alpha, 0f, 1f);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800657 int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
658 updateScrimColor(scrim, alpha, tint);
Adrian Roosa5c63222017-07-27 16:33:39 +0200659 dispatchScrimsVisible();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200660 });
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800661 anim.setInterpolator(mInterpolator);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200662 anim.setStartDelay(mAnimationDelay);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800663 anim.setDuration(mAnimationDuration);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200664 anim.addListener(new AnimatorListenerAdapter() {
Joanne Chunga393ad62019-01-16 21:41:31 +0800665 private Callback lastCallback = mCallback;
666
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200667 @Override
668 public void onAnimationEnd(Animator animation) {
Joanne Chunga393ad62019-01-16 21:41:31 +0800669 onFinished(lastCallback);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800670
671 scrim.setTag(TAG_KEY_ANIM, null);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800672 dispatchScrimsVisible();
673
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200674 if (!mDeferFinishedListener && mOnAnimationFinished != null) {
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200675 mOnAnimationFinished.run();
676 mOnAnimationFinished = null;
677 }
678 }
679 });
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800680
681 // Cache alpha values because we might want to update this animator in the future if
682 // the user expands the panel while the animation is still running.
683 scrim.setTag(TAG_START_ALPHA, current);
684 scrim.setTag(TAG_END_ALPHA, getCurrentScrimAlpha(scrim));
685
John Spurlockbf370992014-06-17 13:58:31 -0400686 scrim.setTag(TAG_KEY_ANIM, anim);
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800687 anim.start();
688 }
689
690 private float getCurrentScrimAlpha(View scrim) {
691 if (scrim == mScrimInFront) {
692 return mCurrentInFrontAlpha;
693 } else if (scrim == mScrimBehind) {
694 return mCurrentBehindAlpha;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800695 } else {
696 throw new IllegalArgumentException("Unknown scrim view");
697 }
698 }
699
700 private int getCurrentScrimTint(View scrim) {
701 if (scrim == mScrimInFront) {
702 return mCurrentInFrontTint;
703 } else if (scrim == mScrimBehind) {
704 return mCurrentBehindTint;
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800705 } else {
706 throw new IllegalArgumentException("Unknown scrim view");
707 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200708 }
709
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200710 @Override
711 public boolean onPreDraw() {
712 mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
713 mUpdatePending = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800714 if (mCallback != null) {
715 mCallback.onStart();
Selim Cinek372d1bd2015-08-14 13:19:37 -0700716 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200717 updateScrims();
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800718 if (mOnAnimationFinished != null && !isAnimating(mScrimInFront)
719 && !isAnimating(mScrimBehind)) {
720 mOnAnimationFinished.run();
721 mOnAnimationFinished = null;
722 }
Selim Cinekedd32b82015-06-23 22:05:58 -0400723 return true;
724 }
725
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800726 private void onFinished() {
Joanne Chunga393ad62019-01-16 21:41:31 +0800727 onFinished(mCallback);
728 }
729
730 private void onFinished(Callback callback) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800731 if (mWakeLockHeld) {
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800732 mWakeLock.release(TAG);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800733 mWakeLockHeld = false;
734 }
Joanne Chunga393ad62019-01-16 21:41:31 +0800735
736 if (callback != null) {
737 callback.onFinished();
738
739 if (callback == mCallback) {
740 mCallback = null;
741 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800742 }
Joanne Chunga393ad62019-01-16 21:41:31 +0800743
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800744 // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
745 // At the end of the animation we need to remove the tint.
746 if (mState == ScrimState.UNLOCKED) {
747 mCurrentInFrontTint = Color.TRANSPARENT;
748 mCurrentBehindTint = Color.TRANSPARENT;
749 }
750 }
751
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700752 private boolean isAnimating(View scrim) {
753 return scrim.getTag(TAG_KEY_ANIM) != null;
754 }
755
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800756 @VisibleForTesting
757 void setOnAnimationFinished(Runnable onAnimationFinished) {
758 mOnAnimationFinished = onAnimationFinished;
759 }
Adrian Roos5f72c922016-03-08 15:54:26 -0800760
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800761 private void updateScrim(ScrimView scrim, float alpha) {
762 final float currentAlpha = scrim.getViewAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800763
764 ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM);
Selim Cinekaac93252015-04-14 20:04:12 -0700765 if (previousAnimator != null) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800766 if (mAnimateChange) {
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200767 // We are not done yet! Defer calling the finished listener.
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800768 mDeferFinishedListener = true;
Selim Cinekaac93252015-04-14 20:04:12 -0700769 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800770 // Previous animators should always be cancelled. Not doing so would cause
771 // overlap, especially on states that don't animate, leading to flickering,
772 // and in the worst case, an internal state that doesn't represent what
773 // transitionTo requested.
774 cancelAnimator(previousAnimator);
775 mDeferFinishedListener = false;
Selim Cinekaac93252015-04-14 20:04:12 -0700776 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800777
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800778 if (mPendingFrameCallback != null) {
779 // Display is off and we're waiting.
780 return;
781 } else if (mBlankScreen) {
782 // Need to blank the display before continuing.
783 blankDisplay();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800784 return;
785 } else if (!mScreenBlankingCallbackCalled) {
786 // Not blanking the screen. Letting the callback know that we're ready
787 // to replace what was on the screen before.
788 if (mCallback != null) {
789 mCallback.onDisplayBlanked();
790 mScreenBlankingCallbackCalled = true;
791 }
792 }
793
Lucas Dupin6afae372017-11-30 13:09:22 -0500794 if (scrim == mScrimBehind) {
Yohei Yukawa795f0102018-04-13 14:55:30 -0700795 dispatchScrimState(alpha);
Lucas Dupin6afae372017-11-30 13:09:22 -0500796 }
797
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800798 final boolean wantsAlphaUpdate = alpha != currentAlpha;
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800799 final boolean wantsTintUpdate = scrim.getTint() != getCurrentScrimTint(scrim);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800800
801 if (wantsAlphaUpdate || wantsTintUpdate) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800802 if (mAnimateChange) {
803 startScrimAnimation(scrim, currentAlpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700804 } else {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800805 // update the alpha directly
806 updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
807 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700808 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800809 } else {
810 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700811 }
812 }
813
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800814 @VisibleForTesting
815 protected void cancelAnimator(ValueAnimator previousAnimator) {
816 if (previousAnimator != null) {
817 previousAnimator.cancel();
818 }
819 }
820
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800821 private void blankDisplay() {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800822 updateScrimColor(mScrimInFront, 1, Color.BLACK);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800823
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800824 // Notify callback that the screen is completely black and we're
825 // ready to change the display power mode
Lucas Dupin0791d972018-03-26 13:32:16 -0700826 mPendingFrameCallback = () -> {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800827 if (mCallback != null) {
828 mCallback.onDisplayBlanked();
829 mScreenBlankingCallbackCalled = true;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800830 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800831
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800832 mBlankingTransitionRunnable = () -> {
833 mBlankingTransitionRunnable = null;
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800834 mPendingFrameCallback = null;
835 mBlankScreen = false;
836 // Try again.
837 updateScrims();
838 };
839
840 // Setting power states can happen after we push out the frame. Make sure we
841 // stay fully opaque until the power state request reaches the lower levels.
Lucas Dupin0791d972018-03-26 13:32:16 -0700842 final int delay = mScreenOn ? 32 : 500;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800843 if (DEBUG) {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800844 Log.d(TAG, "Fading out scrims with delay: " + delay);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800845 }
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800846 mHandler.postDelayed(mBlankingTransitionRunnable, delay);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800847 };
848 doOnTheNextFrame(mPendingFrameCallback);
849 }
850
Lucas Dupin0791d972018-03-26 13:32:16 -0700851 /**
852 * Executes a callback after the frame has hit the display.
853 * @param callback What to run.
854 */
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800855 @VisibleForTesting
Lucas Dupin0791d972018-03-26 13:32:16 -0700856 protected void doOnTheNextFrame(Runnable callback) {
857 // Just calling View#postOnAnimation isn't enough because the frame might not have reached
858 // the display yet. A timeout is the safest solution.
859 mScrimBehind.postOnAnimationDelayed(callback, 32 /* delayMillis */);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800860 }
861
862 @VisibleForTesting
863 protected Handler getHandler() {
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800864 return new Handler();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800865 }
866
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700867 public int getBackgroundColor() {
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700868 int color = mColors.getMainColor();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800869 return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700870 Color.red(color), Color.green(color), Color.blue(color));
Selim Cinekd35c2792016-01-21 13:20:57 -0800871 }
872
873 public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
874 mScrimBehind.setChangeRunnable(changeRunnable);
875 }
Selim Cineke803491c2016-04-09 21:24:45 -0700876
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700877 public void setCurrentUser(int currentUser) {
878 // Don't care in the base class.
879 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700880
881 @Override
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700882 public void onColorsChanged(ColorExtractor colorExtractor, int which) {
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700883 mColors = mColorExtractor.getNeutralColors();
884 mNeedsDrawableColorUpdate = true;
885 scheduleUpdate();
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700886 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200887
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800888 @VisibleForTesting
889 protected WakeLock createWakeLock() {
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800890 return new DelayedWakeLock(mHandler, WakeLock.createPartial(mContext, "Scrims"));
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800891 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200892
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800893 @Override
894 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800895 pw.println(" ScrimController: ");
896 pw.print(" state: "); pw.println(mState);
897 pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200898 pw.print(" alpha="); pw.print(mCurrentInFrontAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200899 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint()));
900
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800901 pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200902 pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200903 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
904
Adrian Roosba7ca592017-08-15 17:48:05 +0200905 pw.print(" mTracking="); pw.println(mTracking);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800906 }
907
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700908 public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800909 mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
910 ScrimState[] states = ScrimState.values();
911 for (int i = 0; i < states.length; i++) {
912 states[i].setWallpaperSupportsAmbientMode(wallpaperSupportsAmbientMode);
913 }
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700914 }
915
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800916 /**
917 * Interrupts blanking transitions once the display notifies that it's already on.
918 */
919 public void onScreenTurnedOn() {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800920 mScreenOn = true;
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800921 if (mHandler.hasCallbacks(mBlankingTransitionRunnable)) {
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800922 if (DEBUG) {
923 Log.d(TAG, "Shorter blanking because screen turned on. All good.");
924 }
Lucas Dupin54fbfb32019-03-05 18:08:13 -0800925 mHandler.removeCallbacks(mBlankingTransitionRunnable);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800926 mBlankingTransitionRunnable.run();
927 }
928 }
929
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800930 public void onScreenTurnedOff() {
931 mScreenOn = false;
932 }
933
Lucas Dupin67f02632018-03-12 11:08:31 -0700934 public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
935 mExpansionAffectsAlpha = expansionAffectsAlpha;
936 }
937
Lucas Dupind5107302018-03-19 15:30:29 -0700938 public void setKeyguardOccluded(boolean keyguardOccluded) {
939 mKeyguardOccluded = keyguardOccluded;
Lucas Dupin63d72172018-06-06 11:42:55 -0700940 updateScrims();
Lucas Dupind5107302018-03-19 15:30:29 -0700941 }
942
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700943 public void setHasBackdrop(boolean hasBackdrop) {
Lucas Dupin193677c2018-06-11 19:16:03 -0700944 for (ScrimState state : ScrimState.values()) {
945 state.setHasBackdrop(hasBackdrop);
946 }
Lucas Dupin9bee5822018-07-09 14:32:53 -0700947
948 // Backdrop event may arrive after state was already applied,
949 // in this case, back-scrim needs to be re-evaluated
950 if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
Lucas Dupin3d36dd82019-01-02 14:38:35 -0800951 float newBehindAlpha = mState.getBehindAlpha();
Lucas Dupin9bee5822018-07-09 14:32:53 -0700952 if (mCurrentBehindAlpha != newBehindAlpha) {
953 mCurrentBehindAlpha = newBehindAlpha;
954 updateScrims();
955 }
956 }
Lucas Dupin193677c2018-06-11 19:16:03 -0700957 }
958
Selim Cinek72cd9a72019-08-09 17:19:57 -0700959 private void setKeyguardFadingAway(boolean fadingAway, long duration) {
Selim Cinek84b2acc2019-07-07 00:40:38 -0700960 for (ScrimState state : ScrimState.values()) {
Selim Cinek72cd9a72019-08-09 17:19:57 -0700961 state.setKeyguardFadingAway(fadingAway, duration);
Selim Cinek84b2acc2019-07-07 00:40:38 -0700962 }
963 }
964
Lucas Dupin193677c2018-06-11 19:16:03 -0700965 public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
966 for (ScrimState state : ScrimState.values()) {
967 state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
Lucas Dupinf8463ee2018-06-11 16:18:15 -0700968 }
969 }
970
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800971 public interface Callback {
972 default void onStart() {
973 }
974 default void onDisplayBlanked() {
975 }
976 default void onFinished() {
977 }
978 default void onCancelled() {
979 }
Jerry Changbde4c0c2019-06-13 16:58:41 +0800980 /** Returns whether to timeout wallpaper or not. */
981 default boolean shouldTimeoutWallpaper() {
982 return false;
983 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200984 }
Lucas Dupin690c6f52018-07-10 15:28:57 -0700985
986 /**
987 * Simple keyguard callback that updates scrims when keyguard visibility changes.
988 */
989 private class KeyguardVisibilityCallback extends KeyguardUpdateMonitorCallback {
990
991 @Override
992 public void onKeyguardVisibilityChanged(boolean showing) {
993 mNeedsDrawableColorUpdate = true;
994 scheduleUpdate();
995 }
996 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200997}