diff options
| author | 2024-11-04 14:12:47 +0000 | |
|---|---|---|
| committer | 2024-11-04 14:12:47 +0000 | |
| commit | f2cd7492526014034ca8af99b1c6fb17d92f5cc1 (patch) | |
| tree | 02c92967c4340ae1e12f47a1697aff4da180fc5a | |
| parent | 7cf1bb4801147f5a22e28a143023be94a0e1614e (diff) | |
| parent | 88228a8a16a6624d450e31be07d920828b11a726 (diff) | |
Merge "Prepare LightBarController for multi display" into main
11 files changed, 394 insertions, 132 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java index 2905a7329d21..646722bee35f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java @@ -116,6 +116,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; +import com.android.systemui.statusbar.data.repository.LightBarControllerStore; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.LightBarController; @@ -208,7 +209,7 @@ public class NavigationBarTest extends SysuiTestCase { @Mock private LightBarController mLightBarController; @Mock - private LightBarController.Factory mLightBarcontrollerFactory; + private LightBarControllerStore mLightBarControllerStore; @Mock private AutoHideController mAutoHideController; @Mock @@ -257,7 +258,7 @@ public class NavigationBarTest extends SysuiTestCase { public void setup() throws Exception { MockitoAnnotations.initMocks(this); - when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController); + when(mLightBarControllerStore.forDisplay(anyInt())).thenReturn(mLightBarController); when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController); when(mNavigationBarView.getHomeButton()).thenReturn(mHomeButton); when(mNavigationBarView.getRecentsButton()).thenReturn(mRecentsButton); @@ -649,8 +650,7 @@ public class NavigationBarTest extends SysuiTestCase { mFakeExecutor, mUiEventLogger, mNavBarHelper, - mLightBarController, - mLightBarcontrollerFactory, + mLightBarControllerStore, mAutoHideController, mAutoHideControllerFactory, Optional.of(mTelecomManager), diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt new file mode 100644 index 000000000000..18eef33813f6 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt @@ -0,0 +1,76 @@ +/* + * 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.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +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 LightBarControllerStoreImplTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val testScope = kosmos.testScope + private val fakeDisplayRepository = kosmos.displayRepository + + private val underTest = kosmos.lightBarControllerStoreImpl + + @Before + fun start() { + underTest.start() + } + + @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) } + + @Test + fun forDisplay_startsInstance() = + 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/LightBarControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java index 88ec18dd65f3..12f6825b462e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java @@ -48,12 +48,10 @@ import com.android.keyguard.TestScopeProvider; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.settings.FakeDisplayTracker; import com.android.systemui.statusbar.data.model.StatusBarAppearance; import com.android.systemui.statusbar.data.model.StatusBarMode; -import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository; +import com.android.systemui.statusbar.data.repository.FakeStatusBarModePerDisplayRepository; import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.util.kotlin.JavaAdapter; import kotlinx.coroutines.test.TestScope; @@ -81,8 +79,8 @@ public class LightBarControllerTest extends SysuiTestCase { private SysuiDarkIconDispatcher mStatusBarIconController; private LightBarController mLightBarController; private final TestScope mTestScope = TestScopeProvider.getTestScope(); - private final FakeStatusBarModeRepository mStatusBarModeRepository = - new FakeStatusBarModeRepository(); + private final FakeStatusBarModePerDisplayRepository mStatusBarModeRepository = + new FakeStatusBarModePerDisplayRepository(); @Before public void setup() { @@ -92,15 +90,15 @@ public class LightBarControllerTest extends SysuiTestCase { mLightBarTransitionsController = mock(LightBarTransitionsController.class); when(mStatusBarIconController.getTransitionsController()).thenReturn( mLightBarTransitionsController); - mLightBarController = new LightBarController( - mContext, - new JavaAdapter(mTestScope), + mLightBarController = new LightBarControllerImpl( + mContext.getDisplayId(), + mTestScope, mStatusBarIconController, mock(BatteryController.class), mock(NavigationModeController.class), mStatusBarModeRepository, mock(DumpManager.class), - new FakeDisplayTracker(mContext)); + mTestScope.getCoroutineContext()); mLightBarController.start(); } @@ -121,7 +119,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -142,7 +140,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(0 /* appearance */, secondBounds) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -165,7 +163,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -190,7 +188,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, thirdBounds) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -214,7 +212,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(0 /* appearance */, secondBounds) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -231,7 +229,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1)) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -249,7 +247,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(0, new Rect(0, 0, 1, 1)) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -266,7 +264,7 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1)) ); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -276,7 +274,7 @@ public class LightBarControllerTest extends SysuiTestCase { reset(mStatusBarIconController); // WHEN the same appearance regions but different status bar mode is sent - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.LIGHTS_OUT_TRANSPARENT, STATUS_BAR_BOUNDS, @@ -298,7 +296,7 @@ public class LightBarControllerTest extends SysuiTestCase { /* start= */ new Rect(0, 0, 10, 10), /* end= */ new Rect(0, 0, 20, 20)); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, startingBounds, @@ -311,7 +309,7 @@ public class LightBarControllerTest extends SysuiTestCase { BoundsPair newBounds = new BoundsPair( /* start= */ new Rect(0, 0, 30, 30), /* end= */ new Rect(0, 0, 40, 40)); - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( + mStatusBarModeRepository.getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, newBounds, diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java index 96c0cac53908..40613c0edc68 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java @@ -149,6 +149,7 @@ import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.data.repository.LightBarControllerStore; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.CentralSurfaces; @@ -258,8 +259,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements private boolean mTransientShownFromGestureOnSystemBar; private int mNavBarMode = NAV_BAR_MODE_3BUTTON; private LightBarController mLightBarController; - private final LightBarController mMainLightBarController; - private final LightBarController.Factory mLightBarControllerFactory; + private final LightBarControllerStore mLightBarControllerStore; private AutoHideController mAutoHideController; private final AutoHideController mMainAutoHideController; private final AutoHideController.Factory mAutoHideControllerFactory; @@ -580,8 +580,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements @Background Executor bgExecutor, UiEventLogger uiEventLogger, NavBarHelper navBarHelper, - LightBarController mainLightBarController, - LightBarController.Factory lightBarControllerFactory, + LightBarControllerStore lightBarControllerStore, AutoHideController mainAutoHideController, AutoHideController.Factory autoHideControllerFactory, Optional<TelecomManager> telecomManagerOptional, @@ -628,8 +627,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mUiEventLogger = uiEventLogger; mNavBarHelper = navBarHelper; mNotificationShadeDepthController = notificationShadeDepthController; - mMainLightBarController = mainLightBarController; - mLightBarControllerFactory = lightBarControllerFactory; + mLightBarControllerStore = lightBarControllerStore; mMainAutoHideController = mainAutoHideController; mAutoHideControllerFactory = autoHideControllerFactory; mTelecomManagerOptional = telecomManagerOptional; @@ -842,8 +840,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements // Unfortunately, we still need it because status bar needs LightBarController // before notifications creation. We cannot directly use getLightBarController() // from NavigationBarFragment directly. - LightBarController lightBarController = mIsOnDefaultDisplay - ? mMainLightBarController : mLightBarControllerFactory.create(mContext); + LightBarController lightBarController = mLightBarControllerStore.forDisplay(mDisplayId); setLightBarController(lightBarController); // TODO(b/118592525): to support multi-display, we start to add something which is diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt index f65ae67efbf1..434120051039 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt @@ -26,6 +26,7 @@ import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.data.StatusBarDataLayerModule +import com.android.systemui.statusbar.data.repository.LightBarControllerStore import com.android.systemui.statusbar.phone.LightBarController import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl @@ -55,26 +56,26 @@ import dagger.multibindings.IntoMap * [com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule], etc.). */ @Module(includes = [StatusBarDataLayerModule::class, SystemBarUtilsProxyImpl.Module::class]) -abstract class StatusBarModule { +interface StatusBarModule { @Binds @IntoMap @ClassKey(OngoingCallController::class) - abstract fun bindOngoingCallController(impl: OngoingCallController): CoreStartable + fun bindOngoingCallController(impl: OngoingCallController): CoreStartable @Binds @IntoMap @ClassKey(LightBarController::class) - abstract fun bindLightBarController(impl: LightBarController): CoreStartable + fun lightBarControllerAsCoreStartable(controller: LightBarController): CoreStartable @Binds @IntoMap @ClassKey(StatusBarSignalPolicy::class) - abstract fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable + fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable @Binds @SysUISingleton - abstract fun statusBarWindowControllerFactory( + fun statusBarWindowControllerFactory( implFactory: StatusBarWindowControllerImpl.Factory ): StatusBarWindowController.Factory @@ -82,6 +83,12 @@ abstract class StatusBarModule { @Provides @SysUISingleton + fun lightBarController(store: LightBarControllerStore): LightBarController { + return store.defaultDisplay + } + + @Provides + @SysUISingleton fun windowControllerStore( multiDisplayImplLazy: Lazy<MultiDisplayStatusBarWindowControllerStore>, singleDisplayImplLazy: Lazy<SingleDisplayStatusBarWindowControllerStore>, 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 f2d926fc22b1..39de28e7cb49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.data import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryModule +import com.android.systemui.statusbar.data.repository.LightBarControllerStoreModule import com.android.systemui.statusbar.data.repository.RemoteInputRepositoryModule import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerModule import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStoreModule @@ -28,6 +29,7 @@ import dagger.Module includes = [ KeyguardStatusBarRepositoryModule::class, + LightBarControllerStoreModule::class, RemoteInputRepositoryModule::class, StatusBarConfigurationControllerModule::class, StatusBarContentInsetsProviderStoreModule::class, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt new file mode 100644 index 000000000000..ff50e3100672 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.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 com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.display.data.repository.DisplayRepository +import com.android.systemui.display.data.repository.DisplayScopeRepository +import com.android.systemui.display.data.repository.PerDisplayStore +import com.android.systemui.display.data.repository.PerDisplayStoreImpl +import com.android.systemui.statusbar.phone.LightBarController +import com.android.systemui.statusbar.phone.LightBarControllerImpl +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope + +/** Provides per display instances of [LightBarController]. */ +interface LightBarControllerStore : PerDisplayStore<LightBarController> + +@SysUISingleton +class LightBarControllerStoreImpl +@Inject +constructor( + @Background backgroundApplicationScope: CoroutineScope, + displayRepository: DisplayRepository, + private val factory: LightBarControllerImpl.Factory, + private val displayScopeRepository: DisplayScopeRepository, + private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore, +) : + LightBarControllerStore, + PerDisplayStoreImpl<LightBarController>(backgroundApplicationScope, displayRepository) { + + override fun createInstanceForDisplay(displayId: Int): LightBarController { + return factory + .create( + displayId, + displayScopeRepository.scopeForDisplay(displayId), + statusBarModeRepositoryStore.forDisplay(displayId), + ) + .also { it.start() } + } + + override suspend fun onDisplayRemovalAction(instance: LightBarController) { + instance.stop() + } + + override val instanceClass = LightBarController::class.java +} + +@Module +interface LightBarControllerStoreModule { + + @Binds fun store(impl: LightBarControllerStoreImpl): LightBarControllerStore + + @Binds + @IntoMap + @ClassKey(LightBarControllerStore::class) + fun storeAsCoreStartable(impl: LightBarControllerStoreImpl): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt new file mode 100644 index 000000000000..b5b3162233c0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt @@ -0,0 +1,69 @@ +/* + * 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.view.WindowInsetsController +import com.android.internal.colorextraction.ColorExtractor +import com.android.internal.view.AppearanceRegion +import com.android.systemui.CoreStartable + +/** Controls how light status bar flag applies to the icons. */ +interface LightBarController : CoreStartable { + + fun stop() + + fun setNavigationBar(navigationBar: LightBarTransitionsController) + + fun setBiometricUnlockController(biometricUnlockController: BiometricUnlockController) + + fun onNavigationBarAppearanceChanged( + @WindowInsetsController.Appearance appearance: Int, + nbModeChanged: Boolean, + navigationBarMode: Int, + navbarColorManagedByIme: Boolean, + ) + + fun onNavigationBarModeChanged(newBarMode: Int) + + fun setQsCustomizing(customizing: Boolean) + + /** Set if Quick Settings is fully expanded, which affects notification scrim visibility. */ + fun setQsExpanded(expanded: Boolean) + + /** Set if Global Actions dialog is visible, which requires dark mode (light buttons). */ + fun setGlobalActionsVisible(visible: Boolean) + + /** + * Controls the light status bar temporarily for back navigation. + * + * @param appearance the customized appearance. + */ + fun customizeStatusBarAppearance(appearance: AppearanceRegion) + + /** + * Sets whether the direct-reply is in use or not. + * + * @param directReplying `true` when the direct-reply is in-use. + */ + fun setDirectReplying(directReplying: Boolean) + + fun setScrimState( + scrimState: ScrimState, + scrimBehindAlpha: Float, + scrimInFrontColor: ColorExtractor.GradientColors, + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java index a33996b99900..6ff9f4c9c820 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.systemui.statusbar.phone; @@ -22,9 +22,9 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_TRANSPARENT; -import android.content.Context; import android.graphics.Rect; import android.util.Log; +import android.view.Display; import android.view.InsetsFlags; import android.view.ViewDebug; import android.view.WindowInsetsController.Appearance; @@ -34,30 +34,32 @@ import androidx.annotation.Nullable; import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.view.AppearanceRegion; -import com.android.systemui.CoreStartable; -import com.android.systemui.Dumpable; -import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.settings.DisplayTracker; import com.android.systemui.statusbar.data.model.StatusBarAppearance; -import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore; +import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.Compile; -import com.android.systemui.util.kotlin.JavaAdapter; +import com.android.systemui.util.kotlin.JavaAdapterKt; + +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; + +import kotlin.coroutines.CoroutineContext; + +import kotlinx.coroutines.CoroutineScope; import java.io.PrintWriter; import java.util.ArrayList; -import javax.inject.Inject; - /** * Controls how light status bar flag applies to the icons. */ -@SysUISingleton -public class LightBarController implements - BatteryController.BatteryStateChangeCallback, Dumpable, CoreStartable { +public class LightBarControllerImpl implements + BatteryController.BatteryStateChangeCallback, LightBarController { private static final String TAG = "LightBarController"; private static final boolean DEBUG_NAVBAR = Compile.IS_DEBUG; @@ -65,10 +67,13 @@ public class LightBarController implements private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f; - private final JavaAdapter mJavaAdapter; + private final CoroutineScope mCoroutineScope; private final SysuiDarkIconDispatcher mStatusBarIconController; private final BatteryController mBatteryController; - private final StatusBarModeRepositoryStore mStatusBarModeRepository; + private final NavigationModeController mNavModeController; + private final DumpManager mDumpManager; + private final StatusBarModePerDisplayRepository mStatusBarModeRepository; + private final CoroutineContext mMainContext; private BiometricUnlockController mBiometricUnlockController; private LightBarTransitionsController mNavigationBarController; @@ -119,42 +124,59 @@ public class LightBarController implements private String mLastNavigationBarAppearanceChangedLog; private StringBuilder mLogStringBuilder = null; - @Inject - public LightBarController( - Context ctx, - JavaAdapter javaAdapter, + private final String mDumpableName; + + private final NavigationModeController.ModeChangedListener mNavigationModeListener = + (mode) -> mNavigationMode = mode; + + @AssistedInject + public LightBarControllerImpl( + @Assisted int displayId, + @Assisted CoroutineScope coroutineScope, DarkIconDispatcher darkIconDispatcher, BatteryController batteryController, NavigationModeController navModeController, - StatusBarModeRepositoryStore statusBarModeRepository, + @Assisted StatusBarModePerDisplayRepository statusBarModeRepository, DumpManager dumpManager, - DisplayTracker displayTracker) { - mJavaAdapter = javaAdapter; + @Main CoroutineContext mainContext) { + mCoroutineScope = coroutineScope; mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher; mBatteryController = batteryController; - mBatteryController.addCallback(this); + mNavModeController = navModeController; + mDumpManager = dumpManager; mStatusBarModeRepository = statusBarModeRepository; - mNavigationMode = navModeController.addListener((mode) -> { - mNavigationMode = mode; - }); - - if (ctx.getDisplayId() == displayTracker.getDefaultDisplayId()) { - dumpManager.registerDumpable(getClass().getSimpleName(), this); - } + mMainContext = mainContext; + String dumpableNameSuffix = + displayId == Display.DEFAULT_DISPLAY ? "" : String.valueOf(displayId); + mDumpableName = getClass().getSimpleName() + dumpableNameSuffix; } @Override public void start() { - mJavaAdapter.alwaysCollectFlow( - mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance(), + mDumpManager.registerCriticalDumpable(mDumpableName, this); + mBatteryController.addCallback(this); + mNavigationMode = mNavModeController.addListener(mNavigationModeListener); + JavaAdapterKt.collectFlow( + mCoroutineScope, + mMainContext, + mStatusBarModeRepository.getStatusBarAppearance(), this::onStatusBarAppearanceChanged); } + @Override + public void stop() { + mDumpManager.unregisterDumpable(mDumpableName); + mBatteryController.removeCallback(this); + mNavModeController.removeListener(mNavigationModeListener); + } + + @Override public void setNavigationBar(LightBarTransitionsController navigationBar) { mNavigationBarController = navigationBar; updateNavigation(); } + @Override public void setBiometricUnlockController( BiometricUnlockController biometricUnlockController) { mBiometricUnlockController = biometricUnlockController; @@ -202,6 +224,7 @@ public class LightBarController implements mNavbarColorManagedByIme = navbarColorManagedByIme; } + @Override public void onNavigationBarAppearanceChanged(@Appearance int appearance, boolean nbModeChanged, int navigationBarMode, boolean navbarColorManagedByIme) { int diff = appearance ^ mAppearance; @@ -244,6 +267,7 @@ public class LightBarController implements mNavbarColorManagedByIme = navbarColorManagedByIme; } + @Override public void onNavigationBarModeChanged(int newBarMode) { mHasLightNavigationBar = isLight(mAppearance, newBarMode, APPEARANCE_LIGHT_NAVIGATION_BARS); } @@ -258,30 +282,28 @@ public class LightBarController implements mNavigationBarMode, mNavbarColorManagedByIme); } + @Override public void setQsCustomizing(boolean customizing) { if (mQsCustomizing == customizing) return; mQsCustomizing = customizing; reevaluate(); } - /** Set if Quick Settings is fully expanded, which affects notification scrim visibility */ + @Override public void setQsExpanded(boolean expanded) { if (mQsExpanded == expanded) return; mQsExpanded = expanded; reevaluate(); } - /** Set if Global Actions dialog is visible, which requires dark mode (light buttons) */ + @Override public void setGlobalActionsVisible(boolean visible) { if (mGlobalActionsVisible == visible) return; mGlobalActionsVisible = visible; reevaluate(); } - /** - * Controls the light status bar temporarily for back navigation. - * @param appearance the custmoized appearance. - */ + @Override public void customizeStatusBarAppearance(AppearanceRegion appearance) { if (appearance != null) { final ArrayList<AppearanceRegion> appearancesList = new ArrayList<>(); @@ -303,16 +325,14 @@ public class LightBarController implements } } - /** - * Sets whether the direct-reply is in use or not. - * @param directReplying {@code true} when the direct-reply is in-use. - */ + @Override public void setDirectReplying(boolean directReplying) { if (mDirectReplying == directReplying) return; mDirectReplying = directReplying; reevaluate(); } + @Override public void setScrimState(ScrimState scrimState, float scrimBehindAlpha, GradientColors scrimInFrontColor) { boolean bouncerVisibleLast = mBouncerVisible; @@ -387,20 +407,17 @@ public class LightBarController implements } } - // If no one is light, all icons become white. if (lightBarBounds.isEmpty()) { - mStatusBarIconController.getTransitionsController().setIconsDark( - false, animateChange()); - } - - // If all stacks are light, all icons get dark. - else if (lightBarBounds.size() == numStacks) { + // If no one is light, all icons become white. + mStatusBarIconController + .getTransitionsController() + .setIconsDark(false, animateChange()); + } else if (lightBarBounds.size() == numStacks) { + // If all stacks are light, all icons get dark. mStatusBarIconController.setIconsDarkArea(null); mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange()); - } - - // Not the same for every stack, magic! - else { + } else { + // Not the same for every stack, magic! mStatusBarIconController.setIconsDarkArea(lightBarBounds); mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange()); } @@ -468,47 +485,15 @@ public class LightBarController implements } } - /** - * Injectable factory for creating a {@link LightBarController}. - */ - public static class Factory { - private final JavaAdapter mJavaAdapter; - private final DarkIconDispatcher mDarkIconDispatcher; - private final BatteryController mBatteryController; - private final NavigationModeController mNavModeController; - private final StatusBarModeRepositoryStore mStatusBarModeRepository; - private final DumpManager mDumpManager; - private final DisplayTracker mDisplayTracker; - - @Inject - public Factory( - JavaAdapter javaAdapter, - DarkIconDispatcher darkIconDispatcher, - BatteryController batteryController, - NavigationModeController navModeController, - StatusBarModeRepositoryStore statusBarModeRepository, - DumpManager dumpManager, - DisplayTracker displayTracker) { - mJavaAdapter = javaAdapter; - mDarkIconDispatcher = darkIconDispatcher; - mBatteryController = batteryController; - mNavModeController = navModeController; - mStatusBarModeRepository = statusBarModeRepository; - mDumpManager = dumpManager; - mDisplayTracker = displayTracker; - } + /** Injectable factory for creating a {@link LightBarControllerImpl}. */ + @AssistedFactory + @FunctionalInterface + public interface Factory { - /** Create an {@link LightBarController} */ - public LightBarController create(Context context) { - return new LightBarController( - context, - mJavaAdapter, - mDarkIconDispatcher, - mBatteryController, - mNavModeController, - mStatusBarModeRepository, - mDumpManager, - mDisplayTracker); - } + /** Creates a {@link LightBarControllerImpl}. */ + LightBarControllerImpl create( + int displayId, + CoroutineScope coroutineScope, + StatusBarModePerDisplayRepository statusBarModePerDisplayRepository); } } diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt index 315912406b6d..63a5b3f1e6f6 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt @@ -20,6 +20,7 @@ import android.view.View import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope import androidx.lifecycle.repeatOnLifecycle +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.lifecycle.repeatWhenAttached @@ -35,7 +36,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn -import com.android.app.tracing.coroutines.launchTraced as launch +import kotlinx.coroutines.plus /** A class allowing Java classes to collect on Kotlin flows. */ @SysUISingleton @@ -102,6 +103,22 @@ fun <T> collectFlow( } } +/** + * Collect information for the given [flow], calling [consumer] for each emitted event on the + * specified [collectContext]. + * + * Collection will continue until the given [scope] is cancelled. + */ +@JvmOverloads +fun <T> collectFlow( + scope: CoroutineScope, + collectContext: CoroutineContext = scope.coroutineContext, + flow: Flow<T>, + consumer: Consumer<T>, +): Job { + return scope.plus(collectContext).launch { flow.collect { consumer.accept(it) } } +} + fun <A, B, R> combineFlows(flow1: Flow<A>, flow2: Flow<B>, bifunction: (A, B) -> R): Flow<R> { return combine(flow1, flow2, bifunction) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreKosmos.kt new file mode 100644 index 000000000000..5f337326b546 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreKosmos.kt @@ -0,0 +1,34 @@ +/* + * 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.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.displayScopeRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import org.mockito.kotlin.mock + +val Kosmos.lightBarControllerStoreImpl by + Kosmos.Fixture { + LightBarControllerStoreImpl( + backgroundApplicationScope = applicationCoroutineScope, + displayRepository = displayRepository, + factory = { _, _, _ -> mock() }, + displayScopeRepository = displayScopeRepository, + statusBarModeRepositoryStore = statusBarModeRepository, + ) + } |