Loading core/java/android/app/admin/DevicePolicyManager.java +16 −4 Original line number Diff line number Diff line Loading @@ -7056,9 +7056,10 @@ public class DevicePolicyManager { public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; /** * Disable all keyguard widgets. Has no effect starting from * {@link android.os.Build.VERSION_CODES#LOLLIPOP} since keyguard widget is only supported * on Android versions lower than 5.0. * Disable all keyguard widgets. Has no effect between {@link * android.os.Build.VERSION_CODES#LOLLIPOP} and {@link * android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} (both inclusive), since keyguard widget is * only supported on Android versions lower than 5.0 and versions higher than 14. */ public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1 << 0; Loading Loading @@ -7157,7 +7158,8 @@ public class DevicePolicyManager { public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY = DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL; | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL | DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL; /** * Keyguard features that when set on a normal or organization-owned managed profile, have Loading Loading @@ -8978,6 +8980,10 @@ public class DevicePolicyManager { * by applications in the managed profile. * </ul> * <p> * From version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, the profile owner of a * managed profile can also set {@link #KEYGUARD_DISABLE_WIDGETS_ALL} which disables keyguard * widgets for the managed profile. * <p> * From version {@link android.os.Build.VERSION_CODES#R} the profile owner of an * organization-owned managed profile can set: * <ul> Loading @@ -8986,6 +8992,12 @@ public class DevicePolicyManager { * <li>{@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} which affects the parent user when called * on the parent profile. * </ul> * Starting from version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} the profile * owner of an organization-owned managed profile can set: * <ul> * <li>{@link #KEYGUARD_DISABLE_WIDGETS_ALL} which affects the parent user when called on the * parent profile. * </ul> * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}, * {@link #KEYGUARD_DISABLE_FACE}, {@link #KEYGUARD_DISABLE_IRIS}, * {@link #KEYGUARD_DISABLE_SECURE_CAMERA} and {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt +34 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.app.admin.devicePolicyManager import android.appwidget.AppWidgetProviderInfo import android.content.Intent import android.content.pm.UserInfo import android.os.UserManager.USER_TYPE_PROFILE_MANAGED import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.provider.Settings Loading Loading @@ -59,6 +60,7 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_FEATURES_NONE) setKeyguardFeaturesDisabled(SECONDARY_USER, KEYGUARD_DISABLE_FEATURES_NONE) setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_FEATURES_NONE) underTest = kosmos.communalSettingsRepository } Loading Loading @@ -131,6 +133,30 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_DEVICE_POLICY) } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() = testScope.runTest { val widgetsAllowedForWorkProfile by collectLastValue(underTest.getAllowedByDevicePolicy(WORK_PROFILE)) assertThat(widgetsAllowedForWorkProfile).isTrue() setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) assertThat(widgetsAllowedForWorkProfile).isFalse() } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() = testScope.runTest { val enabledStateForPrimaryUser by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledStateForPrimaryUser?.enabled).isTrue() setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) assertThat(enabledStateForPrimaryUser?.enabled).isTrue() } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsDisabledByUserAndDevicePolicy() = Loading Loading @@ -189,5 +215,13 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { val PRIMARY_USER = UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN) val SECONDARY_USER = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0) val WORK_PROFILE = UserInfo( 10, "work", /* iconPath= */ "", /* flags= */ 0, USER_TYPE_PROFILE_MANAGED, ) } } packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +96 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.systemui.communal.domain.interactor import android.app.admin.DevicePolicyManager import android.app.admin.devicePolicyManager import android.app.smartspace.SmartspaceTarget import android.appwidget.AppWidgetProviderInfo import android.content.Intent Loading @@ -32,6 +34,7 @@ import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository Loading Loading @@ -71,6 +74,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat Loading Loading @@ -929,7 +933,6 @@ class CommunalInteractorTest : SysuiTestCase() { keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) Loading @@ -937,6 +940,7 @@ class CommunalInteractorTest : SysuiTestCase() { userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() // Widgets available. Loading @@ -955,7 +959,6 @@ class CommunalInteractorTest : SysuiTestCase() { AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, mainUser.id ) runCurrent() // Only the keyguard widget is enabled. assertThat(widgetContent).hasSize(3) Loading @@ -974,7 +977,6 @@ class CommunalInteractorTest : SysuiTestCase() { keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) Loading @@ -982,6 +984,7 @@ class CommunalInteractorTest : SysuiTestCase() { userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() // Widgets available. Loading @@ -1001,7 +1004,6 @@ class CommunalInteractorTest : SysuiTestCase() { AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, mainUser.id ) runCurrent() // All widgets are enabled. assertThat(widgetContent).hasSize(3) Loading @@ -1011,6 +1013,79 @@ class CommunalInteractorTest : SysuiTestCase() { } } @Test fun filterWidgets_whenDisallowedByDevicePolicyForWorkProfile() = testScope.runTest { // Keyguard showing, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() val widgetContent by collectLastValue(underTest.widgetContent) // Given three widgets, and one of them is associated with work profile. val widget1 = createWidgetForUser(1, USER_INFO_WORK.id) val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id) val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) setKeyguardFeaturesDisabled( USER_INFO_WORK, DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL ) // Widget under work profile is filtered out and the remaining two link to main user id. assertThat(widgetContent).hasSize(2) widgetContent!!.forEach { model -> assertThat(model.providerInfo.profile?.identifier).isEqualTo(MAIN_USER_INFO.id) } } @Test fun filterWidgets_whenAllowedByDevicePolicyForWorkProfile() = testScope.runTest { // Keyguard showing, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() val widgetContent by collectLastValue(underTest.widgetContent) // Given three widgets, and one of them is associated with work profile. val widget1 = createWidgetForUser(1, USER_INFO_WORK.id) val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id) val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) setKeyguardFeaturesDisabled( USER_INFO_WORK, DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE ) // Widget under work profile is available. assertThat(widgetContent).hasSize(3) assertThat(widgetContent!![0].providerInfo.profile?.identifier) .isEqualTo(USER_INFO_WORK.id) } private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget { val timer = mock(SmartspaceTarget::class.java) whenever(timer.smartspaceTargetId).thenReturn(id) Loading @@ -1020,6 +1095,15 @@ class CommunalInteractorTest : SysuiTestCase() { return timer } private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) .thenReturn(disabledFlags) kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly( context, Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), ) } private fun createWidgetForUser(appWidgetId: Int, userId: Int): CommunalWidgetContentModel = mock<CommunalWidgetContentModel> { whenever(this.appWidgetId).thenReturn(appWidgetId) Loading @@ -1044,6 +1128,13 @@ class CommunalInteractorTest : SysuiTestCase() { private companion object { val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN) val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE) val USER_INFO_WORK = UserInfo( 10, "work", /* iconPath= */ "", /* flags= */ 0, UserManager.USER_TYPE_PROFILE_MANAGED, ) } } packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt +13 −10 Original line number Diff line number Diff line Loading @@ -57,6 +57,9 @@ interface CommunalSettingsRepository { * Settings. */ fun getWidgetCategories(user: UserInfo): Flow<CommunalWidgetCategories> /** Keyguard widgets enabled state by Device Policy Manager for the specified user. */ fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> } @SysUISingleton Loading Loading @@ -115,6 +118,16 @@ constructor( } .flowOn(bgDispatcher) override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = broadcastDispatcher .broadcastFlow( filter = IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), user = user.userHandle ) .emitOnStart() .map { devicePolicyManager.areKeyguardWidgetsAllowed(user.id) } private fun getEnabledByUser(user: UserInfo): Flow<Boolean> = secureSettings .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.GLANCEABLE_HUB_ENABLED)) Loading @@ -128,16 +141,6 @@ constructor( ) == 1 } private fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = broadcastDispatcher .broadcastFlow( filter = IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), user = user.userHandle ) .emitOnStart() .map { devicePolicyManager.areKeyguardWidgetsAllowed(user.id) } companion object { const val GLANCEABLE_HUB_CONTENT_SETTING = "glanceable_hub_content_setting" private const val ENABLED_SETTING_DEFAULT = 1 Loading packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +22 −2 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ constructor( mediaRepository: CommunalMediaRepository, smartspaceRepository: SmartspaceRepository, keyguardInteractor: KeyguardInteractor, communalSettingsInteractor: CommunalSettingsInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, private val appWidgetHost: CommunalAppWidgetHost, private val editWidgetsActivityStarter: EditWidgetsActivityStarter, private val userTracker: UserTracker, Loading Loading @@ -358,7 +358,14 @@ constructor( /** A list of widget content to be displayed in the communal hub. */ val widgetContent: Flow<List<WidgetContent>> = combine( widgetRepository.communalWidgets.map { filterWidgetsByExistingUsers(it) }, widgetRepository.communalWidgets .map { filterWidgetsByExistingUsers(it) } .combine(communalSettingsInteractor.allowedByDevicePolicyForWorkProfile) { // exclude widgets under work profile if not allowed by device policy widgets, allowedForWorkProfile -> filterWidgetsAllowedByDevicePolicy(widgets, allowedForWorkProfile) }, communalSettingsInteractor.communalWidgetCategories, updateOnWorkProfileBroadcastReceived, ) { widgets, allowedCategories, _ -> Loading @@ -380,6 +387,19 @@ constructor( } } /** Filter widgets based on whether their associated profile is allowed by device policy. */ private fun filterWidgetsAllowedByDevicePolicy( list: List<CommunalWidgetContentModel>, allowedByDevicePolicyForWorkProfile: Boolean ): List<CommunalWidgetContentModel> = if (allowedByDevicePolicyForWorkProfile) { list } else { // Get associated work profile for the currently selected user. val workProfile = userTracker.userProfiles.find { it.isManagedProfile } list.filter { it.providerInfo.profile.identifier != workProfile?.id } } /** A flow of available smartspace targets. Currently only showing timers. */ private val smartspaceTargets: Flow<List<SmartspaceTarget>> = if (!smartspaceRepository.isSmartspaceRemoteViewsEnabled) { Loading Loading
core/java/android/app/admin/DevicePolicyManager.java +16 −4 Original line number Diff line number Diff line Loading @@ -7056,9 +7056,10 @@ public class DevicePolicyManager { public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; /** * Disable all keyguard widgets. Has no effect starting from * {@link android.os.Build.VERSION_CODES#LOLLIPOP} since keyguard widget is only supported * on Android versions lower than 5.0. * Disable all keyguard widgets. Has no effect between {@link * android.os.Build.VERSION_CODES#LOLLIPOP} and {@link * android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} (both inclusive), since keyguard widget is * only supported on Android versions lower than 5.0 and versions higher than 14. */ public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1 << 0; Loading Loading @@ -7157,7 +7158,8 @@ public class DevicePolicyManager { public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY = DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL; | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL | DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL; /** * Keyguard features that when set on a normal or organization-owned managed profile, have Loading Loading @@ -8978,6 +8980,10 @@ public class DevicePolicyManager { * by applications in the managed profile. * </ul> * <p> * From version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, the profile owner of a * managed profile can also set {@link #KEYGUARD_DISABLE_WIDGETS_ALL} which disables keyguard * widgets for the managed profile. * <p> * From version {@link android.os.Build.VERSION_CODES#R} the profile owner of an * organization-owned managed profile can set: * <ul> Loading @@ -8986,6 +8992,12 @@ public class DevicePolicyManager { * <li>{@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} which affects the parent user when called * on the parent profile. * </ul> * Starting from version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} the profile * owner of an organization-owned managed profile can set: * <ul> * <li>{@link #KEYGUARD_DISABLE_WIDGETS_ALL} which affects the parent user when called on the * parent profile. * </ul> * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}, * {@link #KEYGUARD_DISABLE_FACE}, {@link #KEYGUARD_DISABLE_IRIS}, * {@link #KEYGUARD_DISABLE_SECURE_CAMERA} and {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt +34 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.app.admin.devicePolicyManager import android.appwidget.AppWidgetProviderInfo import android.content.Intent import android.content.pm.UserInfo import android.os.UserManager.USER_TYPE_PROFILE_MANAGED import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.provider.Settings Loading Loading @@ -59,6 +60,7 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_FEATURES_NONE) setKeyguardFeaturesDisabled(SECONDARY_USER, KEYGUARD_DISABLE_FEATURES_NONE) setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_FEATURES_NONE) underTest = kosmos.communalSettingsRepository } Loading Loading @@ -131,6 +133,30 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_DEVICE_POLICY) } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() = testScope.runTest { val widgetsAllowedForWorkProfile by collectLastValue(underTest.getAllowedByDevicePolicy(WORK_PROFILE)) assertThat(widgetsAllowedForWorkProfile).isTrue() setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) assertThat(widgetsAllowedForWorkProfile).isFalse() } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() = testScope.runTest { val enabledStateForPrimaryUser by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledStateForPrimaryUser?.enabled).isTrue() setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) assertThat(enabledStateForPrimaryUser?.enabled).isTrue() } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsDisabledByUserAndDevicePolicy() = Loading Loading @@ -189,5 +215,13 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { val PRIMARY_USER = UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN) val SECONDARY_USER = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0) val WORK_PROFILE = UserInfo( 10, "work", /* iconPath= */ "", /* flags= */ 0, USER_TYPE_PROFILE_MANAGED, ) } }
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +96 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.systemui.communal.domain.interactor import android.app.admin.DevicePolicyManager import android.app.admin.devicePolicyManager import android.app.smartspace.SmartspaceTarget import android.appwidget.AppWidgetProviderInfo import android.content.Intent Loading @@ -32,6 +34,7 @@ import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository Loading Loading @@ -71,6 +74,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat Loading Loading @@ -929,7 +933,6 @@ class CommunalInteractorTest : SysuiTestCase() { keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) Loading @@ -937,6 +940,7 @@ class CommunalInteractorTest : SysuiTestCase() { userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() // Widgets available. Loading @@ -955,7 +959,6 @@ class CommunalInteractorTest : SysuiTestCase() { AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, mainUser.id ) runCurrent() // Only the keyguard widget is enabled. assertThat(widgetContent).hasSize(3) Loading @@ -974,7 +977,6 @@ class CommunalInteractorTest : SysuiTestCase() { keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) Loading @@ -982,6 +984,7 @@ class CommunalInteractorTest : SysuiTestCase() { userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() // Widgets available. Loading @@ -1001,7 +1004,6 @@ class CommunalInteractorTest : SysuiTestCase() { AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, mainUser.id ) runCurrent() // All widgets are enabled. assertThat(widgetContent).hasSize(3) Loading @@ -1011,6 +1013,79 @@ class CommunalInteractorTest : SysuiTestCase() { } } @Test fun filterWidgets_whenDisallowedByDevicePolicyForWorkProfile() = testScope.runTest { // Keyguard showing, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() val widgetContent by collectLastValue(underTest.widgetContent) // Given three widgets, and one of them is associated with work profile. val widget1 = createWidgetForUser(1, USER_INFO_WORK.id) val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id) val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) setKeyguardFeaturesDisabled( USER_INFO_WORK, DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL ) // Widget under work profile is filtered out and the remaining two link to main user id. assertThat(widgetContent).hasSize(2) widgetContent!!.forEach { model -> assertThat(model.providerInfo.profile?.identifier).isEqualTo(MAIN_USER_INFO.id) } } @Test fun filterWidgets_whenAllowedByDevicePolicyForWorkProfile() = testScope.runTest { // Keyguard showing, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) userRepository.setSelectedUserInfo(MAIN_USER_INFO) runCurrent() val widgetContent by collectLastValue(underTest.widgetContent) // Given three widgets, and one of them is associated with work profile. val widget1 = createWidgetForUser(1, USER_INFO_WORK.id) val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id) val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) setKeyguardFeaturesDisabled( USER_INFO_WORK, DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE ) // Widget under work profile is available. assertThat(widgetContent).hasSize(3) assertThat(widgetContent!![0].providerInfo.profile?.identifier) .isEqualTo(USER_INFO_WORK.id) } private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget { val timer = mock(SmartspaceTarget::class.java) whenever(timer.smartspaceTargetId).thenReturn(id) Loading @@ -1020,6 +1095,15 @@ class CommunalInteractorTest : SysuiTestCase() { return timer } private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) .thenReturn(disabledFlags) kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly( context, Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), ) } private fun createWidgetForUser(appWidgetId: Int, userId: Int): CommunalWidgetContentModel = mock<CommunalWidgetContentModel> { whenever(this.appWidgetId).thenReturn(appWidgetId) Loading @@ -1044,6 +1128,13 @@ class CommunalInteractorTest : SysuiTestCase() { private companion object { val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN) val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE) val USER_INFO_WORK = UserInfo( 10, "work", /* iconPath= */ "", /* flags= */ 0, UserManager.USER_TYPE_PROFILE_MANAGED, ) } }
packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt +13 −10 Original line number Diff line number Diff line Loading @@ -57,6 +57,9 @@ interface CommunalSettingsRepository { * Settings. */ fun getWidgetCategories(user: UserInfo): Flow<CommunalWidgetCategories> /** Keyguard widgets enabled state by Device Policy Manager for the specified user. */ fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> } @SysUISingleton Loading Loading @@ -115,6 +118,16 @@ constructor( } .flowOn(bgDispatcher) override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = broadcastDispatcher .broadcastFlow( filter = IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), user = user.userHandle ) .emitOnStart() .map { devicePolicyManager.areKeyguardWidgetsAllowed(user.id) } private fun getEnabledByUser(user: UserInfo): Flow<Boolean> = secureSettings .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.GLANCEABLE_HUB_ENABLED)) Loading @@ -128,16 +141,6 @@ constructor( ) == 1 } private fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = broadcastDispatcher .broadcastFlow( filter = IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), user = user.userHandle ) .emitOnStart() .map { devicePolicyManager.areKeyguardWidgetsAllowed(user.id) } companion object { const val GLANCEABLE_HUB_CONTENT_SETTING = "glanceable_hub_content_setting" private const val ENABLED_SETTING_DEFAULT = 1 Loading
packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +22 −2 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ constructor( mediaRepository: CommunalMediaRepository, smartspaceRepository: SmartspaceRepository, keyguardInteractor: KeyguardInteractor, communalSettingsInteractor: CommunalSettingsInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, private val appWidgetHost: CommunalAppWidgetHost, private val editWidgetsActivityStarter: EditWidgetsActivityStarter, private val userTracker: UserTracker, Loading Loading @@ -358,7 +358,14 @@ constructor( /** A list of widget content to be displayed in the communal hub. */ val widgetContent: Flow<List<WidgetContent>> = combine( widgetRepository.communalWidgets.map { filterWidgetsByExistingUsers(it) }, widgetRepository.communalWidgets .map { filterWidgetsByExistingUsers(it) } .combine(communalSettingsInteractor.allowedByDevicePolicyForWorkProfile) { // exclude widgets under work profile if not allowed by device policy widgets, allowedForWorkProfile -> filterWidgetsAllowedByDevicePolicy(widgets, allowedForWorkProfile) }, communalSettingsInteractor.communalWidgetCategories, updateOnWorkProfileBroadcastReceived, ) { widgets, allowedCategories, _ -> Loading @@ -380,6 +387,19 @@ constructor( } } /** Filter widgets based on whether their associated profile is allowed by device policy. */ private fun filterWidgetsAllowedByDevicePolicy( list: List<CommunalWidgetContentModel>, allowedByDevicePolicyForWorkProfile: Boolean ): List<CommunalWidgetContentModel> = if (allowedByDevicePolicyForWorkProfile) { list } else { // Get associated work profile for the currently selected user. val workProfile = userTracker.userProfiles.find { it.isManagedProfile } list.filter { it.providerInfo.profile.identifier != workProfile?.id } } /** A flow of available smartspace targets. Currently only showing timers. */ private val smartspaceTargets: Flow<List<SmartspaceTarget>> = if (!smartspaceRepository.isSmartspaceRemoteViewsEnabled) { Loading