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) + } }