1 /* 2 * Copyright (C) 2023 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.keyguard 18 19 import android.app.IActivityTaskManager 20 import android.util.Log 21 import android.view.IRemoteAnimationFinishedCallback 22 import android.view.RemoteAnimationTarget 23 import android.view.WindowManager 24 import com.android.systemui.dagger.SysUISingleton 25 import com.android.systemui.dagger.qualifiers.Main 26 import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier 27 import com.android.systemui.statusbar.policy.KeyguardStateController 28 import java.util.concurrent.Executor 29 import javax.inject.Inject 30 31 /** 32 * Manages lockscreen and AOD visibility state via the [IActivityTaskManager], and keeps track of 33 * remote animations related to changes in lockscreen visibility. 34 */ 35 @SysUISingleton 36 class WindowManagerLockscreenVisibilityManager 37 @Inject 38 constructor( 39 @Main private val executor: Executor, 40 private val activityTaskManagerService: IActivityTaskManager, 41 private val keyguardStateController: KeyguardStateController, 42 private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier, 43 ) { 44 45 /** 46 * Whether the lockscreen is showing, which we pass to [IActivityTaskManager.setLockScreenShown] 47 * in order to show the lockscreen and hide the surface behind the keyguard (or the inverse). 48 */ 49 private var isLockscreenShowing = true 50 51 /** 52 * Whether AOD is showing, which we pass to [IActivityTaskManager.setLockScreenShown] in order 53 * to show AOD when the lockscreen is visible. 54 */ 55 private var isAodVisible = false 56 57 /** 58 * Whether the keyguard is currently "going away", which we triggered via a call to 59 * [IActivityTaskManager.keyguardGoingAway]. When we tell WM that the keyguard is going away, 60 * the app/launcher surface behind the keyguard is made visible, and WM calls 61 * [onKeyguardGoingAwayRemoteAnimationStart] with a RemoteAnimationTarget so that we can animate 62 * it. 63 * 64 * Going away does not inherently result in [isLockscreenShowing] being set to false; we need to 65 * do that ourselves once we are done animating the surface. 66 * 67 * THIS IS THE ONLY PLACE 'GOING AWAY' TERMINOLOGY SHOULD BE USED. 'Going away' is a WM concept 68 * and we have gotten into trouble using it to mean various different things in the past. Unlock 69 * animations may still be visible when the keyguard is NOT 'going away', for example, when we 70 * play in-window animations, we set the surface to alpha=1f and end the animation immediately. 71 * The remainder of the animation occurs in-window, so while you might expect that the keyguard 72 * is still 'going away' because unlock animations are playing, it's actually not. 73 * 74 * If you want to know if the keyguard is 'going away', you probably want to check if we have 75 * STARTED but not FINISHED a transition to GONE. 76 * 77 * The going away animation will run until: 78 * - We manually call [endKeyguardGoingAwayAnimation] after we're done animating. 79 * - We call [setLockscreenShown] = true, which cancels the going away animation. 80 * - WM calls [onKeyguardGoingAwayRemoteAnimationCancelled] for another reason (such as the 10 81 * second timeout). 82 */ 83 private var isKeyguardGoingAway = false 84 private set(value) { 85 // TODO(b/278086361): Extricate the keyguard state controller. 86 keyguardStateController.notifyKeyguardGoingAway(value) 87 field = value 88 } 89 90 /** Callback provided by WM to call once we're done with the going away animation. */ 91 private var goingAwayRemoteAnimationFinishedCallback: IRemoteAnimationFinishedCallback? = null 92 93 /** 94 * Set the visibility of the surface behind the keyguard, making the appropriate calls to Window 95 * Manager to effect the change. 96 */ 97 fun setSurfaceBehindVisibility(visible: Boolean) { 98 if (isKeyguardGoingAway == visible) { 99 Log.d(TAG, "WmLockscreenVisibilityManager#setVisibility -> already visible=$visible") 100 return 101 } 102 103 // The surface behind is always visible if the lockscreen is not showing, so we're already 104 // visible. 105 if (visible && !isLockscreenShowing) { 106 Log.d(TAG, "#setVisibility -> already visible since the lockscreen isn't showing") 107 return 108 } 109 110 if (visible) { 111 // Make the surface visible behind the keyguard by calling keyguardGoingAway. The 112 // lockscreen is still showing as well, allowing us to animate unlocked. 113 Log.d(TAG, "ActivityTaskManagerService#keyguardGoingAway()") 114 activityTaskManagerService.keyguardGoingAway(0) 115 isKeyguardGoingAway = true 116 } else { 117 // Hide the surface by setting the lockscreen showing. 118 setLockscreenShown(true) 119 } 120 } 121 122 fun setAodVisible(aodVisible: Boolean) { 123 setWmLockscreenState(aodVisible = aodVisible) 124 } 125 126 /** Sets the visibility of the lockscreen. */ 127 fun setLockscreenShown(lockscreenShown: Boolean) { 128 setWmLockscreenState(lockscreenShowing = lockscreenShown) 129 } 130 131 fun onKeyguardGoingAwayRemoteAnimationStart( 132 @WindowManager.TransitionOldType transit: Int, 133 apps: Array<RemoteAnimationTarget>, 134 wallpapers: Array<RemoteAnimationTarget>, 135 nonApps: Array<RemoteAnimationTarget>, 136 finishedCallback: IRemoteAnimationFinishedCallback 137 ) { 138 goingAwayRemoteAnimationFinishedCallback = finishedCallback 139 keyguardSurfaceBehindAnimator.applyParamsToSurface(apps[0]) 140 } 141 142 fun onKeyguardGoingAwayRemoteAnimationCancelled() { 143 // If WM cancelled the animation, we need to end immediately even if we're still using the 144 // animation. 145 endKeyguardGoingAwayAnimation() 146 } 147 148 /** 149 * Whether the going away remote animation target is in-use, which means we're animating it or 150 * intend to animate it. 151 * 152 * Some unlock animations (such as the translation spring animation) are non-deterministic and 153 * might end after the transition to GONE ends. In that case, we want to keep the remote 154 * animation running until the spring ends. 155 */ 156 fun setUsingGoingAwayRemoteAnimation(usingTarget: Boolean) { 157 if (!usingTarget) { 158 endKeyguardGoingAwayAnimation() 159 } 160 } 161 162 private fun setWmLockscreenState( 163 lockscreenShowing: Boolean = this.isLockscreenShowing, 164 aodVisible: Boolean = this.isAodVisible 165 ) { 166 Log.d( 167 TAG, 168 "#setWmLockscreenState(" + 169 "isLockscreenShowing=$lockscreenShowing, " + 170 "aodVisible=$aodVisible)." 171 ) 172 173 if (this.isLockscreenShowing == lockscreenShowing && this.isAodVisible == aodVisible) { 174 return 175 } 176 177 activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible) 178 this.isLockscreenShowing = lockscreenShowing 179 this.isAodVisible = aodVisible 180 } 181 182 private fun endKeyguardGoingAwayAnimation() { 183 if (!isKeyguardGoingAway) { 184 Log.d( 185 TAG, 186 "#endKeyguardGoingAwayAnimation() called when isKeyguardGoingAway=false. " + 187 "Short-circuiting." 188 ) 189 return 190 } 191 192 executor.execute { 193 Log.d(TAG, "Finishing remote animation.") 194 goingAwayRemoteAnimationFinishedCallback?.onAnimationFinished() 195 goingAwayRemoteAnimationFinishedCallback = null 196 197 isKeyguardGoingAway = false 198 199 keyguardSurfaceBehindAnimator.notifySurfaceReleased() 200 } 201 } 202 203 companion object { 204 private val TAG = this::class.java.simpleName 205 } 206 } 207