Loading packages/SystemUI/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2717,6 +2717,9 @@ <!-- Controls dialog confirmation [CHAR LIMIT=30] --> <string name="controls_dialog_confirmation">Controls updated</string> <!-- Controls tile secondary label when device is locked and user does not want access to controls from lockscreen [CHAR LIMIT=20] --> <string name="controls_tile_locked">Device locked</string> <!-- Controls PIN entry dialog, switch to alphanumeric keyboard [CHAR LIMIT=100] --> <string name="controls_pin_use_alphanumeric">PIN contains letters or symbols</string> <!-- Controls PIN entry dialog, title [CHAR LIMIT=30] --> Loading packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt +1 −1 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ class ControlsComponent @Inject constructor( } /** * @return true if controls are feature-enabled and have available services to serve controls * @return true if controls are feature-enabled and the user has the setting enabled */ fun isEnabled() = featureEnabled && lazyControlsController.get().available Loading packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +13 −7 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import com.android.internal.logging.MetricsLogger import com.android.systemui.R import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.ui.ControlsDialog import com.android.systemui.dagger.qualifiers.Background Loading Loading @@ -92,7 +92,7 @@ class DeviceControlsTile @Inject constructor( override fun isAvailable(): Boolean { return featureFlags.isKeyguardLayoutEnabled && controlsLockscreen && controlsComponent.getVisibility() != UNAVAILABLE controlsComponent.getControlsController().isPresent } override fun newTileState(): QSTile.State { Loading @@ -119,7 +119,7 @@ class DeviceControlsTile @Inject constructor( } override fun handleClick() { if (state.state != Tile.STATE_UNAVAILABLE) { if (state.state == Tile.STATE_ACTIVE) { mUiHandler.post { createDialog() controlsDialog?.show(controlsComponent.getControlsUiController().get()) Loading @@ -129,15 +129,21 @@ class DeviceControlsTile @Inject constructor( override fun handleUpdateState(state: QSTile.State, arg: Any?) { state.label = tileLabel state.secondaryLabel = "" state.stateDescription = "" state.contentDescription = state.label state.icon = icon if (hasControlsApps.get()) { state.state = Tile.STATE_ACTIVE if (controlsComponent.isEnabled() && hasControlsApps.get()) { if (controlsDialog == null) { mUiHandler.post(this::createDialog) } if (controlsComponent.getVisibility() == AVAILABLE) { state.state = Tile.STATE_ACTIVE state.secondaryLabel = "" } else { state.state = Tile.STATE_INACTIVE state.secondaryLabel = mContext.getText(R.string.controls_tile_locked) } state.stateDescription = state.secondaryLabel } else { state.state = Tile.STATE_UNAVAILABLE dismissDialog() Loading packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +93 −38 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController Loading @@ -37,9 +36,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.logging.QSLogger import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.settings.FakeSettings Loading @@ -49,7 +46,6 @@ import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock Loading @@ -57,6 +53,7 @@ import org.mockito.Mockito.`when` import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.Optional @SmallTest @RunWith(AndroidTestingRunner::class) Loading @@ -73,6 +70,7 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var activityStarter: ActivityStarter @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var controlsComponent: ControlsComponent @Mock private lateinit var controlsUiController: ControlsUiController Loading @@ -96,54 +94,64 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var testableLooper: TestableLooper private lateinit var tile: DeviceControlsTile @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var userTracker: UserTracker @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var secureSettings: SecureSettings private var featureEnabled = true @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) secureSettings = FakeSettings() `when`(qsHost.context).thenReturn(mContext) `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) `when`(controlsController.available).thenReturn(true) `when`(controlsComponent.isEnabled()).thenReturn(true) secureSettings.putInt(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 1) controlsComponent = ControlsComponent( true, mContext, { controlsController }, { controlsUiController }, { controlsListingController }, lockPatternUtils, keyguardStateController, userTracker, secureSettings ) setupControlsComponent() globalSettings = FakeSettings() globalSettings.putInt(DeviceControlsTile.SETTINGS_FLAG, 1) `when`(featureFlags.isKeyguardLayoutEnabled).thenReturn(true) `when`(userTracker.userHandle.identifier).thenReturn(0) tile = createTile() } private fun setupControlsComponent() { `when`(controlsComponent.getControlsController()).thenAnswer { if (featureEnabled) { Optional.of(controlsController) } else { Optional.empty() } } `when`(controlsComponent.getControlsListingController()).thenAnswer { if (featureEnabled) { Optional.of(controlsListingController) } else { Optional.empty() } } `when`(controlsComponent.getControlsUiController()).thenAnswer { if (featureEnabled) { Optional.of(controlsUiController) } else { Optional.empty() } } } @Test fun testAvailable() { `when`(controlsController.available).thenReturn(true) assertThat(tile.isAvailable).isTrue() } @Test fun testNotAvailableFeature() { `when`(controlsController.available).thenReturn(true) `when`(featureFlags.isKeyguardLayoutEnabled).thenReturn(false) assertThat(tile.isAvailable).isFalse() Loading @@ -151,24 +159,22 @@ class DeviceControlsTileTest : SysuiTestCase() { @Test fun testNotAvailableControls() { controlsComponent = ControlsComponent( false, mContext, { controlsController }, { controlsUiController }, { controlsListingController }, lockPatternUtils, keyguardStateController, userTracker, secureSettings ) featureEnabled = false tile = createTile() assertThat(tile.isAvailable).isFalse() } @Test fun testNotAvailableFlag() { fun testAvailableControlsSettingOff() { `when`(controlsController.available).thenReturn(false) tile = createTile() assertThat(tile.isAvailable).isTrue() } @Test fun testNotAvailableControlsLockscreenFlag() { globalSettings.putInt(DeviceControlsTile.SETTINGS_FLAG, 0) tile = createTile() Loading Loading @@ -206,12 +212,27 @@ class DeviceControlsTileTest : SysuiTestCase() { assertThat(tile.state.state).isEqualTo(Tile.STATE_UNAVAILABLE) } @Test fun testStateUnavailableIfNotEnabled() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.isEnabled()).thenReturn(false) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() assertThat(tile.state.state).isEqualTo(Tile.STATE_UNAVAILABLE) } @Test fun testStateAvailableIfListings() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() Loading @@ -219,6 +240,21 @@ class DeviceControlsTileTest : SysuiTestCase() { assertThat(tile.state.state).isEqualTo(Tile.STATE_ACTIVE) } @Test fun testStateInactiveIfLocked() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()) .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE) } @Test fun testMoveBetweenStates() { verify(controlsListingController).observe( Loading Loading @@ -249,6 +285,7 @@ class DeviceControlsTileTest : SysuiTestCase() { any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() Loading @@ -259,6 +296,24 @@ class DeviceControlsTileTest : SysuiTestCase() { verify(controlsDialog).show(controlsUiController) } @Test fun testNoDialogWhenInactive() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()) .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() tile.click() testableLooper.processAllMessages() verify(controlsDialog, never()).show(any(ControlsUiController::class.java)) } @Test fun testDialogDismissedOnDestroy() { verify(controlsListingController).observe( Loading Loading
packages/SystemUI/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2717,6 +2717,9 @@ <!-- Controls dialog confirmation [CHAR LIMIT=30] --> <string name="controls_dialog_confirmation">Controls updated</string> <!-- Controls tile secondary label when device is locked and user does not want access to controls from lockscreen [CHAR LIMIT=20] --> <string name="controls_tile_locked">Device locked</string> <!-- Controls PIN entry dialog, switch to alphanumeric keyboard [CHAR LIMIT=100] --> <string name="controls_pin_use_alphanumeric">PIN contains letters or symbols</string> <!-- Controls PIN entry dialog, title [CHAR LIMIT=30] --> Loading
packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt +1 −1 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ class ControlsComponent @Inject constructor( } /** * @return true if controls are feature-enabled and have available services to serve controls * @return true if controls are feature-enabled and the user has the setting enabled */ fun isEnabled() = featureEnabled && lazyControlsController.get().available Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +13 −7 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import com.android.internal.logging.MetricsLogger import com.android.systemui.R import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.ui.ControlsDialog import com.android.systemui.dagger.qualifiers.Background Loading Loading @@ -92,7 +92,7 @@ class DeviceControlsTile @Inject constructor( override fun isAvailable(): Boolean { return featureFlags.isKeyguardLayoutEnabled && controlsLockscreen && controlsComponent.getVisibility() != UNAVAILABLE controlsComponent.getControlsController().isPresent } override fun newTileState(): QSTile.State { Loading @@ -119,7 +119,7 @@ class DeviceControlsTile @Inject constructor( } override fun handleClick() { if (state.state != Tile.STATE_UNAVAILABLE) { if (state.state == Tile.STATE_ACTIVE) { mUiHandler.post { createDialog() controlsDialog?.show(controlsComponent.getControlsUiController().get()) Loading @@ -129,15 +129,21 @@ class DeviceControlsTile @Inject constructor( override fun handleUpdateState(state: QSTile.State, arg: Any?) { state.label = tileLabel state.secondaryLabel = "" state.stateDescription = "" state.contentDescription = state.label state.icon = icon if (hasControlsApps.get()) { state.state = Tile.STATE_ACTIVE if (controlsComponent.isEnabled() && hasControlsApps.get()) { if (controlsDialog == null) { mUiHandler.post(this::createDialog) } if (controlsComponent.getVisibility() == AVAILABLE) { state.state = Tile.STATE_ACTIVE state.secondaryLabel = "" } else { state.state = Tile.STATE_INACTIVE state.secondaryLabel = mContext.getText(R.string.controls_tile_locked) } state.stateDescription = state.secondaryLabel } else { state.state = Tile.STATE_UNAVAILABLE dismissDialog() Loading
packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +93 −38 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController Loading @@ -37,9 +36,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.logging.QSLogger import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.settings.FakeSettings Loading @@ -49,7 +46,6 @@ import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock Loading @@ -57,6 +53,7 @@ import org.mockito.Mockito.`when` import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.Optional @SmallTest @RunWith(AndroidTestingRunner::class) Loading @@ -73,6 +70,7 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var activityStarter: ActivityStarter @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var controlsComponent: ControlsComponent @Mock private lateinit var controlsUiController: ControlsUiController Loading @@ -96,54 +94,64 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var testableLooper: TestableLooper private lateinit var tile: DeviceControlsTile @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var userTracker: UserTracker @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var secureSettings: SecureSettings private var featureEnabled = true @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) secureSettings = FakeSettings() `when`(qsHost.context).thenReturn(mContext) `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) `when`(controlsController.available).thenReturn(true) `when`(controlsComponent.isEnabled()).thenReturn(true) secureSettings.putInt(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 1) controlsComponent = ControlsComponent( true, mContext, { controlsController }, { controlsUiController }, { controlsListingController }, lockPatternUtils, keyguardStateController, userTracker, secureSettings ) setupControlsComponent() globalSettings = FakeSettings() globalSettings.putInt(DeviceControlsTile.SETTINGS_FLAG, 1) `when`(featureFlags.isKeyguardLayoutEnabled).thenReturn(true) `when`(userTracker.userHandle.identifier).thenReturn(0) tile = createTile() } private fun setupControlsComponent() { `when`(controlsComponent.getControlsController()).thenAnswer { if (featureEnabled) { Optional.of(controlsController) } else { Optional.empty() } } `when`(controlsComponent.getControlsListingController()).thenAnswer { if (featureEnabled) { Optional.of(controlsListingController) } else { Optional.empty() } } `when`(controlsComponent.getControlsUiController()).thenAnswer { if (featureEnabled) { Optional.of(controlsUiController) } else { Optional.empty() } } } @Test fun testAvailable() { `when`(controlsController.available).thenReturn(true) assertThat(tile.isAvailable).isTrue() } @Test fun testNotAvailableFeature() { `when`(controlsController.available).thenReturn(true) `when`(featureFlags.isKeyguardLayoutEnabled).thenReturn(false) assertThat(tile.isAvailable).isFalse() Loading @@ -151,24 +159,22 @@ class DeviceControlsTileTest : SysuiTestCase() { @Test fun testNotAvailableControls() { controlsComponent = ControlsComponent( false, mContext, { controlsController }, { controlsUiController }, { controlsListingController }, lockPatternUtils, keyguardStateController, userTracker, secureSettings ) featureEnabled = false tile = createTile() assertThat(tile.isAvailable).isFalse() } @Test fun testNotAvailableFlag() { fun testAvailableControlsSettingOff() { `when`(controlsController.available).thenReturn(false) tile = createTile() assertThat(tile.isAvailable).isTrue() } @Test fun testNotAvailableControlsLockscreenFlag() { globalSettings.putInt(DeviceControlsTile.SETTINGS_FLAG, 0) tile = createTile() Loading Loading @@ -206,12 +212,27 @@ class DeviceControlsTileTest : SysuiTestCase() { assertThat(tile.state.state).isEqualTo(Tile.STATE_UNAVAILABLE) } @Test fun testStateUnavailableIfNotEnabled() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.isEnabled()).thenReturn(false) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() assertThat(tile.state.state).isEqualTo(Tile.STATE_UNAVAILABLE) } @Test fun testStateAvailableIfListings() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() Loading @@ -219,6 +240,21 @@ class DeviceControlsTileTest : SysuiTestCase() { assertThat(tile.state.state).isEqualTo(Tile.STATE_ACTIVE) } @Test fun testStateInactiveIfLocked() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()) .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE) } @Test fun testMoveBetweenStates() { verify(controlsListingController).observe( Loading Loading @@ -249,6 +285,7 @@ class DeviceControlsTileTest : SysuiTestCase() { any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() Loading @@ -259,6 +296,24 @@ class DeviceControlsTileTest : SysuiTestCase() { verify(controlsDialog).show(controlsUiController) } @Test fun testNoDialogWhenInactive() { verify(controlsListingController).observe( any(LifecycleOwner::class.java), capture(listingCallbackCaptor) ) `when`(controlsComponent.getVisibility()) .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) testableLooper.processAllMessages() tile.click() testableLooper.processAllMessages() verify(controlsDialog, never()).show(any(ControlsUiController::class.java)) } @Test fun testDialogDismissedOnDestroy() { verify(controlsListingController).observe( Loading