[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:
@@ -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>
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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!!
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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? =
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user