• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 package com.android.systemui.statusbar.phone
17 
18 import android.view.View
19 import com.android.systemui.dagger.SysUISingleton
20 import com.android.systemui.keyguard.WakefulnessLifecycle
21 import com.android.systemui.statusbar.LightRevealScrim
22 import com.android.systemui.unfold.FoldAodAnimationController
23 import com.android.systemui.unfold.SysUIUnfoldComponent
24 import java.util.Optional
25 import javax.inject.Inject
26 
27 @SysUISingleton
28 class ScreenOffAnimationController @Inject constructor(
29     sysUiUnfoldComponent: Optional<SysUIUnfoldComponent>,
30     unlockedScreenOffAnimation: UnlockedScreenOffAnimationController,
31     private val wakefulnessLifecycle: WakefulnessLifecycle,
32 ) : WakefulnessLifecycle.Observer {
33 
34     private val foldToAodAnimation: FoldAodAnimationController? = sysUiUnfoldComponent
35         .orElse(null)?.getFoldAodAnimationController()
36 
37     private val animations: List<ScreenOffAnimation> =
38         listOfNotNull(foldToAodAnimation, unlockedScreenOffAnimation)
39 
initializenull40     fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) {
41         animations.forEach { it.initialize(centralSurfaces, lightRevealScrim) }
42         wakefulnessLifecycle.addObserver(this)
43     }
44 
45     /**
46      * Called when system reports that we are going to sleep
47      */
onStartedGoingToSleepnull48     override fun onStartedGoingToSleep() {
49         animations.firstOrNull { it.startAnimation() }
50     }
51 
52     /**
53      * Called when opaqueness of the light reveal scrim has change
54      * When [isOpaque] is true then scrim is visible and covers the screen
55      */
onScrimOpaqueChangednull56     fun onScrimOpaqueChanged(isOpaque: Boolean) =
57         animations.forEach { it.onScrimOpaqueChanged(isOpaque) }
58 
59     /**
60      * Called when always on display setting changed
61      */
onAlwaysOnChangednull62     fun onAlwaysOnChanged(alwaysOn: Boolean) =
63         animations.forEach { it.onAlwaysOnChanged(alwaysOn) }
64 
65     /**
66      * If returns true we are taking over the screen off animation from display manager to SysUI.
67      * We can play our custom animation instead of default fade out animation.
68      */
shouldControlUnlockedScreenOffnull69     fun shouldControlUnlockedScreenOff(): Boolean =
70         animations.any { it.shouldPlayAnimation() }
71 
72     /**
73      * If returns true it fully expands notification shade, it could be used to make
74      * the scrims visible
75      */
shouldExpandNotificationsnull76     fun shouldExpandNotifications(): Boolean =
77         animations.any { it.isAnimationPlaying() }
78 
79     /**
80      * If returns true it allows to perform custom animation for showing
81      * keyguard in [animateInKeyguard]
82      */
shouldAnimateInKeyguardnull83     fun shouldAnimateInKeyguard(): Boolean =
84         animations.any { it.shouldAnimateInKeyguard() }
85 
86     /**
87      * Called when keyguard is about to be displayed and allows to perform custom animation
88      */
animateInKeyguardnull89     fun animateInKeyguard(keyguardView: View, after: Runnable) =
90         animations.firstOrNull {
91             if (it.shouldAnimateInKeyguard()) {
92                 it.animateInKeyguard(keyguardView, after)
93                 true
94             } else {
95                 false
96             }
97         }
98 
99     /**
100      * If returns true it will disable propagating touches to apps and keyguard
101      */
shouldIgnoreKeyguardTouchesnull102     fun shouldIgnoreKeyguardTouches(): Boolean =
103         animations.any { it.isAnimationPlaying() }
104 
105     /**
106      * If returns true wake up won't be blocked when dozing
107      */
allowWakeUpIfDozingnull108     fun allowWakeUpIfDozing(): Boolean =
109         animations.all { !it.isAnimationPlaying() }
110 
111     /**
112      * Do not allow showing keyguard immediately so it could be postponed e.g. to the point when
113      * the animation ends
114      */
shouldDelayKeyguardShownull115     fun shouldDelayKeyguardShow(): Boolean =
116         animations.any { it.shouldDelayKeyguardShow() }
117 
118     /**
119      * Return true while we want to ignore requests to show keyguard, we need to handle pending
120      * keyguard lock requests manually
121      *
122      * @see [com.android.systemui.keyguard.KeyguardViewMediator.maybeHandlePendingLock]
123      */
isKeyguardShowDelayednull124     fun isKeyguardShowDelayed(): Boolean =
125         animations.any { it.isKeyguardShowDelayed() }
126 
127     /**
128      * Return true to ignore requests to hide keyguard
129      */
isKeyguardHideDelayednull130     fun isKeyguardHideDelayed(): Boolean =
131         animations.any { it.isKeyguardHideDelayed() }
132 
133     /**
134      * Return true to make the status bar expanded so we can animate [LightRevealScrim]
135      */
shouldShowLightRevealScrimnull136     fun shouldShowLightRevealScrim(): Boolean =
137         animations.any { it.shouldPlayAnimation() }
138 
139     /**
140      * Return true to indicate that we should hide [LightRevealScrim] when waking up
141      */
shouldHideLightRevealScrimOnWakeUpnull142     fun shouldHideLightRevealScrimOnWakeUp(): Boolean =
143         animations.any { it.shouldHideScrimOnWakeUp() }
144 
145     /**
146      * Return true to override the dozing state of the notifications to fully dozing,
147      * so the notifications are not visible when playing the animation
148      */
overrideNotificationsFullyDozingOnKeyguardnull149     fun overrideNotificationsFullyDozingOnKeyguard(): Boolean =
150         animations.any { it.overrideNotificationsDozeAmount() }
151 
152     /**
153      * Return true to hide the notifications footer ('manage'/'clear all' buttons)
154      */
shouldHideNotificationsFooternull155     fun shouldHideNotificationsFooter(): Boolean =
156         animations.any { it.isAnimationPlaying() }
157 
158     /**
159      * Return true to clamp screen brightness to 'dimmed' value when devices times out
160      * and goes to sleep
161      */
shouldClampDozeScreenBrightnessnull162     fun shouldClampDozeScreenBrightness(): Boolean =
163         animations.any { it.shouldPlayAnimation() }
164 
165     /**
166      * Return true to show AOD icons even when status bar is in 'shade' state (unlocked)
167      */
shouldShowAodIconsWhenShadenull168     fun shouldShowAodIconsWhenShade(): Boolean =
169         animations.any { it.shouldShowAodIconsWhenShade() }
170 
171     /**
172      * Return true to allow animation of appearing AOD icons
173      */
shouldAnimateAodIconsnull174     fun shouldAnimateAodIcons(): Boolean =
175         animations.all { it.shouldAnimateAodIcons() }
176 
177     /**
178      * Return true to animate doze state change, if returns false dozing will be applied without
179      * animation (sends only 0.0f or 1.0f dozing progress)
180      */
shouldAnimateDozingChangenull181     fun shouldAnimateDozingChange(): Boolean =
182         animations.all { it.shouldAnimateDozingChange() }
183 
184     /**
185      * Returns true when moving display state to power save mode should be
186      * delayed for a few seconds. This might be useful to play animations in full quality,
187      * without reducing FPS.
188      */
shouldDelayDisplayDozeTransitionnull189     fun shouldDelayDisplayDozeTransition(): Boolean =
190         animations.any { it.shouldDelayDisplayDozeTransition() }
191 
192     /**
193      * Return true to animate large <-> small clock transition
194      */
shouldAnimateClockChangenull195     fun shouldAnimateClockChange(): Boolean =
196         animations.all { it.shouldAnimateClockChange() }
197 }
198 
199 interface ScreenOffAnimation {
initializenull200     fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) {}
201 
202     /**
203      * Called when started going to sleep, should return true if the animation will be played
204      */
startAnimationnull205     fun startAnimation(): Boolean = false
206 
207     fun shouldPlayAnimation(): Boolean = false
208     fun isAnimationPlaying(): Boolean = false
209 
210     fun onScrimOpaqueChanged(isOpaque: Boolean) {}
onAlwaysOnChangednull211     fun onAlwaysOnChanged(alwaysOn: Boolean) {}
212 
shouldAnimateInKeyguardnull213     fun shouldAnimateInKeyguard(): Boolean = false
214     fun animateInKeyguard(keyguardView: View, after: Runnable) = after.run()
215 
216     fun shouldDelayKeyguardShow(): Boolean = false
217     fun isKeyguardShowDelayed(): Boolean = false
218     fun isKeyguardHideDelayed(): Boolean = false
219     fun shouldHideScrimOnWakeUp(): Boolean = false
220     fun overrideNotificationsDozeAmount(): Boolean = false
221     fun shouldShowAodIconsWhenShade(): Boolean = false
222     fun shouldDelayDisplayDozeTransition(): Boolean = false
223     fun shouldAnimateAodIcons(): Boolean = true
224     fun shouldAnimateDozingChange(): Boolean = true
225     fun shouldAnimateClockChange(): Boolean = true
226 }
227