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