[Media TTT] Add transferToThisDeviceTriggered callback.

Bug: 203800643
Bug: 203800347
Test: `adb shell cmd statusbar media-ttt-chip-add-sender Device
TransferToThisDeviceTriggered` triggers a chip saying "Playing on this
device" with loading icon
Test: media.taptotransfer tests

Change-Id: Iddc0593603f7fdd96a67b805a808205e77658d8d
This commit is contained in:
Caitlin Cassidy
2022-01-13 20:37:59 +00:00
parent babe2cd5f3
commit b3defd20a4
9 changed files with 110 additions and 5 deletions

View File

@@ -2192,7 +2192,9 @@
<!-- Text to ask the user to move their device closer to a different device (deviceName) in order to transfer media from the different device and back onto the current device. [CHAR LIMIT=75] -->
<string name="media_move_closer_to_end_cast">Move closer to <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g> to play here</string>
<!-- Text informing the user that their media is now playing on a different device (deviceName). [CHAR LIMIT=50] -->
<string name="media_transfer_playing">Playing on <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g></string>
<string name="media_transfer_playing_different_device">Playing on <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g></string>
<!-- Text informing the user that their media is now playing on this device. [CHAR LIMIT=50] -->
<string name="media_transfer_playing_this_device">Playing on this phone</string>
<!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] -->
<string name="media_transfer_failed">Something went wrong</string>

View File

@@ -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.
*

View File

@@ -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!!

View File

@@ -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
}

View File

@@ -49,9 +49,8 @@ class MediaTttChipControllerSender @Inject constructor(
}
// Loading
val showLoading = chipState is TransferToReceiverTriggered
currentChipView.requireViewById<View>(R.id.loading).visibility =
if (showLoading) { View.VISIBLE } else { View.GONE }
if (chipState.showLoading()) { View.VISIBLE } else { View.GONE }
// Undo
val undoClickListener: View.OnClickListener? =

View File

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

View File

@@ -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<String> =
arrayOf(
ADD_CHIP_COMMAND_SENDER_TAG,
DEVICE_NAME,
TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME
)
private fun getTransferSucceededCommand(): Array<String> =
arrayOf(
ADD_CHIP_COMMAND_SENDER_TAG,

View File

@@ -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

View File

@@ -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<TransferToThisDeviceTriggered>())
}
@Test
fun transferToReceiverTriggered_controllerTriggeredWithCorrectState() {
val name = "Fake name"