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