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