1 /*
<lambda>null2  * 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.shade.domain.interactor
18 
19 import com.android.systemui.dagger.SysUISingleton
20 import com.android.systemui.dagger.qualifiers.Application
21 import com.android.systemui.keyguard.data.repository.KeyguardRepository
22 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
23 import com.android.systemui.keyguard.shared.model.DozeStateModel
24 import com.android.systemui.keyguard.shared.model.Edge
25 import com.android.systemui.keyguard.shared.model.KeyguardState
26 import com.android.systemui.power.domain.interactor.PowerInteractor
27 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
28 import com.android.systemui.statusbar.phone.DozeParameters
29 import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
30 import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
31 import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
32 import javax.inject.Inject
33 import kotlinx.coroutines.CoroutineScope
34 import kotlinx.coroutines.flow.Flow
35 import kotlinx.coroutines.flow.SharingStarted
36 import kotlinx.coroutines.flow.StateFlow
37 import kotlinx.coroutines.flow.combine
38 import kotlinx.coroutines.flow.distinctUntilChanged
39 import kotlinx.coroutines.flow.map
40 import kotlinx.coroutines.flow.stateIn
41 
42 /** The non-empty SceneInteractor implementation. */
43 @SysUISingleton
44 class ShadeInteractorImpl
45 @Inject
46 constructor(
47     @Application val scope: CoroutineScope,
48     deviceProvisioningInteractor: DeviceProvisioningInteractor,
49     disableFlagsRepository: DisableFlagsRepository,
50     dozeParams: DozeParameters,
51     keyguardRepository: KeyguardRepository,
52     keyguardTransitionInteractor: KeyguardTransitionInteractor,
53     powerInteractor: PowerInteractor,
54     userSetupRepository: UserSetupRepository,
55     userSwitcherInteractor: UserSwitcherInteractor,
56     private val baseShadeInteractor: BaseShadeInteractor,
57 ) : ShadeInteractor, BaseShadeInteractor by baseShadeInteractor {
58     override val isShadeEnabled: StateFlow<Boolean> =
59         disableFlagsRepository.disableFlags
60             .map { isDisabledByFlags -> isDisabledByFlags.isShadeEnabled() }
61             .distinctUntilChanged()
62             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
63 
64     override val isQsEnabled: StateFlow<Boolean> =
65         disableFlagsRepository.disableFlags
66             .map { it.isQuickSettingsEnabled() }
67             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
68 
69     override val isAnyFullyExpanded: StateFlow<Boolean> =
70         anyExpansion
71             .map { it >= 1f }
72             .distinctUntilChanged()
73             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
74 
75     override val isShadeFullyExpanded: Flow<Boolean> =
76         baseShadeInteractor.shadeExpansion.map { it >= 1f }.distinctUntilChanged()
77 
78     override val isShadeFullyCollapsed: Flow<Boolean> =
79         baseShadeInteractor.shadeExpansion.map { it <= 0f }.distinctUntilChanged()
80 
81     override val isUserInteracting: StateFlow<Boolean> =
82         combine(isUserInteractingWithShade, isUserInteractingWithQs) { shade, qs -> shade || qs }
83             .distinctUntilChanged()
84             .stateIn(scope, SharingStarted.Eagerly, false)
85 
86     override val isShadeTouchable: Flow<Boolean> =
87         combine(
88             powerInteractor.isAsleep,
89             keyguardTransitionInteractor.isInTransition(Edge.create(to = KeyguardState.AOD)),
90             keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING },
91         ) { isAsleep, goingToSleep, isPulsing ->
92             when {
93                 // If the device is going to sleep, only accept touches if we're still
94                 // animating
95                 goingToSleep -> dozeParams.shouldControlScreenOff()
96                 // If the device is asleep, only accept touches if there's a pulse
97                 isAsleep -> isPulsing
98                 else -> true
99             }
100         }
101 
102     override val isExpandToQsEnabled: Flow<Boolean> =
103         combine(
104             disableFlagsRepository.disableFlags,
105             isShadeEnabled,
106             keyguardRepository.isDozing,
107             userSetupRepository.isUserSetUp,
108             deviceProvisioningInteractor.isDeviceProvisioned,
109         ) { disableFlags, isShadeEnabled, isDozing, isUserSetup, isDeviceProvisioned ->
110             isDeviceProvisioned &&
111                 // Disallow QS during setup if it's a simple user switcher. (The user intends to
112                 // use the lock screen user switcher, QS is not needed.)
113                 (isUserSetup || !userSwitcherInteractor.isSimpleUserSwitcher) &&
114                 isShadeEnabled &&
115                 disableFlags.isQuickSettingsEnabled() &&
116                 !isDozing
117         }
118 }
119