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 
18 @file:OptIn(ExperimentalCoroutinesApi::class)
19 
20 package com.android.systemui.keyguard.domain.interactor
21 
22 import android.content.Context
23 import com.android.systemui.CoreStartable
24 import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
25 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
26 import com.android.systemui.dagger.SysUISingleton
27 import com.android.systemui.dagger.qualifiers.Application
28 import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
29 import com.android.systemui.keyguard.shared.ComposeLockscreen
30 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
31 import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
32 import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
33 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
34 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
35 import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
36 import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
37 import com.android.systemui.shade.domain.interactor.ShadeInteractor
38 import com.android.systemui.shade.shared.model.ShadeMode
39 import javax.inject.Inject
40 import kotlinx.coroutines.CoroutineScope
41 import kotlinx.coroutines.ExperimentalCoroutinesApi
42 import kotlinx.coroutines.flow.StateFlow
43 import kotlinx.coroutines.flow.collect
44 import kotlinx.coroutines.flow.filter
45 import kotlinx.coroutines.flow.map
46 import kotlinx.coroutines.launch
47 
48 @SysUISingleton
49 class KeyguardBlueprintInteractor
50 @Inject
51 constructor(
52     private val keyguardBlueprintRepository: KeyguardBlueprintRepository,
53     @Application private val applicationScope: CoroutineScope,
54     private val context: Context,
55     private val shadeInteractor: ShadeInteractor,
56     private val clockInteractor: KeyguardClockInteractor,
57     private val configurationInteractor: ConfigurationInteractor,
58     private val fingerprintPropertyInteractor: FingerprintPropertyInteractor,
59     private val smartspaceSection: SmartspaceSection,
60     private val clockSection: ClockSection,
61 ) : CoreStartable {
62     /** The current blueprint for the lockscreen. */
63     val blueprint: StateFlow<KeyguardBlueprint> = keyguardBlueprintRepository.blueprint
64 
65     /**
66      * Triggered when the blueprint isn't changed, but the ConstraintSet should be rebuilt and
67      * optionally a transition should be fired to move to the rebuilt ConstraintSet.
68      */
69     val refreshTransition = keyguardBlueprintRepository.refreshTransition
70 
71     /** Current BlueprintId */
72     val blueprintId =
73         shadeInteractor.shadeMode.map { shadeMode ->
74             val useSplitShade = shadeMode == ShadeMode.Split && !ComposeLockscreen.isEnabled
75             when {
76                 useSplitShade -> SplitShadeKeyguardBlueprint.ID
77                 else -> DefaultKeyguardBlueprint.DEFAULT
78             }
79         }
80 
81     override fun start() {
82         applicationScope.launch { blueprintId.collect { transitionToBlueprint(it) } }
83         applicationScope.launch {
84             fingerprintPropertyInteractor.propertiesInitialized
85                 .filter { it }
86                 .collect { refreshBlueprint() }
87         }
88         applicationScope.launch {
89             val refreshConfig =
90                 Config(
91                     Type.NoTransition,
92                     rebuildSections = listOf(smartspaceSection),
93                 )
94             configurationInteractor.onAnyConfigurationChange.collect {
95                 refreshBlueprint(refreshConfig)
96             }
97         }
98     }
99 
100     /**
101      * Transitions to a blueprint, or refreshes it if already applied.
102      *
103      * @param blueprintId
104      * @return whether the transition has succeeded.
105      */
106     fun transitionOrRefreshBlueprint(blueprintId: String): Boolean {
107         if (blueprintId == blueprint.value.id) {
108             refreshBlueprint()
109             return true
110         }
111 
112         return keyguardBlueprintRepository.applyBlueprint(blueprintId)
113     }
114 
115     /**
116      * Transitions to a blueprint.
117      *
118      * @param blueprintId
119      * @return whether the transition has succeeded.
120      */
121     fun transitionToBlueprint(blueprintId: String): Boolean {
122         return keyguardBlueprintRepository.applyBlueprint(blueprintId)
123     }
124 
125     /** Emits a value to refresh the blueprint with the appropriate transition. */
126     fun refreshBlueprint(type: Type = Type.NoTransition) = refreshBlueprint(Config(type))
127 
128     /** Emits a value to refresh the blueprint with the appropriate transition. */
129     fun refreshBlueprint(config: Config) = keyguardBlueprintRepository.refreshBlueprint(config)
130 
131     fun getCurrentBlueprint(): KeyguardBlueprint {
132         return keyguardBlueprintRepository.blueprint.value
133     }
134 
135     companion object {
136         private val TAG = "KeyguardBlueprintInteractor"
137     }
138 }
139