Merge "[Device Controls] Handle taps correctly when the tile is in an inactive state." into sc-dev
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 2ab5a3a..6d3190f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -96,21 +96,32 @@
}
override fun handleClick(view: View?) {
- if (state.state == Tile.STATE_ACTIVE) {
- mUiHandler.post {
- val i = Intent().apply {
- component = ComponentName(mContext, ControlsActivity::class.java)
- addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
- putExtra(ControlsUiController.EXTRA_ANIMATE, true)
- }
- if (keyguardStateController.isUnlocked()) {
- val animationController = view?.let {
- ActivityLaunchAnimator.Controller.fromView(it)
- }
- mActivityStarter.startActivity(i, true /* dismissShade */, animationController)
- } else {
+ if (state.state == Tile.STATE_UNAVAILABLE) {
+ return
+ }
+
+ val intent = Intent().apply {
+ component = ComponentName(mContext, ControlsActivity::class.java)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+ putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+ }
+ val animationController = view?.let {
+ ActivityLaunchAnimator.Controller.fromView(it)
+ }
+
+ mUiHandler.post {
+ if (keyguardStateController.isUnlocked) {
+ mActivityStarter.startActivity(
+ intent, true /* dismissShade */, animationController)
+ } else {
+ if (state.state == Tile.STATE_ACTIVE) {
mHost.collapsePanels()
- mContext.startActivity(i)
+ // With an active tile, don't use ActivityStarter so that the activity is
+ // started without prompting keyguard unlock.
+ mContext.startActivity(intent)
+ } else {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ intent, 0 /* delay */, animationController)
}
}
}
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 580cd35..6d1bbd9 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
@@ -17,9 +17,9 @@
package com.android.systemui.qs.tiles
import android.content.ComponentName
-import android.os.Handler
import android.content.Context
import android.content.Intent
+import android.os.Handler
import android.provider.Settings
import android.service.quicksettings.Tile
import android.testing.AndroidTestingRunner
@@ -52,14 +52,17 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.never
+import org.mockito.Mockito.nullable
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
import java.util.Optional
@@ -95,6 +98,8 @@
@Captor
private lateinit var listingCallbackCaptor:
ArgumentCaptor<ControlsListingController.ControlsListingCallback>
+ @Captor
+ private lateinit var intentCaptor: ArgumentCaptor<Intent>
private lateinit var testableLooper: TestableLooper
private lateinit var tile: DeviceControlsTile
@@ -259,21 +264,21 @@
}
@Test
- fun testNoDialogWhenUnavailable() {
+ fun handleClick_unavailable_noActivityStarted() {
tile.click(null /* view */)
testableLooper.processAllMessages()
- verify(activityStarter, never()).startActivity(any(), anyBoolean(),
- any<ActivityLaunchAnimator.Controller>())
+ verifyZeroInteractions(activityStarter)
}
@Test
- fun testDialogShowWhenAvailable() {
+ fun handleClick_availableAndLocked_activityStarted() {
verify(controlsListingController).observe(
any(LifecycleOwner::class.java),
capture(listingCallbackCaptor)
)
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
+ `when`(keyguardStateController.isUnlocked).thenReturn(false)
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -281,18 +286,44 @@
tile.click(null /* view */)
testableLooper.processAllMessages()
- verify(activityStarter).startActivity(any(), eq(true) /* dismissShade */,
- eq(null) as ActivityLaunchAnimator.Controller?)
+ // The activity should be started right away and not require a keyguard dismiss.
+ verifyZeroInteractions(activityStarter)
+ verify(spiedContext).startActivity(intentCaptor.capture())
+ assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
}
@Test
- fun testNoDialogWhenInactive() {
+ fun handleClick_availableAndUnlocked_activityStarted() {
+ verify(controlsListingController).observe(
+ any(LifecycleOwner::class.java),
+ capture(listingCallbackCaptor)
+ )
+ `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
+ `when`(keyguardStateController.isUnlocked).thenReturn(true)
+
+ listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
+ testableLooper.processAllMessages()
+
+ tile.click(null /* view */)
+ testableLooper.processAllMessages()
+
+ verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
+ verify(activityStarter).startActivity(
+ intentCaptor.capture(),
+ eq(true) /* dismissShade */,
+ nullable(ActivityLaunchAnimator.Controller::class.java))
+ assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
+ }
+
+ @Test
+ fun handleClick_availableAfterUnlockAndIsLocked_keyguardDismissRequired() {
verify(controlsListingController).observe(
any(LifecycleOwner::class.java),
capture(listingCallbackCaptor)
)
`when`(controlsComponent.getVisibility())
.thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
+ `when`(keyguardStateController.isUnlocked).thenReturn(false)
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -300,8 +331,39 @@
tile.click(null /* view */)
testableLooper.processAllMessages()
- verify(activityStarter, never()).startActivity(any(), anyBoolean(),
- any<ActivityLaunchAnimator.Controller>())
+ verify(activityStarter, never()).startActivity(
+ any(),
+ anyBoolean() /* dismissShade */,
+ nullable(ActivityLaunchAnimator.Controller::class.java))
+ verify(activityStarter).postStartActivityDismissingKeyguard(
+ intentCaptor.capture(),
+ anyInt(),
+ nullable(ActivityLaunchAnimator.Controller::class.java))
+ assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
+ }
+
+ @Test
+ fun handleClick_availableAfterUnlockAndIsUnlocked_activityStarted() {
+ verify(controlsListingController).observe(
+ any(LifecycleOwner::class.java),
+ capture(listingCallbackCaptor)
+ )
+ `when`(controlsComponent.getVisibility())
+ .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
+ `when`(keyguardStateController.isUnlocked).thenReturn(true)
+
+ listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
+ testableLooper.processAllMessages()
+
+ tile.click(null /* view */)
+ testableLooper.processAllMessages()
+
+ verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
+ verify(activityStarter).startActivity(
+ intentCaptor.capture(),
+ eq(true) /* dismissShade */,
+ nullable(ActivityLaunchAnimator.Controller::class.java))
+ assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
}
private fun createTile(): DeviceControlsTile {
@@ -319,3 +381,5 @@
)
}
}
+
+private const val CONTROLS_ACTIVITY_CLASS_NAME = "com.android.systemui.controls.ui.ControlsActivity"