diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt index 1ec6a39347ca3..376fea28cf82a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt @@ -16,6 +16,7 @@ package com.android.systemui.media.taptotransfer +import android.annotation.SuppressLint import android.content.Context import android.graphics.PixelFormat import android.view.Gravity @@ -28,6 +29,8 @@ import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject +const val TAG = "MediaTapToTransfer" + /** * A controller to display and hide the Media Tap-To-Transfer chip. This chip is shown when a user * is currently playing media on a local "media cast sender" device (e.g. a phone) and gets close @@ -40,14 +43,14 @@ class MediaTttChipController @Inject constructor( private val windowManager: WindowManager, ) { + @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY private val windowLayoutParams = WindowManager.LayoutParams().apply { width = WindowManager.LayoutParams.WRAP_CONTENT height = WindowManager.LayoutParams.WRAP_CONTENT gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY + flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL title = "Media Tap-To-Transfer Chip View" - flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) format = PixelFormat.TRANSLUCENT setTrustedOverlay() } @@ -76,10 +79,20 @@ class MediaTttChipController @Inject constructor( if (showLoading) { View.VISIBLE } else { View.GONE } // Undo - val showUndo = chipState is TransferSucceeded - currentChipView.requireViewById(R.id.undo).visibility = - if (showUndo) { View.VISIBLE } else { View.GONE } + val undoClickListener: View.OnClickListener? = + if (chipState is TransferSucceeded && chipState.undoRunnable != null) + View.OnClickListener { chipState.undoRunnable.run() } + else + null + val undoView = currentChipView.requireViewById(R.id.undo) + undoView.visibility = if (undoClickListener != null) { + View.VISIBLE + } else { + View.GONE + } + undoView.setOnClickListener(undoClickListener) + // Add view if necessary if (oldChipView == null) { windowManager.addView(chipView, windowLayoutParams) } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt index 05b9552a0a713..3b3adfd2297b9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt @@ -50,7 +50,11 @@ class TransferInitiated( /** * 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. */ class TransferSucceeded( - otherDeviceName: String + otherDeviceName: String, + val undoRunnable: Runnable? = null ) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName) 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 9f05c92ff4431..6a02dabb98132 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -16,6 +16,7 @@ package com.android.systemui.media.taptotransfer +import android.util.Log import androidx.annotation.VisibleForTesting import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.commandline.Command @@ -48,7 +49,9 @@ class MediaTttCommandLineHelper @Inject constructor( mediaTttChipController.displayChip(TransferInitiated(otherDeviceName)) } TRANSFER_SUCCEEDED_COMMAND_NAME -> { - mediaTttChipController.displayChip(TransferSucceeded(otherDeviceName)) + mediaTttChipController.displayChip( + TransferSucceeded(otherDeviceName, fakeUndoRunnable) + ) } else -> { pw.println("Chip type must be one of " + @@ -75,6 +78,10 @@ class MediaTttCommandLineHelper @Inject constructor( pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_TAG") } } + + private val fakeUndoRunnable = Runnable { + Log.i(TAG, "Undo runnable triggered") + } } @VisibleForTesting diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt index 50d94dd6ca5f6..bc0cff18d281b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt @@ -89,7 +89,7 @@ class MediaTttChipControllerTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) - assertThat(chipView.getUndoButtonVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) } @Test @@ -99,17 +99,39 @@ class MediaTttChipControllerTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE) - assertThat(chipView.getUndoButtonVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) } @Test - fun transferSucceeded_chipTextContainsDeviceName_noLoadingIcon_undo() { - mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME)) + fun transferSucceededNullUndoRunnable_chipTextContainsDeviceName_noLoadingIcon_noUndo() { + mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME, undoRunnable = null)) val chipView = getChipView() assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) - assertThat(chipView.getUndoButtonVisibility()).isEqualTo(View.VISIBLE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + } + + @Test + fun transferSucceededWithUndoRunnable_chipTextContainsDeviceName_noLoadingIcon_undoWithClick() { + mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME) { }) + + val chipView = getChipView() + assertThat(chipView.getChipText()).contains(DEVICE_NAME) + assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE) + assertThat(chipView.getUndoButton().hasOnClickListeners()).isTrue() + } + + @Test + fun transferSucceededWithUndoRunnable_undoButtonClickRunsRunnable() { + var runnableRun = false + val runnable = Runnable { runnableRun = true } + + mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME, runnable)) + getChipView().getUndoButton().performClick() + + assertThat(runnableRun).isTrue() } @Test @@ -131,9 +153,9 @@ class MediaTttChipControllerTest : SysuiTestCase() { @Test fun changeFromTransferInitiatedToTransferSucceeded_undoButtonAppears() { mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME)) - mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME)) + mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME) { }) - assertThat(getChipView().getUndoButtonVisibility()).isEqualTo(View.VISIBLE) + assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.VISIBLE) } @Test @@ -141,7 +163,7 @@ class MediaTttChipControllerTest : SysuiTestCase() { mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME)) mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME)) - assertThat(getChipView().getUndoButtonVisibility()).isEqualTo(View.GONE) + assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE) } private fun LinearLayout.getChipText(): String = @@ -150,8 +172,7 @@ class MediaTttChipControllerTest : SysuiTestCase() { private fun LinearLayout.getLoadingIconVisibility(): Int = this.requireViewById(R.id.loading).visibility - private fun LinearLayout.getUndoButtonVisibility(): Int = - this.requireViewById(R.id.undo).visibility + private fun LinearLayout.getUndoButton(): View = this.requireViewById(R.id.undo) private fun getChipView(): LinearLayout { val viewCaptor = ArgumentCaptor.forClass(View::class.java)