Use WindowManager callback for add/remove system decorations in DisplayRepository.
Bug: 412580790
Test: DisplayRepositoryTest
Flag: com.android.window.flags.enable_sys_decors_callbacks_via_wm
Change-Id: Ib7a9285e1becf14647e106f8e525de0ea515a07f
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 388ceb0..848c6c0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -18,11 +18,14 @@
import android.hardware.display.DisplayManager
import android.os.fakeHandler
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper
import android.view.Display
import android.view.Display.DEFAULT_DISPLAY
import android.view.Display.TYPE_EXTERNAL
import android.view.Display.TYPE_INTERNAL
+import android.view.IDisplayWindowListener
import android.view.mockIWindowManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -37,6 +40,7 @@
import com.android.systemui.statusbar.mockCommandQueue
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.window.flags.Flags
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@@ -48,6 +52,7 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.eq
import org.mockito.kotlin.whenever
@@ -64,6 +69,7 @@
private val displayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
private val commandQueueCallbacks = kotlinArgumentCaptor<CommandQueue.Callbacks>()
private val connectedDisplayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
+ private lateinit var wmListener: IDisplayWindowListener
private val testHandler = kosmos.fakeHandler
private val testScope = kosmos.testScope
@@ -517,6 +523,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_onStart_emitsDisplaysWithSystemDecorations() =
testScope.runTest {
setDisplays(0, 1, 2)
@@ -530,6 +537,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_systemDecorationAdded_emitsIncludingNewDisplayIds() =
testScope.runTest {
setDisplays(0)
@@ -543,6 +551,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_systemDecorationAdded_emitsToNewSubscribers() =
testScope.runTest {
setDisplays(0)
@@ -558,6 +567,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_systemDecorationRemoved_doesNotEmitRemovedDisplayId() =
testScope.runTest {
val lastDisplayIdsWithSystemDecorations by latestDisplayIdsWithSystemDecorationsValue()
@@ -570,6 +580,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_systemDecorationsRemoved_nonExistentDisplay_noEffect() =
testScope.runTest {
val lastDisplayIdsWithSystemDecorations by latestDisplayIdsWithSystemDecorationsValue()
@@ -581,6 +592,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_displayRemoved_doesNotEmitRemovedDisplayId() =
testScope.runTest {
val lastDisplayIdsWithSystemDecorations by latestDisplayIdsWithSystemDecorationsValue()
@@ -593,6 +605,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_displayRemoved_nonExistentDisplay_noEffect() =
testScope.runTest {
val lastDisplayIdsWithSystemDecorations by latestDisplayIdsWithSystemDecorationsValue()
@@ -604,6 +617,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_onFlowCollection_commandQueueCallbackRegistered() =
testScope.runTest {
val lastDisplayIdsWithSystemDecorations by latestDisplayIdsWithSystemDecorationsValue()
@@ -614,6 +628,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
fun displayIdsWithSystemDecorations_afterFlowCollection_commandQueueCallbackUnregistered() {
testScope.runTest {
val lastDisplayIdsWithSystemDecorations by latestDisplayIdsWithSystemDecorationsValue()
@@ -626,6 +641,100 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
+ fun displayIdsWithSystemDecorations_withWmCallback_systemDecorationAdded_emitsIncludingNewDisplayIds() =
+ testScope.runTest {
+ setDisplays(0)
+ whenever(windowManager.shouldShowSystemDecors(0)).thenReturn(true)
+ val lastDisplayIdsWithSystemDecorations by
+ collectLastValue(displayRepository.displayIdsWithSystemDecorations)
+ captureWmListener()
+
+ wmListener.onDisplayAddSystemDecorations(2)
+ wmListener.onDisplayAddSystemDecorations(3)
+
+ assertThat(lastDisplayIdsWithSystemDecorations).containsExactly(0, 2, 3)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
+ fun displayIdsWithSystemDecorations_withWmCallback_systemDecorationAdded_emitsToNewSubscribers() =
+ testScope.runTest {
+ setDisplays(0)
+ whenever(windowManager.shouldShowSystemDecors(0)).thenReturn(true)
+
+ val priorDisplayIdsWithSystemDecorations by
+ collectLastValue(displayRepository.displayIdsWithSystemDecorations)
+ captureWmListener()
+ wmListener.onDisplayAddSystemDecorations(1)
+ assertThat(priorDisplayIdsWithSystemDecorations).containsExactly(0, 1)
+
+ val lastDisplayIdsWithSystemDecorations by
+ collectLastValue(displayRepository.displayIdsWithSystemDecorations)
+ assertThat(lastDisplayIdsWithSystemDecorations).containsExactly(0, 1)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
+ fun displayIdsWithSystemDecorations_withWmCallback_systemDecorationAdded_doesNotEmitRemovedDisplayId() =
+ testScope.runTest {
+ val lastDisplayIdsWithSystemDecorations by
+ collectLastValue(displayRepository.displayIdsWithSystemDecorations)
+ captureWmListener()
+
+ wmListener.onDisplayAddSystemDecorations(1)
+ wmListener.onDisplayAddSystemDecorations(2)
+ wmListener.onDisplayRemoveSystemDecorations(2)
+
+ assertThat(lastDisplayIdsWithSystemDecorations).containsExactly(1)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
+ fun displayIdsWithSystemDecorations_withWmCallback_systemDecorationsRemoved_nonExistentDisplay_noEffect() =
+ testScope.runTest {
+ val lastDisplayIdsWithSystemDecorations by
+ collectLastValue(displayRepository.displayIdsWithSystemDecorations)
+ captureWmListener()
+
+ wmListener.onDisplayAddSystemDecorations(1)
+ wmListener.onDisplayRemoveSystemDecorations(2)
+
+ assertThat(lastDisplayIdsWithSystemDecorations).containsExactly(1)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
+ fun displayIdsWithSystemDecorations_withWmCallback_displayRemoved_doesNotEmitRemovedDisplayId() =
+ testScope.runTest {
+ val lastDisplayIdsWithSystemDecorations by
+ collectLastValue(displayRepository.displayIdsWithSystemDecorations)
+ captureAddedRemovedListener()
+ captureWmListener()
+
+ wmListener.onDisplayAddSystemDecorations(1)
+ wmListener.onDisplayAddSystemDecorations(2)
+ sendOnDisplayRemoved(2)
+
+ assertThat(lastDisplayIdsWithSystemDecorations).containsExactly(1)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_SYS_DECORS_CALLBACKS_VIA_WM)
+ fun displayIdsWithSystemDecorations_withWmCallback_displayRemoved_nonExistentDisplay_noEffect() =
+ testScope.runTest {
+ val lastDisplayIdsWithSystemDecorations by
+ collectLastValue(displayRepository.displayIdsWithSystemDecorations)
+ captureAddedRemovedListener()
+ captureWmListener()
+
+ wmListener.onDisplayAddSystemDecorations(1)
+ sendOnDisplayRemoved(2)
+
+ assertThat(lastDisplayIdsWithSystemDecorations).containsExactly(1)
+ }
+
+ @Test
fun getDisplay_slowMappingToDisplay_returnsRegardless() =
testScope.runTest {
val displayIds by collectLastValue(displayRepository.displayIds)
@@ -766,4 +875,10 @@
val idsToSet = ids.toSet() + DEFAULT_DISPLAY
setDisplays(idsToSet.map { display(type = TYPE_EXTERNAL, id = it) })
}
+
+ private fun captureWmListener() {
+ val captor = argumentCaptor<IDisplayWindowListener>()
+ verify(windowManager).registerDisplayWindowListener(captor.capture())
+ wmListener = captor.firstValue
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index 5a9f919..d37a4a2 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -18,20 +18,22 @@
import android.hardware.display.DisplayManager
import android.os.Handler
+import android.view.IWindowManager
import com.android.app.displaylib.DisplayLibBackground
import com.android.app.displaylib.DisplayLibComponent
+import com.android.app.displaylib.DisplaysWithDecorationsRepository
import com.android.app.displaylib.PerDisplayRepository
import com.android.app.displaylib.createDisplayLibComponent
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.DisplayLib
import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.display.data.repository.DeviceStateRepositoryImpl
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.data.repository.DisplayRepositoryImpl
import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepositoryImpl
-import com.android.systemui.display.data.repository.DisplaysWithDecorationsRepository
import com.android.systemui.display.data.repository.DisplaysWithDecorationsRepositoryImpl
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
@@ -123,12 +125,14 @@
@SysUISingleton
fun displayLibComponent(
displayManager: DisplayManager,
+ windowManager: IWindowManager,
@Background backgroundHandler: Handler,
@Background bgApplicationScope: CoroutineScope,
@Background backgroundCoroutineDispatcher: CoroutineDispatcher,
): DisplayLibComponent {
return createDisplayLibComponent(
displayManager,
+ windowManager,
backgroundHandler,
bgApplicationScope,
backgroundCoroutineDispatcher,
@@ -142,4 +146,13 @@
): com.android.app.displaylib.DisplayRepository {
return displayLibComponent.displayRepository
}
+
+ @Provides
+ @SysUISingleton
+ @DisplayLib
+ fun providesDisplaysWithDecorationsRepositoryFromLib(
+ displayLibComponent: DisplayLibComponent
+ ): DisplaysWithDecorationsRepository {
+ return displayLibComponent.displaysWithDecorationsRepository
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/dagger/SystemUIDisplaySubcomponent.kt b/packages/SystemUI/src/com/android/systemui/display/dagger/SystemUIDisplaySubcomponent.kt
index c83b99c..cd53751 100644
--- a/packages/SystemUI/src/com/android/systemui/display/dagger/SystemUIDisplaySubcomponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/dagger/SystemUIDisplaySubcomponent.kt
@@ -54,4 +54,10 @@
/** Annotates the display id inside the subcomponent. */
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DisplayId
+
+ /**
+ * Annotates the displaylib implementation of a class.
+ * TODO(b/408503553): Remove this annotation once the flag is cleaned up.
+ */
+ @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DisplayLib
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 01bbf2d..9e72fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -17,7 +17,10 @@
package com.android.systemui.display.data.repository
import com.android.app.displaylib.DisplayRepository as DisplayRepositoryFromLib
+import com.android.app.displaylib.DisplaysWithDecorationsRepository
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.DisplayLib
+import com.android.window.flags.Flags.enableSysDecorsCallbacksViaWm
import javax.inject.Inject
/**
@@ -34,7 +37,13 @@
constructor(
private val displayRepositoryFromLib: com.android.app.displaylib.DisplayRepository,
private val displaysWithDecorationsRepositoryImpl: DisplaysWithDecorationsRepository,
+ @DisplayLib
+ private val displaysWithDecorationsRepositoryImplFromLib: DisplaysWithDecorationsRepository,
) :
DisplayRepositoryFromLib by displayRepositoryFromLib,
- DisplaysWithDecorationsRepository by displaysWithDecorationsRepositoryImpl,
+ DisplaysWithDecorationsRepository by (if (enableSysDecorsCallbacksViaWm()) {
+ displaysWithDecorationsRepositoryImplFromLib
+ } else {
+ displaysWithDecorationsRepositoryImpl
+ }),
DisplayRepository
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepositoryImpl.kt
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt
rename to packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepositoryImpl.kt
index f4a2ed4..cc3081c 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepositoryImpl.kt
@@ -17,6 +17,7 @@
package com.android.systemui.display.data.repository
import android.view.IWindowManager
+import com.android.app.displaylib.DisplaysWithDecorationsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.CommandQueue
@@ -33,12 +34,6 @@
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn
-/** Provides the displays with decorations. */
-interface DisplaysWithDecorationsRepository {
- /** A [StateFlow] that maintains a set of display IDs that should have system decorations. */
- val displayIdsWithSystemDecorations: StateFlow<Set<Int>>
-}
-
@SysUISingleton
class DisplaysWithDecorationsRepositoryImpl
@Inject
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt
index ce1d06d3..bcb6633 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt
@@ -76,7 +76,18 @@
displayRepositoryFromDisplayLib,
)
}
+val Kosmos.displaysWithDecorationsRepositoryFromDisplayLib by Fixture {
+ com.android.app.displaylib.DisplaysWithDecorationsRepositoryImpl(
+ mockIWindowManager,
+ testScope.backgroundScope,
+ displayRepositoryFromDisplayLib,
+ )
+}
val Kosmos.realDisplayRepository by Fixture {
- DisplayRepositoryImpl(displayRepositoryFromDisplayLib, displayWithDecorationsRepository)
+ DisplayRepositoryImpl(
+ displayRepositoryFromDisplayLib,
+ displayWithDecorationsRepository,
+ displaysWithDecorationsRepositoryFromDisplayLib,
+ )
}