1 /* <lambda>null2 * Copyright (C) 2024 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.communal.domain.interactor 18 19 import android.content.pm.UserInfo 20 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 21 import com.android.systemui.communal.data.model.CommunalEnabledState 22 import com.android.systemui.communal.data.model.CommunalWidgetCategories 23 import com.android.systemui.communal.data.repository.CommunalSettingsRepository 24 import com.android.systemui.communal.shared.model.CommunalBackgroundType 25 import com.android.systemui.dagger.SysUISingleton 26 import com.android.systemui.dagger.qualifiers.Background 27 import com.android.systemui.log.dagger.CommunalTableLog 28 import com.android.systemui.log.table.TableLogBuffer 29 import com.android.systemui.log.table.logDiffsForTable 30 import com.android.systemui.settings.UserTracker 31 import com.android.systemui.user.domain.interactor.SelectedUserInteractor 32 import java.util.concurrent.Executor 33 import javax.inject.Inject 34 import kotlinx.coroutines.CoroutineDispatcher 35 import kotlinx.coroutines.CoroutineScope 36 import kotlinx.coroutines.ExperimentalCoroutinesApi 37 import kotlinx.coroutines.channels.awaitClose 38 import kotlinx.coroutines.flow.Flow 39 import kotlinx.coroutines.flow.SharingStarted 40 import kotlinx.coroutines.flow.StateFlow 41 import kotlinx.coroutines.flow.flatMapLatest 42 import kotlinx.coroutines.flow.flowOf 43 import kotlinx.coroutines.flow.flowOn 44 import kotlinx.coroutines.flow.map 45 import kotlinx.coroutines.flow.stateIn 46 47 @OptIn(ExperimentalCoroutinesApi::class) 48 @SysUISingleton 49 class CommunalSettingsInteractor 50 @Inject 51 constructor( 52 @Background private val bgScope: CoroutineScope, 53 @Background private val bgDispatcher: CoroutineDispatcher, 54 @Background private val bgExecutor: Executor, 55 private val repository: CommunalSettingsRepository, 56 userInteractor: SelectedUserInteractor, 57 private val userTracker: UserTracker, 58 @CommunalTableLog tableLogBuffer: TableLogBuffer, 59 ) { 60 /** Whether or not communal is enabled for the currently selected user. */ 61 val isCommunalEnabled: StateFlow<Boolean> = 62 userInteractor.selectedUserInfo 63 .flatMapLatest { user -> repository.getEnabledState(user) } 64 .logDiffsForTable( 65 tableLogBuffer = tableLogBuffer, 66 columnPrefix = "disabledReason", 67 initialValue = CommunalEnabledState() 68 ) 69 .map { model -> model.enabled } 70 // Start this eagerly since the value is accessed synchronously in many places. 71 .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) 72 73 /** What widget categories to show on the hub. */ 74 val communalWidgetCategories: StateFlow<Int> = 75 userInteractor.selectedUserInfo 76 .flatMapLatest { user -> repository.getWidgetCategories(user) } 77 .map { categories -> categories.categories } 78 .stateIn( 79 scope = bgScope, 80 // Start this eagerly since the value can be accessed synchronously. 81 started = SharingStarted.Eagerly, 82 initialValue = CommunalWidgetCategories.defaultCategories 83 ) 84 85 /** The type of background to use for the hub. Used to experiment with different backgrounds */ 86 val communalBackground: Flow<CommunalBackgroundType> = 87 userInteractor.selectedUserInfo 88 .flatMapLatest { user -> repository.getBackground(user) } 89 .flowOn(bgDispatcher) 90 91 private val workProfileUserInfoCallbackFlow: Flow<UserInfo?> = conflatedCallbackFlow { 92 fun send(profiles: List<UserInfo>) { 93 trySend(profiles.find { it.isManagedProfile }) 94 } 95 96 val callback = 97 object : UserTracker.Callback { 98 override fun onProfilesChanged(profiles: List<UserInfo>) { 99 send(profiles) 100 } 101 } 102 userTracker.addCallback(callback, bgExecutor) 103 send(userTracker.userProfiles) 104 105 awaitClose { userTracker.removeCallback(callback) } 106 } 107 108 /** Whether or not keyguard widgets are allowed for work profile by device policy manager. */ 109 val allowedByDevicePolicyForWorkProfile: StateFlow<Boolean> = 110 workProfileUserInfoCallbackFlow 111 .flatMapLatest { workProfile -> 112 workProfile?.let { repository.getAllowedByDevicePolicy(it) } ?: flowOf(false) 113 } 114 .stateIn( 115 scope = bgScope, 116 started = SharingStarted.WhileSubscribed(), 117 initialValue = false 118 ) 119 } 120