blob: 739d8d5c2c67f47e1372bd69f35677859e02cf78 [file] [log] [blame]
Jorim Jaggiecc798e2014-05-26 18:14:37 +02001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator;
Lucas Dupin82aa1632017-12-13 00:13:57 -080022import android.app.AlarmManager;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070023import android.app.WallpaperManager;
John Spurlockd06aa572014-09-10 10:40:49 -040024import android.content.Context;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070025import android.graphics.Color;
Selim Cinek6811d722016-01-19 17:53:12 -080026import android.graphics.Rect;
Anthony Chene658cc22017-04-27 11:17:35 -070027import android.graphics.drawable.Drawable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080028import android.os.Handler;
Adrian Roosa5c63222017-07-27 16:33:39 +020029import android.os.Trace;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080030import android.util.Log;
Lucas Dupina0bf8512017-05-24 17:04:47 -070031import android.util.MathUtils;
Lucas Dupin8c7cb022018-02-05 10:49:03 -080032import android.view.Choreographer;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020033import android.view.View;
Selim Cineke803491c2016-04-09 21:24:45 -070034import android.view.ViewGroup;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020035import android.view.ViewTreeObserver;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020036import android.view.animation.DecelerateInterpolator;
37import android.view.animation.Interpolator;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -070038
Lucas Dupin9e3fa102017-11-08 17:16:55 -080039import com.android.internal.annotations.VisibleForTesting;
Lucas Dupine2292a92017-07-06 14:35:30 -070040import com.android.internal.colorextraction.ColorExtractor;
41import com.android.internal.colorextraction.ColorExtractor.GradientColors;
42import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
Lucas Dupin9324aa92017-07-26 20:29:38 -070043import com.android.internal.graphics.ColorUtils;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070044import com.android.keyguard.KeyguardUpdateMonitor;
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 Cinekaac93252015-04-14 20:04:12 -070049import com.android.systemui.statusbar.ExpandableNotificationRow;
50import com.android.systemui.statusbar.NotificationData;
Selim Cineka0fad3b2014-09-19 17:20:05 +020051import com.android.systemui.statusbar.ScrimView;
Selim Cineka7d4f822016-12-06 14:34:47 -080052import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
Selim Cinek0cfbef42016-11-09 19:06:36 -080053import com.android.systemui.statusbar.stack.ViewState;
Lucas Dupin82aa1632017-12-13 00:13:57 -080054import com.android.systemui.util.AlarmTimeout;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080055import com.android.systemui.util.wakelock.DelayedWakeLock;
56import com.android.systemui.util.wakelock.WakeLock;
John Spurlockbf370992014-06-17 13:58:31 -040057
Lucas Dupin9e3fa102017-11-08 17:16:55 -080058import java.io.FileDescriptor;
Adrian Roosba7ca592017-08-15 17:48:05 +020059import java.io.PrintWriter;
Adrian Roosa5c63222017-07-27 16:33:39 +020060import java.util.function.Consumer;
61
Jorim Jaggiecc798e2014-05-26 18:14:37 +020062/**
63 * Controls both the scrim behind the notifications and in front of the notifications (when a
64 * security method gets shown).
65 */
Selim Cinekaac93252015-04-14 20:04:12 -070066public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
Lucas Dupin9e3fa102017-11-08 17:16:55 -080067 OnHeadsUpChangedListener, OnColorsChangedListener, Dumpable {
68
69 private static final String TAG = "ScrimController";
70 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
71
John Spurlock8b12f222014-09-09 11:54:11 -040072 public static final long ANIMATION_DURATION = 220;
Lucas Dupin82aa1632017-12-13 00:13:57 -080073
74 /**
75 * When both scrims have 0 alpha.
76 */
77 public static final int VISIBILITY_FULLY_TRANSPARENT = 0;
78 /**
79 * When scrims aren't transparent (alpha 0) but also not opaque (alpha 1.)
80 */
81 public static final int VISIBILITY_SEMI_TRANSPARENT = 1;
82 /**
83 * When at least 1 scrim is fully opaque (alpha set to 1.)
84 */
85 public static final int VISIBILITY_FULLY_OPAQUE = 2;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080086 /**
87 * Default alpha value for most scrims.
88 */
Lucas Dupinae90ba82017-06-16 16:45:59 -070089 public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080090 /**
91 * A scrim varies its opacity based on a busyness factor, for example
92 * how many notifications are currently visible.
93 */
Lucas Dupin16446262017-06-26 14:21:16 -070094 public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080095 /**
96 * The most common scrim, the one under the keyguard.
97 */
Lucas Dupina0bf8512017-05-24 17:04:47 -070098 protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
Lucas Dupin9e3fa102017-11-08 17:16:55 -080099
100 static final int TAG_KEY_ANIM = R.id.scrim;
Selim Cinek5104a6d2015-12-18 18:38:31 -0800101 private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
102 private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
Selim Cinek511f2702017-04-10 19:53:01 -0700103 private static final float NOT_INITIALIZED = -1;
John Spurlockbf370992014-06-17 13:58:31 -0400104
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800105 private ScrimState mState = ScrimState.UNINITIALIZED;
106 private final Context mContext;
Xiaohui Chen5da71352016-02-22 10:04:41 -0800107 protected final ScrimView mScrimBehind;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700108 protected final ScrimView mScrimInFront;
Selim Cinekaac93252015-04-14 20:04:12 -0700109 private final View mHeadsUpScrim;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800110 private final LightBarController mLightBarController;
111 private final UnlockMethodCache mUnlockMethodCache;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700112 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800113 private final DozeParameters mDozeParameters;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800114 private final AlarmTimeout mTimeTicker;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200115
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700116 private final SysuiColorExtractor mColorExtractor;
Lucas Dupine2292a92017-07-06 14:35:30 -0700117 private GradientColors mLockColors;
118 private GradientColors mSystemColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700119 private boolean mNeedsDrawableColorUpdate;
120
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800121 protected float mScrimBehindAlpha;
Lucas Dupin9324aa92017-07-26 20:29:38 -0700122 protected float mScrimBehindAlphaResValue;
Evan Rosky9a895012016-04-21 11:26:15 -0700123 protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
Xiaohui Chen4dab4b52016-03-07 12:31:14 -0800124
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800125 // Assuming the shade is expanded during initialization
126 private float mExpansionFraction = 1f;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200127
128 private boolean mDarkenWhileDragging;
Lucas Dupin67f02632018-03-12 11:08:31 -0700129 private boolean mExpansionAffectsAlpha = true;
Evan Rosky9a895012016-04-21 11:26:15 -0700130 protected boolean mAnimateChange;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200131 private boolean mUpdatePending;
Jorim Jaggie93698b2016-11-11 18:24:38 -0800132 private boolean mTracking;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800133 protected long mAnimationDuration = -1;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200134 private long mAnimationDelay;
135 private Runnable mOnAnimationFinished;
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200136 private boolean mDeferFinishedListener;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200137 private final Interpolator mInterpolator = new DecelerateInterpolator();
Selim Cinek511f2702017-04-10 19:53:01 -0700138 private float mCurrentInFrontAlpha = NOT_INITIALIZED;
139 private float mCurrentBehindAlpha = NOT_INITIALIZED;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800140 private int mCurrentInFrontTint;
141 private int mCurrentBehindTint;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800142 private boolean mWallpaperVisibilityTimedOut;
Selim Cinek684a4422015-04-15 16:18:39 -0700143 private int mPinnedHeadsUpCount;
Selim Cinekaac93252015-04-14 20:04:12 -0700144 private float mTopHeadsUpDragAmount;
145 private View mDraggedHeadsUpView;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800146 private int mScrimsVisibility;
147 private final Consumer<Integer> mScrimVisibleListener;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800148 private boolean mBlankScreen;
149 private boolean mScreenBlankingCallbackCalled;
150 private Callback mCallback;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800151 private boolean mWallpaperSupportsAmbientMode;
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800152 private boolean mScreenOn;
Lucas Dupinb380c882018-02-25 21:57:17 -0800153 private float mNotificationDensity;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800154
155 // Scrim blanking callbacks
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800156 private Choreographer.FrameCallback mPendingFrameCallback;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800157 private Runnable mBlankingTransitionRunnable;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800158
159 private final WakeLock mWakeLock;
160 private boolean mWakeLockHeld;
Lucas Dupind5107302018-03-19 15:30:29 -0700161 private boolean mKeyguardOccluded;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200162
Jorim Jaggi40db0292016-06-27 17:58:03 -0700163 public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
Lucas Dupin82aa1632017-12-13 00:13:57 -0800164 ScrimView scrimInFront, View headsUpScrim, Consumer<Integer> scrimVisibleListener,
165 DozeParameters dozeParameters, AlarmManager alarmManager) {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200166 mScrimBehind = scrimBehind;
167 mScrimInFront = scrimInFront;
Selim Cinekaac93252015-04-14 20:04:12 -0700168 mHeadsUpScrim = headsUpScrim;
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);
Jorim Jaggi40db0292016-06-27 17:58:03 -0700174 mLightBarController = lightBarController;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800175 mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
Lucas Dupin82aa1632017-12-13 00:13:57 -0800176 mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
177 "hide_aod_wallpaper", new Handler());
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800178 mWakeLock = createWakeLock();
Lucas Dupin9324aa92017-07-26 20:29:38 -0700179 // Scrim alpha is initially set to the value on the resource but might be changed
180 // to make sure that text on top of it is legible.
181 mScrimBehindAlpha = mScrimBehindAlphaResValue;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800182 mDozeParameters = dozeParameters;
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800183
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700184 mColorExtractor = Dependency.get(SysuiColorExtractor.class);
Lucas Dupin314d41f2017-05-08 15:52:58 -0700185 mColorExtractor.addOnColorsChangedListener(this);
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700186 mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700187 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin5266ad12017-06-17 20:57:28 -0700188 mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700189 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700190 mNeedsDrawableColorUpdate = true;
191
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800192 final ScrimState[] states = ScrimState.values();
193 for (int i = 0; i < states.length; i++) {
194 states[i].init(mScrimInFront, mScrimBehind, mDozeParameters);
195 states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
196 }
197 mState = ScrimState.UNINITIALIZED;
198
Selim Cinekaac93252015-04-14 20:04:12 -0700199 updateHeadsUpScrim(false);
Selim Cinek511f2702017-04-10 19:53:01 -0700200 updateScrims();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200201 }
202
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800203 public void transitionTo(ScrimState state) {
204 transitionTo(state, null);
205 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700206
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800207 public void transitionTo(ScrimState state, Callback callback) {
208 if (state == mState) {
Lucas Dupin19aba8e2017-12-11 12:42:26 -0800209 // Call the callback anyway, unless it's already enqueued
210 if (callback != null && mCallback != callback) {
211 callback.onFinished();
212 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800213 return;
214 } else if (DEBUG) {
215 Log.d(TAG, "State changed to: " + state);
216 }
217
218 if (state == ScrimState.UNINITIALIZED) {
219 throw new IllegalArgumentException("Cannot change to UNINITIALIZED.");
220 }
221
Lucas Dupin8635c442017-12-08 10:36:28 -0800222 final ScrimState oldState = mState;
223 mState = state;
Lucas Dupin5866aaf2018-02-02 14:45:31 -0800224 Trace.traceCounter(Trace.TRACE_TAG_APP, "scrim_state", mState.getIndex());
Lucas Dupin8635c442017-12-08 10:36:28 -0800225
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800226 if (mCallback != null) {
227 mCallback.onCancelled();
228 }
229 mCallback = callback;
230
Lucas Dupin8635c442017-12-08 10:36:28 -0800231 state.prepare(oldState);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800232 mScreenBlankingCallbackCalled = false;
233 mAnimationDelay = 0;
234 mBlankScreen = state.getBlanksScreen();
235 mAnimateChange = state.getAnimateChange();
236 mAnimationDuration = state.getAnimationDuration();
237 mCurrentInFrontTint = state.getFrontTint();
238 mCurrentBehindTint = state.getBehindTint();
239 mCurrentInFrontAlpha = state.getFrontAlpha();
Lucas Dupinb380c882018-02-25 21:57:17 -0800240 mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800241 applyExpansionToAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800242
Lucas Dupin38962d72018-03-14 12:41:39 -0700243 // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
244 // We need to disable focus otherwise AOD would end up with a gray overlay.
245 mScrimInFront.setFocusable(!state.isLowPowerState());
246 mScrimBehind.setFocusable(!state.isLowPowerState());
247
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800248 // Cancel blanking transitions that were pending before we requested a new state
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800249 if (mPendingFrameCallback != null) {
250 Choreographer.getInstance().removeFrameCallback(mPendingFrameCallback);
251 mPendingFrameCallback = null;
252 }
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800253 if (getHandler().hasCallbacks(mBlankingTransitionRunnable)) {
254 getHandler().removeCallbacks(mBlankingTransitionRunnable);
255 mBlankingTransitionRunnable = null;
256 }
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800257
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800258 // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
259 // to do the same when you're just showing the brightness mirror.
260 mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
261
Lucas Dupineea53b32017-12-18 13:47:14 -0800262 // The device might sleep if it's entering AOD, we need to make sure that
263 // the animation plays properly until the last frame.
264 // It's important to avoid holding the wakelock unless necessary because
265 // WakeLock#aqcuire will trigger an IPC and will cause jank.
Lucas Dupin38962d72018-03-14 12:41:39 -0700266 if (mState.isLowPowerState()) {
Lucas Dupineea53b32017-12-18 13:47:14 -0800267 holdWakeLock();
268 }
Lucas Dupin82aa1632017-12-13 00:13:57 -0800269
270 // AOD wallpapers should fade away after a while
271 if (mWallpaperSupportsAmbientMode && mDozeParameters.getAlwaysOn()
Lucas Dupin6680b262018-03-19 12:38:05 -0700272 && mState == ScrimState.AOD) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800273 if (!mWallpaperVisibilityTimedOut) {
274 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
275 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800276 }
Lucas Dupin6680b262018-03-19 12:38:05 -0700277 // Do not re-schedule timeout when pulsing, let's save some extra battery.
278 } else if (mState != ScrimState.PULSING) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800279 mTimeTicker.cancel();
280 mWallpaperVisibilityTimedOut = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800281 }
282
Lucas Dupinff307d52018-02-05 21:16:39 -0800283 if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800284 // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
285 // with too many things at this case, in order to not skip the initial frames.
286 mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
287 mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
Lucas Dupinff307d52018-02-05 21:16:39 -0800288 } else if (!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD) {
289 // Execute first frame immediately when display was completely off.
290 // Scheduling a frame isn't enough because the system may aggressively enter doze,
291 // delaying callbacks or never triggering them until the power button is pressed.
292 onPreDraw();
293 } else {
294 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800295 }
296 }
297
298 public ScrimState getState() {
299 return mState;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200300 }
301
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800302 protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700303 mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800304 ScrimState[] states = ScrimState.values();
305 for (int i = 0; i < states.length; i++) {
306 states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
307 }
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700308 scheduleUpdate();
309 }
310
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200311 public void onTrackingStarted() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800312 mTracking = true;
Selim Cineke8bae622015-07-15 13:24:06 -0700313 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200314 }
315
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200316 public void onExpandingFinished() {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800317 mTracking = false;
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200318 }
319
Lucas Dupin82aa1632017-12-13 00:13:57 -0800320 @VisibleForTesting
321 protected void onHideWallpaperTimeout() {
Lucas Dupin6680b262018-03-19 12:38:05 -0700322 if (mState != ScrimState.AOD) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800323 return;
324 }
325
326 holdWakeLock();
327 mWallpaperVisibilityTimedOut = true;
328 mAnimateChange = true;
329 mAnimationDuration = mDozeParameters.getWallpaperFadeOutDuration();
330 scheduleUpdate();
331 }
332
333 private void holdWakeLock() {
334 if (!mWakeLockHeld) {
335 if (mWakeLock != null) {
336 mWakeLockHeld = true;
337 mWakeLock.acquire();
338 } else {
339 Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
340 }
341 }
342 }
343
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800344 /**
345 * Current state of the shade expansion when pulling it from the top.
346 * This value is 1 when on top of the keyguard and goes to 0 as the user drags up.
347 *
348 * The expansion fraction is tied to the scrim opacity.
349 *
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800350 * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800351 */
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200352 public void setPanelExpansion(float fraction) {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800353 if (mExpansionFraction != fraction) {
354 mExpansionFraction = fraction;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800355
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800356 if (!(mState == ScrimState.UNLOCKED || mState == ScrimState.KEYGUARD)) {
357 return;
358 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800359
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800360 applyExpansionToAlpha();
361
362 if (mUpdatePending) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800363 return;
364 }
365
Selim Cinek131c1e22015-05-11 19:04:49 -0700366 if (mPinnedHeadsUpCount != 0) {
367 updateHeadsUpScrim(false);
368 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800369
370 setOrAdaptCurrentAnimation(mScrimBehind);
371 setOrAdaptCurrentAnimation(mScrimInFront);
372 }
373 }
374
375 private void setOrAdaptCurrentAnimation(View scrim) {
376 if (!isAnimating(scrim)) {
377 updateScrimColor(scrim, getCurrentScrimAlpha(scrim), getCurrentScrimTint(scrim));
378 } else {
379 ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
380 float alpha = getCurrentScrimAlpha(scrim);
381 float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
382 float previousStartValue = (Float) scrim.getTag(TAG_START_ALPHA);
383 float relativeDiff = alpha - previousEndValue;
384 float newStartValue = previousStartValue + relativeDiff;
385 scrim.setTag(TAG_START_ALPHA, newStartValue);
386 scrim.setTag(TAG_END_ALPHA, alpha);
387 previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
Jorim Jaggi93439da2014-06-30 23:53:39 +0200388 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200389 }
390
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800391 private void applyExpansionToAlpha() {
Lucas Dupin67f02632018-03-12 11:08:31 -0700392 if (!mExpansionAffectsAlpha) {
393 return;
394 }
395
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800396 if (mState == ScrimState.UNLOCKED) {
397 // Darken scrim as you pull down the shade when unlocked
398 float behindFraction = getInterpolatedFraction();
399 behindFraction = (float) Math.pow(behindFraction, 0.8f);
400 mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard;
401 mCurrentInFrontAlpha = 0;
402 } else if (mState == ScrimState.KEYGUARD) {
403 // Either darken of make the scrim transparent when you
404 // pull down the shade
405 float interpolatedFract = getInterpolatedFraction();
Lucas Dupinb380c882018-02-25 21:57:17 -0800406 float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800407 if (mDarkenWhileDragging) {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800408 mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
Lucas Dupinb380c882018-02-25 21:57:17 -0800409 interpolatedFract);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800410 mCurrentInFrontAlpha = 0;
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800411 } else {
Lucas Dupinb380c882018-02-25 21:57:17 -0800412 mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800413 interpolatedFract);
414 mCurrentInFrontAlpha = 0;
415 }
416 }
417 }
418
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800419 /**
420 * Keyguard and shade scrim opacity varies according to how many notifications are visible.
421 * @param notificationCount Number of visible notifications.
422 */
Lucas Dupina0bf8512017-05-24 17:04:47 -0700423 public void setNotificationCount(int notificationCount) {
424 final float maxNotificationDensity = 3;
425 float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
Lucas Dupinb380c882018-02-25 21:57:17 -0800426 if (mNotificationDensity == notificationDensity) {
427 return;
428 }
429 mNotificationDensity = notificationDensity;
Lucas Dupina0bf8512017-05-24 17:04:47 -0700430
Lucas Dupinb380c882018-02-25 21:57:17 -0800431 if (mState == ScrimState.KEYGUARD) {
432 applyExpansionToAlpha();
433 scheduleUpdate();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800434 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700435 }
Selim Cinek359c48c2016-07-11 16:59:03 -0700436
Anthony Chene658cc22017-04-27 11:17:35 -0700437 /**
438 * Sets the given drawable as the background of the scrim that shows up behind the
439 * notifications.
440 */
441 public void setScrimBehindDrawable(Drawable drawable) {
442 mScrimBehind.setDrawable(drawable);
443 }
444
Evan Rosky9a895012016-04-21 11:26:15 -0700445 protected void scheduleUpdate() {
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200446 if (mUpdatePending) return;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200447
448 // Make sure that a frame gets scheduled.
449 mScrimBehind.invalidate();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200450 mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
451 mUpdatePending = true;
452 }
453
Xiaohui Chen5da71352016-02-22 10:04:41 -0800454 protected void updateScrims() {
Lucas Dupin9324aa92017-07-26 20:29:38 -0700455 // Make sure we have the right gradients and their opacities will satisfy GAR.
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700456 if (mNeedsDrawableColorUpdate) {
457 mNeedsDrawableColorUpdate = false;
Lucas Dupin9324aa92017-07-26 20:29:38 -0700458 final GradientColors currentScrimColors;
Lucas Dupin05726cd2018-03-13 14:00:24 -0700459 if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_SCRIMMED
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800460 || mState == ScrimState.BOUNCER) {
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700461 // Always animate color changes if we're seeing the keyguard
Lucas Dupin75ec3792017-06-29 14:07:18 -0700462 mScrimInFront.setColors(mLockColors, true /* animated */);
463 mScrimBehind.setColors(mLockColors, true /* animated */);
Lucas Dupin9324aa92017-07-26 20:29:38 -0700464 currentScrimColors = mLockColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700465 } else {
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700466 // Only animate scrim color if the scrim view is actually visible
467 boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
468 boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0;
Lucas Dupin5266ad12017-06-17 20:57:28 -0700469 mScrimInFront.setColors(mSystemColors, animateScrimInFront);
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700470 mScrimBehind.setColors(mSystemColors, animateScrimBehind);
Lucas Dupin9324aa92017-07-26 20:29:38 -0700471 currentScrimColors = mSystemColors;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700472 }
Lucas Dupin9324aa92017-07-26 20:29:38 -0700473
474 // Calculate minimum scrim opacity for white or black text.
475 int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
476 int mainColor = currentScrimColors.getMainColor();
477 float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
478 4.5f /* minimumContrast */) / 255f;
479 mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
Jorim Jaggiff46d4c2017-07-17 16:46:00 +0200480 mLightBarController.setScrimColor(mScrimInFront.getColors());
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700481 }
482
Lucas Dupind5107302018-03-19 15:30:29 -0700483 // We want to override the back scrim opacity for the AOD state
Lucas Dupin82aa1632017-12-13 00:13:57 -0800484 // when it's time to fade the wallpaper away.
Lucas Dupind5107302018-03-19 15:30:29 -0700485 boolean aodWallpaperTimeout = mState == ScrimState.AOD && mWallpaperVisibilityTimedOut;
486 // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
487 boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
488 && mKeyguardOccluded;
489 if (aodWallpaperTimeout || occludedKeyguard) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800490 mCurrentBehindAlpha = 1;
491 }
492
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800493 setScrimInFrontAlpha(mCurrentInFrontAlpha);
494 setScrimBehindAlpha(mCurrentBehindAlpha);
495
Adrian Roosa5c63222017-07-27 16:33:39 +0200496 dispatchScrimsVisible();
497 }
498
499 private void dispatchScrimsVisible() {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800500 final int currentScrimVisibility;
501 if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
502 currentScrimVisibility = VISIBILITY_FULLY_OPAQUE;
503 } else if (mScrimInFront.getViewAlpha() == 0 && mScrimBehind.getViewAlpha() == 0) {
504 currentScrimVisibility = VISIBILITY_FULLY_TRANSPARENT;
505 } else {
506 currentScrimVisibility = VISIBILITY_SEMI_TRANSPARENT;
507 }
Adrian Roosa5c63222017-07-27 16:33:39 +0200508
Lucas Dupin82aa1632017-12-13 00:13:57 -0800509 if (mScrimsVisibility != currentScrimVisibility) {
510 mScrimsVisibility = currentScrimVisibility;
511 mScrimVisibleListener.accept(currentScrimVisibility);
Adrian Roosa5c63222017-07-27 16:33:39 +0200512 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200513 }
514
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800515 private float getInterpolatedFraction() {
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800516 float frac = mExpansionFraction;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200517 // let's start this 20% of the way down the screen
518 frac = frac * 1.2f - 0.2f;
519 if (frac <= 0) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800520 return 0;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200521 } else {
522 // woo, special effects
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800523 return (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200524 }
525 }
526
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700527 private void setScrimBehindAlpha(float alpha) {
528 setScrimAlpha(mScrimBehind, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200529 }
530
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700531 private void setScrimInFrontAlpha(float alpha) {
532 setScrimAlpha(mScrimInFront, alpha);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200533 }
534
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800535 private void setScrimAlpha(ScrimView scrim, float alpha) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800536 if (alpha == 0f) {
537 scrim.setClickable(false);
Selim Cinekaac93252015-04-14 20:04:12 -0700538 } else {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800539 // Eat touch events (unless dozing).
Lucas Dupin38962d72018-03-14 12:41:39 -0700540 scrim.setClickable(!mState.isLowPowerState());
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200541 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800542 updateScrim(scrim, alpha);
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100543 }
544
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800545 private void updateScrimColor(View scrim, float alpha, int tint) {
546 alpha = Math.max(0, Math.min(1.0f, alpha));
Selim Cinekaac93252015-04-14 20:04:12 -0700547 if (scrim instanceof ScrimView) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700548 ScrimView scrimView = (ScrimView) scrim;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700549
Adrian Roosa5c63222017-07-27 16:33:39 +0200550 Trace.traceCounter(Trace.TRACE_TAG_APP,
551 scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
552 (int) (alpha * 255));
553
Adrian Roosa5c63222017-07-27 16:33:39 +0200554 Trace.traceCounter(Trace.TRACE_TAG_APP,
555 scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800556 Color.alpha(tint));
Adrian Roosa5c63222017-07-27 16:33:39 +0200557
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800558 scrimView.setTint(tint);
559 scrimView.setViewAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700560 } else {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800561 scrim.setAlpha(alpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700562 }
Selim Cinek8cd80402017-08-01 10:44:29 -0700563 dispatchScrimsVisible();
Jorim Jaggi048af1f2014-11-11 22:51:10 +0100564 }
565
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800566 private void startScrimAnimation(final View scrim, float current) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800567 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
568 final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() :
569 Color.TRANSPARENT;
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700570 anim.addUpdateListener(animation -> {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800571 final float startAlpha = (Float) scrim.getTag(TAG_START_ALPHA);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800572 final float animAmount = (float) animation.getAnimatedValue();
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800573 final int finalScrimTint = getCurrentScrimTint(scrim);
574 final float finalScrimAlpha = getCurrentScrimAlpha(scrim);
575 float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount);
576 alpha = MathUtils.constrain(alpha, 0f, 1f);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800577 int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
578 updateScrimColor(scrim, alpha, tint);
Adrian Roosa5c63222017-07-27 16:33:39 +0200579 dispatchScrimsVisible();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200580 });
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800581 anim.setInterpolator(mInterpolator);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200582 anim.setStartDelay(mAnimationDelay);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800583 anim.setDuration(mAnimationDuration);
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200584 anim.addListener(new AnimatorListenerAdapter() {
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200585 @Override
586 public void onAnimationEnd(Animator animation) {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800587 onFinished();
588
589 scrim.setTag(TAG_KEY_ANIM, null);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800590 dispatchScrimsVisible();
591
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200592 if (!mDeferFinishedListener && mOnAnimationFinished != null) {
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200593 mOnAnimationFinished.run();
594 mOnAnimationFinished = null;
595 }
596 }
597 });
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800598
599 // Cache alpha values because we might want to update this animator in the future if
600 // the user expands the panel while the animation is still running.
601 scrim.setTag(TAG_START_ALPHA, current);
602 scrim.setTag(TAG_END_ALPHA, getCurrentScrimAlpha(scrim));
603
John Spurlockbf370992014-06-17 13:58:31 -0400604 scrim.setTag(TAG_KEY_ANIM, anim);
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800605 anim.start();
606 }
607
608 private float getCurrentScrimAlpha(View scrim) {
609 if (scrim == mScrimInFront) {
610 return mCurrentInFrontAlpha;
611 } else if (scrim == mScrimBehind) {
612 return mCurrentBehindAlpha;
613 } else if (scrim == mHeadsUpScrim) {
614 return calculateHeadsUpAlpha();
615 } else {
616 throw new IllegalArgumentException("Unknown scrim view");
617 }
618 }
619
620 private int getCurrentScrimTint(View scrim) {
621 if (scrim == mScrimInFront) {
622 return mCurrentInFrontTint;
623 } else if (scrim == mScrimBehind) {
624 return mCurrentBehindTint;
625 } else if (scrim == mHeadsUpScrim) {
626 return Color.TRANSPARENT;
627 } else {
628 throw new IllegalArgumentException("Unknown scrim view");
629 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200630 }
631
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200632 @Override
633 public boolean onPreDraw() {
634 mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
635 mUpdatePending = false;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800636 if (mCallback != null) {
637 mCallback.onStart();
Selim Cinek372d1bd2015-08-14 13:19:37 -0700638 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200639 updateScrims();
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800640 if (mOnAnimationFinished != null && !isAnimating(mScrimInFront)
641 && !isAnimating(mScrimBehind)) {
642 mOnAnimationFinished.run();
643 mOnAnimationFinished = null;
644 }
Selim Cinekedd32b82015-06-23 22:05:58 -0400645 return true;
646 }
647
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800648 private void onFinished() {
649 if (mWakeLockHeld) {
650 mWakeLock.release();
651 mWakeLockHeld = false;
652 }
653 if (mCallback != null) {
654 mCallback.onFinished();
655 mCallback = null;
656 }
657 // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
658 // At the end of the animation we need to remove the tint.
659 if (mState == ScrimState.UNLOCKED) {
660 mCurrentInFrontTint = Color.TRANSPARENT;
661 mCurrentBehindTint = Color.TRANSPARENT;
662 }
663 }
664
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700665 private boolean isAnimating(View scrim) {
666 return scrim.getTag(TAG_KEY_ANIM) != null;
667 }
668
Selim Cinek25503252016-03-03 15:31:43 -0800669 public void setDrawBehindAsSrc(boolean asSrc) {
Selim Cineka0fad3b2014-09-19 17:20:05 +0200670 mScrimBehind.setDrawAsSrc(asSrc);
671 }
Selim Cinekaac93252015-04-14 20:04:12 -0700672
673 @Override
John Spurlockb349af572015-04-29 12:24:19 -0400674 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
Selim Cinekaac93252015-04-14 20:04:12 -0700675 }
676
677 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700678 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
679 mPinnedHeadsUpCount++;
680 updateHeadsUpScrim(true);
681 }
682
683 @Override
684 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
685 mPinnedHeadsUpCount--;
686 if (headsUp == mDraggedHeadsUpView) {
687 mDraggedHeadsUpView = null;
688 mTopHeadsUpDragAmount = 0.0f;
Selim Cinekaac93252015-04-14 20:04:12 -0700689 }
690 updateHeadsUpScrim(true);
691 }
692
693 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700694 public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
Selim Cinekaac93252015-04-14 20:04:12 -0700695 }
696
697 private void updateHeadsUpScrim(boolean animate) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800698 if (animate) {
699 mAnimationDuration = ANIMATION_DURATION;
700 cancelAnimator((ValueAnimator) mHeadsUpScrim.getTag(TAG_KEY_ANIM));
701 startScrimAnimation(mHeadsUpScrim, mHeadsUpScrim.getAlpha());
702 } else {
703 setOrAdaptCurrentAnimation(mHeadsUpScrim);
704 }
Selim Cinek5104a6d2015-12-18 18:38:31 -0800705 }
706
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800707 @VisibleForTesting
708 void setOnAnimationFinished(Runnable onAnimationFinished) {
709 mOnAnimationFinished = onAnimationFinished;
710 }
Adrian Roos5f72c922016-03-08 15:54:26 -0800711
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800712 private void updateScrim(ScrimView scrim, float alpha) {
713 final float currentAlpha = scrim.getViewAlpha();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800714
715 ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM);
Selim Cinekaac93252015-04-14 20:04:12 -0700716 if (previousAnimator != null) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800717 if (mAnimateChange) {
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200718 // We are not done yet! Defer calling the finished listener.
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800719 mDeferFinishedListener = true;
Selim Cinekaac93252015-04-14 20:04:12 -0700720 }
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800721 // Previous animators should always be cancelled. Not doing so would cause
722 // overlap, especially on states that don't animate, leading to flickering,
723 // and in the worst case, an internal state that doesn't represent what
724 // transitionTo requested.
725 cancelAnimator(previousAnimator);
726 mDeferFinishedListener = false;
Selim Cinekaac93252015-04-14 20:04:12 -0700727 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800728
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800729 if (mPendingFrameCallback != null) {
730 // Display is off and we're waiting.
731 return;
732 } else if (mBlankScreen) {
733 // Need to blank the display before continuing.
734 blankDisplay();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800735 return;
736 } else if (!mScreenBlankingCallbackCalled) {
737 // Not blanking the screen. Letting the callback know that we're ready
738 // to replace what was on the screen before.
739 if (mCallback != null) {
740 mCallback.onDisplayBlanked();
741 mScreenBlankingCallbackCalled = true;
742 }
743 }
744
Lucas Dupin6afae372017-11-30 13:09:22 -0500745 // TODO factor mLightBarController out of this class
746 if (scrim == mScrimBehind) {
747 mLightBarController.setScrimAlpha(alpha);
748 }
749
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800750 final boolean wantsAlphaUpdate = alpha != currentAlpha;
Lucas Dupin3503c5f2018-03-02 19:04:00 -0800751 final boolean wantsTintUpdate = scrim.getTint() != getCurrentScrimTint(scrim);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800752
753 if (wantsAlphaUpdate || wantsTintUpdate) {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800754 if (mAnimateChange) {
755 startScrimAnimation(scrim, currentAlpha);
Selim Cinekaac93252015-04-14 20:04:12 -0700756 } else {
Lucas Dupin3daf3b02018-02-27 17:23:41 -0800757 // update the alpha directly
758 updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
759 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700760 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800761 } else {
762 onFinished();
Selim Cinekaac93252015-04-14 20:04:12 -0700763 }
764 }
765
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800766 @VisibleForTesting
767 protected void cancelAnimator(ValueAnimator previousAnimator) {
768 if (previousAnimator != null) {
769 previousAnimator.cancel();
770 }
771 }
772
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800773 private void blankDisplay() {
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800774 updateScrimColor(mScrimInFront, 1, Color.BLACK);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800775
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800776 // Notify callback that the screen is completely black and we're
777 // ready to change the display power mode
778 mPendingFrameCallback = frameTimeNanos -> {
779 if (mCallback != null) {
780 mCallback.onDisplayBlanked();
781 mScreenBlankingCallbackCalled = true;
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800782 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800783
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800784 mBlankingTransitionRunnable = () -> {
785 mBlankingTransitionRunnable = null;
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800786 mPendingFrameCallback = null;
787 mBlankScreen = false;
788 // Try again.
789 updateScrims();
790 };
791
792 // Setting power states can happen after we push out the frame. Make sure we
793 // stay fully opaque until the power state request reaches the lower levels.
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800794 final int delay = mScreenOn ? 16 : 500;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800795 if (DEBUG) {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800796 Log.d(TAG, "Fading out scrims with delay: " + delay);
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800797 }
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800798 getHandler().postDelayed(mBlankingTransitionRunnable, delay);
Lucas Dupin8c7cb022018-02-05 10:49:03 -0800799 };
800 doOnTheNextFrame(mPendingFrameCallback);
801 }
802
803 @VisibleForTesting
804 protected void doOnTheNextFrame(Choreographer.FrameCallback callback) {
805 Choreographer.getInstance().postFrameCallback(callback);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800806 }
807
808 @VisibleForTesting
809 protected Handler getHandler() {
810 return Handler.getMain();
811 }
812
Selim Cinek684a4422015-04-15 16:18:39 -0700813 /**
814 * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means
815 * the heads up is in its resting space and 1 means it's fully dragged out.
816 *
817 * @param draggedHeadsUpView the dragged view
818 * @param topHeadsUpDragAmount how far is it dragged
819 */
Selim Cinekaac93252015-04-14 20:04:12 -0700820 public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) {
821 mTopHeadsUpDragAmount = topHeadsUpDragAmount;
822 mDraggedHeadsUpView = draggedHeadsUpView;
823 updateHeadsUpScrim(false);
824 }
825
826 private float calculateHeadsUpAlpha() {
Selim Cinek131c1e22015-05-11 19:04:49 -0700827 float alpha;
Selim Cinek684a4422015-04-15 16:18:39 -0700828 if (mPinnedHeadsUpCount >= 2) {
Selim Cinek131c1e22015-05-11 19:04:49 -0700829 alpha = 1.0f;
Selim Cinek684a4422015-04-15 16:18:39 -0700830 } else if (mPinnedHeadsUpCount == 0) {
Selim Cinek131c1e22015-05-11 19:04:49 -0700831 alpha = 0.0f;
Selim Cinekaac93252015-04-14 20:04:12 -0700832 } else {
Selim Cinek131c1e22015-05-11 19:04:49 -0700833 alpha = 1.0f - mTopHeadsUpDragAmount;
Selim Cinekaac93252015-04-14 20:04:12 -0700834 }
Lucas Dupin80a3fcc2018-02-07 10:49:55 -0800835 float expandFactor = (1.0f - mExpansionFraction);
Selim Cinek131c1e22015-05-11 19:04:49 -0700836 expandFactor = Math.max(expandFactor, 0.0f);
837 return alpha * expandFactor;
Selim Cinekaac93252015-04-14 20:04:12 -0700838 }
Selim Cinek37c110f2015-05-22 12:38:44 -0700839
Selim Cinek6811d722016-01-19 17:53:12 -0800840 public void setExcludedBackgroundArea(Rect area) {
841 mScrimBehind.setExcludedArea(area);
842 }
Selim Cinekd35c2792016-01-21 13:20:57 -0800843
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700844 public int getBackgroundColor() {
845 int color = mLockColors.getMainColor();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800846 return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700847 Color.red(color), Color.green(color), Color.blue(color));
Selim Cinekd35c2792016-01-21 13:20:57 -0800848 }
849
850 public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
851 mScrimBehind.setChangeRunnable(changeRunnable);
852 }
Selim Cineke803491c2016-04-09 21:24:45 -0700853
Selim Cinek3e7592d2016-04-11 09:35:54 +0800854 public void onDensityOrFontScaleChanged() {
Selim Cineke803491c2016-04-09 21:24:45 -0700855 ViewGroup.LayoutParams layoutParams = mHeadsUpScrim.getLayoutParams();
856 layoutParams.height = mHeadsUpScrim.getResources().getDimensionPixelSize(
857 R.dimen.heads_up_scrim_height);
858 mHeadsUpScrim.setLayoutParams(layoutParams);
859 }
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700860
861 public void setCurrentUser(int currentUser) {
862 // Don't care in the base class.
863 }
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700864
865 @Override
Lucas Dupin7aaa3532017-05-28 08:51:07 -0700866 public void onColorsChanged(ColorExtractor colorExtractor, int which) {
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700867 if ((which & WallpaperManager.FLAG_LOCK) != 0) {
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700868 mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700869 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700870 mNeedsDrawableColorUpdate = true;
871 scheduleUpdate();
872 }
873 if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
Lucas Dupin1ead7fc2017-05-24 14:14:44 -0700874 mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800875 ColorExtractor.TYPE_DARK, mState != ScrimState.UNLOCKED);
Lucas Dupin8da8f2e92017-04-21 14:02:16 -0700876 mNeedsDrawableColorUpdate = true;
877 scheduleUpdate();
878 }
879 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200880
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800881 @VisibleForTesting
882 protected WakeLock createWakeLock() {
883 return new DelayedWakeLock(getHandler(),
884 WakeLock.createPartial(mContext, "Doze"));
885 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200886
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800887 @Override
888 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800889 pw.println(" ScrimController: ");
890 pw.print(" state: "); pw.println(mState);
891 pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200892 pw.print(" alpha="); pw.print(mCurrentInFrontAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200893 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint()));
894
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800895 pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
Adrian Roosba7ca592017-08-15 17:48:05 +0200896 pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
Adrian Roosba7ca592017-08-15 17:48:05 +0200897 pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
898
Adrian Roosba7ca592017-08-15 17:48:05 +0200899 pw.print(" mTracking="); pw.println(mTracking);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800900 }
901
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700902 public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
Lucas Dupin82aa1632017-12-13 00:13:57 -0800903 mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
904 ScrimState[] states = ScrimState.values();
905 for (int i = 0; i < states.length; i++) {
906 states[i].setWallpaperSupportsAmbientMode(wallpaperSupportsAmbientMode);
907 }
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700908 }
909
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800910 /**
911 * Interrupts blanking transitions once the display notifies that it's already on.
912 */
913 public void onScreenTurnedOn() {
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800914 mScreenOn = true;
Lucas Dupin53cf12a2018-02-05 16:14:45 -0800915 final Handler handler = getHandler();
916 if (handler.hasCallbacks(mBlankingTransitionRunnable)) {
917 if (DEBUG) {
918 Log.d(TAG, "Shorter blanking because screen turned on. All good.");
919 }
920 handler.removeCallbacks(mBlankingTransitionRunnable);
921 mBlankingTransitionRunnable.run();
922 }
923 }
924
Lucas Dupin3a64ed72018-02-12 12:44:37 -0800925 public void onScreenTurnedOff() {
926 mScreenOn = false;
927 }
928
Lucas Dupin67f02632018-03-12 11:08:31 -0700929 public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
930 mExpansionAffectsAlpha = expansionAffectsAlpha;
931 }
932
Lucas Dupind5107302018-03-19 15:30:29 -0700933 public void setKeyguardOccluded(boolean keyguardOccluded) {
934 mKeyguardOccluded = keyguardOccluded;
935 }
936
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800937 public interface Callback {
938 default void onStart() {
939 }
940 default void onDisplayBlanked() {
941 }
942 default void onFinished() {
943 }
944 default void onCancelled() {
945 }
Adrian Roosba7ca592017-08-15 17:48:05 +0200946 }
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200947}