From b8bcb11dd7120eebb2fb4d69236c47e9b8ff61d4 Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Wed, 12 Jan 2022 22:23:16 +0000 Subject: [PATCH 1/2] [Media TTT] Add the #closeToReceiverToEndCast callback. Bug: 203800643 Bug: 203800347 Test: verify `adb shell cmd statusbar media-ttt-chip-add-sender Tablet MoveCloserToStartCast` triggers start cast chip Test: verify `adb shell cmd statusbar media-ttt-chip-add-sender Tablet MoveCloserToEndCast` triggers end cast chip Test: media.taptotransfer tests Change-Id: I1be9f1ab9785b47c4b2321e48a61e0985613e112 --- packages/SystemUI/res/values/strings.xml | 2 ++ .../shared/mediattt/IDeviceSenderCallback.aidl | 16 ++++++++++++++++ .../taptotransfer/MediaTttCommandLineHelper.kt | 9 +++++++++ .../taptotransfer/sender/ChipStateSender.kt | 16 ++++++++++++++++ .../sender/MediaTttSenderService.kt | 15 +++++++++++++++ .../MediaTttCommandLineHelperTest.kt | 18 ++++++++++++++++++ .../sender/MediaTttChipControllerSenderTest.kt | 16 ++++++++++++++++ .../sender/MediaTttSenderServiceTest.kt | 12 ++++++++++++ 8 files changed, 104 insertions(+) diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index aebddc9d98f36..a7cd33d92a9ab 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2189,6 +2189,8 @@ Undo Move closer to play on %1$s + + Move closer to %1$s to play here Playing on %1$s diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl index 484791df053eb..a68397deba2aa 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl @@ -43,4 +43,20 @@ interface IDeviceSenderCallback { */ oneway void closeToReceiverToStartCast( in MediaRoute2Info mediaInfo, in DeviceInfo otherDeviceInfo); + + /** + * Invoke to notify System UI that this device (the sender) is close to a receiver device, so + * the user can potentially *end* a cast on the receiver device if the user moves this device a + * bit closer. + * + * Important notes: + * - When this callback triggers, the device is close enough to inform the user that + * transferring is an option, but the device is *not* close enough to actually initiate a + * transfer yet. + * - This callback is for *ending* a cast. It should be used when media is currently being + * played on the receiver device and the media should be transferred to play locally + * instead. + */ + oneway void closeToReceiverToEndCast( + in MediaRoute2Info mediaInfo, in DeviceInfo otherDeviceInfo); } 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 460d38f45b4d9..6142188c7d410 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -33,6 +33,7 @@ import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerR import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService +import com.android.systemui.media.taptotransfer.sender.MoveCloserToEndCast import com.android.systemui.media.taptotransfer.sender.MoveCloserToStartCast import com.android.systemui.media.taptotransfer.sender.TransferInitiated import com.android.systemui.media.taptotransfer.sender.TransferSucceeded @@ -90,6 +91,11 @@ class MediaTttCommandLineHelper @Inject constructor( senderCallback.closeToReceiverToStartCast(mediaInfo, otherDeviceInfo) } } + MOVE_CLOSER_TO_END_CAST_COMMAND_NAME -> { + runOnService { senderCallback -> + senderCallback.closeToReceiverToEndCast(mediaInfo, otherDeviceInfo) + } + } // TODO(b/203800643): Migrate other commands to invoke the service instead of the // controller. @@ -119,6 +125,7 @@ class MediaTttCommandLineHelper @Inject constructor( else -> { pw.println("Chip type must be one of " + "$MOVE_CLOSER_TO_START_CAST_COMMAND_NAME, " + + "$MOVE_CLOSER_TO_END_CAST_COMMAND_NAME, " + "$TRANSFER_INITIATED_COMMAND_NAME, " + TRANSFER_SUCCEEDED_COMMAND_NAME ) @@ -226,6 +233,8 @@ const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver" @VisibleForTesting val MOVE_CLOSER_TO_START_CAST_COMMAND_NAME = MoveCloserToStartCast::class.simpleName!! @VisibleForTesting +val MOVE_CLOSER_TO_END_CAST_COMMAND_NAME = MoveCloserToEndCast::class.simpleName!! +@VisibleForTesting val TRANSFER_INITIATED_COMMAND_NAME = TransferInitiated::class.simpleName!! @VisibleForTesting val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!! diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt index dd434e7756fbe..55dffa7513064 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt @@ -55,6 +55,22 @@ class MoveCloserToStartCast( otherDeviceName ) +/** + * A state representing that the two devices are close but not close enough to *end* a cast that's + * currently occurring the receiver device. The chip will instruct the user to move closer in order + * to initiate the transfer from the receiver and back onto this device (the original sender). + */ +class MoveCloserToEndCast( + appIconDrawable: Drawable, + appIconContentDescription: String, + otherDeviceName: String, +) : ChipStateSender( + appIconDrawable, + appIconContentDescription, + R.string.media_move_closer_to_end_cast, + otherDeviceName +) + /** * A state representing that a transfer has been initiated (but not completed). * diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt index b56a69903ea4f..9142056842a01 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt @@ -43,6 +43,12 @@ class MediaTttSenderService @Inject constructor( ) { this@MediaTttSenderService.closeToReceiverToStartCast(mediaInfo, otherDeviceInfo) } + + override fun closeToReceiverToEndCast( + mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo + ) { + this@MediaTttSenderService.closeToReceiverToEndCast(mediaInfo, otherDeviceInfo) + } } // TODO(b/203800643): Use the app icon from the media info instead of a fake one. @@ -63,4 +69,13 @@ class MediaTttSenderService @Inject constructor( ) controller.displayChip(chipState) } + + private fun closeToReceiverToEndCast(mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo) { + val chipState = MoveCloserToEndCast( + appIconDrawable = fakeAppIconDrawable, + appIconContentDescription = mediaInfo.name.toString(), + otherDeviceName = otherDeviceInfo.name + ) + controller.displayChip(chipState) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt index 4839bdea1b701..e6673a5fcbea8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt @@ -126,6 +126,17 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) } + @Test + fun sender_moveCloserToEndCast_serviceCallbackCalled() { + commandRegistry.onShellCommand(pw, getMoveCloserToEndCastCommand()) + + assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue() + + val deviceInfoCaptor = argumentCaptor() + verify(mediaSenderService).closeToReceiverToEndCast(any(), capture(deviceInfoCaptor)) + assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) + } + @Test fun sender_transferInitiated_chipDisplayWithCorrectState() { commandRegistry.onShellCommand(pw, getTransferInitiatedCommand()) @@ -168,6 +179,13 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { MOVE_CLOSER_TO_START_CAST_COMMAND_NAME ) + private fun getMoveCloserToEndCastCommand(): Array = + arrayOf( + ADD_CHIP_COMMAND_SENDER_TAG, + DEVICE_NAME, + MOVE_CLOSER_TO_END_CAST_COMMAND_NAME + ) + private fun getTransferInitiatedCommand(): Array = arrayOf( ADD_CHIP_COMMAND_SENDER_TAG, diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index ecc4c46634b98..b58eecbfc85af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -77,6 +77,18 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) } + @Test + fun moveCloserToEndCast_appIcon_chipTextContainsDeviceName_noLoadingIcon_noUndo() { + controllerSender.displayChip(moveCloserToEndCast()) + + val chipView = getChipView() + assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC) + assertThat(chipView.getChipText()).contains(DEVICE_NAME) + assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + } + @Test fun transferInitiated_futureNotResolvedYet_appIcon_loadingIcon_noUndo() { val future: SettableFuture = SettableFuture.create() @@ -243,6 +255,10 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { private fun moveCloserToStartCast() = MoveCloserToStartCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME) + /** Helper method providing default parameters to not clutter up the tests. */ + private fun moveCloserToEndCast() = + MoveCloserToEndCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME) + /** Helper method providing default parameters to not clutter up the tests. */ private fun transferInitiated( future: Future = TEST_FUTURE diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt index 8f64698a5a6c1..e9ee0bdbd4c91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt @@ -45,4 +45,16 @@ class MediaTttSenderServiceTest : SysuiTestCase() { val chipState = chipStateCaptor.value!! assertThat(chipState.otherDeviceName).isEqualTo(name) } + + @Test + fun closeToReceiverToEndCast_controllerTriggeredWithMoveCloserToEndCastState() { + val name = "Fake name" + callback.closeToReceiverToEndCast(mediaInfo, DeviceInfo(name)) + + val chipStateCaptor = argumentCaptor() + verify(controller).displayChip(capture(chipStateCaptor)) + + val chipState = chipStateCaptor.value!! + assertThat(chipState.otherDeviceName).isEqualTo(name) + } } From a0cf54232c492b6483aebd7e6f68b95d16469fdc Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Thu, 13 Jan 2022 19:06:41 +0000 Subject: [PATCH 2/2] [Media TTT] Add error state. Screenshot of chip is in the linked bug. Fixes: 211493953 Test: manual: verify `adb shell cmd statusbar media-ttt-chip-add-sender Tablet TransferFailed` triggers failed chip Test: media.taptotransfer tests Change-Id: Ic4074394af1bf619581bad479eb6828ff04368d1 --- packages/SystemUI/res/drawable/ic_warning.xml | 19 +++++++ .../SystemUI/res/layout/media_ttt_chip.xml | 23 ++++++-- packages/SystemUI/res/values/dimens.xml | 5 +- packages/SystemUI/res/values/strings.xml | 2 + .../mediattt/IDeviceSenderCallback.aidl | 8 +++ .../MediaTttCommandLineHelper.kt | 11 +++- .../taptotransfer/sender/ChipStateSender.kt | 14 +++++ .../sender/MediaTttChipControllerSender.kt | 14 ++++- .../sender/MediaTttSenderService.kt | 15 +++++ .../MediaTttCommandLineHelperTest.kt | 15 +++++ .../MediaTttChipControllerSenderTest.kt | 57 +++++++++++++++---- .../sender/MediaTttSenderServiceTest.kt | 8 +++ 12 files changed, 170 insertions(+), 21 deletions(-) create mode 100644 packages/SystemUI/res/drawable/ic_warning.xml diff --git a/packages/SystemUI/res/drawable/ic_warning.xml b/packages/SystemUI/res/drawable/ic_warning.xml new file mode 100644 index 0000000000000..fbed779ec70f1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_warning.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/packages/SystemUI/res/layout/media_ttt_chip.xml b/packages/SystemUI/res/layout/media_ttt_chip.xml index 2d082dc7d5e2e..a5fdcd9e2671d 100644 --- a/packages/SystemUI/res/layout/media_ttt_chip.xml +++ b/packages/SystemUI/res/layout/media_ttt_chip.xml @@ -28,8 +28,8 @@ @@ -41,23 +41,34 @@ android:textColor="?android:attr/textColorPrimary" /> + + + + 16dp 16sp - 24dp - 20dp + 24dp + 20dp 8dp -8dp + 12dp 100dp diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a7cd33d92a9ab..3a9159094433b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2193,6 +2193,8 @@ Move closer to %1$s to play here Playing on %1$s + + Something went wrong Inactive, check app diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl index a68397deba2aa..9aae7d993185f 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl @@ -59,4 +59,12 @@ interface IDeviceSenderCallback { */ oneway void closeToReceiverToEndCast( in MediaRoute2Info mediaInfo, in DeviceInfo otherDeviceInfo); + + /** + * Invoke to notify System UI that the attempted transfer has failed. + * + * This callback will be used for both the transfer that should've *started* playing the media + * on the receiver and the transfer that should've *ended* the playing on the receiver. + */ + oneway void transferFailed(in MediaRoute2Info mediaInfo, in DeviceInfo otherDeviceInfo); } 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 6142188c7d410..613dfe03433d9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -35,6 +35,7 @@ import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSen import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService import com.android.systemui.media.taptotransfer.sender.MoveCloserToEndCast import com.android.systemui.media.taptotransfer.sender.MoveCloserToStartCast +import com.android.systemui.media.taptotransfer.sender.TransferFailed import com.android.systemui.media.taptotransfer.sender.TransferInitiated import com.android.systemui.media.taptotransfer.sender.TransferSucceeded import com.android.systemui.shared.mediattt.DeviceInfo @@ -122,12 +123,18 @@ class MediaTttCommandLineHelper @Inject constructor( ) ) } + TRANSFER_FAILED_COMMAND_NAME -> { + runOnService { senderCallback -> + senderCallback.transferFailed(mediaInfo, otherDeviceInfo) + } + } else -> { pw.println("Chip type must be one of " + "$MOVE_CLOSER_TO_START_CAST_COMMAND_NAME, " + "$MOVE_CLOSER_TO_END_CAST_COMMAND_NAME, " + "$TRANSFER_INITIATED_COMMAND_NAME, " + - TRANSFER_SUCCEEDED_COMMAND_NAME + "$TRANSFER_SUCCEEDED_COMMAND_NAME, " + + TRANSFER_FAILED_COMMAND_NAME ) } } @@ -238,6 +245,8 @@ val MOVE_CLOSER_TO_END_CAST_COMMAND_NAME = MoveCloserToEndCast::class.simpleName val TRANSFER_INITIATED_COMMAND_NAME = TransferInitiated::class.simpleName!! @VisibleForTesting val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!! +@VisibleForTesting +val TRANSFER_FAILED_COMMAND_NAME = TransferFailed::class.simpleName!! private const val FUTURE_WAIT_TIME = 2000L private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt index 55dffa7513064..e6f4ca54004fb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt @@ -107,3 +107,17 @@ class TransferSucceeded( R.string.media_transfer_playing, otherDeviceName ) + +/** A state representing that a transfer has failed. */ +class TransferFailed( + appIconDrawable: Drawable, + appIconContentDescription: String, + // TODO(b/211493953): The failed chip doesn't need [otherDeviceName] so we may want to remove + // [otherDeviceName] from the superclass [ChipStateSender]. + otherDeviceName: String, +) : ChipStateSender( + appIconDrawable, + appIconContentDescription, + R.string.media_transfer_failed, + otherDeviceName +) diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index 77d3d70fc98c5..6453b79757ad2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -73,6 +73,11 @@ class MediaTttChipControllerSender @Inject constructor( } undoView.setOnClickListener(undoClickListener) + // Failure + val showFailure = chipState is TransferFailed + currentChipView.requireViewById(R.id.failure_icon).visibility = + if (showFailure) { View.VISIBLE } else { View.GONE } + // Future handling if (chipState is TransferInitiated) { addFutureCallback(chipState) @@ -101,9 +106,14 @@ class MediaTttChipControllerSender @Inject constructor( ) } } catch (ex: Exception) { - // TODO(b/203800327): Maybe show a failure chip here if UX decides we need one. mainExecutor.execute { - removeChip() + displayChip( + TransferFailed( + chipState.appIconDrawable, + chipState.appIconContentDescription, + chipState.otherDeviceName, + ) + ) } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt index 9142056842a01..84794cb098f01 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt @@ -49,6 +49,12 @@ class MediaTttSenderService @Inject constructor( ) { this@MediaTttSenderService.closeToReceiverToEndCast(mediaInfo, otherDeviceInfo) } + + override fun transferFailed( + mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo + ) { + this@MediaTttSenderService.transferFailed(mediaInfo, otherDeviceInfo) + } } // TODO(b/203800643): Use the app icon from the media info instead of a fake one. @@ -78,4 +84,13 @@ class MediaTttSenderService @Inject constructor( ) controller.displayChip(chipState) } + + private fun transferFailed(mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo) { + val chipState = TransferFailed( + appIconDrawable = fakeAppIconDrawable, + appIconContentDescription = mediaInfo.name.toString(), + otherDeviceName = otherDeviceInfo.name + ) + controller.displayChip(chipState) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt index e6673a5fcbea8..be082be974844 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt @@ -151,6 +151,14 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { verify(mediaTttChipControllerSender).displayChip(any(TransferSucceeded::class.java)) } + @Test + fun sender_transferFailed_serviceCallbackCalled() { + commandRegistry.onShellCommand(pw, getTransferFailedCommand()) + + assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue() + verify(mediaSenderService).transferFailed(any(), any()) + } + @Test fun sender_removeCommand_chipRemoved() { commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_SENDER_TAG)) @@ -200,6 +208,13 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { TRANSFER_SUCCEEDED_COMMAND_NAME ) + private fun getTransferFailedCommand(): Array = + arrayOf( + ADD_CHIP_COMMAND_SENDER_TAG, + DEVICE_NAME, + TRANSFER_FAILED_COMMAND_NAME + ) + class EmptyCommand : Command { override fun execute(pw: PrintWriter, args: List) { } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index b58eecbfc85af..937d221286d55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -66,7 +66,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } @Test - fun moveCloserToStartCast_appIcon_chipTextContainsDeviceName_noLoadingIcon_noUndo() { + fun moveCloserToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() { controllerSender.displayChip(moveCloserToStartCast()) val chipView = getChipView() @@ -75,10 +75,11 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) } @Test - fun moveCloserToEndCast_appIcon_chipTextContainsDeviceName_noLoadingIcon_noUndo() { + fun moveCloserToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() { controllerSender.displayChip(moveCloserToEndCast()) val chipView = getChipView() @@ -87,10 +88,11 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) } @Test - fun transferInitiated_futureNotResolvedYet_appIcon_loadingIcon_noUndo() { + fun transferInitiated_futureNotResolvedYet_appIcon_loadingIcon_noUndo_noFailureIcon() { val future: SettableFuture = SettableFuture.create() controllerSender.displayChip(transferInitiated(future)) @@ -103,6 +105,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) } @Test @@ -128,7 +131,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } @Test - fun transferInitiated_futureCancelled_chipRemoved() { + fun transferInitiated_futureCancelled_switchesToTransferFailed() { val future: SettableFuture = SettableFuture.create() controllerSender.displayChip(transferInitiated(future)) @@ -141,12 +144,15 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { // Assert we ran the future callback assertThat(numRun).isEqualTo(1) - // Assert that we've hidden the chip - verify(windowManager).removeView(any()) + // Assert that we've moved to the failed state + val chipView = getChipView() + assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE) } @Test - fun transferInitiated_futureNotResolvedAfterTimeout_chipRemoved() { + fun transferInitiated_futureNotResolvedAfterTimeout_switchesToTransferFailed() { val future: SettableFuture = SettableFuture.create() controllerSender.displayChip(transferInitiated(future)) @@ -160,12 +166,15 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { // Assert we eventually decide to not wait for the future anymore assertThat(numRun).isEqualTo(1) - // Assert we've hidden the chip - verify(windowManager).removeView(any()) + // Assert that we've moved to the failed state + val chipView = getChipView() + assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE) } @Test - fun transferSucceeded_appIcon_chipTextContainsDeviceName_noLoadingIcon() { + fun transferSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() { controllerSender.displayChip(transferSucceeded()) val chipView = getChipView() @@ -173,6 +182,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC) assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) } @Test @@ -203,6 +213,19 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(runnableRun).isTrue() } + @Test + fun transferFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() { + controllerSender.displayChip(transferFailed()) + + val chipView = getChipView() + assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC) + assertThat(chipView.getChipText()).doesNotContain(DEVICE_NAME) + assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE) + } + @Test fun changeFromCloserToStartToTransferInitiated_loadingIconAppears() { controllerSender.displayChip(moveCloserToStartCast()) @@ -235,6 +258,14 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE) } + @Test + fun changeFromTransferInitiatedToTransferFailed_failureIconAppears() { + controllerSender.displayChip(transferInitiated()) + controllerSender.displayChip(transferFailed()) + + assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE) + } + private fun LinearLayout.getAppIconView() = this.requireViewById(R.id.app_icon) private fun LinearLayout.getChipText(): String = @@ -245,6 +276,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { private fun LinearLayout.getUndoButton(): View = this.requireViewById(R.id.undo) + private fun LinearLayout.getFailureIcon(): View = this.requireViewById(R.id.failure_icon) + private fun getChipView(): LinearLayout { val viewCaptor = ArgumentCaptor.forClass(View::class.java) verify(windowManager).addView(viewCaptor.capture(), any()) @@ -268,6 +301,10 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { private fun transferSucceeded( undoRunnable: Runnable? = null ) = TransferSucceeded(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoRunnable) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferFailed() = + TransferFailed(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME) } private const val DEVICE_NAME = "My Tablet" diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt index e9ee0bdbd4c91..66e3fe6c5fdaf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt @@ -5,6 +5,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.shared.mediattt.DeviceInfo import com.android.systemui.shared.mediattt.IDeviceSenderCallback +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.google.common.truth.Truth.assertThat @@ -57,4 +58,11 @@ class MediaTttSenderServiceTest : SysuiTestCase() { val chipState = chipStateCaptor.value!! assertThat(chipState.otherDeviceName).isEqualTo(name) } + + @Test + fun transferFailed_controllerTriggeredWithTransferFailedState() { + callback.transferFailed(mediaInfo, DeviceInfo("Fake name")) + + verify(controller).displayChip(any()) + } }