Merge changes Iceea7c10,Iba98b916,I912caa44,Id5aef5c4,Iddc05936, ...
* changes:
[Media TTT] Add NoLongerCloseToReceiver callback.
[Media TTT] Add TransferToThisDeviceSucceeded callback.
[Media TTT] Add an undo callback to the interface for when a transfer has succeeded. The callback will be invoked when the user presses the undo button.
[Media TTT] Add the #transferToReceiverSucceeded callback.
[Media TTT] Add transferToThisDeviceTriggered callback.
[Media TTT] Update chip states to not require otherDeviceName if they don't need it. Define a #getChipTextString method instead.
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 34e5aef..41d5735 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2161,7 +2161,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>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderService.aidl
similarity index 60%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl
rename to packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderService.aidl
index 8db3e9d..eb1c9d0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderService.aidl
@@ -18,16 +18,17 @@
import android.media.MediaRoute2Info;
import com.android.systemui.shared.mediattt.DeviceInfo;
+import com.android.systemui.shared.mediattt.IUndoTransferCallback;
/**
- * A callback interface that can be invoked to trigger media transfer events on System UI.
+ * An interface that can be invoked to trigger media transfer events on System UI.
*
* This interface is for the *sender* device, which is the device currently playing media. This
* sender device can transfer the media to a different device, called the receiver.
*
* System UI will implement this interface and other services will invoke it.
*/
-interface IDeviceSenderCallback {
+interface IDeviceSenderService {
/**
* Invoke to notify System UI that this device (the sender) is close to a receiver device, so
* the user can potentially *start* a cast to the receiver device if the user moves their device
@@ -73,10 +74,60 @@
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 a media transfer from this device (the sender) to a receiver
+ * device has finished successfully.
+ *
+ * Important notes:
+ * - This callback is for *starting* a cast. It should be used when this device had previously
+ * been playing media locally and the media has successfully been transferred to the
+ * receiver device instead.
+ *
+ * @param undoCallback will be invoked if the user chooses to undo this transfer.
+ */
+ oneway void transferToReceiverSucceeded(
+ in MediaRoute2Info mediaInfo,
+ in DeviceInfo otherDeviceInfo,
+ in IUndoTransferCallback undoCallback);
+
+ /**
+ * Invoke to notify System UI that a media transfer from the receiver and back to this device
+ * (the sender) has finished successfully.
+ *
+ * Important notes:
+ * - This callback is for *ending* a cast. It should be used when media was previously being
+ * played on the receiver device and has been successfully transferred to play locally on
+ * this device instead.
+ *
+ * @param undoCallback will be invoked if the user chooses to undo this transfer.
+ */
+ oneway void transferToThisDeviceSucceeded(
+ in MediaRoute2Info mediaInfo,
+ in DeviceInfo otherDeviceInfo,
+ in IUndoTransferCallback undoCallback);
+
+ /**
* 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);
+
+ /**
+ * Invoke to notify System UI that this device is no longer close to the receiver device.
+ */
+ oneway void noLongerCloseToReceiver(
+ in MediaRoute2Info mediaInfo, in DeviceInfo otherDeviceInfo);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IUndoTransferCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IUndoTransferCallback.aidl
new file mode 100644
index 0000000..b47be87
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IUndoTransferCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.mediattt;
+
+/**
+ * An interface that will be invoked by System UI if the user choose to undo a transfer.
+ *
+ * Other services will implement this interface and System UI will invoke it.
+ */
+interface IUndoTransferCallback {
+
+ /**
+ * Invoked by SystemUI when the user requests to undo the media transfer that just occurred.
+ *
+ * Implementors of this method are repsonsible for actually undoing the transfer.
+ */
+ oneway void onUndoTriggered();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index dd60b30..4baef3a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -112,7 +112,6 @@
MediaTttFlags mediaTttFlags,
CommandRegistry commandRegistry,
Context context,
- MediaTttChipControllerSender mediaTttChipControllerSender,
MediaTttChipControllerReceiver mediaTttChipControllerReceiver) {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
@@ -121,7 +120,6 @@
new MediaTttCommandLineHelper(
commandRegistry,
context,
- mediaTttChipControllerSender,
mediaTttChipControllerReceiver));
}
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 e8a847f..3720851 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -30,15 +30,17 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
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.TransferFailed
import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered
-import com.android.systemui.media.taptotransfer.sender.TransferSucceeded
+import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded
+import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered
+import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded
import com.android.systemui.shared.mediattt.DeviceInfo
-import com.android.systemui.shared.mediattt.IDeviceSenderCallback
+import com.android.systemui.shared.mediattt.IDeviceSenderService
+import com.android.systemui.shared.mediattt.IUndoTransferCallback
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import java.io.PrintWriter
@@ -52,10 +54,9 @@
class MediaTttCommandLineHelper @Inject constructor(
commandRegistry: CommandRegistry,
private val context: Context,
- private val mediaTttChipControllerSender: MediaTttChipControllerSender,
private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver,
) {
- private var senderCallback: IDeviceSenderCallback? = null
+ private var senderService: IDeviceSenderService? = null
private val senderServiceConnection = SenderServiceConnection()
private val appIconDrawable =
@@ -64,17 +65,15 @@
}
init {
- commandRegistry.registerCommand(
- ADD_CHIP_COMMAND_SENDER_TAG) { AddChipCommandSender() }
- commandRegistry.registerCommand(
- REMOVE_CHIP_COMMAND_SENDER_TAG) { RemoveChipCommandSender() }
+ commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
commandRegistry.registerCommand(
ADD_CHIP_COMMAND_RECEIVER_TAG) { AddChipCommandReceiver() }
commandRegistry.registerCommand(
REMOVE_CHIP_COMMAND_RECEIVER_TAG) { RemoveChipCommandReceiver() }
}
- inner class AddChipCommandSender : Command {
+ /** All commands for the sender device. */
+ inner class SenderCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
val otherDeviceName = args[0]
val mediaInfo = MediaRoute2Info.Builder("id", "Test Name")
@@ -84,65 +83,99 @@
when (args[1]) {
MOVE_CLOSER_TO_START_CAST_COMMAND_NAME -> {
- runOnService { senderCallback ->
- senderCallback.closeToReceiverToStartCast(mediaInfo, otherDeviceInfo)
+ runOnService { senderService ->
+ senderService.closeToReceiverToStartCast(mediaInfo, otherDeviceInfo)
}
}
MOVE_CLOSER_TO_END_CAST_COMMAND_NAME -> {
- runOnService { senderCallback ->
- senderCallback.closeToReceiverToEndCast(mediaInfo, otherDeviceInfo)
+ runOnService { senderService ->
+ senderService.closeToReceiverToEndCast(mediaInfo, otherDeviceInfo)
}
}
TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME -> {
- runOnService { senderCallback ->
- senderCallback.transferToReceiverTriggered(mediaInfo, otherDeviceInfo)
+ runOnService { senderService ->
+ senderService.transferToReceiverTriggered(mediaInfo, otherDeviceInfo)
}
}
- // TODO(b/203800643): Migrate this command to invoke the service instead of the
- // controller.
- TRANSFER_SUCCEEDED_COMMAND_NAME -> {
- mediaTttChipControllerSender.displayChip(
- TransferSucceeded(
- appIconDrawable,
- APP_ICON_CONTENT_DESCRIPTION,
- otherDeviceName,
- fakeUndoRunnable
- )
- )
+ TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME -> {
+ runOnService { senderService ->
+ senderService.transferToThisDeviceTriggered(mediaInfo, otherDeviceInfo)
+ }
+ }
+ TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME -> {
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {
+ Log.i(TAG, "Undo transfer to receiver callback triggered")
+ // The external services that implement this callback would kick off a
+ // transfer back to this device, so mimic that here.
+ runOnService { senderService ->
+ senderService
+ .transferToThisDeviceTriggered(mediaInfo, otherDeviceInfo)
+ }
+ }
+ }
+ runOnService { senderService ->
+ senderService
+ .transferToReceiverSucceeded(mediaInfo, otherDeviceInfo, undoCallback)
+ }
+ }
+ TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME -> {
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {
+ Log.i(TAG, "Undo transfer to this device callback triggered")
+ // The external services that implement this callback would kick off a
+ // transfer back to the receiver, so mimic that here.
+ runOnService { senderService ->
+ senderService
+ .transferToReceiverTriggered(mediaInfo, otherDeviceInfo)
+ }
+ }
+ }
+ runOnService { senderService ->
+ senderService
+ .transferToThisDeviceSucceeded(mediaInfo, otherDeviceInfo, undoCallback)
+ }
}
TRANSFER_FAILED_COMMAND_NAME -> {
- runOnService { senderCallback ->
- senderCallback.transferFailed(mediaInfo, otherDeviceInfo)
+ runOnService { senderService ->
+ senderService.transferFailed(mediaInfo, otherDeviceInfo)
+ }
+ }
+ NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME -> {
+ runOnService { senderService ->
+ senderService.noLongerCloseToReceiver(mediaInfo, otherDeviceInfo)
+ context.unbindService(senderServiceConnection)
}
}
else -> {
- pw.println("Chip type must be one of " +
+ pw.println("Sender command must be one of " +
"$MOVE_CLOSER_TO_START_CAST_COMMAND_NAME, " +
"$MOVE_CLOSER_TO_END_CAST_COMMAND_NAME, " +
"$TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME, " +
- "$TRANSFER_SUCCEEDED_COMMAND_NAME, " +
- TRANSFER_FAILED_COMMAND_NAME
+ "$TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME, " +
+ "$TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME, " +
+ "$TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME, " +
+ "$TRANSFER_FAILED_COMMAND_NAME, " +
+ NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME
)
}
}
}
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar " +
- "$ADD_CHIP_COMMAND_SENDER_TAG <deviceName> <chipStatus>"
- )
+ pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND <deviceName> <chipStatus>")
}
- private fun runOnService(command: SenderCallbackCommand) {
- val currentServiceCallback = senderCallback
- if (currentServiceCallback != null) {
- command.run(currentServiceCallback)
+ private fun runOnService(command: SenderServiceCommand) {
+ val currentService = senderService
+ if (currentService != null) {
+ command.run(currentService)
} else {
bindService(command)
}
}
- private fun bindService(command: SenderCallbackCommand) {
+ private fun bindService(command: SenderServiceCommand) {
senderServiceConnection.pendingCommand = command
val binding = context.bindService(
Intent(context, MediaTttSenderService::class.java),
@@ -153,19 +186,6 @@
}
}
- /** A command to REMOVE the media ttt chip on the SENDER device. */
- inner class RemoveChipCommandSender : Command {
- override fun execute(pw: PrintWriter, args: List<String>) {
- mediaTttChipControllerSender.removeChip()
- if (senderCallback != null) {
- context.unbindService(senderServiceConnection)
- }
- }
- override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_SENDER_TAG")
- }
- }
-
/** A command to DISPLAY the media ttt chip on the RECEIVER device. */
inner class AddChipCommandReceiver : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
@@ -188,36 +208,32 @@
}
}
- /** A service connection for [IDeviceSenderCallback]. */
+ /** A service connection for [IDeviceSenderService]. */
private inner class SenderServiceConnection : ServiceConnection {
// A command that should be run when the service gets connected.
- var pendingCommand: SenderCallbackCommand? = null
+ var pendingCommand: SenderServiceCommand? = null
override fun onServiceConnected(className: ComponentName, service: IBinder) {
- val newCallback = IDeviceSenderCallback.Stub.asInterface(service)
- senderCallback = newCallback
+ val newCallback = IDeviceSenderService.Stub.asInterface(service)
+ senderService = newCallback
pendingCommand?.run(newCallback)
pendingCommand = null
}
override fun onServiceDisconnected(className: ComponentName) {
- senderCallback = null
+ senderService = null
}
}
- /** An interface defining a command that should be run on the sender callback. */
- private fun interface SenderCallbackCommand {
- /** Runs the command on the provided [senderCallback]. */
- fun run(senderCallback: IDeviceSenderCallback)
- }
-
- private val fakeUndoRunnable = Runnable {
- Log.i(TAG, "Undo runnable triggered")
+ /** An interface defining a command that should be run on the sender service. */
+ private fun interface SenderServiceCommand {
+ /** Runs the command on the provided [senderService]. */
+ fun run(senderService: IDeviceSenderService)
}
}
@VisibleForTesting
-const val ADD_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-add-sender"
+const val SENDER_COMMAND = "media-ttt-chip-sender"
@VisibleForTesting
const val REMOVE_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-remove-sender"
@VisibleForTesting
@@ -231,9 +247,17 @@
@VisibleForTesting
val TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME = TransferToReceiverTriggered::class.simpleName!!
@VisibleForTesting
-val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!!
+val TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME =
+ TransferToThisDeviceTriggered::class.simpleName!!
+@VisibleForTesting
+val TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME = TransferToReceiverSucceeded::class.simpleName!!
+@VisibleForTesting
+val TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME =
+ TransferToThisDeviceSucceeded::class.simpleName!!
@VisibleForTesting
val TRANSFER_FAILED_COMMAND_NAME = TransferFailed::class.simpleName!!
+@VisibleForTesting
+val NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME = "NoLongerCloseToReceiver"
private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon"
private const val TAG = "MediaTapToTransferCli"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 67721a5..adae07b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -81,6 +81,9 @@
/** Hides the chip. */
fun removeChip() {
+ // TODO(b/203800347): We may not want to hide the chip if we're currently in a
+ // TransferTriggered state: Once the user has initiated the transfer, they should be able
+ // to move away from the receiver device but still see the status of the transfer.
if (chipView == null) { return }
windowManager.removeView(chipView)
chipView = null
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 1fd3af4..c656df2 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
@@ -16,10 +16,12 @@
package com.android.systemui.media.taptotransfer.sender
+import android.content.Context
import android.graphics.drawable.Drawable
-import androidx.annotation.StringRes
+import android.view.View
import com.android.systemui.R
import com.android.systemui.media.taptotransfer.common.MediaTttChipState
+import com.android.systemui.shared.mediattt.IUndoTransferCallback
/**
* A class that stores all the information necessary to display the media tap-to-transfer chip on
@@ -27,91 +29,181 @@
*
* This is a sealed class where each subclass represents a specific chip state. Each subclass can
* contain additional information that is necessary for only that state.
- *
- * @property chipText a string resource for the text that the chip should display.
- * @property otherDeviceName the name of the other device involved in the transfer.
*/
sealed class ChipStateSender(
appIconDrawable: Drawable,
- appIconContentDescription: String,
- @StringRes internal val chipText: Int,
- internal val otherDeviceName: String,
-) : MediaTttChipState(appIconDrawable, appIconContentDescription)
+ appIconContentDescription: String
+) : 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. */
+ open fun showLoading(): Boolean = false
+
+ /**
+ * Returns a click listener for the undo button on the chip. Returns null if this chip state
+ * doesn't have an undo button.
+ *
+ * @param controllerSender passed as a parameter in case we want to display a new chip state
+ * when undo is clicked.
+ */
+ open fun undoClickListener(
+ controllerSender: MediaTttChipControllerSender
+ ): View.OnClickListener? = null
+}
/**
* A state representing that the two devices are close but not close enough to *start* a cast to
* the receiver device. The chip will instruct the user to move closer in order to initiate the
* transfer to the receiver.
+ *
+ * @property otherDeviceName the name of the other device involved in the transfer.
*/
class MoveCloserToStartCast(
appIconDrawable: Drawable,
appIconContentDescription: String,
- otherDeviceName: String,
-) : ChipStateSender(
- appIconDrawable,
- appIconContentDescription,
- R.string.media_move_closer_to_start_cast,
- otherDeviceName
-)
+ private val otherDeviceName: String,
+) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ override fun getChipTextString(context: Context): String {
+ return context.getString(R.string.media_move_closer_to_start_cast, 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).
+ *
+ * @property otherDeviceName the name of the other device involved in the transfer.
*/
class MoveCloserToEndCast(
appIconDrawable: Drawable,
appIconContentDescription: String,
- otherDeviceName: String,
-) : ChipStateSender(
- appIconDrawable,
- appIconContentDescription,
- R.string.media_move_closer_to_end_cast,
- otherDeviceName
-)
+ private val otherDeviceName: String,
+) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ override fun getChipTextString(context: Context): String {
+ return context.getString(R.string.media_move_closer_to_end_cast, otherDeviceName)
+ }
+}
/**
* A state representing that a transfer to the receiver device has been initiated (but not
* completed).
+ *
+ * @property otherDeviceName the name of the other device involved in the transfer.
*/
class TransferToReceiverTriggered(
appIconDrawable: Drawable,
appIconContentDescription: String,
- otherDeviceName: String
-) : ChipStateSender(
- appIconDrawable,
- appIconContentDescription,
- R.string.media_transfer_playing,
- otherDeviceName
-)
+ private val otherDeviceName: String
+) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ override fun getChipTextString(context: Context): String {
+ return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName)
+ }
+
+ override fun showLoading() = true
+}
/**
- * A state representing that a transfer has been successfully completed.
- *
- * @property undoRunnable if present, the runnable that should be run to undo the transfer. We will
- * show an Undo button on the chip if this runnable is present.
+ * A state representing that a transfer from the receiver device and back to this device (the
+ * sender) has been initiated (but not completed).
*/
-class TransferSucceeded(
+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
+}
+
+/**
+ * A state representing that a transfer to the receiver device has been successfully completed.
+ *
+ * @property otherDeviceName the name of the other device involved in the transfer.
+ * @property undoCallback if present, the callback that should be called when the user clicks the
+ * undo button. The undo button will only be shown if this is non-null.
+ */
+class TransferToReceiverSucceeded(
appIconDrawable: Drawable,
appIconContentDescription: String,
- otherDeviceName: String,
- val undoRunnable: Runnable? = null
-) : ChipStateSender(appIconDrawable,
- appIconContentDescription,
- R.string.media_transfer_playing,
- otherDeviceName
-)
+ private val otherDeviceName: String,
+ val undoCallback: IUndoTransferCallback? = null
+) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ override fun getChipTextString(context: Context): String {
+ return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName)
+ }
+
+ override fun undoClickListener(
+ controllerSender: MediaTttChipControllerSender
+ ): View.OnClickListener? {
+ if (undoCallback == null) {
+ return null
+ }
+
+ return View.OnClickListener {
+ this.undoCallback.onUndoTriggered()
+ // The external service should eventually send us a TransferToThisDeviceTriggered state,
+ // but that may take too long to go through the binder and the user may be confused as
+ // to why the UI hasn't changed yet. So, we immediately change the UI here.
+ controllerSender.displayChip(
+ TransferToThisDeviceTriggered(
+ this.appIconDrawable,
+ this.appIconContentDescription
+ )
+ )
+ }
+ }
+}
+
+/**
+ * A state representing that a transfer back to this device has been successfully completed.
+ *
+ * @property otherDeviceName the name of the other device involved in the transfer.
+ * @property undoCallback if present, the callback that should be called when the user clicks the
+ * undo button. The undo button will only be shown if this is non-null.
+ */
+class TransferToThisDeviceSucceeded(
+ appIconDrawable: Drawable,
+ appIconContentDescription: String,
+ private val otherDeviceName: String,
+ val undoCallback: IUndoTransferCallback? = null
+) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ override fun getChipTextString(context: Context): String {
+ return context.getString(R.string.media_transfer_playing_this_device)
+ }
+
+ override fun undoClickListener(
+ controllerSender: MediaTttChipControllerSender
+ ): View.OnClickListener? {
+ if (undoCallback == null) {
+ return null
+ }
+
+ return View.OnClickListener {
+ this.undoCallback.onUndoTriggered()
+ // The external service should eventually send us a TransferToReceiverTriggered state,
+ // but that may take too long to go through the binder and the user may be confused as
+ // to why the UI hasn't changed yet. So, we immediately change the UI here.
+ controllerSender.displayChip(
+ TransferToReceiverTriggered(
+ this.appIconDrawable,
+ this.appIconContentDescription,
+ this.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
-)
+ appIconContentDescription: String
+) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ override fun getChipTextString(context: Context): String {
+ return context.getString(R.string.media_transfer_failed)
+ }
+}
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 84672ab..453e3d6 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
@@ -45,27 +45,18 @@
// Text
currentChipView.requireViewById<TextView>(R.id.text).apply {
- text = context.getString(chipState.chipText, chipState.otherDeviceName)
+ text = chipState.getChipTextString(context)
}
// 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? =
- if (chipState is TransferSucceeded && chipState.undoRunnable != null)
- View.OnClickListener { chipState.undoRunnable.run() }
- else
- null
val undoView = currentChipView.requireViewById<View>(R.id.undo)
- undoView.visibility = if (undoClickListener != null) {
- View.VISIBLE
- } else {
- View.GONE
- }
+ val undoClickListener = chipState.undoClickListener(this)
undoView.setOnClickListener(undoClickListener)
+ undoView.visibility = if (undoClickListener != null) { View.VISIBLE } else { View.GONE }
// Failure
val showFailure = chipState is TransferFailed
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 0fe324e..717752e 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
@@ -25,7 +25,8 @@
import android.os.IBinder
import com.android.systemui.R
import com.android.systemui.shared.mediattt.DeviceInfo
-import com.android.systemui.shared.mediattt.IDeviceSenderCallback
+import com.android.systemui.shared.mediattt.IUndoTransferCallback
+import com.android.systemui.shared.mediattt.IDeviceSenderService
import javax.inject.Inject
/**
@@ -37,7 +38,7 @@
) : Service() {
// TODO(b/203800643): Add logging when callbacks trigger.
- private val binder: IBinder = object : IDeviceSenderCallback.Stub() {
+ private val binder: IBinder = object : IDeviceSenderService.Stub() {
override fun closeToReceiverToStartCast(
mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo
) {
@@ -53,7 +54,7 @@
override fun transferFailed(
mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo
) {
- this@MediaTttSenderService.transferFailed(mediaInfo, otherDeviceInfo)
+ this@MediaTttSenderService.transferFailed(mediaInfo)
}
override fun transferToReceiverTriggered(
@@ -61,6 +62,39 @@
) {
this@MediaTttSenderService.transferToReceiverTriggered(mediaInfo, otherDeviceInfo)
}
+
+ override fun transferToThisDeviceTriggered(
+ mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo
+ ) {
+ this@MediaTttSenderService.transferToThisDeviceTriggered(mediaInfo)
+ }
+
+ override fun transferToReceiverSucceeded(
+ mediaInfo: MediaRoute2Info,
+ otherDeviceInfo: DeviceInfo,
+ undoCallback: IUndoTransferCallback
+ ) {
+ this@MediaTttSenderService.transferToReceiverSucceeded(
+ mediaInfo, otherDeviceInfo, undoCallback
+ )
+ }
+
+ override fun transferToThisDeviceSucceeded(
+ mediaInfo: MediaRoute2Info,
+ otherDeviceInfo: DeviceInfo,
+ undoCallback: IUndoTransferCallback
+ ) {
+ this@MediaTttSenderService.transferToThisDeviceSucceeded(
+ mediaInfo, otherDeviceInfo, undoCallback
+ )
+ }
+
+ override fun noLongerCloseToReceiver(
+ mediaInfo: MediaRoute2Info,
+ otherDeviceInfo: DeviceInfo
+ ) {
+ this@MediaTttSenderService.noLongerCloseToReceiver()
+ }
}
// TODO(b/203800643): Use the app icon from the media info instead of a fake one.
@@ -91,11 +125,10 @@
controller.displayChip(chipState)
}
- private fun transferFailed(mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo) {
+ private fun transferFailed(mediaInfo: MediaRoute2Info) {
val chipState = TransferFailed(
appIconDrawable = fakeAppIconDrawable,
- appIconContentDescription = mediaInfo.name.toString(),
- otherDeviceName = otherDeviceInfo.name
+ appIconContentDescription = mediaInfo.name.toString()
)
controller.displayChip(chipState)
}
@@ -110,4 +143,40 @@
)
controller.displayChip(chipState)
}
+
+ private fun transferToThisDeviceTriggered(mediaInfo: MediaRoute2Info) {
+ val chipState = TransferToThisDeviceTriggered(
+ appIconDrawable = fakeAppIconDrawable,
+ appIconContentDescription = mediaInfo.name.toString()
+ )
+ controller.displayChip(chipState)
+ }
+
+ private fun transferToReceiverSucceeded(
+ mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo, undoCallback: IUndoTransferCallback
+ ) {
+ val chipState = TransferToReceiverSucceeded(
+ appIconDrawable = fakeAppIconDrawable,
+ appIconContentDescription = mediaInfo.name.toString(),
+ otherDeviceName = otherDeviceInfo.name,
+ undoCallback = undoCallback
+ )
+ controller.displayChip(chipState)
+ }
+
+ private fun transferToThisDeviceSucceeded(
+ mediaInfo: MediaRoute2Info, otherDeviceInfo: DeviceInfo, undoCallback: IUndoTransferCallback
+ ) {
+ val chipState = TransferToThisDeviceSucceeded(
+ appIconDrawable = fakeAppIconDrawable,
+ appIconContentDescription = mediaInfo.name.toString(),
+ otherDeviceName = otherDeviceInfo.name,
+ undoCallback = undoCallback
+ )
+ controller.displayChip(chipState)
+ }
+
+ private fun noLongerCloseToReceiver() {
+ controller.removeChip()
+ }
}
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 cf5d477..a1ec38f 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
@@ -21,9 +21,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
-import com.android.systemui.media.taptotransfer.sender.*
+import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService
import com.android.systemui.shared.mediattt.DeviceInfo
-import com.android.systemui.shared.mediattt.IDeviceSenderCallback
+import com.android.systemui.shared.mediattt.IDeviceSenderService
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.mockito.any
@@ -51,11 +51,9 @@
private lateinit var mediaTttCommandLineHelper: MediaTttCommandLineHelper
@Mock
- private lateinit var mediaTttChipControllerSender: MediaTttChipControllerSender
- @Mock
private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver
@Mock
- private lateinit var mediaSenderService: IDeviceSenderCallback.Stub
+ private lateinit var mediaSenderService: IDeviceSenderService.Stub
private lateinit var mediaSenderServiceComponentName: ComponentName
@Before
@@ -71,27 +69,15 @@
MediaTttCommandLineHelper(
commandRegistry,
context,
- mediaTttChipControllerSender,
mediaTttChipControllerReceiver,
)
}
@Test(expected = IllegalStateException::class)
- fun constructor_addSenderCommandAlreadyRegistered() {
- // Since creating the chip controller should automatically register the add command, it
+ fun constructor_senderCommandAlreadyRegistered() {
+ // Since creating the chip controller should automatically register the sender command, it
// should throw when registering it again.
- commandRegistry.registerCommand(
- ADD_CHIP_COMMAND_SENDER_TAG
- ) { EmptyCommand() }
- }
-
- @Test(expected = IllegalStateException::class)
- fun constructor_removeSenderCommandAlreadyRegistered() {
- // Since creating the chip controller should automatically register the remove command, it
- // should throw when registering it again.
- commandRegistry.registerCommand(
- REMOVE_CHIP_COMMAND_SENDER_TAG
- ) { EmptyCommand() }
+ commandRegistry.registerCommand(SENDER_COMMAND) { EmptyCommand() }
}
@Test(expected = IllegalStateException::class)
@@ -146,10 +132,35 @@
}
@Test
- fun sender_transferSucceeded_chipDisplayWithCorrectState() {
- commandRegistry.onShellCommand(pw, getTransferSucceededCommand())
+ fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() {
+ commandRegistry.onShellCommand(pw, getTransferToThisDeviceTriggeredCommand())
- verify(mediaTttChipControllerSender).displayChip(any(TransferSucceeded::class.java))
+ assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+ verify(mediaSenderService).transferToThisDeviceTriggered(any(), any())
+ }
+
+ @Test
+ fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() {
+ commandRegistry.onShellCommand(pw, getTransferToReceiverSucceededCommand())
+
+ assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+
+ val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
+ verify(mediaSenderService)
+ .transferToReceiverSucceeded(any(), capture(deviceInfoCaptor), any())
+ assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+ }
+
+ @Test
+ fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() {
+ commandRegistry.onShellCommand(pw, getTransferToThisDeviceSucceededCommand())
+
+ assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+
+ val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
+ verify(mediaSenderService)
+ .transferToThisDeviceSucceeded(any(), capture(deviceInfoCaptor), any())
+ assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
}
@Test
@@ -161,10 +172,12 @@
}
@Test
- fun sender_removeCommand_chipRemoved() {
- commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_SENDER_TAG))
+ fun sender_noLongerCloseToReceiver_serviceCallbackCalledAndServiceUnbound() {
+ commandRegistry.onShellCommand(pw, getNoLongerCloseToReceiverCommand())
- verify(mediaTttChipControllerSender).removeChip()
+ // Once we're no longer close to the receiver, we should unbind the service.
+ assertThat(context.isBound(mediaSenderServiceComponentName)).isFalse()
+ verify(mediaSenderService).noLongerCloseToReceiver(any(), any())
}
@Test
@@ -183,39 +196,60 @@
private fun getMoveCloserToStartCastCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_SENDER_TAG,
+ SENDER_COMMAND,
DEVICE_NAME,
MOVE_CLOSER_TO_START_CAST_COMMAND_NAME
)
private fun getMoveCloserToEndCastCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_SENDER_TAG,
+ SENDER_COMMAND,
DEVICE_NAME,
MOVE_CLOSER_TO_END_CAST_COMMAND_NAME
)
private fun getTransferToReceiverTriggeredCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_SENDER_TAG,
+ SENDER_COMMAND,
DEVICE_NAME,
TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME
)
- private fun getTransferSucceededCommand(): Array<String> =
+ private fun getTransferToThisDeviceTriggeredCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_SENDER_TAG,
+ SENDER_COMMAND,
DEVICE_NAME,
- TRANSFER_SUCCEEDED_COMMAND_NAME
+ TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME
+ )
+
+ private fun getTransferToReceiverSucceededCommand(): Array<String> =
+ arrayOf(
+ SENDER_COMMAND,
+ DEVICE_NAME,
+ TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME
+ )
+
+ private fun getTransferToThisDeviceSucceededCommand(): Array<String> =
+ arrayOf(
+ SENDER_COMMAND,
+ DEVICE_NAME,
+ TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME
)
private fun getTransferFailedCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_SENDER_TAG,
+ SENDER_COMMAND,
DEVICE_NAME,
TRANSFER_FAILED_COMMAND_NAME
)
+ private fun getNoLongerCloseToReceiverCommand(): Array<String> =
+ arrayOf(
+ SENDER_COMMAND,
+ DEVICE_NAME,
+ NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME
+ )
+
class EmptyCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
}
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 e9ddf3d..509ae33 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
@@ -26,6 +26,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.mediattt.IUndoTransferCallback
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -53,12 +54,13 @@
@Test
fun moveCloserToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
- controllerSender.displayChip(moveCloserToStartCast())
+ val state = moveCloserToStartCast()
+ controllerSender.displayChip(state)
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.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -66,12 +68,13 @@
@Test
fun moveCloserToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
- controllerSender.displayChip(moveCloserToEndCast())
+ val state = moveCloserToEndCast()
+ controllerSender.displayChip(state)
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.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -79,40 +82,59 @@
@Test
fun transferToReceiverTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
- controllerSender.displayChip(transferToReceiverTriggered())
+ val state = transferToReceiverTriggered()
+ controllerSender.displayChip(state)
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.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() {
- controllerSender.displayChip(transferSucceeded())
+ 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()).contains(DEVICE_NAME)
+ 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 transferToReceiverSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
+ val state = transferToReceiverSucceeded()
+ 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.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
}
@Test
- fun transferSucceededNullUndoRunnable_noUndo() {
- controllerSender.displayChip(transferSucceeded(undoRunnable = null))
+ fun transferToReceiverSucceeded_nullUndoRunnable_noUndo() {
+ controllerSender.displayChip(transferToReceiverSucceeded(undoCallback = null))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
}
@Test
- fun transferSucceededWithUndoRunnable_undoWithClick() {
- controllerSender.displayChip(transferSucceeded { })
+ fun transferToReceiverSucceeded_withUndoRunnable_undoWithClick() {
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ }
+ controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -120,24 +142,103 @@
}
@Test
- fun transferSucceededWithUndoRunnable_undoButtonClickRunsRunnable() {
- var runnableRun = false
- val runnable = Runnable { runnableRun = true }
+ fun transferToReceiverSucceeded_withUndoRunnable_undoButtonClickRunsRunnable() {
+ var undoCallbackCalled = false
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {
+ undoCallbackCalled = true
+ }
+ }
- controllerSender.displayChip(transferSucceeded(undoRunnable = runnable))
+ controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
- assertThat(runnableRun).isTrue()
+ assertThat(undoCallbackCalled).isTrue()
}
@Test
- fun transferFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
- controllerSender.displayChip(transferFailed())
+ fun transferToReceiverSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggered() {
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ }
+ controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+
+ getChipView().getUndoButton().performClick()
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferToThisDeviceTriggered().getChipTextString(context))
+ }
+
+ @Test
+ fun transferToThisDeviceSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
+ val state = transferToThisDeviceSucceeded()
+ controllerSender.displayChip(state)
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.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
+ assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun transferToThisDeviceSucceeded_nullUndoRunnable_noUndo() {
+ controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback = null))
+
+ val chipView = getChipView()
+ assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun transferToThisDeviceSucceeded_withUndoRunnable_undoWithClick() {
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ }
+ controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+
+ val chipView = getChipView()
+ assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
+ assertThat(chipView.getUndoButton().hasOnClickListeners()).isTrue()
+ }
+
+ @Test
+ fun transferToThisDeviceSucceeded_withUndoRunnable_undoButtonClickRunsRunnable() {
+ var undoCallbackCalled = false
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {
+ undoCallbackCalled = true
+ }
+ }
+
+ controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+ getChipView().getUndoButton().performClick()
+
+ assertThat(undoCallbackCalled).isTrue()
+ }
+
+ @Test
+ fun transferToThisDeviceSucceeded_undoButtonClick_switchesToTransferToReceiverTriggered() {
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ }
+ controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+
+ getChipView().getUndoButton().performClick()
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferToReceiverTriggered().getChipTextString(context))
+ }
+
+ @Test
+ fun transferFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
+ val state = transferFailed()
+ 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.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE)
@@ -154,7 +255,7 @@
@Test
fun changeFromTransferTriggeredToTransferSucceeded_loadingIconDisappears() {
controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(transferSucceeded())
+ controllerSender.displayChip(transferToReceiverSucceeded())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
}
@@ -162,14 +263,20 @@
@Test
fun changeFromTransferTriggeredToTransferSucceeded_undoButtonAppears() {
controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(transferSucceeded { })
+ controllerSender.displayChip(
+ transferToReceiverSucceeded(
+ object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ }
+ )
+ )
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.VISIBLE)
}
@Test
fun changeFromTransferSucceededToMoveCloserToStart_undoButtonDisappears() {
- controllerSender.displayChip(transferSucceeded())
+ controllerSender.displayChip(transferToReceiverSucceeded())
controllerSender.displayChip(moveCloserToStartCast())
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
@@ -214,13 +321,23 @@
TransferToReceiverTriggered(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
/** Helper method providing default parameters to not clutter up the tests. */
- private fun transferSucceeded(
- undoRunnable: Runnable? = null
- ) = TransferSucceeded(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoRunnable)
+ private fun transferToThisDeviceTriggered() =
+ TransferToThisDeviceTriggered(appIconDrawable, APP_ICON_CONTENT_DESC)
/** Helper method providing default parameters to not clutter up the tests. */
- private fun transferFailed() =
- TransferFailed(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+ private fun transferToReceiverSucceeded(undoCallback: IUndoTransferCallback? = null) =
+ TransferToReceiverSucceeded(
+ appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoCallback
+ )
+
+ /** Helper method providing default parameters to not clutter up the tests. */
+ private fun transferToThisDeviceSucceeded(undoCallback: IUndoTransferCallback? = null) =
+ TransferToThisDeviceSucceeded(
+ appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoCallback
+ )
+
+ /** Helper method providing default parameters to not clutter up the tests. */
+ private fun transferFailed() = TransferFailed(appIconDrawable, APP_ICON_CONTENT_DESC)
}
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 ca90945..11b727e 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
@@ -4,7 +4,8 @@
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.shared.mediattt.IDeviceSenderService
+import com.android.systemui.shared.mediattt.IUndoTransferCallback
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -18,8 +19,7 @@
@SmallTest
class MediaTttSenderServiceTest : SysuiTestCase() {
- private lateinit var service: MediaTttSenderService
- private lateinit var callback: IDeviceSenderCallback
+ private lateinit var service: IDeviceSenderService
@Mock
private lateinit var controller: MediaTttChipControllerSender
@@ -31,50 +31,94 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- service = MediaTttSenderService(context, controller)
- callback = IDeviceSenderCallback.Stub.asInterface(service.onBind(null))
+ val mediaTttSenderService = MediaTttSenderService(context, controller)
+ service = IDeviceSenderService.Stub.asInterface(mediaTttSenderService.onBind(null))
}
@Test
fun closeToReceiverToStartCast_controllerTriggeredWithCorrectState() {
val name = "Fake name"
- callback.closeToReceiverToStartCast(mediaInfo, DeviceInfo(name))
+ service.closeToReceiverToStartCast(mediaInfo, DeviceInfo(name))
val chipStateCaptor = argumentCaptor<MoveCloserToStartCast>()
verify(controller).displayChip(capture(chipStateCaptor))
val chipState = chipStateCaptor.value!!
- assertThat(chipState.otherDeviceName).isEqualTo(name)
+ assertThat(chipState.getChipTextString(context)).contains(name)
}
@Test
fun closeToReceiverToEndCast_controllerTriggeredWithCorrectState() {
val name = "Fake name"
- callback.closeToReceiverToEndCast(mediaInfo, DeviceInfo(name))
+ service.closeToReceiverToEndCast(mediaInfo, DeviceInfo(name))
val chipStateCaptor = argumentCaptor<MoveCloserToEndCast>()
verify(controller).displayChip(capture(chipStateCaptor))
val chipState = chipStateCaptor.value!!
- assertThat(chipState.otherDeviceName).isEqualTo(name)
+ assertThat(chipState.getChipTextString(context)).contains(name)
+ }
+
+ @Test
+ fun transferToThisDeviceTriggered_controllerTriggeredWithCorrectState() {
+ service.transferToThisDeviceTriggered(mediaInfo, DeviceInfo("Fake name"))
+
+ verify(controller).displayChip(any<TransferToThisDeviceTriggered>())
}
@Test
fun transferToReceiverTriggered_controllerTriggeredWithCorrectState() {
val name = "Fake name"
- callback.transferToReceiverTriggered(mediaInfo, DeviceInfo(name))
+ service.transferToReceiverTriggered(mediaInfo, DeviceInfo(name))
val chipStateCaptor = argumentCaptor<TransferToReceiverTriggered>()
verify(controller).displayChip(capture(chipStateCaptor))
val chipState = chipStateCaptor.value!!
- assertThat(chipState.otherDeviceName).isEqualTo(name)
+ assertThat(chipState.getChipTextString(context)).contains(name)
+ }
+
+ @Test
+ fun transferToReceiverSucceeded_controllerTriggeredWithCorrectState() {
+ val name = "Fake name"
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ }
+ service.transferToReceiverSucceeded(mediaInfo, DeviceInfo(name), undoCallback)
+
+ val chipStateCaptor = argumentCaptor<TransferToReceiverSucceeded>()
+ verify(controller).displayChip(capture(chipStateCaptor))
+
+ val chipState = chipStateCaptor.value!!
+ assertThat(chipState.getChipTextString(context)).contains(name)
+ assertThat(chipState.undoCallback).isEqualTo(undoCallback)
+ }
+
+ @Test
+ fun transferToThisDeviceSucceeded_controllerTriggeredWithCorrectState() {
+ val undoCallback = object : IUndoTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ }
+ service.transferToThisDeviceSucceeded(mediaInfo, DeviceInfo("name"), undoCallback)
+
+ val chipStateCaptor = argumentCaptor<TransferToThisDeviceSucceeded>()
+ verify(controller).displayChip(capture(chipStateCaptor))
+
+ val chipState = chipStateCaptor.value!!
+ assertThat(chipState.undoCallback).isEqualTo(undoCallback)
}
@Test
fun transferFailed_controllerTriggeredWithTransferFailedState() {
- callback.transferFailed(mediaInfo, DeviceInfo("Fake name"))
+ service.transferFailed(mediaInfo, DeviceInfo("Fake name"))
verify(controller).displayChip(any<TransferFailed>())
}
+
+ @Test
+ fun noLongerCloseToReceiver_controllerRemoveChipTriggered() {
+ service.noLongerCloseToReceiver(mediaInfo, DeviceInfo("Fake name"))
+
+ verify(controller).removeChip()
+ }
}