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.data.repository
18
19 import android.app.admin.DevicePolicyManager
20 import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
21 import android.content.IntentFilter
22 import android.content.pm.UserInfo
23 import android.provider.Settings
24 import com.android.systemui.Flags.communalHub
25 import com.android.systemui.broadcast.BroadcastDispatcher
26 import com.android.systemui.communal.data.model.CommunalEnabledState
27 import com.android.systemui.communal.data.model.CommunalWidgetCategories
28 import com.android.systemui.communal.data.model.DisabledReason
29 import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_DEVICE_POLICY
30 import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_FLAG
31 import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_INVALID_USER
32 import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_USER_SETTING
33 import com.android.systemui.communal.shared.model.CommunalBackgroundType
34 import com.android.systemui.dagger.SysUISingleton
35 import com.android.systemui.dagger.qualifiers.Background
36 import com.android.systemui.flags.FeatureFlagsClassic
37 import com.android.systemui.flags.Flags
38 import com.android.systemui.util.kotlin.emitOnStart
39 import com.android.systemui.util.settings.SecureSettings
40 import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
41 import java.util.EnumSet
42 import javax.inject.Inject
43 import kotlinx.coroutines.CoroutineDispatcher
44 import kotlinx.coroutines.flow.Flow
45 import kotlinx.coroutines.flow.combine
46 import kotlinx.coroutines.flow.flowOf
47 import kotlinx.coroutines.flow.flowOn
48 import kotlinx.coroutines.flow.map
49 import kotlinx.coroutines.flow.onStart
50
51 interface CommunalSettingsRepository {
52 /** A [CommunalEnabledState] for the specified user. */
53 fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState>
54
55 /**
56 * A flow that reports the widget categories to show on the hub as selected by the user in
57 * Settings.
58 */
59 fun getWidgetCategories(user: UserInfo): Flow<CommunalWidgetCategories>
60
61 /** Keyguard widgets enabled state by Device Policy Manager for the specified user. */
62 fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean>
63
64 /** The type of background to use for the hub. Used to experiment with different backgrounds. */
65 fun getBackground(user: UserInfo): Flow<CommunalBackgroundType>
66 }
67
68 @SysUISingleton
69 class CommunalSettingsRepositoryImpl
70 @Inject
71 constructor(
72 @Background private val bgDispatcher: CoroutineDispatcher,
73 private val featureFlagsClassic: FeatureFlagsClassic,
74 private val secureSettings: SecureSettings,
75 private val broadcastDispatcher: BroadcastDispatcher,
76 private val devicePolicyManager: DevicePolicyManager,
77 ) : CommunalSettingsRepository {
78
<lambda>null79 private val flagEnabled: Boolean by lazy {
80 featureFlagsClassic.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) && communalHub()
81 }
82
getEnabledStatenull83 override fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState> {
84 if (!user.isMain) {
85 return flowOf(CommunalEnabledState(DISABLED_REASON_INVALID_USER))
86 }
87 if (!flagEnabled) {
88 return flowOf(CommunalEnabledState(DISABLED_REASON_FLAG))
89 }
90 return combine(
91 getEnabledByUser(user).mapToReason(DISABLED_REASON_USER_SETTING),
92 getAllowedByDevicePolicy(user).mapToReason(DISABLED_REASON_DEVICE_POLICY),
93 ) { reasons ->
94 reasons.filterNotNull()
95 }
96 .map { reasons ->
97 if (reasons.isEmpty()) {
98 EnumSet.noneOf(DisabledReason::class.java)
99 } else {
100 EnumSet.copyOf(reasons)
101 }
102 }
103 .map { reasons -> CommunalEnabledState(reasons) }
104 .flowOn(bgDispatcher)
105 }
106
getWidgetCategoriesnull107 override fun getWidgetCategories(user: UserInfo): Flow<CommunalWidgetCategories> =
108 secureSettings
109 .observerFlow(userId = user.id, names = arrayOf(GLANCEABLE_HUB_CONTENT_SETTING))
110 // Force an update
111 .onStart { emit(Unit) }
<lambda>null112 .map {
113 CommunalWidgetCategories(
114 secureSettings.getIntForUser(
115 GLANCEABLE_HUB_CONTENT_SETTING,
116 CommunalWidgetCategories.defaultCategories,
117 user.id
118 )
119 )
120 }
121 .flowOn(bgDispatcher)
122
getAllowedByDevicePolicynull123 override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> =
124 broadcastDispatcher
125 .broadcastFlow(
126 filter =
127 IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
128 user = user.userHandle
129 )
130 .emitOnStart()
131 .map { devicePolicyManager.areKeyguardWidgetsAllowed(user.id) }
132
getBackgroundnull133 override fun getBackground(user: UserInfo): Flow<CommunalBackgroundType> =
134 secureSettings
135 .observerFlow(userId = user.id, names = arrayOf(GLANCEABLE_HUB_BACKGROUND_SETTING))
136 .emitOnStart()
137 .map {
138 val intType =
139 secureSettings.getIntForUser(
140 GLANCEABLE_HUB_BACKGROUND_SETTING,
141 CommunalBackgroundType.DEFAULT.value,
142 user.id
143 )
144 CommunalBackgroundType.entries.find { type -> type.value == intType }
145 ?: CommunalBackgroundType.DEFAULT
146 }
147
getEnabledByUsernull148 private fun getEnabledByUser(user: UserInfo): Flow<Boolean> =
149 secureSettings
150 .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.GLANCEABLE_HUB_ENABLED))
151 // Force an update
152 .onStart { emit(Unit) }
<lambda>null153 .map {
154 secureSettings.getIntForUser(
155 Settings.Secure.GLANCEABLE_HUB_ENABLED,
156 ENABLED_SETTING_DEFAULT,
157 user.id,
158 ) == 1
159 }
160
161 companion object {
162 const val GLANCEABLE_HUB_CONTENT_SETTING = "glanceable_hub_content_setting"
163 const val GLANCEABLE_HUB_BACKGROUND_SETTING = "glanceable_hub_background"
164 private const val ENABLED_SETTING_DEFAULT = 1
165 }
166 }
167
DevicePolicyManagernull168 private fun DevicePolicyManager.areKeyguardWidgetsAllowed(userId: Int): Boolean =
169 (getKeyguardDisabledFeatures(null, userId) and KEYGUARD_DISABLE_WIDGETS_ALL) == 0
170
171 private fun Flow<Boolean>.mapToReason(reason: DisabledReason) = map { enabled ->
172 if (enabled) null else reason
173 }
174