• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.data.repository
18 
19 import android.app.trust.TrustManager
20 import com.android.keyguard.TrustGrantFlags
21 import com.android.keyguard.logging.TrustRepositoryLogger
22 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
23 import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
24 import com.android.systemui.dagger.SysUISingleton
25 import com.android.systemui.dagger.qualifiers.Application
26 import com.android.systemui.dagger.qualifiers.Background
27 import com.android.systemui.keyguard.shared.model.ActiveUnlockModel
28 import com.android.systemui.keyguard.shared.model.TrustManagedModel
29 import com.android.systemui.keyguard.shared.model.TrustModel
30 import com.android.systemui.user.data.repository.UserRepository
31 import javax.inject.Inject
32 import kotlinx.coroutines.CoroutineDispatcher
33 import kotlinx.coroutines.CoroutineScope
34 import kotlinx.coroutines.channels.awaitClose
35 import kotlinx.coroutines.flow.Flow
36 import kotlinx.coroutines.flow.SharingStarted
37 import kotlinx.coroutines.flow.StateFlow
38 import kotlinx.coroutines.flow.combine
39 import kotlinx.coroutines.flow.distinctUntilChanged
40 import kotlinx.coroutines.flow.filter
41 import kotlinx.coroutines.flow.flatMapLatest
42 import kotlinx.coroutines.flow.flowOf
43 import kotlinx.coroutines.flow.map
44 import kotlinx.coroutines.flow.onEach
45 import kotlinx.coroutines.flow.onStart
46 import kotlinx.coroutines.flow.shareIn
47 import kotlinx.coroutines.flow.stateIn
48 import kotlinx.coroutines.withContext
49 
50 /** Encapsulates any state relevant to trust agents and trust grants. */
51 interface TrustRepository {
52     /** Flow representing whether the current user has enabled any trust agents. */
53     val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean>
54 
55     /** Flow representing whether the current user is trusted. */
56     val isCurrentUserTrusted: StateFlow<Boolean>
57 
58     /** Flow representing whether active unlock is running for the current user. */
59     val isCurrentUserActiveUnlockRunning: Flow<Boolean>
60 
61     /**
62      * Reports whether a trust agent is currently enabled and managing the trust of the current user
63      */
64     val isCurrentUserTrustManaged: StateFlow<Boolean>
65 
66     /** A trust agent is requesting to dismiss the keyguard from a trust change. */
67     val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
68 
69     /** Reports a keyguard visibility change. */
reportKeyguardShowingChangednull70     suspend fun reportKeyguardShowingChanged()
71 }
72 
73 @SysUISingleton
74 class TrustRepositoryImpl
75 @Inject
76 constructor(
77     @Application private val applicationScope: CoroutineScope,
78     @Background private val backgroundDispatcher: CoroutineDispatcher,
79     private val userRepository: UserRepository,
80     private val trustManager: TrustManager,
81     private val logger: TrustRepositoryLogger,
82 ) : TrustRepository {
83     private val latestTrustModelForUser = mutableMapOf<Int, TrustModel>()
84     private val activeUnlockRunningForUser = mutableMapOf<Int, ActiveUnlockModel>()
85     private val trustManagedForUser = mutableMapOf<Int, TrustManagedModel>()
86 
87     private val trust =
88         conflatedCallbackFlow {
89                 val callback =
90                     object : TrustManager.TrustListener {
91                         override fun onTrustChanged(
92                             enabled: Boolean,
93                             newlyUnlocked: Boolean,
94                             userId: Int,
95                             flags: Int,
96                             grantMsgs: List<String>?
97                         ) {
98                             logger.onTrustChanged(enabled, newlyUnlocked, userId, flags, grantMsgs)
99                             trySendWithFailureLogging(
100                                 TrustModel(enabled, userId, TrustGrantFlags(flags)),
101                                 TrustRepositoryLogger.TAG,
102                                 "onTrustChanged"
103                             )
104                         }
105 
106                         override fun onTrustError(message: CharSequence?) = Unit
107 
108                         override fun onEnabledTrustAgentsChanged(userId: Int) = Unit
109 
110                         override fun onIsActiveUnlockRunningChanged(
111                             isRunning: Boolean,
112                             userId: Int
113                         ) {
114                             trySendWithFailureLogging(
115                                 ActiveUnlockModel(isRunning, userId),
116                                 TrustRepositoryLogger.TAG,
117                                 "onActiveUnlockRunningChanged"
118                             )
119                         }
120 
121                         override fun onTrustManagedChanged(isTrustManaged: Boolean, userId: Int) {
122                             logger.onTrustManagedChanged(isTrustManaged, userId)
123                             trySendWithFailureLogging(
124                                 TrustManagedModel(userId, isTrustManaged),
125                                 TrustRepositoryLogger.TAG,
126                                 "onTrustManagedChanged"
127                             )
128                         }
129                     }
130                 trustManager.registerTrustListener(callback)
131                 logger.trustListenerRegistered()
132                 awaitClose {
133                     logger.trustListenerUnregistered()
134                     trustManager.unregisterTrustListener(callback)
135                 }
136             }
137             .onEach {
138                 when (it) {
139                     is TrustModel -> {
140                         latestTrustModelForUser[it.userId] = it
141                         logger.trustModelEmitted(it)
142                     }
143                     is ActiveUnlockModel -> {
144                         activeUnlockRunningForUser[it.userId] = it
145                         logger.activeUnlockModelEmitted(it)
146                     }
147                     is TrustManagedModel -> {
148                         trustManagedForUser[it.userId] = it
149                         logger.trustManagedModelEmitted(it)
150                     }
151                 }
152             }
153             .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
154 
155     override val isCurrentUserActiveUnlockRunning: Flow<Boolean> =
156         combine(trust, userRepository.selectedUserInfo, ::Pair)
157             .map { activeUnlockRunningForUser[it.second.id]?.isRunning ?: false }
158             .distinctUntilChanged()
159             .onEach { logger.isCurrentUserActiveUnlockRunning(it) }
160             .onStart {
161                 emit(
162                     activeUnlockRunningForUser[userRepository.getSelectedUserInfo().id]?.isRunning
163                         ?: false
164                 )
165             }
166 
167     override val isCurrentUserTrustManaged: StateFlow<Boolean>
168         get() =
169             combine(trust, userRepository.selectedUserInfo, ::Pair)
170                 .map { isUserTrustManaged(it.second.id) }
171                 .distinctUntilChanged()
172                 .onEach { logger.isCurrentUserTrustManaged(it) }
173                 .onStart { emit(false) }
174                 .stateIn(
175                     scope = applicationScope,
176                     started = SharingStarted.WhileSubscribed(),
177                     initialValue = false
178                 )
179 
180     override val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
181         get() =
182             combine(trust, userRepository.selectedUserInfo, ::Pair)
183                 .map { latestTrustModelForUser[it.second.id] }
184                 .distinctUntilChanged()
185                 .filter {
186                     it != null &&
187                         (it.flags.isInitiatedByUser || it.flags.dismissKeyguardRequested())
188                 }
189                 .map { it!! }
190 
191     override val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean> =
192         userRepository.selectedUserInfo
193             .flatMapLatest { flowOf(trustManager.isTrustUsuallyManaged(it.id)) }
194             .stateIn(applicationScope, started = SharingStarted.Eagerly, false)
195 
196     private fun isUserTrustManaged(userId: Int) =
197         trustManagedForUser[userId]?.isTrustManaged ?: false
198 
199     override val isCurrentUserTrusted: StateFlow<Boolean>
200         get() =
201             combine(trust, userRepository.selectedUserInfo, ::Pair)
202                 .map { isCurrentUserTrusted(it.second.id) }
203                 .distinctUntilChanged()
204                 .onEach { logger.isCurrentUserTrusted(it) }
205                 .onStart { emit(false) }
206                 .stateIn(
207                     scope = applicationScope,
208                     started = SharingStarted.WhileSubscribed(),
209                     initialValue = isCurrentUserTrusted(),
210                 )
211 
212     private fun isCurrentUserTrusted(
213         selectedUserId: Int = userRepository.getSelectedUserInfo().id
214     ): Boolean {
215         return latestTrustModelForUser[selectedUserId]?.isTrusted ?: false
216     }
217 
218     override suspend fun reportKeyguardShowingChanged() {
219         withContext(backgroundDispatcher) { trustManager.reportKeyguardShowingChanged() }
220     }
221 }
222