diff options
| author | 2024-10-23 09:40:33 +0100 | |
|---|---|---|
| committer | 2024-10-23 09:42:07 +0100 | |
| commit | 613c82b4aa5512b2836de1438048f607d3e8f6bc (patch) | |
| tree | 643ea2069e3f7699be42505544e05675308d42b8 | |
| parent | 3d454fb1b3371a4677442cb931d8df1cae74513e (diff) | |
Introduce StatusBarContentInsetsProviderStore for multiple displays
Test: Tested by parent abstract class
Test: MultiDisplayStatusBarContentInsetsProviderStoreTest
Test: StatusBarContentInsetsProviderTest
Test: Build & run
Flag: com.android.systemui.status_bar_connected_displays
Bug: 362720432
Change-Id: Ib08054879f6b714d640e22153cf7d77aae3a0ef9
30 files changed, 698 insertions, 71 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt index f38bf13d0bda..ab5fa8ef43fb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt @@ -6,12 +6,11 @@ import android.graphics.Rect import android.view.DisplayCutout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.battery.BatteryMeterView -import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider -import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever +import com.android.systemui.res.R +import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Rule @@ -19,6 +18,8 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.junit.MockitoJUnit +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) @@ -35,9 +36,12 @@ class QsBatteryModeControllerTest : SysuiTestCase() { const val QS_END_FRAME = 58 } + private val kosmos = testKosmos() + private val insetsProviderStore = kosmos.fakeStatusBarContentInsetsProviderStore + private val insetsProvider = insetsProviderStore.defaultDisplay + @JvmField @Rule val mockitoRule = MockitoJUnit.rule()!! - @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider @Mock private lateinit var mockedContext: Context @Mock private lateinit var mockedResources: Resources @@ -49,8 +53,7 @@ class QsBatteryModeControllerTest : SysuiTestCase() { whenever(mockedResources.getInteger(R.integer.fade_in_start_frame)).thenReturn(QS_END_FRAME) whenever(mockedResources.getInteger(R.integer.fade_out_complete_frame)) .thenReturn(QQS_START_FRAME) - - controller = QsBatteryModeController(mockedContext, insetsProvider) + controller = QsBatteryModeController(mockedContext, insetsProviderStore) } @Test @@ -96,5 +99,6 @@ class QsBatteryModeControllerTest : SysuiTestCase() { } private fun Int.prevFrameToFraction(): Float = (this - 1) / MOTION_LAYOUT_MAX_FRAME.toFloat() + private fun Int.nextFrameToFraction(): Float = (this + 1) / MOTION_LAYOUT_MAX_FRAME.toFloat() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt new file mode 100644 index 000000000000..0eebab0de831 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt @@ -0,0 +1,77 @@ +/* + * 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.data.repository + +import android.view.Display.DEFAULT_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 kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.never +import org.mockito.kotlin.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +class MultiDisplayStatusBarContentInsetsProviderStoreTest : SysuiTestCase() { + + private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher } + private val testScope = kosmos.testScope + private val fakeDisplayRepository = kosmos.displayRepository + private val underTest = kosmos.multiDisplayStatusBarContentInsetsProviderStore + + @Before + fun start() { + underTest.start() + } + + @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) } + + @Test + fun forDisplay_startsInstances() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + verify(instance).start() + } + + @Test + fun beforeDisplayRemoved_doesNotStopInstances() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + verify(instance, never()).stop() + } + + @Test + fun displayRemoved_stopsInstance() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY) + + verify(instance).stop() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index 68e17c1b2d73..157f8189276a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -63,6 +63,7 @@ import com.android.systemui.res.R; import com.android.systemui.shade.ShadeViewStateProvider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.phone.ui.StatusBarIconController; import com.android.systemui.statusbar.phone.ui.TintedIconManager; @@ -119,6 +120,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { @Mock private StatusBarContentInsetsProvider mStatusBarContentInsetsProvider; @Mock + private StatusBarContentInsetsProviderStore mStatusBarContentInsetsProviderStore; + @Mock private UserManager mUserManager; @Mock private StatusBarUserChipViewModel mStatusBarUserChipViewModel; @@ -143,7 +146,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { mShadeViewStateProvider = new TestShadeViewStateProvider(); MockitoAnnotations.initMocks(this); - + when(mStatusBarContentInsetsProviderStore.getDefaultDisplay()) + .thenReturn(mStatusBarContentInsetsProvider); when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager); allowTestableLooperAsMainThread(); @@ -175,7 +179,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { mKosmos.getKeyguardStatusBarViewModel(), mBiometricUnlockController, mStatusBarStateController, - mStatusBarContentInsetsProvider, + mStatusBarContentInsetsProviderStore, mUserManager, mStatusBarUserChipViewModel, mSecureSettings, 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 ba5fb7f8df00..a862fdfeca22 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 @@ -36,14 +36,15 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation -import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import junit.framework.Assert.assertTrue +import com.google.common.truth.Truth.assertWithMessage import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @SmallTest @@ -1018,7 +1019,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { // Regression test for b/245799099 @Test - fun onMaxBoundsChanged_listenerNotified() { + fun onMaxBoundsChanged_afterStart_listenerNotified() { // Start out with an existing configuration with bounds configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100) configurationController.onConfigurationChanged(configuration) @@ -1038,6 +1039,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { triggered = true } } + provider.start() provider.addCallback(listener) // WHEN the config is updated with new bounds @@ -1049,7 +1051,39 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { } @Test - fun onDensityOrFontScaleChanged_listenerNotified() { + fun onMaxBoundsChanged_beforeStart_listenerNotNotified() { + // Start out with an existing configuration with bounds + configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100) + configurationController.onConfigurationChanged(configuration) + val provider = + StatusBarContentInsetsProviderImpl( + contextMock, + configurationController, + mock<DumpManager>(), + mock<CommandRegistry>(), + mock<SysUICutoutProvider>(), + ) + val listener = + object : StatusBarContentInsetsChangedListener { + var triggered = false + + override fun onStatusBarContentInsetsChanged() { + triggered = true + } + } + provider.addCallback(listener) + + // WHEN the config is updated with new bounds + // but provider is not started + configuration.windowConfiguration.setMaxBounds(0, 0, 456, 789) + configurationController.onConfigurationChanged(configuration) + + // THEN the listener is not notified + assertThat(listener.triggered).isFalse() + } + + @Test + fun onDensityOrFontScaleChanged_beforeStart_listenerNotNotified() { configuration.densityDpi = 12 val provider = StatusBarContentInsetsProviderImpl( @@ -1069,6 +1103,36 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { } provider.addCallback(listener) + // WHEN the config is updated, but the provider is not started + configuration.densityDpi = 20 + configurationController.onConfigurationChanged(configuration) + + // THEN the listener is NOT notified + assertThat(listener.triggered).isFalse() + } + + @Test + fun onDensityOrFontScaleChanged_afterStart_listenerNotified() { + configuration.densityDpi = 12 + val provider = + StatusBarContentInsetsProviderImpl( + contextMock, + configurationController, + mock<DumpManager>(), + mock<CommandRegistry>(), + mock<SysUICutoutProvider>(), + ) + val listener = + object : StatusBarContentInsetsChangedListener { + var triggered = false + + override fun onStatusBarContentInsetsChanged() { + triggered = true + } + } + provider.start() + provider.addCallback(listener) + // WHEN the config is updated configuration.densityDpi = 20 configurationController.onConfigurationChanged(configuration) @@ -1078,7 +1142,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { } @Test - fun onThemeChanged_listenerNotified() { + fun onThemeChanged_afterStart_listenerNotified() { val provider = StatusBarContentInsetsProviderImpl( contextMock, @@ -1095,6 +1159,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { triggered = true } } + provider.start() provider.addCallback(listener) configurationController.notifyThemeChanged() @@ -1103,18 +1168,44 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { assertThat(listener.triggered).isTrue() } + @Test + fun onThemeChanged_beforeStart_listenerNotNotified() { + val provider = + StatusBarContentInsetsProviderImpl( + contextMock, + configurationController, + mock<DumpManager>(), + mock<CommandRegistry>(), + mock<SysUICutoutProvider>(), + ) + val listener = + object : StatusBarContentInsetsChangedListener { + var triggered = false + + override fun onStatusBarContentInsetsChanged() { + triggered = true + } + } + provider.addCallback(listener) + + configurationController.notifyThemeChanged() + + assertThat(listener.triggered).isFalse() + } + private fun assertRects( expected: Rect, actual: Rect, @Rotation currentRotation: Int, @Rotation targetRotation: Int, ) { - assertTrue( - "Rects must match. currentRotation=${RotationUtils.toString(currentRotation)}" + - " targetRotation=${RotationUtils.toString(targetRotation)}" + - " expected=$expected actual=$actual", - expected.equals(actual), - ) + assertWithMessage( + "Rects must match. currentRotation=${RotationUtils.toString(currentRotation)}" + + " targetRotation=${RotationUtils.toString(targetRotation)}" + + " expected=$expected actual=$actual" + ) + .that(actual) + .isEqualTo(expected) } private fun setNoCutout() { @@ -1136,8 +1227,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { } private fun setCameraProtectionBounds(protectionBounds: Rect) { - val protectionInfo = - mock<CameraProtectionInfo> { whenever(this.bounds).thenReturn(protectionBounds) } + val protectionInfo = mock<CameraProtectionInfo> { on { bounds } doReturn protectionBounds } whenever(sysUICutout.cameraProtection).thenReturn(protectionInfo) } 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 index 2ce3e43389fa..2c4345556f15 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt @@ -76,7 +76,7 @@ abstract class PerDisplayStoreImpl<T>( } } - abstract fun createInstanceForDisplay(displayId: Int): T + protected abstract fun createInstanceForDisplay(displayId: Int): T override fun start() { val instanceType = instanceClass.simpleName diff --git a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt index 1fcb70c6bc95..91627d63980e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt @@ -2,9 +2,9 @@ package com.android.systemui.shade import android.content.Context import android.view.DisplayCutout -import com.android.systemui.res.R import com.android.systemui.battery.BatteryMeterView -import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider +import com.android.systemui.res.R +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore import javax.inject.Inject /** @@ -15,9 +15,11 @@ class QsBatteryModeController @Inject constructor( private val context: Context, - private val insetsProvider: StatusBarContentInsetsProvider, + insetsProviderStore: StatusBarContentInsetsProviderStore, ) { + private val insetsProvider = insetsProviderStore.defaultDisplay + private companion object { // MotionLayout frames are in [0, 100]. Where 0 and 100 are reserved for start and end // frames. @@ -65,6 +67,5 @@ constructor( private fun hasCenterCutout(cutout: DisplayCutout?): Boolean = cutout?.let { !insetsProvider.currentRotationHasCornerCutout() && !it.boundingRectTop.isEmpty - } - ?: false + } ?: false } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index cb589aa10cd9..d0f038698a8e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -57,7 +57,7 @@ import com.android.systemui.shade.ShadeHeaderController.Companion.QS_HEADER_CONS import com.android.systemui.shade.ShadeViewProviderModule.Companion.SHADE_HEADER import com.android.systemui.shade.carrier.ShadeCarrierGroup import com.android.systemui.shade.carrier.ShadeCarrierGroupController -import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.phone.StatusOverlayHoverListenerFactory @@ -90,7 +90,7 @@ constructor( private val statusBarIconController: StatusBarIconController, private val tintedIconManagerFactory: TintedIconManager.Factory, private val privacyIconsController: HeaderPrivacyIconsController, - private val insetsProvider: StatusBarContentInsetsProvider, + private val insetsProviderStore: StatusBarContentInsetsProviderStore, private val configurationController: ConfigurationController, private val variableDateViewControllerFactory: VariableDateViewController.Factory, @Named(SHADE_HEADER) private val batteryMeterViewController: BatteryMeterViewController, @@ -104,6 +104,8 @@ constructor( private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory, ) : ViewController<View>(header), Dumpable { + private val insetsProvider = insetsProviderStore.defaultDisplay + companion object { /** IDs for transitions and constraints for the [MotionLayout]. */ @VisibleForTesting internal val HEADER_TRANSITION_ID = R.id.header_transition @@ -262,7 +264,7 @@ constructor( left, header.paddingTop, header.paddingRight, - header.paddingBottom + header.paddingBottom, ) systemIconsHoverContainer.setPaddingRelative( resources.getDimensionPixelSize( @@ -276,7 +278,7 @@ constructor( ), resources.getDimensionPixelSize( R.dimen.hover_system_icons_container_padding_bottom - ) + ), ) } @@ -317,7 +319,7 @@ constructor( batteryIcon.updateColors( fgColor /* foreground */, bgColor /* background */, - fgColor /* single tone (current default) */ + fgColor, /* single tone (current default) */ ) carrierIconSlots = @@ -426,7 +428,7 @@ constructor( if (view.isLayoutRtl) cutoutRight else cutoutLeft, header.paddingStart, if (view.isLayoutRtl) cutoutLeft else cutoutRight, - header.paddingEnd + header.paddingEnd, ) if (cutout != null) { @@ -437,7 +439,7 @@ constructor( changes += combinedShadeHeadersConstraintManager.centerCutoutConstraints( view.isLayoutRtl, - (view.width - view.paddingLeft - view.paddingRight - topCutout.width()) / 2 + (view.width - view.paddingLeft - view.paddingRight - topCutout.width()) / 2, ) } } else { @@ -563,7 +565,7 @@ constructor( clockPaddingStart, clock.paddingTop, clockPaddingEnd, - clock.paddingBottom + clock.paddingBottom, ) } @@ -602,9 +604,8 @@ constructor( @VisibleForTesting internal fun simulateViewDetached() = this.onViewDetached() - inner class CustomizerAnimationListener( - private val enteringCustomizing: Boolean, - ) : AnimatorListenerAdapter() { + inner class CustomizerAnimationListener(private val enteringCustomizing: Boolean) : + AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { super.onAnimationEnd(animation) header.animate().setListener(null) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt index e6270b8740a6..c416bf7b4f92 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.data import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryModule import com.android.systemui.statusbar.data.repository.RemoteInputRepositoryModule import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerModule +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStoreModule import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryModule import com.android.systemui.statusbar.phone.data.StatusBarPhoneDataLayerModule import dagger.Module @@ -28,6 +29,7 @@ import dagger.Module KeyguardStatusBarRepositoryModule::class, RemoteInputRepositoryModule::class, StatusBarConfigurationControllerModule::class, + StatusBarContentInsetsProviderStoreModule::class, StatusBarModeRepositoryModule::class, StatusBarPhoneDataLayerModule::class, ] diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt new file mode 100644 index 000000000000..e471b12c1d58 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt @@ -0,0 +1,119 @@ +/* + * 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.data.repository + +import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR +import com.android.systemui.CameraProtectionLoaderImpl +import com.android.systemui.CoreStartable +import com.android.systemui.SysUICutoutProviderImpl +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 com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider +import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl +import dagger.Lazy +import dagger.Module +import dagger.Provides +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope + +/** Provides per display instances of [StatusBarContentInsetsProvider]. */ +interface StatusBarContentInsetsProviderStore : PerDisplayStore<StatusBarContentInsetsProvider> + +@SysUISingleton +class MultiDisplayStatusBarContentInsetsProviderStore +@Inject +constructor( + @Background backgroundApplicationScope: CoroutineScope, + displayRepository: DisplayRepository, + private val factory: StatusBarContentInsetsProviderImpl.Factory, + private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository, + private val statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore, + private val sysUICutoutProviderFactory: SysUICutoutProviderImpl.Factory, + private val cameraProtectionLoaderFactory: CameraProtectionLoaderImpl.Factory, +) : + StatusBarContentInsetsProviderStore, + PerDisplayStoreImpl<StatusBarContentInsetsProvider>( + backgroundApplicationScope, + displayRepository, + ) { + + override fun createInstanceForDisplay(displayId: Int): StatusBarContentInsetsProvider { + val context = displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR).context + val cameraProtectionLoader = cameraProtectionLoaderFactory.create(context) + return factory + .create( + context, + statusBarConfigurationControllerStore.forDisplay(displayId), + sysUICutoutProviderFactory.create(context, cameraProtectionLoader), + ) + .also { it.start() } + } + + override suspend fun onDisplayRemovalAction(instance: StatusBarContentInsetsProvider) { + instance.stop() + } + + override val instanceClass = StatusBarContentInsetsProvider::class.java +} + +@SysUISingleton +class SingleDisplayStatusBarContentInsetsProviderStore +@Inject +constructor(statusBarContentInsetsProvider: StatusBarContentInsetsProvider) : + StatusBarContentInsetsProviderStore, + PerDisplayStore<StatusBarContentInsetsProvider> by SingleDisplayStore( + defaultInstance = statusBarContentInsetsProvider + ) + +@Module +object StatusBarContentInsetsProviderStoreModule { + + @Provides + @SysUISingleton + @IntoMap + @ClassKey(StatusBarContentInsetsProviderStore::class) + fun storeAsCoreStartable( + multiDisplayLazy: Lazy<MultiDisplayStatusBarContentInsetsProviderStore> + ): CoreStartable { + return if (StatusBarConnectedDisplays.isEnabled) { + return multiDisplayLazy.get() + } else { + CoreStartable.NOP + } + } + + @Provides + @SysUISingleton + fun store( + singleDisplayLazy: Lazy<SingleDisplayStatusBarContentInsetsProviderStore>, + multiDisplayLazy: Lazy<MultiDisplayStatusBarContentInsetsProviderStore>, + ): StatusBarContentInsetsProviderStore { + return if (StatusBarConnectedDisplays.isEnabled) { + multiDisplayLazy.get() + } else { + singleDisplayLazy.get() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt index 0eef8d63c2d1..2506c95ad800 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt @@ -34,6 +34,7 @@ import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.StatusBarState.SHADE import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.policy.ConfigurationController @@ -730,8 +731,12 @@ object PrivacyDotViewControllerModule { factory: PrivacyDotViewControllerImpl.Factory, @Application scope: CoroutineScope, configurationController: ConfigurationController, - contentInsetsProvider: StatusBarContentInsetsProvider, + contentInsetsProviderStore: StatusBarContentInsetsProviderStore, ): PrivacyDotViewController { - return factory.create(scope, configurationController, contentInsetsProvider) + return factory.create( + scope, + configurationController, + contentInsetsProviderStore.defaultDisplay, + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt index 35816c25e976..b28660590ad0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt @@ -33,6 +33,7 @@ import androidx.core.animation.ValueAnimator import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dagger.SysUISingleton import com.android.systemui.res.R +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.window.StatusBarWindowController @@ -453,12 +454,12 @@ object SystemEventChipAnimationControllerModule { factory: SystemEventChipAnimationControllerImpl.Factory, context: Context, statusBarWindowControllerStore: StatusBarWindowControllerStore, - contentInsetsProvider: StatusBarContentInsetsProvider, + contentInsetsProviderStore: StatusBarContentInsetsProviderStore, ): SystemEventChipAnimationController { return factory.create( context, statusBarWindowControllerStore.defaultDisplay, - contentInsetsProvider, + contentInsetsProviderStore.defaultDisplay, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index cd59d4ebfd73..be2fb68ab88d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -58,6 +58,7 @@ import com.android.systemui.shade.ShadeViewStateProvider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore; import com.android.systemui.statusbar.disableflags.DisableStateTracker; import com.android.systemui.statusbar.events.SystemStatusAnimationCallback; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; @@ -300,7 +301,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat KeyguardStatusBarViewModel keyguardStatusBarViewModel, BiometricUnlockController biometricUnlockController, SysuiStatusBarStateController statusBarStateController, - StatusBarContentInsetsProvider statusBarContentInsetsProvider, + StatusBarContentInsetsProviderStore statusBarContentInsetsProviderStore, UserManager userManager, StatusBarUserChipViewModel userChipViewModel, SecureSettings secureSettings, @@ -327,7 +328,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat mKeyguardStatusBarViewModel = keyguardStatusBarViewModel; mBiometricUnlockController = biometricUnlockController; mStatusBarStateController = statusBarStateController; - mInsetsProvider = statusBarContentInsetsProvider; + mInsetsProvider = statusBarContentInsetsProviderStore.getDefaultDisplay(); mUserManager = userManager; mStatusBarUserChipViewModel = userChipViewModel; mSecureSettings = secureSettings; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index ff7c14308fcb..746d6a75a567 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -38,6 +38,7 @@ import com.android.systemui.shade.ShadeLogger import com.android.systemui.shade.ShadeViewController import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore import com.android.systemui.statusbar.policy.Clock import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.window.StatusBarWindowStateController @@ -333,7 +334,7 @@ private constructor( private val configurationController: ConfigurationController, private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory, private val darkIconDispatcher: DarkIconDispatcher, - private val statusBarContentInsetsProvider: StatusBarContentInsetsProvider, + private val statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore, ) { fun create(view: PhoneStatusBarView): PhoneStatusBarViewController { val statusBarMoveFromCenterAnimationController = @@ -359,7 +360,7 @@ private constructor( configurationController, statusOverlayHoverListenerFactory, darkIconDispatcher, - statusBarContentInsetsProvider, + statusBarContentInsetsProviderStore.defaultDisplay, ) } } 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 c6f6bd90fce6..d991b1df45fe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt @@ -24,6 +24,7 @@ import android.graphics.Point import android.graphics.Rect import android.util.LruCache import android.util.Pair +import android.view.Display.DEFAULT_DISPLAY import android.view.DisplayCutout import android.view.Surface import androidx.annotation.VisibleForTesting @@ -37,7 +38,7 @@ import com.android.systemui.SysUICutoutProvider 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.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.policy.CallbackController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE @@ -70,6 +71,17 @@ interface StatusBarContentInsetsProvider : CallbackController<StatusBarContentInsetsChangedListener> { /** + * Called when the [StatusBarContentInsetsProvider] should start doing its work and allocate its + * resources. + */ + fun start() + + /** + * Called when the [StatusBarContentInsetsProvider] should stop and do any required clean up. + */ + fun stop() + + /** * 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. @@ -157,10 +169,15 @@ constructor( context.resources.getBoolean(R.bool.config_enablePrivacyDot) } - init { + private val nameSuffix = + if (context.displayId == DEFAULT_DISPLAY) "" else context.displayId.toString() + private val dumpableName = TAG + nameSuffix + private val commandName = StatusBarInsetsCommand.NAME + nameSuffix + + override fun start() { configurationController.addCallback(this) - dumpManager.registerDumpable(TAG, this) - commandRegistry.registerCommand(StatusBarInsetsCommand.NAME) { + dumpManager.registerDumpable(dumpableName, this) + commandRegistry.registerCommand(commandName) { StatusBarInsetsCommand( object : StatusBarInsetsCommand.Callback { override fun onExecute( @@ -174,6 +191,13 @@ constructor( } } + override fun stop() { + StatusBarConnectedDisplays.assertInNewMode() + configurationController.removeCallback(this) + dumpManager.unregisterDumpable(dumpableName) + commandRegistry.unregisterCommand(commandName) + } + override fun addCallback(listener: StatusBarContentInsetsChangedListener) { listeners.add(listener) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt index ae0e76f01faa..584cd3b00a57 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt @@ -23,6 +23,7 @@ import com.android.app.viewcapture.ViewCaptureAwareWindowManager import com.android.systemui.animation.ActivityTransitionAnimator import com.android.systemui.fragments.FragmentHostManager import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController +import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import java.util.Optional /** Encapsulates all logic for the status bar window state management. */ @@ -82,6 +83,7 @@ interface StatusBarWindowController { context: Context, viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager, statusBarConfigurationController: StatusBarConfigurationController, + contentInsetsProvider: StatusBarContentInsetsProvider, ): StatusBarWindowController } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java index e4c6737856f0..6953bbf735f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java @@ -99,7 +99,7 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController @Assisted ViewCaptureAwareWindowManager viewCaptureAwareWindowManager, @Assisted StatusBarConfigurationController statusBarConfigurationController, IWindowManager iWindowManager, - StatusBarContentInsetsProvider contentInsetsProvider, + @Assisted StatusBarContentInsetsProvider contentInsetsProvider, FragmentService fragmentService, Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider) { mContext = context; @@ -370,7 +370,8 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController StatusBarWindowControllerImpl create( @NonNull Context context, @NonNull ViewCaptureAwareWindowManager viewCaptureAwareWindowManager, - @NonNull StatusBarConfigurationController statusBarConfigurationController); + @NonNull StatusBarConfigurationController statusBarConfigurationController, + @NonNull StatusBarContentInsetsProvider contentInsetsProvider); } } 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 d83a2371ec92..051d463a8b97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt @@ -28,6 +28,7 @@ import com.android.systemui.display.data.repository.PerDisplayStoreImpl import com.android.systemui.display.data.repository.SingleDisplayStore import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore +import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -43,6 +44,7 @@ constructor( private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository, private val viewCaptureAwareWindowManagerFactory: ViewCaptureAwareWindowManager.Factory, private val statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore, + private val statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore, displayRepository: DisplayRepository, ) : StatusBarWindowControllerStore, @@ -64,6 +66,7 @@ constructor( statusBarDisplayContext.context, viewCaptureAwareWindowManager, statusBarConfigurationControllerStore.forDisplay(displayId), + statusBarContentInsetsProviderStore.forDisplay(displayId), ) } @@ -78,6 +81,7 @@ constructor( viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager, factory: StatusBarWindowControllerImpl.Factory, statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore, + statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore, ) : StatusBarWindowControllerStore, PerDisplayStore<StatusBarWindowController> by SingleDisplayStore( @@ -85,6 +89,7 @@ constructor( context, viewCaptureAwareWindowManager, statusBarConfigurationControllerStore.defaultDisplay, + statusBarContentInsetsProviderStore.defaultDisplay, ) ) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt index fc2ad60cfa72..eae828562223 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt @@ -53,7 +53,7 @@ import com.android.systemui.shade.ShadeHeaderController.Companion.QQS_HEADER_CON import com.android.systemui.shade.ShadeHeaderController.Companion.QS_HEADER_CONSTRAINT import com.android.systemui.shade.carrier.ShadeCarrierGroup import com.android.systemui.shade.carrier.ShadeCarrierGroupController -import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider +import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.phone.StatusOverlayHoverListenerFactory import com.android.systemui.statusbar.phone.ui.StatusBarIconController @@ -63,6 +63,7 @@ import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.statusbar.policy.NextAlarmController import com.android.systemui.statusbar.policy.VariableDateView import com.android.systemui.statusbar.policy.VariableDateViewController +import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture @@ -93,6 +94,10 @@ private val EMPTY_CHANGES = ConstraintsChanges() @RunWith(AndroidTestingRunner::class) class ShadeHeaderControllerTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val insetsProviderStore = kosmos.fakeStatusBarContentInsetsProviderStore + private val insetsProvider = insetsProviderStore.defaultDisplay + @Mock(answer = Answers.RETURNS_MOCKS) private lateinit var view: MotionLayout @Mock private lateinit var statusIcons: StatusIconContainer @Mock private lateinit var statusBarIconController: StatusBarIconController @@ -107,7 +112,6 @@ class ShadeHeaderControllerTest : SysuiTestCase() { @Mock private lateinit var batteryMeterView: BatteryMeterView @Mock private lateinit var batteryMeterViewController: BatteryMeterViewController @Mock private lateinit var privacyIconsController: HeaderPrivacyIconsController - @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider @Mock private lateinit var variableDateViewControllerFactory: VariableDateViewController.Factory @Mock private lateinit var variableDateViewController: VariableDateViewController @Mock private lateinit var dumpManager: DumpManager @@ -190,7 +194,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { statusBarIconController, iconManagerFactory, privacyIconsController, - insetsProvider, + insetsProviderStore, configurationController, variableDateViewControllerFactory, batteryMeterViewController, @@ -201,7 +205,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { qsBatteryModeController, nextAlarmController, activityStarter, - mStatusOverlayHoverListenerFactory + mStatusOverlayHoverListenerFactory, ) whenever(view.isAttachedToWindow).thenReturn(true) shadeHeaderController.init() @@ -597,7 +601,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { anyInt(), anyInt(), anyInt(), - anyInt() + anyInt(), ) ) .thenReturn(mockConstraintsChanges) @@ -631,7 +635,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { anyInt(), anyInt(), anyInt(), - anyInt() + anyInt(), ) ) .thenReturn(mockConstraintsChanges) @@ -751,7 +755,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { whenever( combinedShadeHeadersConstraintManager.centerCutoutConstraints( Mockito.anyBoolean(), - anyInt() + anyInt(), ) ) .thenReturn(mockConstraintsChanges) @@ -788,7 +792,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { whenever( combinedShadeHeadersConstraintManager.centerCutoutConstraints( Mockito.anyBoolean(), - anyInt() + anyInt(), ) ) .thenReturn(mockConstraintsChanges) @@ -899,7 +903,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { top: Int, right: Int, bottom: Int, - listener: View.OnLayoutChangeListener + listener: View.OnLayoutChangeListener, ) { val oldLeft = this.left val oldTop = this.top @@ -920,7 +924,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { left, top, right, - bottom + bottom, ) } @@ -941,7 +945,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { /* left= */ insets.first, /* top= */ 0, /* right= */ insets.second, - /* bottom= */ 0 + /* bottom= */ 0, ) ) whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(cornerCutout) @@ -968,7 +972,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { anyInt(), anyInt(), anyInt(), - anyInt() + anyInt(), ) ) .thenReturn(EMPTY_CHANGES) @@ -977,7 +981,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { whenever( combinedShadeHeadersConstraintManager.centerCutoutConstraints( Mockito.anyBoolean(), - anyInt() + anyInt(), ) ) .thenReturn(EMPTY_CHANGES) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 83d0bcc55cb0..008e8ce92736 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -37,7 +37,6 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.battery.BatteryMeterView import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.kosmos.Kosmos import com.android.systemui.plugins.fakeDarkIconDispatcher import com.android.systemui.res.R import com.android.systemui.scene.ui.view.WindowRootView @@ -46,9 +45,12 @@ import com.android.systemui.shade.ShadeLogger import com.android.systemui.shade.ShadeViewController import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore +import com.android.systemui.statusbar.data.repository.statusBarContentInsetsProviderStore import com.android.systemui.statusbar.policy.Clock import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.window.StatusBarWindowStateController +import com.android.systemui.testKosmos import com.android.systemui.unfold.SysUIUnfoldComponent import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider @@ -75,7 +77,9 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class PhoneStatusBarViewControllerTest : SysuiTestCase() { - private val kosmos = Kosmos() + private val kosmos = testKosmos() + private val statusBarContentInsetsProviderStore = kosmos.fakeStatusBarContentInsetsProviderStore + private val statusBarContentInsetsProvider = statusBarContentInsetsProviderStore.defaultDisplay private val fakeDarkIconDispatcher = kosmos.fakeDarkIconDispatcher @Mock private lateinit var shadeViewController: ShadeViewController @@ -93,7 +97,6 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { @Mock private lateinit var windowRootView: Provider<WindowRootView> @Mock private lateinit var shadeLogger: ShadeLogger @Mock private lateinit var viewUtil: ViewUtil - @Mock private lateinit var statusBarContentInsetsProvider: StatusBarContentInsetsProvider private lateinit var statusBarWindowStateController: StatusBarWindowStateController private lateinit var view: PhoneStatusBarView @@ -396,7 +399,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { configurationController, mStatusOverlayHoverListenerFactory, fakeDarkIconDispatcher, - statusBarContentInsetsProvider, + statusBarContentInsetsProviderStore, ) .create(view) .also { it.init() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/CameraProtectionLoaderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/CameraProtectionLoaderKosmos.kt new file mode 100644 index 000000000000..7625049594a4 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/CameraProtectionLoaderKosmos.kt @@ -0,0 +1,25 @@ +/* + * 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 + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.fakeCameraProtectionLoaderFactory by + Kosmos.Fixture { FakeCameraProtectionLoaderFactory() } + +var Kosmos.cameraProtectionLoaderFactory: CameraProtectionLoaderImpl.Factory by + Kosmos.Fixture { fakeCameraProtectionLoaderFactory } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeCameraProtectionLoaderFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeCameraProtectionLoaderFactory.kt new file mode 100644 index 000000000000..87428b0679ba --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeCameraProtectionLoaderFactory.kt @@ -0,0 +1,27 @@ +/* + * 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 + +import android.content.Context +import org.mockito.kotlin.mock + +class FakeCameraProtectionLoaderFactory : CameraProtectionLoaderImpl.Factory { + + override fun create(context: Context): CameraProtectionLoaderImpl { + return mock<CameraProtectionLoaderImpl>() + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSysUICutoutProviderFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSysUICutoutProviderFactory.kt new file mode 100644 index 000000000000..4eb3780d7663 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSysUICutoutProviderFactory.kt @@ -0,0 +1,30 @@ +/* + * 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 + +import android.content.Context +import org.mockito.kotlin.mock + +class FakeSysUICutoutProviderFactory : SysUICutoutProviderImpl.Factory { + + override fun create( + context: Context, + cameraProtectionLoader: CameraProtectionLoader, + ): SysUICutoutProviderImpl { + return mock<SysUICutoutProviderImpl>() + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUICutoutProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUICutoutProviderKosmos.kt new file mode 100644 index 000000000000..412ed72e89f7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUICutoutProviderKosmos.kt @@ -0,0 +1,24 @@ +/* + * 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 + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.fakeSysUICutoutProviderFactory by Kosmos.Fixture { FakeSysUICutoutProviderFactory() } + +var Kosmos.sysUICutoutProviderFactory: SysUICutoutProviderImpl.Factory by + Kosmos.Fixture { fakeSysUICutoutProviderFactory } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarConfigurationControllerStore.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarConfigurationControllerStore.kt new file mode 100644 index 000000000000..46bb2c169731 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarConfigurationControllerStore.kt @@ -0,0 +1,32 @@ +/* + * 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.data.repository + +import android.view.Display +import org.mockito.kotlin.mock + +class FakeStatusBarConfigurationControllerStore : StatusBarConfigurationControllerStore { + + private val perDisplayMockControllers = mutableMapOf<Int, StatusBarConfigurationController>() + + override val defaultDisplay: StatusBarConfigurationController + get() = forDisplay(Display.DEFAULT_DISPLAY) + + override fun forDisplay(displayId: Int): StatusBarConfigurationController { + return perDisplayMockControllers.computeIfAbsent(displayId) { mock() } + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarContentInsetsProviderStore.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarContentInsetsProviderStore.kt new file mode 100644 index 000000000000..642c2ff38338 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarContentInsetsProviderStore.kt @@ -0,0 +1,33 @@ +/* + * 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.data.repository + +import android.view.Display +import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider +import org.mockito.kotlin.mock + +class FakeStatusBarContentInsetsProviderStore() : StatusBarContentInsetsProviderStore { + + private val perDisplayMockProviders = mutableMapOf<Int, StatusBarContentInsetsProvider>() + + override val defaultDisplay: StatusBarContentInsetsProvider + get() = forDisplay(Display.DEFAULT_DISPLAY) + + override fun forDisplay(displayId: Int): StatusBarContentInsetsProvider { + return perDisplayMockProviders.computeIfAbsent(displayId) { mock() } + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStoreKosmos.kt new file mode 100644 index 000000000000..03b63c2a8757 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStoreKosmos.kt @@ -0,0 +1,26 @@ +/* + * 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.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.fakeStatusBarConfigurationControllerStore by Kosmos.Fixture { + FakeStatusBarConfigurationControllerStore() +} + +var Kosmos.statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore by + Kosmos.Fixture { fakeStatusBarConfigurationControllerStore } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStoreKosmos.kt new file mode 100644 index 000000000000..a34fb0998c79 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStoreKosmos.kt @@ -0,0 +1,44 @@ +/* + * 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.data.repository + +import com.android.systemui.cameraProtectionLoaderFactory +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.displayWindowPropertiesRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.statusbar.phone.statusBarContentInsetsProviderFactory +import com.android.systemui.sysUICutoutProviderFactory + +val Kosmos.fakeStatusBarContentInsetsProviderStore by + Kosmos.Fixture { FakeStatusBarContentInsetsProviderStore() } + +val Kosmos.multiDisplayStatusBarContentInsetsProviderStore by + Kosmos.Fixture { + MultiDisplayStatusBarContentInsetsProviderStore( + applicationCoroutineScope, + displayRepository, + statusBarContentInsetsProviderFactory, + displayWindowPropertiesRepository, + statusBarConfigurationControllerStore, + sysUICutoutProviderFactory, + cameraProtectionLoaderFactory, + ) + } + +var Kosmos.statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore by + Kosmos.Fixture { fakeStatusBarContentInsetsProviderStore } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/FakeStatusBarContentInsetsProviderFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/FakeStatusBarContentInsetsProviderFactory.kt new file mode 100644 index 000000000000..4fb8cf4a328b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/FakeStatusBarContentInsetsProviderFactory.kt @@ -0,0 +1,33 @@ +/* + * 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.phone + +import android.content.Context +import com.android.systemui.SysUICutoutProvider +import com.android.systemui.statusbar.policy.ConfigurationController +import org.mockito.kotlin.mock + +class FakeStatusBarContentInsetsProviderFactory : StatusBarContentInsetsProviderImpl.Factory { + + override fun create( + context: Context, + configurationController: ConfigurationController, + sysUICutoutProvider: SysUICutoutProvider, + ): StatusBarContentInsetsProviderImpl { + return mock<StatusBarContentInsetsProviderImpl>() + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderKosmos.kt index 9c9673c3a924..705df3c15d18 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderKosmos.kt @@ -23,3 +23,9 @@ val Kosmos.mockStatusBarContentInsetsProvider by Kosmos.Fixture { mock<StatusBarContentInsetsProvider>() } var Kosmos.statusBarContentInsetsProvider by Kosmos.Fixture { mockStatusBarContentInsetsProvider } + +val Kosmos.fakeStatusBarContentInsetsProviderFactory by + Kosmos.Fixture { FakeStatusBarContentInsetsProviderFactory() } + +var Kosmos.statusBarContentInsetsProviderFactory: StatusBarContentInsetsProviderImpl.Factory by + Kosmos.Fixture { fakeStatusBarContentInsetsProviderFactory } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerFactory.kt index 65247a55348d..7eaecb1c4544 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerFactory.kt @@ -19,11 +19,13 @@ package com.android.systemui.statusbar.window import android.content.Context import com.android.app.viewcapture.ViewCaptureAwareWindowManager import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController +import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider class FakeStatusBarWindowControllerFactory : StatusBarWindowController.Factory { override fun create( context: Context, viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager, statusBarConfigurationController: StatusBarConfigurationController, + contentInsetsProvider: StatusBarContentInsetsProvider, ) = FakeStatusBarWindowController() } |