diff --git a/packages/SystemUI/res/drawable/media_ttt_chip_background.xml b/packages/SystemUI/res/drawable/media_ttt_chip_background.xml
new file mode 100644
index 0000000000000..3abf4d72c5386
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_ttt_chip_background.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/layout/media_ttt_chip.xml b/packages/SystemUI/res/layout/media_ttt_chip.xml
new file mode 100644
index 0000000000000..5b3590bfb0a79
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_ttt_chip.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a437ae6169995..89c9a359af439 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -976,6 +976,10 @@
4dp
16sp
+
+ 16dp
+ 16sp
+
35dp
15dp
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 300cb2d38dffd..180c8ae982c0d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2173,6 +2173,14 @@
Play %1$s from %2$s
+
+
+ Undo
+
+ Move closer to play on %1$s
+
+ Playing on %1$s
+
Inactive, check app
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 237d0771bec20..cf679f070c3a1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -83,6 +83,6 @@ public interface MediaModule {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
}
- return Optional.of(new MediaTttChipController(context, commandRegistry, windowManager));
+ return Optional.of(new MediaTttChipController(commandRegistry, context, windowManager));
}
}
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 85e5b336575b9..9964d881ff925 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
@@ -19,9 +19,13 @@ package com.android.systemui.media.taptotransfer
import android.content.Context
import android.graphics.PixelFormat
import android.view.Gravity
+import android.view.LayoutInflater
import android.view.WindowManager
+import android.widget.LinearLayout
import android.widget.TextView
+import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
@@ -36,8 +40,8 @@ import javax.inject.Inject
*/
@SysUISingleton
class MediaTttChipController @Inject constructor(
- context: Context,
commandRegistry: CommandRegistry,
+ private val context: Context,
private val windowManager: WindowManager,
) {
init {
@@ -46,9 +50,9 @@ class MediaTttChipController @Inject constructor(
}
private val windowLayoutParams = WindowManager.LayoutParams().apply {
- width = WindowManager.LayoutParams.MATCH_PARENT
- height = WindowManager.LayoutParams.MATCH_PARENT
- gravity = Gravity.CENTER_HORIZONTAL
+ width = WindowManager.LayoutParams.WRAP_CONTENT
+ height = WindowManager.LayoutParams.WRAP_CONTENT
+ gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
title = "Media Tap-To-Transfer Chip View"
flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -57,29 +61,61 @@ class MediaTttChipController @Inject constructor(
setTrustedOverlay()
}
- // TODO(b/203800327): Create a layout that matches UX.
- private val chipView: TextView = TextView(context).apply {
- text = "Media Tap-To-Transfer Chip"
- }
+ /** The chip view currently being displayed. Null if the chip is not being displayed. */
+ private var chipView: LinearLayout? = null
- private var chipDisplaying: Boolean = false
+ private fun displayChip(chipType: ChipType, otherDeviceName: String) {
+ val oldChipView = chipView
+ if (chipView == null) {
+ chipView = LayoutInflater
+ .from(context)
+ .inflate(R.layout.media_ttt_chip, null) as LinearLayout
+ }
+ val currentChipView = chipView!!
- private fun addChip() {
- if (chipDisplaying) { return }
- windowManager.addView(chipView, windowLayoutParams)
- chipDisplaying = true
+ // Text
+ currentChipView.requireViewById(R.id.text).apply {
+ text = context.getString(chipType.chipText, otherDeviceName)
+ }
+
+ if (oldChipView == null) {
+ windowManager.addView(chipView, windowLayoutParams)
+ }
}
private fun removeChip() {
- if (!chipDisplaying) { return }
+ if (chipView == null) { return }
windowManager.removeView(chipView)
- chipDisplaying = false
+ chipView = null
+ }
+
+ @VisibleForTesting
+ enum class ChipType(
+ @StringRes internal val chipText: Int
+ ) {
+ MOVE_CLOSER_TO_TRANSFER(R.string.media_move_closer_to_transfer),
+ TRANSFER_INITIATED(R.string.media_transfer_playing),
+ TRANSFER_SUCCEEDED(R.string.media_transfer_playing),
}
inner class AddChipCommand : Command {
- override fun execute(pw: PrintWriter, args: List) = addChip()
+ override fun execute(pw: PrintWriter, args: List) {
+ val chipTypeArg = args[1]
+ ChipType.values().forEach {
+ if (it.name == chipTypeArg) {
+ displayChip(it, otherDeviceName = args[0])
+ return
+ }
+ }
+
+ pw.println("Chip type must be one of " +
+ ChipType.values().map { it.name }.reduce { acc, s -> "$acc, $s" })
+ }
+
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_TAG")
+ pw.println(
+ "Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_TAG "
+ )
}
}
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 efb493123a338..9438ee3dace2b 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
@@ -16,14 +16,20 @@
package com.android.systemui.media.taptotransfer
+import android.view.View
import android.view.WindowManager
+import android.widget.LinearLayout
+import android.widget.TextView
import androidx.test.filters.SmallTest
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
@@ -48,7 +54,7 @@ class MediaTttChipControllerTest : SysuiTestCase() {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- mediaTttChipController = MediaTttChipController(context, commandRegistry, windowManager)
+ mediaTttChipController = MediaTttChipController(commandRegistry, context, windowManager)
}
@Test(expected = IllegalStateException::class)
@@ -71,24 +77,24 @@ class MediaTttChipControllerTest : SysuiTestCase() {
@Test
fun addChipCommand_chipAdded() {
- commandRegistry.onShellCommand(pw, arrayOf(MediaTttChipController.ADD_CHIP_COMMAND_TAG))
+ commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand())
verify(windowManager).addView(any(), any())
}
@Test
fun addChipCommand_twice_chipNotAddedTwice() {
- commandRegistry.onShellCommand(pw, arrayOf(MediaTttChipController.ADD_CHIP_COMMAND_TAG))
+ commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand())
reset(windowManager)
- commandRegistry.onShellCommand(pw, arrayOf(MediaTttChipController.ADD_CHIP_COMMAND_TAG))
+ commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand())
verify(windowManager, never()).addView(any(), any())
}
@Test
fun removeChipCommand_chipRemoved() {
// First, add the chip
- commandRegistry.onShellCommand(pw, arrayOf(MediaTttChipController.ADD_CHIP_COMMAND_TAG))
+ commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand())
// Then, remove it
commandRegistry.onShellCommand(pw, arrayOf(MediaTttChipController.REMOVE_CHIP_COMMAND_TAG))
@@ -103,6 +109,55 @@ class MediaTttChipControllerTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any())
}
+ @Test
+ fun moveCloserToTransfer_chipTextContainsDeviceName() {
+ commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand())
+
+ assertThat(getChipText()).contains(DEVICE_NAME)
+ }
+
+ @Test
+ fun transferInitiated_chipTextContainsDeviceName() {
+ commandRegistry.onShellCommand(pw, getTransferInitiatedCommand())
+
+ assertThat(getChipText()).contains(DEVICE_NAME)
+ }
+
+ @Test
+ fun transferSucceeded_chipTextContainsDeviceName() {
+ commandRegistry.onShellCommand(pw, getTransferSucceededCommand())
+
+ assertThat(getChipText()).contains(DEVICE_NAME)
+ }
+
+ private fun getMoveCloserToTransferCommand(): Array =
+ arrayOf(
+ MediaTttChipController.ADD_CHIP_COMMAND_TAG,
+ DEVICE_NAME,
+ MediaTttChipController.ChipType.MOVE_CLOSER_TO_TRANSFER.name
+ )
+
+ private fun getTransferInitiatedCommand(): Array =
+ arrayOf(
+ MediaTttChipController.ADD_CHIP_COMMAND_TAG,
+ DEVICE_NAME,
+ MediaTttChipController.ChipType.TRANSFER_INITIATED.name
+ )
+
+ private fun getTransferSucceededCommand(): Array =
+ arrayOf(
+ MediaTttChipController.ADD_CHIP_COMMAND_TAG,
+ DEVICE_NAME,
+ MediaTttChipController.ChipType.TRANSFER_SUCCEEDED.name
+ )
+
+ private fun getChipText(): String {
+ val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+ verify(windowManager).addView(viewCaptor.capture(), any())
+ val chipView = viewCaptor.value as LinearLayout
+ return (chipView.requireViewById(R.id.text) as TextView).text as String
+ }
+
class EmptyCommand : Command {
override fun execute(pw: PrintWriter, args: List) {
}
@@ -111,3 +166,5 @@ class MediaTttChipControllerTest : SysuiTestCase() {
}
}
}
+
+private const val DEVICE_NAME = "My Tablet"