Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca400ac4 authored by Caitlin Cassidy's avatar Caitlin Cassidy
Browse files

[Media TTT] Add TransferToThisDeviceSucceeded callback.

Bug: 203800643
Bug: 203800347
Test: verify `adb shell cmd statusbar media-ttt-chip-add-sender Device
TransferToThisDeviceSucceeded` shows the chip
Test: media.taptotransfer tests

Change-Id: Iba98b91617e25126e03c99d03e0a628994e6516a
parent 5852540a
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -101,6 +101,22 @@ interface IDeviceSenderService {
        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.
     *
+23 −1
Original line number Diff line number Diff line
@@ -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.TransferToThisDeviceSucceeded
import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered
import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded
import com.android.systemui.shared.mediattt.DeviceInfo
@@ -108,7 +109,7 @@ class MediaTttCommandLineHelper @Inject constructor(
                TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME -> {
                    val undoCallback = object : IUndoTransferCallback.Stub() {
                        override fun onUndoTriggered() {
                            Log.i(TAG, "Undo callback triggered")
                            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 ->
@@ -122,6 +123,23 @@ class MediaTttCommandLineHelper @Inject constructor(
                            .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 { senderService ->
                        senderService.transferFailed(mediaInfo, otherDeviceInfo)
@@ -134,6 +152,7 @@ class MediaTttCommandLineHelper @Inject constructor(
                            "$TRANSFER_TO_RECEIVER_TRIGGERED_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
                    )
                }
@@ -245,6 +264,9 @@ val TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME =
@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!!

private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon"
+73 −8
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.media.taptotransfer.sender

import android.content.Context
import android.graphics.drawable.Drawable
import android.view.View
import com.android.systemui.R
import com.android.systemui.media.taptotransfer.common.MediaTttChipState
import com.android.systemui.shared.mediattt.IUndoTransferCallback
@@ -37,7 +38,18 @@ sealed class ChipStateSender(
    abstract fun getChipTextString(context: Context): String

    /** Returns true if the loading icon should be displayed and false otherwise. */
    abstract fun showLoading(): Boolean
    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
}

/**
@@ -55,8 +67,6 @@ class MoveCloserToStartCast(
    override fun getChipTextString(context: Context): String {
        return context.getString(R.string.media_move_closer_to_start_cast, otherDeviceName)
    }

    override fun showLoading() = false
}

/**
@@ -74,8 +84,6 @@ class MoveCloserToEndCast(
    override fun getChipTextString(context: Context): String {
        return context.getString(R.string.media_move_closer_to_end_cast, otherDeviceName)
    }

    override fun showLoading() = false
}

/**
@@ -128,7 +136,66 @@ class TransferToReceiverSucceeded(
        return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName)
    }

    override fun showLoading() = false
    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. */
@@ -139,6 +206,4 @@ class TransferFailed(
    override fun getChipTextString(context: Context): String {
        return context.getString(R.string.media_transfer_failed)
    }

    override fun showLoading() = false
}
+2 −22
Original line number Diff line number Diff line
@@ -53,30 +53,10 @@ class MediaTttChipControllerSender @Inject constructor(
            if (chipState.showLoading()) { View.VISIBLE } else { View.GONE }

        // Undo
        val undoClickListener: View.OnClickListener? =
            if (chipState is TransferToReceiverSucceeded && chipState.undoCallback != null)
                View.OnClickListener {
                    chipState.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.
                    displayChip(
                        TransferToThisDeviceTriggered(
                            chipState.appIconDrawable,
                            chipState.appIconContentDescription
                        )
                    )
                }
            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
+22 −0
Original line number Diff line number Diff line
@@ -78,6 +78,16 @@ class MediaTttSenderService @Inject constructor(
                mediaInfo, otherDeviceInfo, undoCallback
            )
        }

        override fun transferToThisDeviceSucceeded(
            mediaInfo: MediaRoute2Info,
            otherDeviceInfo: DeviceInfo,
            undoCallback: IUndoTransferCallback
        ) {
            this@MediaTttSenderService.transferToThisDeviceSucceeded(
                mediaInfo, otherDeviceInfo, undoCallback
            )
        }
    }

    // TODO(b/203800643): Use the app icon from the media info instead of a fake one.
@@ -146,4 +156,16 @@ class MediaTttSenderService @Inject constructor(
        )
        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)
    }
}
Loading