Add "list" and "any_external" options to shade_display_override command
Those options allow to list the available displays (and see which one had the shade), and set the shade window on the first non-default display without caring about display ids.
+ Small refactor to use dagger in ShadePrimaryDisplayCommand and decouple it from ShadeDisplaysRepository
To use them "adb shell cmd statusbar shade_display_override list" or "any_external"
Bug: 362719719
Bug: 374264564
Test: ShadePrimaryDisplayCommandTest
Flag: com.android.systemui.shade_window_goes_around
Change-Id: Ib2be5359c2cd77e903bb7db592354d63cee17a09
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
similarity index 69%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
index 4e7839e..af01547 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
@@ -21,7 +21,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.ShadePrimaryDisplayCommand
import com.android.systemui.statusbar.commandline.commandRegistry
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -34,13 +36,16 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-class ShadeDisplaysRepositoryTest : SysuiTestCase() {
+class ShadePrimaryDisplayCommandTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val commandRegistry = kosmos.commandRegistry
+ private val displayRepository = kosmos.displayRepository
+ private val shadeDisplaysRepository = ShadeDisplaysRepositoryImpl()
private val pw = PrintWriter(StringWriter())
- private val underTest = ShadeDisplaysRepositoryImpl(commandRegistry)
+ private val underTest =
+ ShadePrimaryDisplayCommand(commandRegistry, displayRepository, shadeDisplaysRepository)
@Before
fun setUp() {
@@ -50,7 +55,7 @@
@Test
fun commandDisplayOverride_updatesDisplayId() =
testScope.runTest {
- val displayId by collectLastValue(underTest.displayId)
+ val displayId by collectLastValue(shadeDisplaysRepository.displayId)
assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
val newDisplayId = 2
@@ -65,7 +70,7 @@
@Test
fun commandShadeDisplayOverride_resetsDisplayId() =
testScope.runTest {
- val displayId by collectLastValue(underTest.displayId)
+ val displayId by collectLastValue(shadeDisplaysRepository.displayId)
assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
val newDisplayId = 2
@@ -78,4 +83,17 @@
commandRegistry.onShellCommand(pw, arrayOf("shade_display_override", "reset"))
assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
}
+
+ @Test
+ fun commandShadeDisplayOverride_anyExternalDisplay_notOnDefaultAnymore() =
+ testScope.runTest {
+ val displayId by collectLastValue(shadeDisplaysRepository.displayId)
+ assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
+ val newDisplayId = 2
+ displayRepository.addDisplay(displayId = newDisplayId)
+
+ commandRegistry.onShellCommand(pw, arrayOf("shade_display_override", "any_external"))
+
+ assertThat(displayId).isEqualTo(newDisplayId)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index fed4a26..4f73a345 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -164,10 +164,8 @@
@Provides
@IntoMap
- @ClassKey(ShadeDisplaysRepositoryImpl::class)
- fun provideShadePositionRepositoryAsCoreStartable(
- impl: ShadeDisplaysRepositoryImpl
- ): CoreStartable {
+ @ClassKey(ShadePrimaryDisplayCommand::class)
+ fun provideShadePrimaryDisplayCommand(impl: ShadePrimaryDisplayCommand): CoreStartable {
return if (ShadeWindowGoesAround.isEnabled) {
impl
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
index 506b4e9..a5d9e96 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
@@ -17,40 +17,107 @@
package com.android.systemui.shade
import android.view.Display
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
import java.io.PrintWriter
+import javax.inject.Inject
-class ShadePrimaryDisplayCommand(private val positionRepository: ShadeDisplaysRepository) :
- Command {
+@SysUISingleton
+class ShadePrimaryDisplayCommand
+@Inject
+constructor(
+ private val commandRegistry: CommandRegistry,
+ private val displaysRepository: DisplayRepository,
+ private val positionRepository: ShadeDisplaysRepository,
+) : Command, CoreStartable {
- override fun execute(pw: PrintWriter, args: List<String>) {
- if (args[0].lowercase() == "reset") {
- positionRepository.resetDisplayId()
- pw.println("Reset shade primary display id to ${Display.DEFAULT_DISPLAY}")
- return
- }
-
- val displayId: Int =
- try {
- args[0].toInt()
- } catch (e: NumberFormatException) {
- pw.println("Error: task id should be an integer")
- return
- }
-
- if (displayId < 0) {
- pw.println("Error: display id should be positive integer")
- }
-
- positionRepository.setDisplayId(displayId)
- pw.println("New shade primary display id is $displayId")
+ override fun start() {
+ commandRegistry.registerCommand("shade_display_override") { this }
}
override fun help(pw: PrintWriter) {
pw.println("shade_display_override <displayId> ")
pw.println("Set the display which is holding the shade.")
+ pw.println()
pw.println("shade_display_override reset ")
pw.println("Reset the display which is holding the shade.")
+ pw.println()
+ pw.println("shade_display_override (list|status) ")
+ pw.println("Lists available displays and which has the shade")
+ pw.println()
+ pw.println("shade_display_override any_external")
+ pw.println("Moves the shade to the first not-default display available")
+ }
+
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ CommandHandler(pw, args).execute()
+ }
+
+ /** Wrapper class to avoid propagating [PrintWriter] to all methods. */
+ private inner class CommandHandler(
+ private val pw: PrintWriter,
+ private val args: List<String>,
+ ) {
+
+ fun execute() {
+ when (val command = args.getOrNull(0)?.lowercase()) {
+ "reset" -> reset()
+ "list",
+ "status" -> printStatus()
+ "any_external" -> anyExternal()
+ else -> {
+ val cmdAsInteger = command?.toIntOrNull()
+ if (cmdAsInteger != null) {
+ changeDisplay(displayId = cmdAsInteger)
+ } else {
+ help(pw)
+ }
+ }
+ }
+ }
+
+ private fun reset() {
+ positionRepository.resetDisplayId()
+ pw.println("Reset shade primary display id to ${Display.DEFAULT_DISPLAY}")
+ }
+
+ private fun printStatus() {
+ val displays = displaysRepository.displays.value
+ val shadeDisplay = positionRepository.displayId.value
+ pw.println("Available displays: ")
+ displays.forEach {
+ pw.print(" - ${it.displayId}")
+ pw.println(if (it.displayId == shadeDisplay) " (Shade window is here)" else "")
+ }
+ }
+
+ private fun anyExternal() {
+ val anyExternalDisplay =
+ displaysRepository.displays.value.firstOrNull {
+ it.displayId != Display.DEFAULT_DISPLAY
+ }
+ if (anyExternalDisplay == null) {
+ pw.println("No external displays available.")
+ return
+ }
+ setDisplay(anyExternalDisplay.displayId)
+ }
+
+ private fun changeDisplay(displayId: Int) {
+ if (displayId < 0) {
+ pw.println("Error: display id should be positive integer")
+ }
+
+ setDisplay(displayId)
+ }
+
+ private fun setDisplay(id: Int) {
+ positionRepository.setDisplayId(id)
+ pw.println("New shade primary display id is $id")
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
index e920aba..4a95e33 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
@@ -17,10 +17,7 @@
package com.android.systemui.shade.data.repository
import android.view.Display
-import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.shade.ShadePrimaryDisplayCommand
-import com.android.systemui.statusbar.commandline.CommandRegistry
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -41,9 +38,7 @@
/** Source of truth for the display currently holding the shade. */
@SysUISingleton
-class ShadeDisplaysRepositoryImpl
-@Inject
-constructor(private val commandRegistry: CommandRegistry) : ShadeDisplaysRepository, CoreStartable {
+class ShadeDisplaysRepositoryImpl @Inject constructor() : ShadeDisplaysRepository {
private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
override val displayId: StateFlow<Int>
@@ -56,10 +51,4 @@
override fun resetDisplayId() {
_displayId.value = Display.DEFAULT_DISPLAY
}
-
- override fun start() {
- commandRegistry.registerCommand("shade_display_override") {
- ShadePrimaryDisplayCommand(this)
- }
- }
}