diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 3a9159094433b..078356f4ef122 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2192,7 +2192,9 @@ Move closer to %1$s to play here - Playing on %1$s + Playing on %1$s + + Playing on this phone Something went wrong 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 8db3e9d135a06..eb026e2187c46 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 @@ -72,6 +72,18 @@ interface IDeviceSenderCallback { oneway void transferToReceiverTriggered( in MediaRoute2Info mediaInfo, in DeviceInfo otherDeviceInfo); + /** + * Invoke to notify System UI that a media transfer from the receiver and back to this device + * (the sender) has been started. + * + * Important notes: + * - This callback is for *ending* a cast. It should be used when media is currently being + * played on the receiver device and the media has started being transferred to play locally + * instead. + */ + oneway void transferToThisDeviceTriggered( + in MediaRoute2Info mediaInfo, in DeviceInfo otherDeviceInfo); + /** * Invoke to notify System UI that the attempted transfer has failed. * 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 e8a847f6ae418..5ce9d56c15375 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -36,6 +36,7 @@ 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.TransferToReceiverTriggered +import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered import com.android.systemui.media.taptotransfer.sender.TransferSucceeded import com.android.systemui.shared.mediattt.DeviceInfo import com.android.systemui.shared.mediattt.IDeviceSenderCallback @@ -98,6 +99,11 @@ class MediaTttCommandLineHelper @Inject constructor( senderCallback.transferToReceiverTriggered(mediaInfo, otherDeviceInfo) } } + TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME -> { + runOnService { senderCallback -> + senderCallback.transferToThisDeviceTriggered(mediaInfo, otherDeviceInfo) + } + } // TODO(b/203800643): Migrate this command to invoke the service instead of the // controller. TRANSFER_SUCCEEDED_COMMAND_NAME -> { @@ -120,6 +126,7 @@ class MediaTttCommandLineHelper @Inject constructor( "$MOVE_CLOSER_TO_START_CAST_COMMAND_NAME, " + "$MOVE_CLOSER_TO_END_CAST_COMMAND_NAME, " + "$TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME, " + + "$TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME, " + "$TRANSFER_SUCCEEDED_COMMAND_NAME, " + TRANSFER_FAILED_COMMAND_NAME ) @@ -231,6 +238,9 @@ val MOVE_CLOSER_TO_END_CAST_COMMAND_NAME = MoveCloserToEndCast::class.simpleName @VisibleForTesting val TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME = TransferToReceiverTriggered::class.simpleName!! @VisibleForTesting +val TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME = + TransferToThisDeviceTriggered::class.simpleName!! +@VisibleForTesting val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!! @VisibleForTesting val TRANSFER_FAILED_COMMAND_NAME = TransferFailed::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 0f2715c4a6e35..abfd9d3e498af 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 @@ -34,6 +34,9 @@ sealed class ChipStateSender( ) : MediaTttChipState(appIconDrawable, appIconContentDescription) { /** Returns a fully-formed string with the text that the chip should display. */ abstract fun getChipTextString(context: Context): String + + /** Returns true if the loading icon should be displayed and false otherwise. */ + abstract fun showLoading(): Boolean } /** @@ -51,6 +54,8 @@ class MoveCloserToStartCast( override fun getChipTextString(context: Context): String { return context.getString(R.string.media_move_closer_to_start_cast, otherDeviceName) } + + override fun showLoading() = false } /** @@ -68,6 +73,8 @@ class MoveCloserToEndCast( override fun getChipTextString(context: Context): String { return context.getString(R.string.media_move_closer_to_end_cast, otherDeviceName) } + + override fun showLoading() = false } /** @@ -82,8 +89,25 @@ class TransferToReceiverTriggered( private val otherDeviceName: String ) : ChipStateSender(appIconDrawable, appIconContentDescription) { override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_transfer_playing, otherDeviceName) + return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName) } + + override fun showLoading() = true +} + +/** + * A state representing that a transfer from the receiver device and back to this device (the + * sender) has been initiated (but not completed). + */ +class TransferToThisDeviceTriggered( + appIconDrawable: Drawable, + appIconContentDescription: String +) : ChipStateSender(appIconDrawable, appIconContentDescription) { + override fun getChipTextString(context: Context): String { + return context.getString(R.string.media_transfer_playing_this_device) + } + + override fun showLoading() = true } /** @@ -100,8 +124,10 @@ class TransferSucceeded( val undoRunnable: Runnable? = null ) : ChipStateSender(appIconDrawable, appIconContentDescription) { override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_transfer_playing, otherDeviceName) + return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName) } + + override fun showLoading() = false } /** A state representing that a transfer has failed. */ @@ -112,4 +138,6 @@ class TransferFailed( override fun getChipTextString(context: Context): String { return context.getString(R.string.media_transfer_failed) } + + override fun showLoading() = false } 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 88264b6e669ee..5cfd674b21cb7 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 @@ -49,9 +49,8 @@ class MediaTttChipControllerSender @Inject constructor( } // Loading - val showLoading = chipState is TransferToReceiverTriggered currentChipView.requireViewById(R.id.loading).visibility = - if (showLoading) { View.VISIBLE } else { View.GONE } + if (chipState.showLoading()) { View.VISIBLE } else { View.GONE } // Undo val undoClickListener: View.OnClickListener? = 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 cbf646209b007..56f33a8dcf755 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 @@ -61,6 +61,12 @@ class MediaTttSenderService @Inject constructor( ) { this@MediaTttSenderService.transferToReceiverTriggered(mediaInfo, otherDeviceInfo) } + + override fun transferToThisDeviceTriggered( + mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo + ) { + this@MediaTttSenderService.transferToThisDeviceTriggered(mediaInfo) + } } // TODO(b/203800643): Use the app icon from the media info instead of a fake one. @@ -109,4 +115,12 @@ class MediaTttSenderService @Inject constructor( ) controller.displayChip(chipState) } + + private fun transferToThisDeviceTriggered(mediaInfo: MediaRoute2Info) { + val chipState = TransferToThisDeviceTriggered( + appIconDrawable = fakeAppIconDrawable, + appIconContentDescription = mediaInfo.name.toString() + ) + 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 cf5d47747e4c4..6275c240921a1 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 @@ -145,6 +145,14 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) } + @Test + fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() { + commandRegistry.onShellCommand(pw, getTransferToThisDeviceTriggeredCommand()) + + assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue() + verify(mediaSenderService).transferToThisDeviceTriggered(any(), any()) + } + @Test fun sender_transferSucceeded_chipDisplayWithCorrectState() { commandRegistry.onShellCommand(pw, getTransferSucceededCommand()) @@ -202,6 +210,13 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME ) + private fun getTransferToThisDeviceTriggeredCommand(): Array = + arrayOf( + ADD_CHIP_COMMAND_SENDER_TAG, + DEVICE_NAME, + TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME + ) + private fun getTransferSucceededCommand(): 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 b6c1834e68f1a..703f6b0d57458 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 @@ -93,6 +93,20 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) } + @Test + fun transferToThisDeviceTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() { + val state = transferToThisDeviceTriggered() + controllerSender.displayChip(state) + + val chipView = getChipView() + assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC) + assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) + } + @Test fun transferSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() { val state = transferSucceeded() @@ -218,6 +232,10 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { private fun transferToReceiverTriggered() = TransferToReceiverTriggered(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME) + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferToThisDeviceTriggered() = + TransferToThisDeviceTriggered(appIconDrawable, APP_ICON_CONTENT_DESC) + /** Helper method providing default parameters to not clutter up the tests. */ private fun transferSucceeded( undoRunnable: Runnable? = null 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 8a491c220592b..1abf49f2c4bf6 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 @@ -59,6 +59,13 @@ class MediaTttSenderServiceTest : SysuiTestCase() { assertThat(chipState.getChipTextString(context)).contains(name) } + @Test + fun transferToThisDeviceTriggered_controllerTriggeredWithCorrectState() { + callback.transferToThisDeviceTriggered(mediaInfo, DeviceInfo("Fake name")) + + verify(controller).displayChip(any()) + } + @Test fun transferToReceiverTriggered_controllerTriggeredWithCorrectState() { val name = "Fake name"