Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarterTest.kt 0 → 100644 +136 −0 Original line number Diff line number Diff line /* * 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 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.testScope import com.android.systemui.testKosmos import com.google.common.truth.Expect import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.verify @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) class MultiDisplayStatusBarStarterTest : SysuiTestCase() { @get:Rule val expect: Expect = Expect.create() private val kosmos = testKosmos().also { it.statusBarOrchestratorFactory = it.fakeStatusBarOrchestratorFactory it.statusBarInitializerStore = it.fakeStatusBarInitializerStore } private val testScope = kosmos.testScope private val fakeDisplayRepository = kosmos.displayRepository private val fakeOrchestratorFactory = kosmos.fakeStatusBarOrchestratorFactory private val fakeInitializerStore = kosmos.fakeStatusBarInitializerStore // Lazy, so that @EnableFlags is set before initializer is instantiated. private val underTest by lazy { kosmos.multiDisplayStatusBarStarter } @Test fun start_startsInitializersForCurrentDisplays() = testScope.runTest { fakeDisplayRepository.addDisplay(displayId = 1) fakeDisplayRepository.addDisplay(displayId = 2) underTest.start() runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 1).startedByCoreStartable) .isTrue() expect .that(fakeInitializerStore.forDisplay(displayId = 2).startedByCoreStartable) .isTrue() } @Test fun start_startsOrchestratorForCurrentDisplays() = testScope.runTest { fakeDisplayRepository.addDisplay(displayId = 1) fakeDisplayRepository.addDisplay(displayId = 2) underTest.start() runCurrent() verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = 1)!!).start() verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = 2)!!).start() } @Test fun displayAdded_orchestratorForNewDisplayIsStarted() = testScope.runTest { underTest.start() runCurrent() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = 3)!!).start() } @Test fun displayAdded_initializerForNewDisplayIsStarted() = testScope.runTest { underTest.start() runCurrent() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 3).startedByCoreStartable) .isTrue() } @Test fun displayAddedDuringStart_initializerForNewDisplayIsStarted() = testScope.runTest { underTest.start() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 3).startedByCoreStartable) .isTrue() } @Test fun displayAddedDuringStart_orchestratorForNewDisplayIsStarted() = testScope.runTest { underTest.start() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 3).startedByCoreStartable) .isTrue() } } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt +1 −2 Original line number Diff line number Diff line Loading @@ -60,10 +60,9 @@ class StatusBarInitializerTest : SysuiTestCase() { val underTest = StatusBarInitializerImpl( displayId = context.displayId, statusBarWindowControllerStore = windowControllerStore, collapsedStatusBarFragmentProvider = { mock(CollapsedStatusBarFragment::class.java) }, creationListeners = setOf(), statusBarWindowController = windowController, ) @Test Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt +39 −46 Original line number Diff line number Diff line Loading @@ -38,13 +38,10 @@ import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT_TRANSPARENT import com.android.systemui.statusbar.data.model.StatusBarMode.OPAQUE import com.android.systemui.statusbar.data.model.StatusBarMode.TRANSPARENT import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository import com.android.systemui.statusbar.phone.mockPhoneStatusBarTransitions import com.android.systemui.statusbar.phone.mockPhoneStatusBarViewController import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository import com.android.systemui.statusbar.window.data.model.StatusBarWindowState import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStateRepositoryStore import com.android.systemui.statusbar.window.data.repository.statusBarWindowStateRepositoryStore import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStatePerDisplayRepository import com.android.systemui.statusbar.window.fakeStatusBarWindowController import com.android.systemui.testKosmos import com.android.wm.shell.bubbles.bubbles import com.google.common.truth.Truth.assertThat Loading @@ -60,25 +57,20 @@ import org.mockito.kotlin.verify @RunWith(AndroidJUnit4::class) class StatusBarOrchestratorTest : SysuiTestCase() { private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher it.statusBarWindowStateRepositoryStore = it.fakeStatusBarWindowStateRepositoryStore } private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher } private val testScope = kosmos.testScope private val statusBarViewController = kosmos.mockPhoneStatusBarViewController private val statusBarWindowControllerStore = kosmos.fakeStatusBarWindowControllerStore private val statusBarModeRepository = kosmos.fakeStatusBarModeRepository private val pluginDependencyProvider = kosmos.mockPluginDependencyProvider private val notificationShadeWindowViewController = private val fakeStatusBarModePerDisplayRepository = kosmos.fakeStatusBarModePerDisplayRepository private val mockPluginDependencyProvider = kosmos.mockPluginDependencyProvider private val mockNotificationShadeWindowViewController = kosmos.mockNotificationShadeWindowViewController private val shadeSurface = kosmos.mockShadeSurface private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository private val fakeStatusBarWindowStateRepositoryStore = kosmos.fakeStatusBarWindowStateRepositoryStore private val mockShadeSurface = kosmos.mockShadeSurface private val fakeBouncerRepository = kosmos.fakeKeyguardBouncerRepository private val fakeStatusBarWindowStatePerDisplayRepository = kosmos.fakeStatusBarWindowStatePerDisplayRepository private val fakePowerRepository = kosmos.fakePowerRepository private val mockPhoneStatusBarTransitions = kosmos.mockPhoneStatusBarTransitions private val mockBubbles = kosmos.bubbles private val fakeStatusBarWindowController = kosmos.fakeStatusBarWindowController private val fakeStatusBarInitializer = kosmos.fakeStatusBarInitializer private val orchestrator = kosmos.statusBarOrchestrator Loading @@ -86,30 +78,31 @@ class StatusBarOrchestratorTest : SysuiTestCase() { fun start_setsUpPluginDependencies() { orchestrator.start() verify(pluginDependencyProvider).allowPluginDependency(DarkIconDispatcher::class.java) verify(pluginDependencyProvider).allowPluginDependency(StatusBarStateController::class.java) verify(mockPluginDependencyProvider).allowPluginDependency(DarkIconDispatcher::class.java) verify(mockPluginDependencyProvider) .allowPluginDependency(StatusBarStateController::class.java) } @Test fun start_attachesWindow() { orchestrator.start() assertThat(statusBarWindowControllerStore.defaultDisplay.isAttached).isTrue() assertThat(fakeStatusBarWindowController.isAttached).isTrue() } @Test fun start_setsStatusBarControllerOnShade() { orchestrator.start() verify(notificationShadeWindowViewController) .setStatusBarViewController(statusBarViewController) verify(mockNotificationShadeWindowViewController) .setStatusBarViewController(fakeStatusBarInitializer.statusBarViewController) } @Test fun start_updatesShadeExpansion() { orchestrator.start() verify(shadeSurface).updateExpansionAndVisibility() verify(mockShadeSurface).updateExpansionAndVisibility() } @Test Loading @@ -117,9 +110,9 @@ class StatusBarOrchestratorTest : SysuiTestCase() { testScope.runTest { orchestrator.start() bouncerRepository.setPrimaryShow(isShowing = true) fakeBouncerRepository.setPrimaryShow(isShowing = true) verify(statusBarViewController) verify(fakeStatusBarInitializer.statusBarViewController) .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) } Loading @@ -128,9 +121,9 @@ class StatusBarOrchestratorTest : SysuiTestCase() { testScope.runTest { orchestrator.start() bouncerRepository.setPrimaryShow(isShowing = false) fakeBouncerRepository.setPrimaryShow(isShowing = false) verify(statusBarViewController) verify(fakeStatusBarInitializer.statusBarViewController) .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) } Loading @@ -141,7 +134,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions).finishAnimations() verify(fakeStatusBarInitializer.statusBarTransitions).finishAnimations() } @Test Loading @@ -151,7 +144,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions, never()).finishAnimations() verify(fakeStatusBarInitializer.statusBarTransitions, never()).finishAnimations() } @Test Loading Loading @@ -208,7 +201,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(TRANSPARENT.toTransitionModeInt(), /* animate= */ true) } Loading @@ -222,19 +215,19 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(TRANSPARENT.toTransitionModeInt(), /* animate= */ true) setStatusBarMode(OPAQUE) verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(OPAQUE.toTransitionModeInt(), /* animate= */ true) setStatusBarMode(LIGHTS_OUT) verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(LIGHTS_OUT.toTransitionModeInt(), /* animate= */ true) setStatusBarMode(LIGHTS_OUT_TRANSPARENT) verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(LIGHTS_OUT_TRANSPARENT.toTransitionModeInt(), /* animate= */ true) } Loading @@ -248,7 +241,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(/* mode= */ TRANSPARENT.toTransitionModeInt(), /* animate= */ false) } Loading @@ -262,7 +255,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(/* mode= */ TRANSPARENT.toTransitionModeInt(), /* animate= */ false) } Loading @@ -276,7 +269,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(/* mode= */ TRANSPARENT.toTransitionModeInt(), /* animate= */ false) } Loading @@ -295,7 +288,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { setTransientStatusBar() clearTransientStatusBar() verify(mockPhoneStatusBarTransitions, times(1)) verify(fakeStatusBarInitializer.statusBarTransitions, times(1)) .transitionTo(TRANSPARENT.toTransitionModeInt(), /* animate= */ true) } Loading @@ -318,18 +311,18 @@ class StatusBarOrchestratorTest : SysuiTestCase() { } private fun setTransientStatusBar() { statusBarModeRepository.defaultDisplay.showTransient() fakeStatusBarModePerDisplayRepository.showTransient() } private fun clearTransientStatusBar() { statusBarModeRepository.defaultDisplay.clearTransient() fakeStatusBarModePerDisplayRepository.clearTransient() } private fun setStatusBarWindowState(state: StatusBarWindowState) { fakeStatusBarWindowStateRepositoryStore.defaultDisplay.setWindowState(state) fakeStatusBarWindowStatePerDisplayRepository.setWindowState(state) } private fun setStatusBarMode(statusBarMode: StatusBarMode) { statusBarModeRepository.defaultDisplay.statusBarMode.value = statusBarMode fakeStatusBarModePerDisplayRepository.statusBarMode.value = statusBarMode } } packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * 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.view.Display import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.display.data.repository.DisplayRepository import com.android.systemui.display.data.repository.DisplayScopeRepository import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore import com.android.systemui.util.kotlin.pairwiseBy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch /** * Responsible for creating and starting the status bar components for each display. Also does it * for newly added displays. */ @SysUISingleton class MultiDisplayStatusBarStarter @Inject constructor( @Application private val applicationScope: CoroutineScope, private val displayScopeRepository: DisplayScopeRepository, private val statusBarOrchestratorFactory: StatusBarOrchestrator.Factory, private val statusBarWindowStateRepositoryStore: StatusBarWindowStateRepositoryStore, private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore, private val displayRepository: DisplayRepository, private val initializerStore: StatusBarInitializerStore, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, private val statusBarInitializerStore: StatusBarInitializerStore, ) : CoreStartable { init { StatusBarConnectedDisplays.assertInNewMode() } override fun start() { applicationScope.launch { displayRepository.displays .pairwiseBy { previousDisplays, currentDisplays -> currentDisplays - previousDisplays } .onStart { emit(displayRepository.displays.value) } .collect { newDisplays -> newDisplays.forEach { createAndStartComponentsForDisplay(it) } } } } private fun createAndStartComponentsForDisplay(display: Display) { val displayId = display.displayId createAndStartOrchestratorForDisplay(displayId) createAndStartInitializerForDisplay(displayId) } private fun createAndStartOrchestratorForDisplay(displayId: Int) { statusBarOrchestratorFactory .create( displayId, displayScopeRepository.scopeForDisplay(displayId), statusBarWindowStateRepositoryStore.forDisplay(displayId), statusBarModeRepositoryStore.forDisplay(displayId), initializerStore.forDisplay(displayId), statusBarWindowControllerStore.forDisplay(displayId), ) .start() } private fun createAndStartInitializerForDisplay(displayId: Int) { statusBarInitializerStore.forDisplay(displayId).start() } } packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt +9 −8 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions import com.android.systemui.statusbar.phone.PhoneStatusBarViewController import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import com.android.systemui.statusbar.window.StatusBarWindowController import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject Loading @@ -37,7 +37,7 @@ import javax.inject.Provider * Responsible for creating the status bar window and initializing the root components of that * window (see [CollapsedStatusBarFragment]) */ interface StatusBarInitializer { interface StatusBarInitializer : CoreStartable { var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener? Loading Loading @@ -68,18 +68,17 @@ interface StatusBarInitializer { } interface Factory { fun create(displayId: Int): StatusBarInitializer fun create(statusBarWindowController: StatusBarWindowController): StatusBarInitializer } } class StatusBarInitializerImpl @AssistedInject constructor( @Assisted private val displayId: Int, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, @Assisted private val statusBarWindowController: StatusBarWindowController, private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>, private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>, ) : CoreStartable, StatusBarInitializer { ) : StatusBarInitializer { private var component: StatusBarFragmentComponent? = null @get:VisibleForTesting Loading Loading @@ -111,7 +110,7 @@ constructor( private fun doStart() { initialized = true statusBarWindowControllerStore.defaultDisplay.fragmentHostManager statusBarWindowController.fragmentHostManager .addTagListener( CollapsedStatusBarFragment.TAG, object : FragmentHostManager.FragmentListener { Loading Loading @@ -145,6 +144,8 @@ constructor( @AssistedFactory interface Factory : StatusBarInitializer.Factory { override fun create(displayId: Int): StatusBarInitializerImpl override fun create( statusBarWindowController: StatusBarWindowController ): StatusBarInitializerImpl } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarterTest.kt 0 → 100644 +136 −0 Original line number Diff line number Diff line /* * 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 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.testScope import com.android.systemui.testKosmos import com.google.common.truth.Expect import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.verify @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) class MultiDisplayStatusBarStarterTest : SysuiTestCase() { @get:Rule val expect: Expect = Expect.create() private val kosmos = testKosmos().also { it.statusBarOrchestratorFactory = it.fakeStatusBarOrchestratorFactory it.statusBarInitializerStore = it.fakeStatusBarInitializerStore } private val testScope = kosmos.testScope private val fakeDisplayRepository = kosmos.displayRepository private val fakeOrchestratorFactory = kosmos.fakeStatusBarOrchestratorFactory private val fakeInitializerStore = kosmos.fakeStatusBarInitializerStore // Lazy, so that @EnableFlags is set before initializer is instantiated. private val underTest by lazy { kosmos.multiDisplayStatusBarStarter } @Test fun start_startsInitializersForCurrentDisplays() = testScope.runTest { fakeDisplayRepository.addDisplay(displayId = 1) fakeDisplayRepository.addDisplay(displayId = 2) underTest.start() runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 1).startedByCoreStartable) .isTrue() expect .that(fakeInitializerStore.forDisplay(displayId = 2).startedByCoreStartable) .isTrue() } @Test fun start_startsOrchestratorForCurrentDisplays() = testScope.runTest { fakeDisplayRepository.addDisplay(displayId = 1) fakeDisplayRepository.addDisplay(displayId = 2) underTest.start() runCurrent() verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = 1)!!).start() verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = 2)!!).start() } @Test fun displayAdded_orchestratorForNewDisplayIsStarted() = testScope.runTest { underTest.start() runCurrent() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = 3)!!).start() } @Test fun displayAdded_initializerForNewDisplayIsStarted() = testScope.runTest { underTest.start() runCurrent() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 3).startedByCoreStartable) .isTrue() } @Test fun displayAddedDuringStart_initializerForNewDisplayIsStarted() = testScope.runTest { underTest.start() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 3).startedByCoreStartable) .isTrue() } @Test fun displayAddedDuringStart_orchestratorForNewDisplayIsStarted() = testScope.runTest { underTest.start() fakeDisplayRepository.addDisplay(displayId = 3) runCurrent() expect .that(fakeInitializerStore.forDisplay(displayId = 3).startedByCoreStartable) .isTrue() } }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt +1 −2 Original line number Diff line number Diff line Loading @@ -60,10 +60,9 @@ class StatusBarInitializerTest : SysuiTestCase() { val underTest = StatusBarInitializerImpl( displayId = context.displayId, statusBarWindowControllerStore = windowControllerStore, collapsedStatusBarFragmentProvider = { mock(CollapsedStatusBarFragment::class.java) }, creationListeners = setOf(), statusBarWindowController = windowController, ) @Test Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt +39 −46 Original line number Diff line number Diff line Loading @@ -38,13 +38,10 @@ import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT_TRANSPARENT import com.android.systemui.statusbar.data.model.StatusBarMode.OPAQUE import com.android.systemui.statusbar.data.model.StatusBarMode.TRANSPARENT import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository import com.android.systemui.statusbar.phone.mockPhoneStatusBarTransitions import com.android.systemui.statusbar.phone.mockPhoneStatusBarViewController import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository import com.android.systemui.statusbar.window.data.model.StatusBarWindowState import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStateRepositoryStore import com.android.systemui.statusbar.window.data.repository.statusBarWindowStateRepositoryStore import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStatePerDisplayRepository import com.android.systemui.statusbar.window.fakeStatusBarWindowController import com.android.systemui.testKosmos import com.android.wm.shell.bubbles.bubbles import com.google.common.truth.Truth.assertThat Loading @@ -60,25 +57,20 @@ import org.mockito.kotlin.verify @RunWith(AndroidJUnit4::class) class StatusBarOrchestratorTest : SysuiTestCase() { private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher it.statusBarWindowStateRepositoryStore = it.fakeStatusBarWindowStateRepositoryStore } private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher } private val testScope = kosmos.testScope private val statusBarViewController = kosmos.mockPhoneStatusBarViewController private val statusBarWindowControllerStore = kosmos.fakeStatusBarWindowControllerStore private val statusBarModeRepository = kosmos.fakeStatusBarModeRepository private val pluginDependencyProvider = kosmos.mockPluginDependencyProvider private val notificationShadeWindowViewController = private val fakeStatusBarModePerDisplayRepository = kosmos.fakeStatusBarModePerDisplayRepository private val mockPluginDependencyProvider = kosmos.mockPluginDependencyProvider private val mockNotificationShadeWindowViewController = kosmos.mockNotificationShadeWindowViewController private val shadeSurface = kosmos.mockShadeSurface private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository private val fakeStatusBarWindowStateRepositoryStore = kosmos.fakeStatusBarWindowStateRepositoryStore private val mockShadeSurface = kosmos.mockShadeSurface private val fakeBouncerRepository = kosmos.fakeKeyguardBouncerRepository private val fakeStatusBarWindowStatePerDisplayRepository = kosmos.fakeStatusBarWindowStatePerDisplayRepository private val fakePowerRepository = kosmos.fakePowerRepository private val mockPhoneStatusBarTransitions = kosmos.mockPhoneStatusBarTransitions private val mockBubbles = kosmos.bubbles private val fakeStatusBarWindowController = kosmos.fakeStatusBarWindowController private val fakeStatusBarInitializer = kosmos.fakeStatusBarInitializer private val orchestrator = kosmos.statusBarOrchestrator Loading @@ -86,30 +78,31 @@ class StatusBarOrchestratorTest : SysuiTestCase() { fun start_setsUpPluginDependencies() { orchestrator.start() verify(pluginDependencyProvider).allowPluginDependency(DarkIconDispatcher::class.java) verify(pluginDependencyProvider).allowPluginDependency(StatusBarStateController::class.java) verify(mockPluginDependencyProvider).allowPluginDependency(DarkIconDispatcher::class.java) verify(mockPluginDependencyProvider) .allowPluginDependency(StatusBarStateController::class.java) } @Test fun start_attachesWindow() { orchestrator.start() assertThat(statusBarWindowControllerStore.defaultDisplay.isAttached).isTrue() assertThat(fakeStatusBarWindowController.isAttached).isTrue() } @Test fun start_setsStatusBarControllerOnShade() { orchestrator.start() verify(notificationShadeWindowViewController) .setStatusBarViewController(statusBarViewController) verify(mockNotificationShadeWindowViewController) .setStatusBarViewController(fakeStatusBarInitializer.statusBarViewController) } @Test fun start_updatesShadeExpansion() { orchestrator.start() verify(shadeSurface).updateExpansionAndVisibility() verify(mockShadeSurface).updateExpansionAndVisibility() } @Test Loading @@ -117,9 +110,9 @@ class StatusBarOrchestratorTest : SysuiTestCase() { testScope.runTest { orchestrator.start() bouncerRepository.setPrimaryShow(isShowing = true) fakeBouncerRepository.setPrimaryShow(isShowing = true) verify(statusBarViewController) verify(fakeStatusBarInitializer.statusBarViewController) .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) } Loading @@ -128,9 +121,9 @@ class StatusBarOrchestratorTest : SysuiTestCase() { testScope.runTest { orchestrator.start() bouncerRepository.setPrimaryShow(isShowing = false) fakeBouncerRepository.setPrimaryShow(isShowing = false) verify(statusBarViewController) verify(fakeStatusBarInitializer.statusBarViewController) .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) } Loading @@ -141,7 +134,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions).finishAnimations() verify(fakeStatusBarInitializer.statusBarTransitions).finishAnimations() } @Test Loading @@ -151,7 +144,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions, never()).finishAnimations() verify(fakeStatusBarInitializer.statusBarTransitions, never()).finishAnimations() } @Test Loading Loading @@ -208,7 +201,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(TRANSPARENT.toTransitionModeInt(), /* animate= */ true) } Loading @@ -222,19 +215,19 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(TRANSPARENT.toTransitionModeInt(), /* animate= */ true) setStatusBarMode(OPAQUE) verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(OPAQUE.toTransitionModeInt(), /* animate= */ true) setStatusBarMode(LIGHTS_OUT) verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(LIGHTS_OUT.toTransitionModeInt(), /* animate= */ true) setStatusBarMode(LIGHTS_OUT_TRANSPARENT) verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(LIGHTS_OUT_TRANSPARENT.toTransitionModeInt(), /* animate= */ true) } Loading @@ -248,7 +241,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(/* mode= */ TRANSPARENT.toTransitionModeInt(), /* animate= */ false) } Loading @@ -262,7 +255,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(/* mode= */ TRANSPARENT.toTransitionModeInt(), /* animate= */ false) } Loading @@ -276,7 +269,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { orchestrator.start() verify(mockPhoneStatusBarTransitions) verify(fakeStatusBarInitializer.statusBarTransitions) .transitionTo(/* mode= */ TRANSPARENT.toTransitionModeInt(), /* animate= */ false) } Loading @@ -295,7 +288,7 @@ class StatusBarOrchestratorTest : SysuiTestCase() { setTransientStatusBar() clearTransientStatusBar() verify(mockPhoneStatusBarTransitions, times(1)) verify(fakeStatusBarInitializer.statusBarTransitions, times(1)) .transitionTo(TRANSPARENT.toTransitionModeInt(), /* animate= */ true) } Loading @@ -318,18 +311,18 @@ class StatusBarOrchestratorTest : SysuiTestCase() { } private fun setTransientStatusBar() { statusBarModeRepository.defaultDisplay.showTransient() fakeStatusBarModePerDisplayRepository.showTransient() } private fun clearTransientStatusBar() { statusBarModeRepository.defaultDisplay.clearTransient() fakeStatusBarModePerDisplayRepository.clearTransient() } private fun setStatusBarWindowState(state: StatusBarWindowState) { fakeStatusBarWindowStateRepositoryStore.defaultDisplay.setWindowState(state) fakeStatusBarWindowStatePerDisplayRepository.setWindowState(state) } private fun setStatusBarMode(statusBarMode: StatusBarMode) { statusBarModeRepository.defaultDisplay.statusBarMode.value = statusBarMode fakeStatusBarModePerDisplayRepository.statusBarMode.value = statusBarMode } }
packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * 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.view.Display import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.display.data.repository.DisplayRepository import com.android.systemui.display.data.repository.DisplayScopeRepository import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore import com.android.systemui.util.kotlin.pairwiseBy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch /** * Responsible for creating and starting the status bar components for each display. Also does it * for newly added displays. */ @SysUISingleton class MultiDisplayStatusBarStarter @Inject constructor( @Application private val applicationScope: CoroutineScope, private val displayScopeRepository: DisplayScopeRepository, private val statusBarOrchestratorFactory: StatusBarOrchestrator.Factory, private val statusBarWindowStateRepositoryStore: StatusBarWindowStateRepositoryStore, private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore, private val displayRepository: DisplayRepository, private val initializerStore: StatusBarInitializerStore, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, private val statusBarInitializerStore: StatusBarInitializerStore, ) : CoreStartable { init { StatusBarConnectedDisplays.assertInNewMode() } override fun start() { applicationScope.launch { displayRepository.displays .pairwiseBy { previousDisplays, currentDisplays -> currentDisplays - previousDisplays } .onStart { emit(displayRepository.displays.value) } .collect { newDisplays -> newDisplays.forEach { createAndStartComponentsForDisplay(it) } } } } private fun createAndStartComponentsForDisplay(display: Display) { val displayId = display.displayId createAndStartOrchestratorForDisplay(displayId) createAndStartInitializerForDisplay(displayId) } private fun createAndStartOrchestratorForDisplay(displayId: Int) { statusBarOrchestratorFactory .create( displayId, displayScopeRepository.scopeForDisplay(displayId), statusBarWindowStateRepositoryStore.forDisplay(displayId), statusBarModeRepositoryStore.forDisplay(displayId), initializerStore.forDisplay(displayId), statusBarWindowControllerStore.forDisplay(displayId), ) .start() } private fun createAndStartInitializerForDisplay(displayId: Int) { statusBarInitializerStore.forDisplay(displayId).start() } }
packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt +9 −8 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions import com.android.systemui.statusbar.phone.PhoneStatusBarViewController import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import com.android.systemui.statusbar.window.StatusBarWindowController import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject Loading @@ -37,7 +37,7 @@ import javax.inject.Provider * Responsible for creating the status bar window and initializing the root components of that * window (see [CollapsedStatusBarFragment]) */ interface StatusBarInitializer { interface StatusBarInitializer : CoreStartable { var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener? Loading Loading @@ -68,18 +68,17 @@ interface StatusBarInitializer { } interface Factory { fun create(displayId: Int): StatusBarInitializer fun create(statusBarWindowController: StatusBarWindowController): StatusBarInitializer } } class StatusBarInitializerImpl @AssistedInject constructor( @Assisted private val displayId: Int, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, @Assisted private val statusBarWindowController: StatusBarWindowController, private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>, private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>, ) : CoreStartable, StatusBarInitializer { ) : StatusBarInitializer { private var component: StatusBarFragmentComponent? = null @get:VisibleForTesting Loading Loading @@ -111,7 +110,7 @@ constructor( private fun doStart() { initialized = true statusBarWindowControllerStore.defaultDisplay.fragmentHostManager statusBarWindowController.fragmentHostManager .addTagListener( CollapsedStatusBarFragment.TAG, object : FragmentHostManager.FragmentListener { Loading Loading @@ -145,6 +144,8 @@ constructor( @AssistedFactory interface Factory : StatusBarInitializer.Factory { override fun create(displayId: Int): StatusBarInitializerImpl override fun create( statusBarWindowController: StatusBarWindowController ): StatusBarInitializerImpl } }