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.logging.TrustRepositoryLogger 21 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging 22 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 23 import com.android.systemui.dagger.SysUISingleton 24 import com.android.systemui.dagger.qualifiers.Application 25 import com.android.systemui.keyguard.shared.model.ActiveUnlockModel 26 import com.android.systemui.keyguard.shared.model.TrustManagedModel 27 import com.android.systemui.keyguard.shared.model.TrustModel 28 import com.android.systemui.user.data.repository.UserRepository 29 import javax.inject.Inject 30 import kotlinx.coroutines.CoroutineScope 31 import kotlinx.coroutines.channels.awaitClose 32 import kotlinx.coroutines.flow.Flow 33 import kotlinx.coroutines.flow.SharingStarted 34 import kotlinx.coroutines.flow.StateFlow 35 import kotlinx.coroutines.flow.combine 36 import kotlinx.coroutines.flow.distinctUntilChanged 37 import kotlinx.coroutines.flow.map 38 import kotlinx.coroutines.flow.onEach 39 import kotlinx.coroutines.flow.onStart 40 import kotlinx.coroutines.flow.shareIn 41 import kotlinx.coroutines.flow.stateIn 42 43 /** Encapsulates any state relevant to trust agents and trust grants. */ 44 interface TrustRepository { 45 /** Flow representing whether the current user is trusted. */ 46 val isCurrentUserTrusted: Flow<Boolean> 47 48 /** Flow representing whether active unlock is running for the current user. */ 49 val isCurrentUserActiveUnlockRunning: Flow<Boolean> 50 51 /** Reports that whether trust is managed has changed for the current user. */ 52 val isCurrentUserTrustManaged: StateFlow<Boolean> 53 } 54 55 @SysUISingleton 56 class TrustRepositoryImpl 57 @Inject 58 constructor( 59 @Application private val applicationScope: CoroutineScope, 60 private val userRepository: UserRepository, 61 private val trustManager: TrustManager, 62 private val logger: TrustRepositoryLogger, 63 ) : TrustRepository { 64 private val latestTrustModelForUser = mutableMapOf<Int, TrustModel>() 65 private val activeUnlockRunningForUser = mutableMapOf<Int, ActiveUnlockModel>() 66 private val trustManagedForUser = mutableMapOf<Int, TrustManagedModel>() 67 68 private val trust = 69 conflatedCallbackFlow { 70 val callback = 71 object : TrustManager.TrustListener { 72 override fun onTrustChanged( 73 enabled: Boolean, 74 newlyUnlocked: Boolean, 75 userId: Int, 76 flags: Int, 77 grantMsgs: List<String>? 78 ) { 79 logger.onTrustChanged(enabled, newlyUnlocked, userId, flags, grantMsgs) 80 trySendWithFailureLogging( 81 TrustModel(enabled, userId), 82 TrustRepositoryLogger.TAG, 83 "onTrustChanged" 84 ) 85 } 86 87 override fun onTrustError(message: CharSequence?) = Unit 88 89 override fun onEnabledTrustAgentsChanged(userId: Int) = Unit 90 91 override fun onIsActiveUnlockRunningChanged( 92 isRunning: Boolean, 93 userId: Int 94 ) { 95 trySendWithFailureLogging( 96 ActiveUnlockModel(isRunning, userId), 97 TrustRepositoryLogger.TAG, 98 "onActiveUnlockRunningChanged" 99 ) 100 } 101 102 override fun onTrustManagedChanged(isTrustManaged: Boolean, userId: Int) { 103 logger.onTrustManagedChanged(isTrustManaged, userId) 104 trySendWithFailureLogging( 105 TrustManagedModel(userId, isTrustManaged), 106 TrustRepositoryLogger.TAG, 107 "onTrustManagedChanged" 108 ) 109 } 110 } 111 trustManager.registerTrustListener(callback) 112 logger.trustListenerRegistered() 113 awaitClose { 114 logger.trustListenerUnregistered() 115 trustManager.unregisterTrustListener(callback) 116 } 117 } 118 .onEach { 119 when (it) { 120 is TrustModel -> { 121 latestTrustModelForUser[it.userId] = it 122 logger.trustModelEmitted(it) 123 } 124 is ActiveUnlockModel -> { 125 activeUnlockRunningForUser[it.userId] = it 126 logger.activeUnlockModelEmitted(it) 127 } 128 is TrustManagedModel -> { 129 trustManagedForUser[it.userId] = it 130 logger.trustManagedModelEmitted(it) 131 } 132 } 133 } 134 .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1) 135 136 override val isCurrentUserActiveUnlockRunning: Flow<Boolean> = 137 combine(trust, userRepository.selectedUserInfo, ::Pair) 138 .map { activeUnlockRunningForUser[it.second.id]?.isRunning ?: false } 139 .distinctUntilChanged() 140 .onEach { logger.isCurrentUserActiveUnlockRunning(it) } 141 .onStart { 142 emit( 143 activeUnlockRunningForUser[userRepository.getSelectedUserInfo().id]?.isRunning 144 ?: false 145 ) 146 } 147 148 override val isCurrentUserTrustManaged: StateFlow<Boolean> 149 get() = 150 combine(trust, userRepository.selectedUserInfo, ::Pair) 151 .map { isUserTrustManaged(it.second.id) } 152 .distinctUntilChanged() 153 .onEach { logger.isCurrentUserTrustManaged(it) } 154 .onStart { emit(false) } 155 .stateIn( 156 scope = applicationScope, 157 started = SharingStarted.WhileSubscribed(), 158 initialValue = false 159 ) 160 161 private fun isUserTrustManaged(userId: Int) = 162 trustManagedForUser[userId]?.isTrustManaged ?: false 163 164 override val isCurrentUserTrusted: Flow<Boolean> 165 get() = 166 combine(trust, userRepository.selectedUserInfo, ::Pair) 167 .map { latestTrustModelForUser[it.second.id]?.isTrusted ?: false } 168 .distinctUntilChanged() 169 .onEach { logger.isCurrentUserTrusted(it) } 170 .onStart { emit(false) } 171 } 172