diff options
4 files changed, 110 insertions, 46 deletions
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 3b42600076ac..70e8b8946ae6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -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] --> diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt index 36937d622b5b..6b7a1ac8cb7e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt index 41445917a011..3b9f5dc8ea03 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt @@ -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 @@ -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 { @@ -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()) @@ -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() diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt index d3dbe2bf7d2b..ccd9548b269f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -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() @@ -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() @@ -207,11 +213,26 @@ class DeviceControlsTileTest : SysuiTestCase() { } @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() @@ -220,6 +241,21 @@ class DeviceControlsTileTest : SysuiTestCase() { } @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( any(LifecycleOwner::class.java), @@ -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() @@ -260,6 +297,24 @@ class DeviceControlsTileTest : SysuiTestCase() { } @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( any(LifecycleOwner::class.java), |