1 /*
2  * Copyright (C) 2024 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.data.repository
18 
19 import android.app.ActivityManager.RunningTaskInfo
20 import android.app.WindowConfiguration
21 import com.android.systemui.dagger.SysUISingleton
22 import javax.inject.Inject
23 import kotlinx.coroutines.flow.MutableStateFlow
24 
25 /**
26  * Information about the SHOW_WHEN_LOCKED activity that is either newly on top of the task stack, or
27  * newly not on top of the task stack.
28  */
29 data class ShowWhenLockedActivityInfo(
30     /** Whether the activity is on top. If not, we're unoccluding and will be animating it out. */
31     val isOnTop: Boolean,
32 
33     /**
34      * Information about the activity, which we use for transition internals and also to customize
35      * animations.
36      */
37     val taskInfo: RunningTaskInfo? = null
38 ) {
isDreamnull39     fun isDream(): Boolean {
40         return taskInfo?.topActivityType == WindowConfiguration.ACTIVITY_TYPE_DREAM
41     }
42 }
43 
44 /**
45  * Maintains state about "occluding" activities - activities with FLAG_SHOW_WHEN_LOCKED, which are
46  * capable of displaying over the lockscreen while the device is still locked (such as Google Maps
47  * navigation).
48  *
49  * Window Manager considers the device to be in the "occluded" state whenever such an activity is on
50  * top of the task stack, including while we're unlocked, while keyguard code considers us to be
51  * occluded only when we're locked, with an occluding activity currently displaying over the
52  * lockscreen.
53  *
54  * This dual definition is confusing, so this repository collects all of the signals WM gives us,
55  * and consolidates them into [showWhenLockedActivityInfo.isOnTop], which is the actual question WM
56  * is answering when they say whether we're 'occluded'. Keyguard then uses this signal to
57  * conditionally transition to [KeyguardState.OCCLUDED] where appropriate.
58  */
59 @SysUISingleton
60 class KeyguardOcclusionRepository @Inject constructor() {
61     val showWhenLockedActivityInfo = MutableStateFlow(ShowWhenLockedActivityInfo(isOnTop = false))
62 
63     /**
64      * Sets whether there's a SHOW_WHEN_LOCKED activity on top of the task stack, and optionally,
65      * information about the activity itself.
66      *
67      * If no value is provided for [taskInfo], we'll default to the current [taskInfo].
68      *
69      * The [taskInfo] is always present when this method is called from the occlude/unocclude
70      * animation runners. We use the default when calling from [KeyguardService.isOccluded], since
71      * we only receive a true/false value there. isOccluded is mostly redundant - it's almost always
72      * called with true after an occlusion animation has started, and with false after an unocclude
73      * animation has started. In those cases, we don't want to clear out the taskInfo just because
74      * it wasn't available at that call site.
75      */
setShowWhenLockedActivityInfonull76     fun setShowWhenLockedActivityInfo(
77         onTop: Boolean,
78         taskInfo: RunningTaskInfo? = showWhenLockedActivityInfo.value.taskInfo
79     ) {
80         showWhenLockedActivityInfo.value =
81             ShowWhenLockedActivityInfo(
82                 isOnTop = onTop,
83                 taskInfo = taskInfo,
84             )
85     }
86 }
87