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