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.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
24 import com.android.systemui.dagger.SysUISingleton
25 import com.android.systemui.dagger.qualifiers.Application
26 import com.android.systemui.keyguard.shared.model.ActiveUnlockModel
27 import com.android.systemui.keyguard.shared.model.TrustManagedModel
28 import com.android.systemui.keyguard.shared.model.TrustModel
29 import com.android.systemui.user.data.repository.UserRepository
30 import javax.inject.Inject
31 import kotlinx.coroutines.CoroutineScope
32 import kotlinx.coroutines.ExperimentalCoroutinesApi
33 import kotlinx.coroutines.channels.awaitClose
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.filter
40 import kotlinx.coroutines.flow.flatMapLatest
41 import kotlinx.coroutines.flow.flowOf
42 import kotlinx.coroutines.flow.map
43 import kotlinx.coroutines.flow.onEach
44 import kotlinx.coroutines.flow.onStart
45 import kotlinx.coroutines.flow.shareIn
46 import kotlinx.coroutines.flow.stateIn
47 
48 /** Encapsulates any state relevant to trust agents and trust grants. */
49 interface TrustRepository {
50     /** Flow representing whether the current user has enabled any trust agents. */
51     val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean>
52 
53     /** Flow representing whether the current user is trusted. */
54     val isCurrentUserTrusted: Flow<Boolean>
55 
56     /** Flow representing whether active unlock is running for the current user. */
57     val isCurrentUserActiveUnlockRunning: Flow<Boolean>
58 
59     /**
60      * Reports whether a trust agent is currently enabled and managing the trust of the current user
61      */
62     val isCurrentUserTrustManaged: StateFlow<Boolean>
63 
64     /** A trust agent is requesting to dismiss the keyguard from a trust change. */
65     val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
66 }
67 
68 @OptIn(ExperimentalCoroutinesApi::class)
69 @SysUISingleton
70 class TrustRepositoryImpl
71 @Inject
72 constructor(
73     @Application private val applicationScope: CoroutineScope,
74     private val userRepository: UserRepository,
75     private val trustManager: TrustManager,
76     private val logger: TrustRepositoryLogger,
77 ) : TrustRepository {
78     private val latestTrustModelForUser = mutableMapOf<Int, TrustModel>()
79     private val activeUnlockRunningForUser = mutableMapOf<Int, ActiveUnlockModel>()
80     private val trustManagedForUser = mutableMapOf<Int, TrustManagedModel>()
81 
82     private val trust =
<lambda>null83         conflatedCallbackFlow {
84                 val callback =
85                     object : TrustManager.TrustListener {
86                         override fun onTrustChanged(
87                             enabled: Boolean,
88                             newlyUnlocked: Boolean,
89                             userId: Int,
90                             flags: Int,
91                             grantMsgs: List<String>?
92                         ) {
93                             logger.onTrustChanged(enabled, newlyUnlocked, userId, flags, grantMsgs)
94                             trySendWithFailureLogging(
95                                 TrustModel(enabled, userId, TrustGrantFlags(flags)),
96                                 TrustRepositoryLogger.TAG,
97                                 "onTrustChanged"
98                             )
99                         }
100 
101                         override fun onTrustError(message: CharSequence?) = Unit
102 
103                         override fun onEnabledTrustAgentsChanged(userId: Int) = Unit
104 
105                         override fun onIsActiveUnlockRunningChanged(
106                             isRunning: Boolean,
107                             userId: Int
108                         ) {
109                             trySendWithFailureLogging(
110                                 ActiveUnlockModel(isRunning, userId),
111                                 TrustRepositoryLogger.TAG,
112                                 "onActiveUnlockRunningChanged"
113                             )
114                         }
115 
116                         override fun onTrustManagedChanged(isTrustManaged: Boolean, userId: Int) {
117                             logger.onTrustManagedChanged(isTrustManaged, userId)
118                             trySendWithFailureLogging(
119                                 TrustManagedModel(userId, isTrustManaged),
120                                 TrustRepositoryLogger.TAG,
121                                 "onTrustManagedChanged"
122                             )
123                         }
124                     }
125                 trustManager.registerTrustListener(callback)
126                 logger.trustListenerRegistered()
127                 awaitClose {
128                     logger.trustListenerUnregistered()
129                     trustManager.unregisterTrustListener(callback)
130                 }
131             }
<lambda>null132             .onEach {
133                 when (it) {
134                     is TrustModel -> {
135                         latestTrustModelForUser[it.userId] = it
136                         logger.trustModelEmitted(it)
137                     }
138                     is ActiveUnlockModel -> {
139                         activeUnlockRunningForUser[it.userId] = it
140                         logger.activeUnlockModelEmitted(it)
141                     }
142                     is TrustManagedModel -> {
143                         trustManagedForUser[it.userId] = it
144                         logger.trustManagedModelEmitted(it)
145                     }
146                 }
147             }
148             .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
149 
150     override val isCurrentUserActiveUnlockRunning: Flow<Boolean> =
151         combine(trust, userRepository.selectedUserInfo, ::Pair)
<lambda>null152             .map { activeUnlockRunningForUser[it.second.id]?.isRunning ?: false }
153             .distinctUntilChanged()
<lambda>null154             .onEach { logger.isCurrentUserActiveUnlockRunning(it) }
<lambda>null155             .onStart {
156                 emit(
157                     activeUnlockRunningForUser[userRepository.getSelectedUserInfo().id]?.isRunning
158                         ?: false
159                 )
160             }
161 
162     override val isCurrentUserTrustManaged: StateFlow<Boolean>
163         get() =
164             combine(trust, userRepository.selectedUserInfo, ::Pair)
<lambda>null165                 .map { isUserTrustManaged(it.second.id) }
166                 .distinctUntilChanged()
<lambda>null167                 .onEach { logger.isCurrentUserTrustManaged(it) }
<lambda>null168                 .onStart { emit(false) }
169                 .stateIn(
170                     scope = applicationScope,
171                     started = SharingStarted.WhileSubscribed(),
172                     initialValue = false
173                 )
174 
175     override val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
176         get() =
177             combine(trust, userRepository.selectedUserInfo, ::Pair)
<lambda>null178                 .map { latestTrustModelForUser[it.second.id] }
179                 .distinctUntilChanged()
<lambda>null180                 .filter {
181                     it != null &&
182                         (it.flags.isInitiatedByUser || it.flags.dismissKeyguardRequested())
183                 }
<lambda>null184                 .map { it!! }
185 
186     override val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean> =
187         userRepository.selectedUserInfo
<lambda>null188             .flatMapLatest { flowOf(trustManager.isTrustUsuallyManaged(it.id)) }
189             .stateIn(applicationScope, started = SharingStarted.Eagerly, false)
190 
isUserTrustManagednull191     private fun isUserTrustManaged(userId: Int) =
192         trustManagedForUser[userId]?.isTrustManaged ?: false
193 
194     override val isCurrentUserTrusted: Flow<Boolean>
195         get() =
196             combine(trust, userRepository.selectedUserInfo, ::Pair)
197                 .map { latestTrustModelForUser[it.second.id]?.isTrusted ?: false }
198                 .distinctUntilChanged()
<lambda>null199                 .onEach { logger.isCurrentUserTrusted(it) }
<lambda>null200                 .onStart { emit(false) }
201 }
202