diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt index a4a9680674627..647beb95a3bcb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -61,7 +61,7 @@ class MediaTttCommandLineHelper @Inject constructor( @SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager - val routeInfo = MediaRoute2Info.Builder("id", args[0]) + val routeInfo = MediaRoute2Info.Builder(if (args.size >= 4) args[3] else "id", args[0]) .addFeature("feature") val useAppIcon = !(args.size >= 3 && args[2] == "useAppIcon=false") if (useAppIcon) { @@ -107,7 +107,7 @@ class MediaTttCommandLineHelper @Inject constructor( override fun help(pw: PrintWriter) { pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND " + - " useAppIcon=[true|false]") + " useAppIcon=[true|false] ") } } @@ -127,8 +127,10 @@ class MediaTttCommandLineHelper @Inject constructor( @SuppressLint("WrongConstant") // sysui is allowed to call STATUS_BAR_SERVICE val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager - val routeInfo = MediaRoute2Info.Builder("id", "Test Name") - .addFeature("feature") + val routeInfo = MediaRoute2Info.Builder( + if (args.size >= 3) args[2] else "id", + "Test Name" + ).addFeature("feature") val useAppIcon = !(args.size >= 2 && args[1] == "useAppIcon=false") if (useAppIcon) { routeInfo.setClientPackageName(TEST_PACKAGE_NAME) @@ -144,7 +146,7 @@ class MediaTttCommandLineHelper @Inject constructor( override fun help(pw: PrintWriter) { pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " + - " useAppIcon=[true|false]") + " useAppIcon=[true|false] ") } } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index 8bddffc842f52..691953aaba36d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -121,18 +121,32 @@ class MediaTttChipControllerReceiver @Inject constructor( uiEventLogger.logReceiverStateChange(chipState) if (chipState == ChipStateReceiver.FAR_FROM_SENDER) { - removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER.name) + removeView(routeInfo.id, removalReason = ChipStateReceiver.FAR_FROM_SENDER.name) return } if (appIcon == null) { - displayView(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName)) + displayView( + ChipReceiverInfo( + routeInfo, + appIconDrawableOverride = null, + appName, + id = routeInfo.id, + ) + ) return } appIcon.loadDrawableAsync( context, Icon.OnDrawableLoadedListener { drawable -> - displayView(ChipReceiverInfo(routeInfo, drawable, appName)) + displayView( + ChipReceiverInfo( + routeInfo, + drawable, + appName, + id = routeInfo.id, + ) + ) }, // Notify the listener on the main handler since the listener will update // the UI. @@ -234,4 +248,5 @@ data class ChipReceiverInfo( val appNameOverride: CharSequence?, override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER, override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER, + override val id: String, ) : TemporaryViewInfo() diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt index d1ea2d0c83bdb..bb7bc6fff99fa 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt @@ -108,7 +108,7 @@ constructor( } displayedState = null - chipbarCoordinator.removeView(removalReason) + chipbarCoordinator.removeView(routeInfo.id, removalReason) } else { displayedState = chipState chipbarCoordinator.displayView( @@ -162,6 +162,7 @@ constructor( windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER, wakeReason = MediaTttUtils.WAKE_REASON_SENDER, timeoutMs = chipStateSender.timeout, + id = routeInfo.id, ) } diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt index 82703364a1d57..a9d05d11dc009 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt @@ -93,6 +93,13 @@ abstract class TemporaryViewDisplayController> = ArrayDeque() + /** * Displays the view with the provided [newInfo]. * @@ -102,6 +109,12 @@ abstract class TemporaryViewDisplayController(R.id.app_icon) diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt index 8572478589fd2..09f0d4a10410d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt @@ -119,7 +119,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { ) ) - verify(logger).logViewAddition("Fake Window Title") + verify(logger).logViewAddition("id", "Fake Window Title") } @Test @@ -153,7 +153,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { underTest.displayView(getState()) assertThat(fakeWakeLock.isHeld).isTrue() - underTest.removeView("test reason") + underTest.removeView("id", "test reason") assertThat(fakeWakeLock.isHeld).isFalse() } @@ -262,6 +262,127 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name") } + @Test + fun multipleViewsWithDifferentIds_recentActiveViewIsDisplayed() { + underTest.displayView(ViewInfo("First name", id = "id1")) + + verify(windowManager).addView(any(), any()) + + reset(windowManager) + underTest.displayView(ViewInfo("Second name", id = "id2")) + underTest.removeView("id2", "test reason") + + verify(windowManager).removeView(any()) + + fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) + + assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1") + assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name") + + reset(windowManager) + fakeClock.advanceTime(TIMEOUT_MS + 1) + + verify(windowManager).removeView(any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + } + + @Test + fun multipleViewsWithDifferentIds_oldViewRemoved_recentViewIsDisplayed() { + underTest.displayView(ViewInfo("First name", id = "id1")) + + verify(windowManager).addView(any(), any()) + + reset(windowManager) + underTest.displayView(ViewInfo("Second name", id = "id2")) + underTest.removeView("id1", "test reason") + + verify(windowManager, never()).removeView(any()) + assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2") + assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name") + + fakeClock.advanceTime(TIMEOUT_MS + 1) + + verify(windowManager).removeView(any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + } + + @Test + fun multipleViewsWithDifferentIds_threeDifferentViews_recentActiveViewIsDisplayed() { + underTest.displayView(ViewInfo("First name", id = "id1")) + underTest.displayView(ViewInfo("Second name", id = "id2")) + underTest.displayView(ViewInfo("Third name", id = "id3")) + + verify(windowManager).addView(any(), any()) + + reset(windowManager) + underTest.removeView("id3", "test reason") + + verify(windowManager).removeView(any()) + + fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) + + assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2") + assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name") + + reset(windowManager) + underTest.removeView("id2", "test reason") + + verify(windowManager).removeView(any()) + + fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) + + assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1") + assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name") + + reset(windowManager) + fakeClock.advanceTime(TIMEOUT_MS + 1) + + verify(windowManager).removeView(any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + } + + @Test + fun multipleViewsWithDifferentIds_oneViewStateChanged_stackHasRecentState() { + underTest.displayView(ViewInfo("First name", id = "id1")) + underTest.displayView(ViewInfo("New name", id = "id1")) + + verify(windowManager).addView(any(), any()) + + reset(windowManager) + underTest.displayView(ViewInfo("Second name", id = "id2")) + underTest.removeView("id2", "test reason") + + verify(windowManager).removeView(any()) + + fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) + + assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1") + assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("New name") + assertThat(underTest.activeViews[0].second.name).isEqualTo("New name") + + reset(windowManager) + fakeClock.advanceTime(TIMEOUT_MS + 1) + + verify(windowManager).removeView(any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + } + + @Test + fun multipleViewsWithDifferentIds_viewsTimeouts_noViewLeftToDisplay() { + underTest.displayView(ViewInfo("First name", id = "id1")) + fakeClock.advanceTime(TIMEOUT_MS / 3) + underTest.displayView(ViewInfo("Second name", id = "id2")) + fakeClock.advanceTime(TIMEOUT_MS / 3) + underTest.displayView(ViewInfo("Third name", id = "id3")) + + reset(windowManager) + fakeClock.advanceTime(TIMEOUT_MS + 1) + + verify(windowManager).removeView(any()) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + } + @Test fun removeView_viewRemovedAndRemovalLogged() { // First, add the view @@ -269,15 +390,16 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { // Then, remove it val reason = "test reason" - underTest.removeView(reason) + val deviceId = "id" + underTest.removeView(deviceId, reason) verify(windowManager).removeView(any()) - verify(logger).logViewRemoval(reason) + verify(logger).logViewRemoval(deviceId, reason) } @Test fun removeView_noAdd_viewNotRemoved() { - underTest.removeView("reason") + underTest.removeView("id", "reason") verify(windowManager, never()).removeView(any()) } @@ -329,7 +451,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { val name: String, override val windowTitle: String = "Window Title", override val wakeReason: String = "WAKE_REASON", - override val timeoutMs: Int = 1 + override val timeoutMs: Int = 1, + override val id: String = "id", ) : TemporaryViewInfo() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt index d155050ce932d..116b8fe62b37a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt @@ -44,7 +44,7 @@ class TemporaryViewLoggerTest : SysuiTestCase() { @Test fun logViewAddition_bufferHasLog() { - logger.logViewAddition("Test Window Title") + logger.logViewAddition("test id", "Test Window Title") val stringWriter = StringWriter() buffer.dump(PrintWriter(stringWriter), tailLength = 0) @@ -57,7 +57,8 @@ class TemporaryViewLoggerTest : SysuiTestCase() { @Test fun logViewRemoval_bufferHasTagAndReason() { val reason = "test reason" - logger.logViewRemoval(reason) + val deviceId = "test id" + logger.logViewRemoval(deviceId, reason) val stringWriter = StringWriter() buffer.dump(PrintWriter(stringWriter), tailLength = 0) @@ -65,6 +66,7 @@ class TemporaryViewLoggerTest : SysuiTestCase() { assertThat(actualString).contains(TAG) assertThat(actualString).contains(reason) + assertThat(actualString).contains(deviceId) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt index 8e37aa2922402..47c84ab480935 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt @@ -377,6 +377,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { windowTitle = WINDOW_TITLE, wakeReason = WAKE_REASON, timeoutMs = TIMEOUT, + id = DEVICE_ID, ) } @@ -401,3 +402,4 @@ class ChipbarCoordinatorTest : SysuiTestCase() { private const val TIMEOUT = 10000 private const val WINDOW_TITLE = "Test Chipbar Window Title" private const val WAKE_REASON = "TEST_CHIPBAR_WAKE_REASON" +private const val DEVICE_ID = "id"