summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt)59
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt113
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt108
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt179
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt73
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarInitializerStoreTest.kt97
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt49
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt2
10 files changed, 397 insertions, 369 deletions
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
index faaa4c415d28..1dd8ca9221a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
@@ -14,23 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.window
+package com.android.systemui.display.data.repository
-import android.platform.test.annotations.EnableFlags
import android.view.Display
-import android.view.WindowManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.app.viewcapture.ViewCaptureAwareWindowManager
-import com.android.app.viewcapture.mockViewCaptureAwareWindowManager
import com.android.systemui.SysuiTestCase
-import com.android.systemui.display.data.repository.displayRepository
-import com.android.systemui.display.data.repository.fakeDisplayWindowPropertiesRepository
-import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.unconfinedTestDispatcher
-import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
@@ -43,28 +35,13 @@ import org.mockito.kotlin.mock
@RunWith(AndroidJUnit4::class)
@SmallTest
-@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
-class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
+class PerDisplayStoreImplTest : SysuiTestCase() {
private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher }
private val testScope = kosmos.testScope
private val fakeDisplayRepository = kosmos.displayRepository
- private val store =
- MultiDisplayStatusBarWindowControllerStore(
- backgroundApplicationScope = kosmos.applicationCoroutineScope,
- controllerFactory = kosmos.fakeStatusBarWindowControllerFactory,
- displayWindowPropertiesRepository = kosmos.fakeDisplayWindowPropertiesRepository,
- viewCaptureAwareWindowManagerFactory =
- object : ViewCaptureAwareWindowManager.Factory {
- override fun create(
- windowManager: WindowManager
- ): ViewCaptureAwareWindowManager {
- return kosmos.mockViewCaptureAwareWindowManager
- }
- },
- displayRepository = fakeDisplayRepository,
- )
+ private val store = kosmos.fakePerDisplayStore
@Before
fun start() {
@@ -80,34 +57,52 @@ class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
@Test
fun forDisplay_defaultDisplay_multipleCalls_returnsSameInstance() =
testScope.runTest {
- val controller = store.defaultDisplay
+ val instance = store.defaultDisplay
- assertThat(store.defaultDisplay).isSameInstanceAs(controller)
+ assertThat(store.defaultDisplay).isSameInstanceAs(instance)
}
@Test
fun forDisplay_nonDefaultDisplay_multipleCalls_returnsSameInstance() =
testScope.runTest {
- val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+ val instance = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
- assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isSameInstanceAs(controller)
+ assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isSameInstanceAs(instance)
}
@Test
fun forDisplay_nonDefaultDisplay_afterDisplayRemoved_returnsNewInstance() =
testScope.runTest {
- val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+ val instance = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
fakeDisplayRepository.removeDisplay(NON_DEFAULT_DISPLAY_ID)
fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
- assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isNotSameInstanceAs(controller)
+ assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isNotSameInstanceAs(instance)
}
@Test(expected = IllegalArgumentException::class)
fun forDisplay_nonExistingDisplayId_throws() =
testScope.runTest { store.forDisplay(NON_EXISTING_DISPLAY_ID) }
+ @Test
+ fun forDisplay_afterDisplayRemoved_onDisplayRemovalActionInvoked() =
+ testScope.runTest {
+ val instance = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+ fakeDisplayRepository.removeDisplay(NON_DEFAULT_DISPLAY_ID)
+
+ assertThat(store.removalActions).containsExactly(instance)
+ }
+
+ @Test
+ fun forDisplay_withoutDisplayRemoval_onDisplayRemovalActionIsNotInvoked() =
+ testScope.runTest {
+ store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+ assertThat(store.removalActions).isEmpty()
+ }
+
private fun createDisplay(displayId: Int): Display = mock {
on { getDisplayId() } doReturn displayId
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
index c804fc6990ae..ba5fb7f8df00 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -98,7 +98,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
var chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
@@ -135,7 +135,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
@@ -164,8 +164,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
val chipWidth = 30
val dotWidth = 10
val isRtl = false
- val contentRect =
- Rect(/* left = */ 0, /* top = */ 10, /* right = */ 1000, /* bottom = */ 100)
+ val contentRect = Rect(/* left= */ 0, /* top= */ 10, /* right= */ 1000, /* bottom= */ 100)
val chipBounds =
getPrivacyChipBoundingRectForInsets(contentRect, dotWidth, chipWidth, isRtl)
@@ -207,7 +206,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -228,7 +227,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -251,7 +250,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -263,7 +262,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
minLeftPadding,
0,
screenBounds.height() - dcBounds.height() - dotWidth,
- sbHeightLandscape
+ sbHeightLandscape,
)
bounds =
@@ -278,7 +277,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -320,7 +319,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -331,7 +330,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
protectionBounds.bottom,
0,
screenBounds.height() - minRightPadding,
- sbHeightLandscape
+ sbHeightLandscape,
)
bounds =
@@ -346,7 +345,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -369,7 +368,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -381,7 +380,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
minLeftPadding,
0,
screenBounds.height() - protectionBounds.bottom - dotWidth,
- sbHeightLandscape
+ sbHeightLandscape,
)
bounds =
@@ -396,7 +395,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -415,7 +414,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
left = screenBounds.right - dcWidth,
top = 0,
right = screenBounds.right,
- bottom = dcHeight
+ bottom = dcHeight,
)
val dcBoundsLandscape = Rect(left = 0, top = 0, right = dcHeight, bottom = dcWidth)
val dcBoundsSeascape =
@@ -423,14 +422,14 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
left = screenBounds.right - dcHeight,
top = screenBounds.bottom - dcWidth,
right = screenBounds.right - dcHeight,
- bottom = screenBounds.bottom - dcWidth
+ bottom = screenBounds.bottom - dcWidth,
)
val dcBoundsUpsideDown =
Rect(
left = 0,
top = screenBounds.bottom - dcHeight,
right = dcWidth,
- bottom = screenBounds.bottom - dcHeight
+ bottom = screenBounds.bottom - dcHeight,
)
val minLeftPadding = 20
val minRightPadding = 20
@@ -448,7 +447,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
left = minLeftPadding,
top = 0,
right = dcBoundsPortrait.left - dotWidth,
- bottom = sbHeightPortrait
+ bottom = sbHeightPortrait,
)
var bounds =
@@ -463,7 +462,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -475,7 +474,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
left = dcBoundsLandscape.height(),
top = 0,
right = screenBounds.height() - minRightPadding,
- bottom = sbHeightLandscape
+ bottom = sbHeightLandscape,
)
bounds =
@@ -490,7 +489,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -502,7 +501,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
left = minLeftPadding,
top = 0,
right = screenBounds.width() - minRightPadding,
- bottom = sbHeightPortrait
+ bottom = sbHeightPortrait,
)
bounds =
@@ -517,7 +516,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -529,7 +528,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
left = minLeftPadding,
top = 0,
right = screenBounds.height() - minRightPadding,
- bottom = sbHeightLandscape
+ bottom = sbHeightLandscape,
)
bounds =
@@ -544,7 +543,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -584,7 +583,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -595,7 +594,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
protectionBounds.bottom,
0,
screenBounds.height() - minRightPadding,
- sbHeightLandscape
+ sbHeightLandscape,
)
bounds =
@@ -610,7 +609,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -633,7 +632,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -645,7 +644,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
minLeftPadding,
0,
screenBounds.height() - protectionBounds.bottom - dotWidth,
- sbHeightLandscape
+ sbHeightLandscape,
)
bounds =
@@ -660,7 +659,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -682,7 +681,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl = false,
dotWidth = 10,
bottomAlignedMargin = BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight = 15
+ statusBarContentHeight = 15,
)
assertThat(bounds.top).isEqualTo(0)
@@ -704,7 +703,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl = false,
dotWidth = 10,
bottomAlignedMargin = 5,
- statusBarContentHeight = 15
+ statusBarContentHeight = 15,
)
// Content in the status bar is centered vertically. To achieve the bottom margin we want,
@@ -756,7 +755,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -777,7 +776,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -798,7 +797,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -809,7 +808,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
minLeftPadding,
0,
screenBounds.height() - dcBounds.height() - dotWidth,
- sbHeightLandscape
+ sbHeightLandscape,
)
bounds =
@@ -824,7 +823,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -860,7 +859,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -880,7 +879,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -900,7 +899,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -920,7 +919,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -958,7 +957,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
isRtl,
dotWidth,
BOTTOM_ALIGNED_MARGIN_NONE,
- statusBarContentHeight
+ statusBarContentHeight,
)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -968,12 +967,12 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
fun testDisplayChanged_returnsUpdatedInsets() {
// GIVEN: get insets on the first display and switch to the second display
val provider =
- StatusBarContentInsetsProvider(
+ StatusBarContentInsetsProviderImpl(
contextMock,
configurationController,
mock<DumpManager>(),
mock<CommandRegistry>(),
- mock<SysUICutoutProvider>()
+ mock<SysUICutoutProvider>(),
)
configuration.windowConfiguration.setMaxBounds(Rect(0, 0, 1080, 2160))
@@ -993,12 +992,12 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
// GIVEN: get insets on the first display, switch to the second display,
// get insets and switch back
val provider =
- StatusBarContentInsetsProvider(
+ StatusBarContentInsetsProviderImpl(
contextMock,
configurationController,
mock<DumpManager>(),
mock<CommandRegistry>(),
- mock<SysUICutoutProvider>()
+ mock<SysUICutoutProvider>(),
)
configuration.windowConfiguration.setMaxBounds(Rect(0, 0, 1080, 2160))
@@ -1024,12 +1023,12 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100)
configurationController.onConfigurationChanged(configuration)
val provider =
- StatusBarContentInsetsProvider(
+ StatusBarContentInsetsProviderImpl(
contextMock,
configurationController,
mock<DumpManager>(),
mock<CommandRegistry>(),
- mock<SysUICutoutProvider>()
+ mock<SysUICutoutProvider>(),
)
val listener =
object : StatusBarContentInsetsChangedListener {
@@ -1053,12 +1052,12 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
fun onDensityOrFontScaleChanged_listenerNotified() {
configuration.densityDpi = 12
val provider =
- StatusBarContentInsetsProvider(
+ StatusBarContentInsetsProviderImpl(
contextMock,
configurationController,
mock<DumpManager>(),
mock<CommandRegistry>(),
- mock<SysUICutoutProvider>()
+ mock<SysUICutoutProvider>(),
)
val listener =
object : StatusBarContentInsetsChangedListener {
@@ -1081,12 +1080,12 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
@Test
fun onThemeChanged_listenerNotified() {
val provider =
- StatusBarContentInsetsProvider(
+ StatusBarContentInsetsProviderImpl(
contextMock,
configurationController,
mock<DumpManager>(),
mock<CommandRegistry>(),
- mock<SysUICutoutProvider>()
+ mock<SysUICutoutProvider>(),
)
val listener =
object : StatusBarContentInsetsChangedListener {
@@ -1108,13 +1107,13 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
expected: Rect,
actual: Rect,
@Rotation currentRotation: Int,
- @Rotation targetRotation: Int
+ @Rotation targetRotation: Int,
) {
assertTrue(
"Rects must match. currentRotation=${RotationUtils.toString(currentRotation)}" +
" targetRotation=${RotationUtils.toString(targetRotation)}" +
" expected=$expected actual=$actual",
- expected.equals(actual)
+ expected.equals(actual),
)
}
@@ -1126,7 +1125,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
left: Rect = Rect(),
top: Rect = Rect(),
right: Rect = Rect(),
- bottom: Rect = Rect()
+ bottom: Rect = Rect(),
) {
whenever(dc.boundingRects)
.thenReturn(listOf(left, top, right, bottom).filter { !it.isEmpty })
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
new file mode 100644
index 000000000000..2ce3e43389fa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.view.Display
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.qualifiers.Background
+import java.io.PrintWriter
+import java.util.concurrent.ConcurrentHashMap
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/** Provides per display instances of [T]. */
+interface PerDisplayStore<T> {
+
+ /**
+ * The instance for the default/main display of the device. For example, on a phone or a tablet,
+ * the default display is the internal/built-in display of the device.
+ *
+ * Note that the id of the default display is [Display.DEFAULT_DISPLAY].
+ */
+ val defaultDisplay: T
+
+ /**
+ * Returns an instance for a specific display id.
+ *
+ * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
+ * displays.
+ */
+ fun forDisplay(displayId: Int): T
+}
+
+abstract class PerDisplayStoreImpl<T>(
+ @Background private val backgroundApplicationScope: CoroutineScope,
+ private val displayRepository: DisplayRepository,
+) : PerDisplayStore<T>, CoreStartable {
+
+ private val perDisplayInstances = ConcurrentHashMap<Int, T>()
+
+ /**
+ * The instance for the default/main display of the device. For example, on a phone or a tablet,
+ * the default display is the internal/built-in display of the device.
+ *
+ * Note that the id of the default display is [Display.DEFAULT_DISPLAY].
+ */
+ override val defaultDisplay: T
+ get() = forDisplay(Display.DEFAULT_DISPLAY)
+
+ /**
+ * Returns an instance for a specific display id.
+ *
+ * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
+ * displays.
+ */
+ override fun forDisplay(displayId: Int): T {
+ if (displayRepository.getDisplay(displayId) == null) {
+ throw IllegalArgumentException("Display with id $displayId doesn't exist.")
+ }
+ return perDisplayInstances.computeIfAbsent(displayId) {
+ createInstanceForDisplay(displayId)
+ }
+ }
+
+ abstract fun createInstanceForDisplay(displayId: Int): T
+
+ override fun start() {
+ val instanceType = instanceClass.simpleName
+ backgroundApplicationScope.launch(CoroutineName("PerDisplayStore#<$instanceType>start")) {
+ displayRepository.displayRemovalEvent.collect { removedDisplayId ->
+ val removedInstance = perDisplayInstances.remove(removedDisplayId)
+ removedInstance?.let { onDisplayRemovalAction(it) }
+ }
+ }
+ }
+
+ abstract val instanceClass: Class<T>
+
+ /**
+ * Will be called when the display associated with [instance] was removed. It allows to perform
+ * any clean up if needed.
+ */
+ open suspend fun onDisplayRemovalAction(instance: T) {}
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println(perDisplayInstances)
+ }
+}
+
+class SingleDisplayStore<T>(defaultInstance: T) : PerDisplayStore<T> {
+ override val defaultDisplay: T = defaultInstance
+
+ override fun forDisplay(displayId: Int): T = defaultDisplay
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
index 6c3802676f26..041f0b0fdf93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
@@ -16,88 +16,52 @@
package com.android.systemui.statusbar.core
-import android.view.Display
-import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.PerDisplayStore
+import com.android.systemui.display.data.repository.PerDisplayStoreImpl
+import com.android.systemui.display.data.repository.SingleDisplayStore
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
-import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
/** Provides per display instances of [StatusBarInitializer]. */
-interface StatusBarInitializerStore {
- /**
- * The instance for the default/main display of the device. For example, on a phone or a tablet,
- * the default display is the internal/built-in display of the device.
- *
- * Note that the id of the default display is [Display.DEFAULT_DISPLAY].
- */
- val defaultDisplay: StatusBarInitializer
-
- /**
- * Returns an instance for a specific display id.
- *
- * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
- * displays.
- */
- fun forDisplay(displayId: Int): StatusBarInitializer
-}
+interface StatusBarInitializerStore : PerDisplayStore<StatusBarInitializer>
@SysUISingleton
class MultiDisplayStatusBarInitializerStore
@Inject
constructor(
- @Background private val backgroundApplicationScope: CoroutineScope,
+ @Background backgroundApplicationScope: CoroutineScope,
+ displayRepository: DisplayRepository,
private val factory: StatusBarInitializer.Factory,
- private val displayRepository: DisplayRepository,
private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
-) : StatusBarInitializerStore, CoreStartable {
+) :
+ StatusBarInitializerStore,
+ PerDisplayStoreImpl<StatusBarInitializer>(backgroundApplicationScope, displayRepository) {
init {
StatusBarConnectedDisplays.assertInNewMode()
}
- private val perDisplayInitializers = ConcurrentHashMap<Int, StatusBarInitializer>()
-
- override val defaultDisplay: StatusBarInitializer
- get() = forDisplay(Display.DEFAULT_DISPLAY)
-
- override fun forDisplay(displayId: Int): StatusBarInitializer {
- if (displayRepository.getDisplay(displayId) == null) {
- throw IllegalArgumentException("Display with id $displayId doesn't exist.")
- }
- return perDisplayInitializers.computeIfAbsent(displayId) {
- factory.create(
- statusBarWindowController = statusBarWindowControllerStore.forDisplay(displayId)
- )
- }
+ override fun createInstanceForDisplay(displayId: Int): StatusBarInitializer {
+ return factory.create(
+ statusBarWindowController = statusBarWindowControllerStore.forDisplay(displayId)
+ )
}
- override fun start() {
- backgroundApplicationScope.launch(
- CoroutineName("MultiDisplayStatusBarInitializerStore#start")
- ) {
- displayRepository.displayRemovalEvent.collect { removedDisplayId ->
- perDisplayInitializers.remove(removedDisplayId)
- }
- }
- }
+ override val instanceClass = StatusBarInitializer::class.java
}
@SysUISingleton
class SingleDisplayStatusBarInitializerStore
@Inject
-constructor(private val defaultInstance: StatusBarInitializer) : StatusBarInitializerStore {
+constructor(defaultInitializer: StatusBarInitializer) :
+ StatusBarInitializerStore,
+ PerDisplayStore<StatusBarInitializer> by SingleDisplayStore(defaultInitializer) {
init {
StatusBarConnectedDisplays.assertInLegacyMode()
}
-
- override val defaultDisplay: StatusBarInitializer = defaultInstance
-
- override fun forDisplay(displayId: Int): StatusBarInitializer = defaultInstance
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 5aad11fe1034..f6f4503b210a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -17,17 +17,20 @@
package com.android.systemui.statusbar.dagger
import android.content.Context
-import com.android.app.viewcapture.ViewCaptureAwareWindowManager
import com.android.systemui.CoreStartable
+import com.android.systemui.SysUICutoutProvider
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.data.StatusBarDataLayerModule
import com.android.systemui.statusbar.phone.LightBarController
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
+import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl
import com.android.systemui.statusbar.window.MultiDisplayStatusBarWindowControllerStore
import com.android.systemui.statusbar.window.SingleDisplayStatusBarWindowControllerStore
@@ -108,5 +111,16 @@ abstract class StatusBarModule {
fun provideOngoingCallLogBuffer(factory: LogBufferFactory): LogBuffer {
return factory.create("OngoingCall", 75)
}
+
+ @Provides
+ @SysUISingleton
+ fun contentInsetsProvider(
+ factory: StatusBarContentInsetsProviderImpl.Factory,
+ context: Context,
+ configurationController: ConfigurationController,
+ sysUICutoutProvider: SysUICutoutProvider,
+ ): StatusBarContentInsetsProvider {
+ return factory.create(context, configurationController, sysUICutoutProvider)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
index 613efaa148f5..c6f6bd90fce6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
@@ -34,10 +34,10 @@ import com.android.systemui.Dumpable
import com.android.systemui.StatusBarInsetsCommand
import com.android.systemui.SysUICutoutInformation
import com.android.systemui.SysUICutoutProvider
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.res.R
import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl.CacheKey
import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
@@ -47,9 +47,11 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
import com.android.systemui.util.leak.RotationUtils.Rotation
import com.android.systemui.util.leak.RotationUtils.getExactRotation
import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import java.io.PrintWriter
import java.lang.Math.max
-import javax.inject.Inject
/**
* Encapsulates logic that can solve for the left/right insets required for the status bar contents.
@@ -64,19 +66,87 @@ import javax.inject.Inject
*
* NOTE: This class is not threadsafe
*/
-@SysUISingleton
-class StatusBarContentInsetsProvider
-@Inject
+interface StatusBarContentInsetsProvider :
+ CallbackController<StatusBarContentInsetsChangedListener> {
+
+ /**
+ * Some views may need to care about whether or not the current top display cutout is located in
+ * the corner rather than somewhere in the center. In the case of a corner cutout, the status
+ * bar area is contiguous.
+ */
+ fun currentRotationHasCornerCutout(): Boolean
+
+ /**
+ * Calculates the maximum bounding rectangle for the privacy chip animation + ongoing privacy
+ * dot in the coordinates relative to the given rotation.
+ *
+ * @param rotation the rotation for which the bounds are required. This is an absolute value
+ * (i.e., ROTATION_NONE will always return the same bounds regardless of the context from
+ * which this method is called)
+ */
+ fun getBoundingRectForPrivacyChipForRotation(
+ @Rotation rotation: Int,
+ displayCutout: DisplayCutout?,
+ ): Rect
+
+ /**
+ * Calculate the distance from the left, right and top edges of the screen to the status bar
+ * content area. This differs from the content area rects in that these values can be used
+ * directly as padding.
+ *
+ * @param rotation the target rotation for which to calculate insets
+ */
+ fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Insets
+
+ /**
+ * Calculate the insets for the status bar content in the device's current rotation
+ *
+ * @see getStatusBarContentAreaForRotation
+ */
+ fun getStatusBarContentInsetsForCurrentRotation(): Insets
+
+ /**
+ * Calculates the area of the status bar contents invariant of the current device rotation, in
+ * the target rotation's coordinates
+ *
+ * @param rotation the rotation for which the bounds are required. This is an absolute value
+ * (i.e., ROTATION_NONE will always return the same bounds regardless of the context from
+ * which this method is called)
+ */
+ fun getStatusBarContentAreaForRotation(@Rotation rotation: Int): Rect
+
+ /** Get the status bar content area for the given rotation, in absolute bounds */
+ fun getStatusBarContentAreaForCurrentRotation(): Rect
+
+ fun getStatusBarPaddingTop(@Rotation rotation: Int? = null): Int
+
+ interface Factory {
+ fun create(
+ context: Context,
+ configurationController: ConfigurationController,
+ sysUICutoutProvider: SysUICutoutProvider,
+ ): StatusBarContentInsetsProvider
+ }
+}
+
+class StatusBarContentInsetsProviderImpl
+@AssistedInject
constructor(
- val context: Context,
- val configurationController: ConfigurationController,
+ @Assisted val context: Context,
+ @Assisted val configurationController: ConfigurationController,
val dumpManager: DumpManager,
val commandRegistry: CommandRegistry,
- val sysUICutoutProvider: SysUICutoutProvider,
-) :
- CallbackController<StatusBarContentInsetsChangedListener>,
- ConfigurationController.ConfigurationListener,
- Dumpable {
+ @Assisted val sysUICutoutProvider: SysUICutoutProvider,
+) : StatusBarContentInsetsProvider, ConfigurationController.ConfigurationListener, Dumpable {
+
+ @AssistedFactory
+ interface Factory : StatusBarContentInsetsProvider.Factory {
+ override fun create(
+ context: Context,
+ configurationController: ConfigurationController,
+ sysUICutoutProvider: SysUICutoutProvider,
+ ): StatusBarContentInsetsProviderImpl
+ }
// Limit cache size as potentially we may connect large number of displays
// (e.g. network displays)
@@ -95,7 +165,7 @@ constructor(
object : StatusBarInsetsCommand.Callback {
override fun onExecute(
command: StatusBarInsetsCommand,
- printWriter: PrintWriter
+ printWriter: PrintWriter,
) {
executeCommand(command, printWriter)
}
@@ -133,12 +203,7 @@ constructor(
listeners.forEach { it.onStatusBarContentInsetsChanged() }
}
- /**
- * Some views may need to care about whether or not the current top display cutout is located in
- * the corner rather than somewhere in the center. In the case of a corner cutout, the status
- * bar area is contiguous.
- */
- fun currentRotationHasCornerCutout(): Boolean {
+ override fun currentRotationHasCornerCutout(): Boolean {
val cutout = checkNotNull(context.display).cutout ?: return false
val topBounds = cutout.boundingRectTop
@@ -148,17 +213,9 @@ constructor(
return topBounds.left <= 0 || topBounds.right >= point.x
}
- /**
- * Calculates the maximum bounding rectangle for the privacy chip animation + ongoing privacy
- * dot in the coordinates relative to the given rotation.
- *
- * @param rotation the rotation for which the bounds are required. This is an absolute value
- * (i.e., ROTATION_NONE will always return the same bounds regardless of the context from
- * which this method is called)
- */
- fun getBoundingRectForPrivacyChipForRotation(
+ override fun getBoundingRectForPrivacyChipForRotation(
@Rotation rotation: Int,
- displayCutout: DisplayCutout?
+ displayCutout: DisplayCutout?,
): Rect {
val key = getCacheKey(rotation, displayCutout)
var insets = insetsCache[key]
@@ -176,14 +233,7 @@ constructor(
return getPrivacyChipBoundingRectForInsets(insets, dotWidth, chipWidth, isRtl)
}
- /**
- * Calculate the distance from the left, right and top edges of the screen to the status bar
- * content area. This differs from the content area rects in that these values can be used
- * directly as padding.
- *
- * @param rotation the target rotation for which to calculate insets
- */
- fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Insets =
+ override fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Insets =
traceSection(tag = "StatusBarContentInsetsProvider.getStatusBarContentInsetsForRotation") {
val sysUICutout = sysUICutoutProvider.cutoutInfoForCurrentDisplayAndRotation()
val displayCutout = sysUICutout?.cutout
@@ -202,31 +252,17 @@ constructor(
rotation,
sysUICutout,
getResourcesForRotation(rotation, context),
- key
+ key,
)
Insets.of(area.left, area.top, /* right= */ width - area.right, /* bottom= */ 0)
}
- /**
- * Calculate the insets for the status bar content in the device's current rotation
- *
- * @see getStatusBarContentAreaForRotation
- */
- fun getStatusBarContentInsetsForCurrentRotation(): Insets {
+ override fun getStatusBarContentInsetsForCurrentRotation(): Insets {
return getStatusBarContentInsetsForRotation(getExactRotation(context))
}
- /**
- * Calculates the area of the status bar contents invariant of the current device rotation, in
- * the target rotation's coordinates
- *
- * @param rotation the rotation for which the bounds are required. This is an absolute value
- * (i.e., ROTATION_NONE will always return the same bounds regardless of the context from
- * which this method is called)
- */
- @JvmOverloads
- fun getStatusBarContentAreaForRotation(@Rotation rotation: Int): Rect {
+ override fun getStatusBarContentAreaForRotation(@Rotation rotation: Int): Rect {
val sysUICutout = sysUICutoutProvider.cutoutInfoForCurrentDisplayAndRotation()
val displayCutout = sysUICutout?.cutout
val key = getCacheKey(rotation, displayCutout)
@@ -235,12 +271,11 @@ constructor(
rotation,
sysUICutout,
getResourcesForRotation(rotation, context),
- key
+ key,
)
}
- /** Get the status bar content area for the given rotation, in absolute bounds */
- fun getStatusBarContentAreaForCurrentRotation(): Rect {
+ override fun getStatusBarContentAreaForCurrentRotation(): Rect {
val rotation = getExactRotation(context)
return getStatusBarContentAreaForRotation(rotation)
}
@@ -249,7 +284,7 @@ constructor(
@Rotation targetRotation: Int,
sysUICutout: SysUICutoutInformation?,
rotatedResources: Resources,
- key: CacheKey
+ key: CacheKey,
): Rect {
return getCalculatedAreaForRotation(sysUICutout, targetRotation, rotatedResources).also {
insetsCache.put(key, it)
@@ -259,7 +294,7 @@ constructor(
private fun getCalculatedAreaForRotation(
sysUICutout: SysUICutoutInformation?,
@Rotation targetRotation: Int,
- rotatedResources: Resources
+ rotatedResources: Resources,
): Rect {
val currentRotation = getExactRotation(context)
@@ -299,7 +334,7 @@ constructor(
configurationController.isLayoutRtl,
dotWidth,
bottomAlignedMargin,
- statusBarContentHeight
+ statusBarContentHeight,
)
}
@@ -349,7 +384,7 @@ constructor(
return resources.getDimensionPixelSize(dimenRes)
}
- fun getStatusBarPaddingTop(@Rotation rotation: Int? = null): Int {
+ override fun getStatusBarPaddingTop(@Rotation rotation: Int?): Int {
val res = rotation?.let { it -> getResourcesForRotation(it, context) } ?: context.resources
return res.getDimensionPixelSize(R.dimen.status_bar_padding_top)
}
@@ -364,13 +399,13 @@ constructor(
CacheKey(
rotation = rotation,
displaySize = Rect(context.resources.configuration.windowConfiguration.maxBounds),
- displayCutout = displayCutout
+ displayCutout = displayCutout,
)
private data class CacheKey(
@Rotation val rotation: Int,
val displaySize: Rect,
- val displayCutout: DisplayCutout?
+ val displayCutout: DisplayCutout?,
)
}
@@ -395,21 +430,21 @@ fun getPrivacyChipBoundingRectForInsets(
contentRect: Rect,
dotWidth: Int,
chipWidth: Int,
- isRtl: Boolean
+ isRtl: Boolean,
): Rect {
return if (isRtl) {
Rect(
contentRect.left - dotWidth,
contentRect.top,
contentRect.left + chipWidth,
- contentRect.bottom
+ contentRect.bottom,
)
} else {
Rect(
contentRect.right - chipWidth,
contentRect.top,
contentRect.right + dotWidth,
- contentRect.bottom
+ contentRect.bottom,
)
}
}
@@ -443,7 +478,7 @@ fun calculateInsetsForRotationWithRotatedResources(
isRtl: Boolean,
dotWidth: Int,
bottomAlignedMargin: Int,
- statusBarContentHeight: Int
+ statusBarContentHeight: Int,
): Rect {
/*
TODO: Check if this is ever used for devices with no rounded corners
@@ -467,7 +502,7 @@ fun calculateInsetsForRotationWithRotatedResources(
targetRotation,
currentRotation,
bottomAlignedMargin,
- statusBarContentHeight
+ statusBarContentHeight,
)
}
@@ -503,7 +538,7 @@ private fun getStatusBarContentBounds(
@Rotation targetRotation: Int,
@Rotation currentRotation: Int,
bottomAlignedMargin: Int,
- statusBarContentHeight: Int
+ statusBarContentHeight: Int,
): Rect {
val insetTop = getInsetTop(bottomAlignedMargin, statusBarContentHeight, sbHeight)
@@ -597,7 +632,7 @@ private val DisplayCutout.boundingRectsLeftRightTop
private fun getInsetTop(
bottomAlignedMargin: Int,
statusBarContentHeight: Int,
- statusBarHeight: Int
+ statusBarHeight: Int,
): Int {
val bottomAlignmentEnabled = bottomAlignedMargin >= 0
if (!bottomAlignmentEnabled) {
@@ -610,7 +645,7 @@ private fun getInsetTop(
private fun sbRect(
@Rotation relativeRotation: Int,
sbHeight: Int,
- displaySize: Pair<Int, Int>
+ displaySize: Pair<Int, Int>,
): Rect {
val w = displaySize.first
val h = displaySize.second
@@ -626,7 +661,7 @@ private fun shareShortEdge(
sbRect: Rect,
cutoutRect: Rect,
currentWidth: Int,
- currentHeight: Int
+ currentHeight: Int,
): Boolean {
if (currentWidth < currentHeight) {
// Check top/bottom edges by extending the width of the display cutout rect and checking
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
index 7d0dadcf8c6e..7a88dcd92b88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -17,78 +17,40 @@
package com.android.systemui.statusbar.window
import android.content.Context
-import android.view.Display
import android.view.WindowManager
import com.android.app.viewcapture.ViewCaptureAwareWindowManager
-import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.data.repository.PerDisplayStore
+import com.android.systemui.display.data.repository.PerDisplayStoreImpl
+import com.android.systemui.display.data.repository.SingleDisplayStore
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
-import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
/** Store that allows to retrieve per display instances of [StatusBarWindowController]. */
-interface StatusBarWindowControllerStore {
- /**
- * The instance for the default/main display of the device. For example, on a phone or a tablet,
- * the default display is the internal/built-in display of the device.
- *
- * Note that the id of the default display is [Display.DEFAULT_DISPLAY].
- */
- val defaultDisplay: StatusBarWindowController
-
- /**
- * Returns an instance for a specific display id.
- *
- * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
- * displays.
- */
- fun forDisplay(displayId: Int): StatusBarWindowController
-}
+interface StatusBarWindowControllerStore : PerDisplayStore<StatusBarWindowController>
@SysUISingleton
class MultiDisplayStatusBarWindowControllerStore
@Inject
constructor(
- @Background private val backgroundApplicationScope: CoroutineScope,
+ @Background backgroundApplicationScope: CoroutineScope,
private val controllerFactory: StatusBarWindowController.Factory,
private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
private val viewCaptureAwareWindowManagerFactory: ViewCaptureAwareWindowManager.Factory,
- private val displayRepository: DisplayRepository,
-) : StatusBarWindowControllerStore, CoreStartable {
+ displayRepository: DisplayRepository,
+) :
+ StatusBarWindowControllerStore,
+ PerDisplayStoreImpl<StatusBarWindowController>(backgroundApplicationScope, displayRepository) {
init {
StatusBarConnectedDisplays.assertInNewMode()
}
- private val perDisplayControllers = ConcurrentHashMap<Int, StatusBarWindowController>()
-
- override fun start() {
- backgroundApplicationScope.launch(CoroutineName("StatusBarWindowController#start")) {
- displayRepository.displayRemovalEvent.collect { displayId ->
- perDisplayControllers.remove(displayId)
- }
- }
- }
-
- override val defaultDisplay: StatusBarWindowController
- get() = forDisplay(Display.DEFAULT_DISPLAY)
-
- override fun forDisplay(displayId: Int): StatusBarWindowController {
- if (displayRepository.getDisplay(displayId) == null) {
- throw IllegalArgumentException("Display with id $displayId doesn't exist.")
- }
- return perDisplayControllers.computeIfAbsent(displayId) {
- createControllerForDisplay(displayId)
- }
- }
-
- private fun createControllerForDisplay(displayId: Int): StatusBarWindowController {
+ override fun createInstanceForDisplay(displayId: Int): StatusBarWindowController {
val statusBarDisplayContext =
displayWindowPropertiesRepository.get(
displayId = displayId,
@@ -101,6 +63,8 @@ constructor(
viewCaptureAwareWindowManager,
)
}
+
+ override val instanceClass = StatusBarWindowController::class.java
}
@SysUISingleton
@@ -110,16 +74,13 @@ constructor(
context: Context,
viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
factory: StatusBarWindowControllerImpl.Factory,
-) : StatusBarWindowControllerStore {
+) :
+ StatusBarWindowControllerStore,
+ PerDisplayStore<StatusBarWindowController> by SingleDisplayStore(
+ factory.create(context, viewCaptureAwareWindowManager)
+ ) {
init {
StatusBarConnectedDisplays.assertInLegacyMode()
}
-
- private val controller: StatusBarWindowController =
- factory.create(context, viewCaptureAwareWindowManager)
-
- override val defaultDisplay = controller
-
- override fun forDisplay(displayId: Int) = controller
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarInitializerStoreTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarInitializerStoreTest.kt
deleted file mode 100644
index 0d1d37af7e5b..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarInitializerStoreTest.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.core
-
-import android.platform.test.annotations.EnableFlags
-import android.view.Display
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.display.data.repository.displayRepository
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.kosmos.unconfinedTestDispatcher
-import com.android.systemui.testKosmos
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
-class MultiDisplayStatusBarInitializerStoreTest : SysuiTestCase() {
-
- private val kosmos =
- testKosmos().also {
- // Using unconfinedTestDispatcher to avoid having to call `runCurrent` in the tests.
- it.testDispatcher = it.unconfinedTestDispatcher
- }
- private val testScope = kosmos.testScope
- private val fakeDisplayRepository = kosmos.displayRepository
- private val store = kosmos.multiDisplayStatusBarInitializerStore
-
- @Before
- fun start() {
- store.start()
- }
-
- @Before
- fun addDisplays() = runBlocking {
- fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY_ID)
- fakeDisplayRepository.addDisplay(NON_DEFAULT_DISPLAY_ID)
- }
-
- @Test
- fun forDisplay_defaultDisplay_multipleCalls_returnsSameInstance() =
- testScope.runTest {
- val controller = store.defaultDisplay
-
- assertThat(store.defaultDisplay).isSameInstanceAs(controller)
- }
-
- @Test
- fun forDisplay_nonDefaultDisplay_multipleCalls_returnsSameInstance() =
- testScope.runTest {
- val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
-
- assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isSameInstanceAs(controller)
- }
-
- @Test
- fun forDisplay_nonDefaultDisplay_afterDisplayRemoved_returnsNewInstance() =
- testScope.runTest {
- val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
-
- fakeDisplayRepository.removeDisplay(NON_DEFAULT_DISPLAY_ID)
- fakeDisplayRepository.addDisplay(NON_DEFAULT_DISPLAY_ID)
-
- assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isNotSameInstanceAs(controller)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun forDisplay_nonExistingDisplayId_throws() =
- testScope.runTest { store.forDisplay(NON_EXISTING_DISPLAY_ID) }
-
- companion object {
- private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
- private const val NON_DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1
- private const val NON_EXISTING_DISPLAY_ID = Display.DEFAULT_DISPLAY + 2
- }
-}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
new file mode 100644
index 000000000000..e3797260ed6d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import kotlinx.coroutines.CoroutineScope
+
+class FakePerDisplayStore(
+ backgroundApplicationScope: CoroutineScope,
+ displayRepository: DisplayRepository,
+) : PerDisplayStoreImpl<TestPerDisplayInstance>(backgroundApplicationScope, displayRepository) {
+
+ val removalActions = mutableListOf<TestPerDisplayInstance>()
+
+ override fun createInstanceForDisplay(displayId: Int): TestPerDisplayInstance {
+ return TestPerDisplayInstance(displayId)
+ }
+
+ override val instanceClass = TestPerDisplayInstance::class.java
+
+ override suspend fun onDisplayRemovalAction(instance: TestPerDisplayInstance) {
+ removalActions += instance
+ }
+}
+
+data class TestPerDisplayInstance(val displayId: Int)
+
+val Kosmos.fakePerDisplayStore by
+ Kosmos.Fixture {
+ FakePerDisplayStore(
+ backgroundApplicationScope = applicationCoroutineScope,
+ displayRepository = displayRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
index 8066b9138c99..303529b7f7b0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
@@ -34,8 +34,8 @@ val Kosmos.multiDisplayStatusBarInitializerStore by
Kosmos.Fixture {
MultiDisplayStatusBarInitializerStore(
applicationCoroutineScope,
- fakeStatusBarInitializerFactory,
displayRepository,
+ fakeStatusBarInitializerFactory,
fakeStatusBarWindowControllerStore,
)
}