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