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