Loading packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt +18 −5 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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() } Loading Loading @@ -76,10 +79,20 @@ class MediaTttChipController @Inject constructor( if (showLoading) { View.VISIBLE } else { View.GONE } // Undo val showUndo = chipState is TransferSucceeded currentChipView.requireViewById<View>(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<View>(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) } Loading packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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) packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +8 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 " + Loading @@ -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 Loading packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt +31 −10 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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.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.getUndoButtonVisibility()).isEqualTo(View.VISIBLE) 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 Loading @@ -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 Loading @@ -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 = Loading @@ -150,8 +172,7 @@ class MediaTttChipControllerTest : SysuiTestCase() { private fun LinearLayout.getLoadingIconVisibility(): Int = this.requireViewById<View>(R.id.loading).visibility private fun LinearLayout.getUndoButtonVisibility(): Int = this.requireViewById<View>(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) Loading Loading
packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt +18 −5 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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() } Loading Loading @@ -76,10 +79,20 @@ class MediaTttChipController @Inject constructor( if (showLoading) { View.VISIBLE } else { View.GONE } // Undo val showUndo = chipState is TransferSucceeded currentChipView.requireViewById<View>(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<View>(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) } Loading
packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt +5 −1 Original line number Diff line number Diff line Loading @@ -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)
packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +8 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 " + Loading @@ -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 Loading
packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt +31 −10 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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.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.getUndoButtonVisibility()).isEqualTo(View.VISIBLE) 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 Loading @@ -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 Loading @@ -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 = Loading @@ -150,8 +172,7 @@ class MediaTttChipControllerTest : SysuiTestCase() { private fun LinearLayout.getLoadingIconVisibility(): Int = this.requireViewById<View>(R.id.loading).visibility private fun LinearLayout.getUndoButtonVisibility(): Int = this.requireViewById<View>(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) Loading