• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 
17 package com.android.systemui.statusbar.phone;
18 
19 import static com.android.systemui.statusbar.phone.ScrimController.BUSY_SCRIM_ALPHA;
20 
21 import android.graphics.Color;
22 
23 import com.android.app.tracing.coroutines.TrackTracer;
24 import com.android.systemui.Flags;
25 import com.android.systemui.dock.DockManager;
26 import com.android.systemui.res.R;
27 import com.android.systemui.scrim.ScrimView;
28 import com.android.systemui.shade.ui.ShadeColors;
29 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
30 
31 import java.util.function.Supplier;
32 
33 import kotlinx.coroutines.ExperimentalCoroutinesApi;
34 
35 /**
36  * Possible states of the ScrimController state machine.
37  */
38 @ExperimentalCoroutinesApi
39 public enum ScrimState {
40 
41     /**
42      * Initial state.
43      */
44     UNINITIALIZED,
45 
46     /**
47      * When turned off by sensors (prox, presence.)
48      */
49     OFF {
50         @Override
prepare(ScrimState previousState)51         public void prepare(ScrimState previousState) {
52             mFrontTint = mBackgroundColor;
53             mBehindTint = mBackgroundColor;
54 
55             mFrontAlpha = 1f;
56             mBehindAlpha = 1f;
57 
58             if (previousState == AOD) {
59                 mAnimateChange = false;
60             } else {
61                 mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
62             }
63         }
64 
65         @Override
isLowPowerState()66         public boolean isLowPowerState() {
67             return true;
68         }
69     },
70 
71     /**
72      * On the lock screen.
73      */
74     KEYGUARD {
75         @Override
prepare(ScrimState previousState)76         public void prepare(ScrimState previousState) {
77             mBlankScreen = false;
78             if (previousState == ScrimState.AOD) {
79                 mAnimationDuration = StackStateAnimator.ANIMATION_DURATION_WAKEUP_SCRIM;
80                 if (mDisplayRequiresBlanking) {
81                     // DisplayPowerManager will blank the screen, we'll just
82                     // set our scrim to black in this frame to avoid flickering and
83                     // fade it out afterwards.
84                     mBlankScreen = true;
85                 }
86             } else if (previousState == ScrimState.KEYGUARD) {
87                 mAnimationDuration = StackStateAnimator.ANIMATION_DURATION_WAKEUP_SCRIM;
88             } else {
89                 mAnimationDuration = ScrimController.ANIMATION_DURATION;
90             }
91             if (Flags.notificationShadeBlur()) {
92                 mBehindTint = Color.TRANSPARENT;
93                 mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(),
94                         mIsBlurSupported.get());
95                 mBehindAlpha = 0.0f;
96                 mNotifAlpha = 0.0f;
97                 mFrontAlpha = 0.0f;
98             } else {
99                 mFrontTint = mBackgroundColor;
100                 mBehindTint = mBackgroundColor;
101                 mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
102                 mFrontAlpha = 0;
103                 mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard;
104                 mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0;
105                 if (mClipQsScrim) {
106                     updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
107                 }
108             }
109 
110         }
111     },
112 
113     /**
114      * Showing password challenge on the keyguard.
115      */
116     BOUNCER {
117         @Override
prepare(ScrimState previousState)118         public void prepare(ScrimState previousState) {
119             if (Flags.bouncerUiRevamp()) {
120                 mBehindAlpha = mDefaultScrimAlpha;
121                 mNotifAlpha = 0f;
122                 mBehindTint = mNotifTint = mSurfaceColor;
123                 mFrontAlpha = 0f;
124                 return;
125             }
126             mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
127             mBehindTint = mClipQsScrim ? mBackgroundColor : mSurfaceColor;
128             mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
129             mNotifTint = Color.TRANSPARENT;
130             mFrontAlpha = 0f;
131         }
132 
133         @Override
setSurfaceColor(int surfaceColor)134         public void setSurfaceColor(int surfaceColor) {
135             super.setSurfaceColor(surfaceColor);
136             if (Flags.bouncerUiRevamp()) {
137                 mBehindTint = mNotifTint = mSurfaceColor;
138                 return;
139             }
140             if (!mClipQsScrim) {
141                 mBehindTint = mSurfaceColor;
142             }
143         }
144     },
145 
146     /**
147      * Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity.
148      */
149     BOUNCER_SCRIMMED {
150         @ExperimentalCoroutinesApi
151         @Override
prepare(ScrimState previousState)152         public void prepare(ScrimState previousState) {
153             if (Flags.bouncerUiRevamp()) {
154                 // Add unlocked here because scrim state is unlocked when there is an app on top of
155                 // the lockscreen and shade is pulled over it.
156                 if (previousState == SHADE_LOCKED || previousState == UNLOCKED) {
157                     mBehindAlpha = previousState.getBehindAlpha();
158                     mNotifAlpha = previousState.getNotifAlpha();
159                 } else {
160                     mNotifAlpha = 0f;
161                     mBehindAlpha = 0f;
162                 }
163                 mFrontAlpha = mDefaultScrimAlpha;
164                 mFrontTint = mSurfaceColor;
165                 return;
166             }
167             mBehindAlpha = 0;
168             mFrontAlpha = mDefaultScrimAlpha;
169         }
170 
171         @Override
shouldBlendWithMainColor()172         public boolean shouldBlendWithMainColor() {
173             return !Flags.bouncerUiRevamp();
174         }
175     },
176 
177     SHADE_LOCKED {
178         @Override
setDefaultScrimAlpha(float defaultScrimAlpha)179         public void setDefaultScrimAlpha(float defaultScrimAlpha) {
180             super.setDefaultScrimAlpha(defaultScrimAlpha);
181             if (!Flags.notificationShadeBlur()) {
182                 // Temporary change that prevents the shade from being semi-transparent when
183                 // bouncer blur is enabled but notification shade blur is not enabled. This is
184                 // required to perf test these two flags independently.
185                 mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
186             }
187         }
188 
189         @Override
prepare(ScrimState previousState)190         public void prepare(ScrimState previousState) {
191             if (Flags.notificationShadeBlur()) {
192                 mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources(),
193                         mIsBlurSupported.get());
194                 mBehindAlpha = Color.alpha(mBehindTint) / 255.0f;
195                 mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(),
196                         mIsBlurSupported.get());
197                 mNotifAlpha = Color.alpha(mNotifTint) / 255.0f;
198                 mFrontAlpha = 0.0f;
199             } else {
200                 if (Flags.bouncerUiRevamp()) {
201                     // This is only required until shade blur flag is fully enabled, shade is always
202                     // opaque when shade blur is not enabled, and mClipQsScrim is always false.
203                     mBehindAlpha = 1f;
204                     mNotifAlpha = 1f;
205                     mFrontAlpha = 0f;
206                     mBehindTint = mBackgroundColor;
207                     return;
208                 }
209                 mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
210                 mNotifAlpha = 1f;
211                 mFrontAlpha = 0f;
212                 mBehindTint = mClipQsScrim ? Color.TRANSPARENT : mBackgroundColor;
213 
214                 if (mClipQsScrim) {
215                     updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
216                 }
217             }
218         }
219     },
220 
221     /**
222      * Changing screen brightness from quick settings.
223      */
224     BRIGHTNESS_MIRROR {
225         @Override
prepare(ScrimState previousState)226         public void prepare(ScrimState previousState) {
227             mBehindAlpha = 0;
228             mFrontAlpha = 0;
229         }
230     },
231 
232     /**
233      * Always on display or screen off.
234      */
235     AOD {
236         @Override
prepare(ScrimState previousState)237         public void prepare(ScrimState previousState) {
238             final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
239             final boolean quickPickupEnabled = mDozeParameters.isQuickPickupEnabled();
240             final boolean isDocked = mDockManager.isDocked();
241             mBlankScreen = mDisplayRequiresBlanking;
242 
243             mFrontTint = mBackgroundColor;
244             mFrontAlpha = (alwaysOnEnabled || isDocked || quickPickupEnabled)
245                     ? mAodFrontScrimAlpha : 1f;
246 
247             mBehindTint = mBackgroundColor;
248             mBehindAlpha = ScrimController.TRANSPARENT;
249 
250             mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
251             if (previousState == OFF) {
252                 mAnimateChange = false;
253             } else {
254                 // DisplayPowerManager may blank the screen for us, or we might blank it by
255                 // animating the screen off via the LightRevelScrim. In either case we just need to
256                 // set our state.
257                 mAnimateChange = mDozeParameters.shouldControlScreenOff()
258                         && !mDozeParameters.shouldShowLightRevealScrim();
259             }
260         }
261 
262         @Override
isLowPowerState()263         public boolean isLowPowerState() {
264             return true;
265         }
266 
267         @Override
shouldBlendWithMainColor()268         public boolean shouldBlendWithMainColor() {
269             return false;
270         }
271     },
272 
273     /**
274      * When phone wakes up because you received a notification.
275      */
276     PULSING {
277         @Override
prepare(ScrimState previousState)278         public void prepare(ScrimState previousState) {
279             mFrontAlpha = mAodFrontScrimAlpha;
280             mBehindTint = mBackgroundColor;
281             mFrontTint = mBackgroundColor;
282             mBlankScreen = mDisplayRequiresBlanking;
283             mAnimationDuration = mWakeLockScreenSensorActive
284                     ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
285         }
286     },
287 
288     /**
289      * Unlocked on top of an app (launcher or any other activity.)
290      */
291     UNLOCKED {
292         @Override
prepare(ScrimState previousState)293         public void prepare(ScrimState previousState) {
294             // State that UI will sync to.
295             mBehindAlpha = mClipQsScrim ? 1 : 0;
296             mNotifAlpha = 0;
297             mFrontAlpha = 0;
298             mAnimationDuration = mKeyguardFadingAway
299                     ? mKeyguardFadingAwayDuration
300                     : CentralSurfaces.FADE_KEYGUARD_DURATION;
301 
302             boolean fromAod = previousState == AOD || previousState == PULSING;
303             // If launch/occlude animations were playing, they already animated the scrim
304             // alpha to 0f as part of the animation. If we animate it now, we'll set it back
305             // to 1f and animate it back to 0f, causing an unwanted scrim flash.
306             mAnimateChange = !mLaunchingAffordanceWithPreview
307                     && !mOccludeAnimationPlaying
308                     && !fromAod;
309 
310             mFrontTint = Color.TRANSPARENT;
311             mBehindTint = mBackgroundColor;
312             mBlankScreen = false;
313 
314             if (mDisplayRequiresBlanking && previousState == ScrimState.AOD) {
315                 // Set all scrims black, before they fade transparent.
316                 updateScrimColor(mScrimInFront, 1f /* alpha */, mBackgroundColor /* tint */);
317                 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor /* tint */);
318 
319                 // Scrims should still be black at the end of the transition.
320                 mFrontTint = mBackgroundColor;
321                 mBehindTint = mBackgroundColor;
322                 mBlankScreen = true;
323             } else if (Flags.notificationShadeBlur()) {
324                 mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources(),
325                         mIsBlurSupported.get());
326                 mBehindAlpha = Color.alpha(mBehindTint) / 255.0f;
327                 mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(),
328                         mIsBlurSupported.get());
329                 mNotifAlpha = Color.alpha(mNotifTint) / 255.0f;
330                 mFrontAlpha = 0.0f;
331                 return;
332             }
333 
334             if (mClipQsScrim) {
335                 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
336             }
337         }
338     },
339 
340     DREAMING {
341         @Override
prepare(ScrimState previousState)342         public void prepare(ScrimState previousState) {
343             mFrontTint = Color.TRANSPARENT;
344             mBehindTint = mBackgroundColor;
345             mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
346 
347             mFrontAlpha = 0;
348             mBehindAlpha = mClipQsScrim ? 1 : 0;
349             mNotifAlpha = 0;
350 
351             mBlankScreen = false;
352 
353             if (mClipQsScrim) {
354                 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
355             }
356         }
357     },
358 
359     /**
360      * Device is on the lockscreen and user has swiped from the right edge to enter the glanceable
361      * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen,
362      * as well as swipe down for the notifications and up for the bouncer.
363      */
364     GLANCEABLE_HUB {
365         @Override
prepare(ScrimState previousState)366         public void prepare(ScrimState previousState) {
367             // No scrims should be visible by default in this state.
368             mBehindAlpha = 0;
369             mNotifAlpha = 0;
370             mFrontAlpha = 0;
371 
372             mFrontTint = Color.TRANSPARENT;
373             mBehindTint = mBackgroundColor;
374             mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
375         }
376     },
377 
378     /**
379      * Device is dreaming and user has swiped from the right edge to enter the glanceable hub UI.
380      * From this state, the user can swipe from the left edge to go back to the  dream, as well as
381      * swipe down for the notifications and up for the bouncer.
382      *
383      * This is a separate state from {@link #GLANCEABLE_HUB} because the scrims behave differently
384      * when the dream is running.
385      */
386     GLANCEABLE_HUB_OVER_DREAM {
387         @Override
prepare(ScrimState previousState)388         public void prepare(ScrimState previousState) {
389             // No scrims should be visible by default in this state.
390             mBehindAlpha = 0;
391             mNotifAlpha = 0;
392             mFrontAlpha = 0;
393 
394             mFrontTint = Color.TRANSPARENT;
395             mBehindTint = mBackgroundColor;
396             mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
397         }
398     };
399 
400     boolean mBlankScreen = false;
401     long mAnimationDuration = ScrimController.ANIMATION_DURATION;
402     int mFrontTint = Color.TRANSPARENT;
403     int mBehindTint = Color.TRANSPARENT;
404     int mNotifTint = Color.TRANSPARENT;
405     int mSurfaceColor = Color.TRANSPARENT;
406 
407     boolean mAnimateChange = true;
408     float mAodFrontScrimAlpha;
409     float mFrontAlpha;
410     float mBehindAlpha;
411     float mNotifAlpha;
412 
413     float mScrimBehindAlphaKeyguard;
414     float mDefaultScrimAlpha;
415     ScrimView mScrimInFront;
416     ScrimView mScrimBehind;
417 
418     DozeParameters mDozeParameters;
419     DockManager mDockManager;
420     boolean mDisplayRequiresBlanking;
421     protected Supplier<Boolean> mIsBlurSupported;
422     boolean mLaunchingAffordanceWithPreview;
423     boolean mOccludeAnimationPlaying;
424     boolean mWakeLockScreenSensorActive;
425     boolean mKeyguardFadingAway;
426     long mKeyguardFadingAwayDuration;
427     boolean mClipQsScrim;
428     int mBackgroundColor;
429 
430     // This is needed to blur the scrim behind the scrimmed bouncer to avoid showing
431     // the notification section border
432     protected float mNotifBlurRadius = 0.0f;
433 
init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters, DockManager dockManager, Supplier<Boolean> isBlurSupported)434     public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters,
435             DockManager dockManager, Supplier<Boolean> isBlurSupported) {
436         mBackgroundColor = scrimBehind.getContext().getColor(R.color.shade_scrim_background_dark);
437         mScrimInFront = scrimInFront;
438         mScrimBehind = scrimBehind;
439 
440         mDozeParameters = dozeParameters;
441         mDockManager = dockManager;
442         mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking();
443         mIsBlurSupported = isBlurSupported;
444     }
445 
446     /** Prepare state for transition. */
prepare(ScrimState previousState)447     public void prepare(ScrimState previousState) {
448     }
449 
450     /**
451      * Whether a particular state should enable blending with extracted theme colors.
452      */
shouldBlendWithMainColor()453     public boolean shouldBlendWithMainColor() {
454         return true;
455     }
456 
getFrontAlpha()457     public float getFrontAlpha() {
458         return mFrontAlpha;
459     }
460 
getBehindAlpha()461     public float getBehindAlpha() {
462         return mBehindAlpha;
463     }
464 
getNotifAlpha()465     public float getNotifAlpha() {
466         return mNotifAlpha;
467     }
468 
getFrontTint()469     public int getFrontTint() {
470         return mFrontTint;
471     }
472 
getBehindTint()473     public int getBehindTint() {
474         return mBehindTint;
475     }
476 
getNotifTint()477     public int getNotifTint() {
478         return mNotifTint;
479     }
480 
getAnimationDuration()481     public long getAnimationDuration() {
482         return mAnimationDuration;
483     }
484 
getBlanksScreen()485     public boolean getBlanksScreen() {
486         return mBlankScreen;
487     }
488 
updateScrimColor(ScrimView scrim, float alpha, int tint)489     public void updateScrimColor(ScrimView scrim, float alpha, int tint) {
490         if (ScrimController.DEBUG_MODE) {
491             tint = scrim == mScrimInFront ? ScrimController.DEBUG_FRONT_TINT
492                     : ScrimController.DEBUG_BEHIND_TINT;
493         }
494         TrackTracer.instantForGroup("scrim",
495                 scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
496                 (int) (alpha * 255));
497 
498         TrackTracer.instantForGroup("scrim",
499                 scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
500                 Color.alpha(tint));
501 
502         scrim.setTint(tint);
503         scrim.setViewAlpha(alpha);
504     }
505 
getAnimateChange()506     public boolean getAnimateChange() {
507         return mAnimateChange;
508     }
509 
setAodFrontScrimAlpha(float aodFrontScrimAlpha)510     public void setAodFrontScrimAlpha(float aodFrontScrimAlpha) {
511         mAodFrontScrimAlpha = aodFrontScrimAlpha;
512     }
513 
setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard)514     public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) {
515         mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
516     }
517 
setDefaultScrimAlpha(float defaultScrimAlpha)518     public void setDefaultScrimAlpha(float defaultScrimAlpha) {
519         mDefaultScrimAlpha = defaultScrimAlpha;
520     }
521 
setSurfaceColor(int surfaceColor)522     public void setSurfaceColor(int surfaceColor) {
523         mSurfaceColor = surfaceColor;
524     }
525 
setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview)526     public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
527         mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview;
528     }
529 
setOccludeAnimationPlaying(boolean occludeAnimationPlaying)530     public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) {
531         mOccludeAnimationPlaying = occludeAnimationPlaying;
532     }
533 
isLowPowerState()534     public boolean isLowPowerState() {
535         return false;
536     }
537 
setWakeLockScreenSensorActive(boolean active)538     public void setWakeLockScreenSensorActive(boolean active) {
539         mWakeLockScreenSensorActive = active;
540     }
541 
setKeyguardFadingAway(boolean fadingAway, long duration)542     public void setKeyguardFadingAway(boolean fadingAway, long duration) {
543         mKeyguardFadingAway = fadingAway;
544         mKeyguardFadingAwayDuration = duration;
545     }
546 
setClipQsScrim(boolean clipsQsScrim)547     public void setClipQsScrim(boolean clipsQsScrim) {
548         mClipQsScrim = clipsQsScrim;
549     }
550 
getNotifBlurRadius()551     public float getNotifBlurRadius() {
552         return mNotifBlurRadius;
553     }
554 
setNotifBlurRadius(float value)555     public void setNotifBlurRadius(float value) {
556         mNotifBlurRadius = value;
557     }
558 }
559