diff options
7 files changed, 623 insertions, 9 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/StatusBarStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/StatusBarStartableTest.kt new file mode 100644 index 000000000000..9601f20add8e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/StatusBarStartableTest.kt @@ -0,0 +1,365 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.scene.domain.startable + +import android.app.StatusBarManager +import android.provider.DeviceConfig +import android.view.WindowManagerPolicyConstants +import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags +import com.android.internal.statusbar.statusBarService +import com.android.systemui.SysuiTestCase +import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.concurrency.fakeExecutor +import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository +import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus +import com.android.systemui.kosmos.testScope +import com.android.systemui.navigationbar.NavigationModeController +import com.android.systemui.navigationbar.navigationModeController +import com.android.systemui.power.data.repository.fakePowerRepository +import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.power.shared.model.WakefulnessState +import com.android.systemui.scene.data.repository.setSceneTransition +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor +import com.android.systemui.testKosmos +import com.android.systemui.util.fakeDeviceConfigProxy +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import kotlin.reflect.full.memberProperties +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.atLeastOnce +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import platform.test.runner.parameterized.Parameter +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters + +@SmallTest +@RunWith(ParameterizedAndroidJunit4::class) +@EnableSceneContainer +class StatusBarStartableTest : SysuiTestCase() { + + companion object { + @Parameters(name = "{0}") + @JvmStatic + fun testSpecs(): List<TestSpec> { + return listOf( + TestSpec( + id = 0, + expectedFlags = StatusBarManager.DISABLE_NONE, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = false, + isPowerGestureIntercepted = false, + ), + ), + TestSpec( + id = 1, + expectedFlags = StatusBarManager.DISABLE_NONE, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = true, + isOccluded = true, + isPowerGestureIntercepted = false, + ), + ), + TestSpec( + id = 2, + expectedFlags = StatusBarManager.DISABLE_NONE, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = false, + isPowerGestureIntercepted = true, + isOccluded = false, + ), + ), + TestSpec( + id = 3, + expectedFlags = StatusBarManager.DISABLE_NONE, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = true, + isOccluded = true, + isPowerGestureIntercepted = true, + isAuthenticationMethodSecure = false, + ), + ), + TestSpec( + id = 4, + expectedFlags = StatusBarManager.DISABLE_NONE, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = true, + isOccluded = true, + isPowerGestureIntercepted = true, + isAuthenticationMethodSecure = true, + isFaceEnrolledAndEnabled = false, + ), + ), + TestSpec( + id = 5, + expectedFlags = StatusBarManager.DISABLE_RECENT, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = true, + isOccluded = true, + isPowerGestureIntercepted = true, + isAuthenticationMethodSecure = true, + isFaceEnrolledAndEnabled = true, + ), + ), + TestSpec( + id = 6, + expectedFlags = StatusBarManager.DISABLE_RECENT, + Preconditions( + isForceHideHomeAndRecents = true, + isShowHomeOverLockscreen = true, + isGesturalMode = true, + isPowerGestureIntercepted = false, + ), + ), + TestSpec( + id = 7, + expectedFlags = StatusBarManager.DISABLE_RECENT, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = true, + isOccluded = false, + isShowHomeOverLockscreen = true, + isGesturalMode = true, + isPowerGestureIntercepted = false, + ), + ), + TestSpec( + id = 8, + expectedFlags = + StatusBarManager.DISABLE_RECENT or StatusBarManager.DISABLE_HOME, + Preconditions( + isForceHideHomeAndRecents = true, + isShowHomeOverLockscreen = true, + isGesturalMode = false, + isPowerGestureIntercepted = false, + ), + ), + TestSpec( + id = 9, + expectedFlags = + StatusBarManager.DISABLE_RECENT or StatusBarManager.DISABLE_HOME, + Preconditions( + isForceHideHomeAndRecents = false, + isKeyguardShowing = true, + isOccluded = false, + isShowHomeOverLockscreen = false, + isPowerGestureIntercepted = false, + ), + ), + ) + } + + @BeforeClass + @JvmStatic + fun setUpClass() { + val seenIds = mutableSetOf<Int>() + testSpecs().forEach { testSpec -> + assertWithMessage("Duplicate TestSpec id=${testSpec.id}") + .that(seenIds) + .doesNotContain(testSpec.id) + seenIds.add(testSpec.id) + } + } + } + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + + private val statusBarServiceMock = kosmos.statusBarService + private val flagsCaptor = argumentCaptor<Int>() + + private val navigationModeControllerMock = kosmos.navigationModeController + private var currentNavigationMode = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON + set(value) { + field = value + modeChangedListeners.forEach { listener -> listener.onNavigationModeChanged(field) } + } + + private val modeChangedListeners = mutableListOf<NavigationModeController.ModeChangedListener>() + + private val underTest = kosmos.statusBarStartable + + @JvmField @Parameter(0) var testSpec: TestSpec? = null + + @Before + fun setUp() { + whenever(navigationModeControllerMock.addListener(any())).thenAnswer { invocation -> + val listener = invocation.arguments[0] as NavigationModeController.ModeChangedListener + modeChangedListeners.add(listener) + currentNavigationMode + } + + underTest.start() + } + + @Test + fun test() = + testScope.runTest { + val preconditions = checkNotNull(testSpec).preconditions + preconditions.assertValid() + + setUpWith(preconditions) + + runCurrent() + + verify(statusBarServiceMock, atLeastOnce()) + .disableForUser(flagsCaptor.capture(), any(), any(), anyInt()) + assertThat(flagsCaptor.lastValue).isEqualTo(checkNotNull(testSpec).expectedFlags) + } + + /** Sets up the state to match what's specified in the given [preconditions]. */ + private fun TestScope.setUpWith( + preconditions: Preconditions, + ) { + if (!preconditions.isKeyguardShowing) { + kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( + SuccessFingerprintAuthenticationStatus(0, true) + ) + } + if (preconditions.isForceHideHomeAndRecents) { + whenIdle(Scenes.Bouncer) + } else if (preconditions.isKeyguardShowing) { + whenIdle(Scenes.Lockscreen) + } else { + whenIdle(Scenes.Gone) + } + runCurrent() + + kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( + showWhenLockedActivityOnTop = preconditions.isOccluded, + taskInfo = if (preconditions.isOccluded) mock() else null, + ) + + kosmos.fakeDeviceConfigProxy.setProperty( + DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, + preconditions.isShowHomeOverLockscreen.toString(), + /* makeDefault= */ false, + ) + kosmos.fakeExecutor.runAllReady() + + currentNavigationMode = + if (preconditions.isGesturalMode) { + WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL + } else { + WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON + } + + kosmos.fakeAuthenticationRepository.setAuthenticationMethod( + if (preconditions.isAuthenticationMethodSecure) { + AuthenticationMethodModel.Pin + } else { + AuthenticationMethodModel.None + } + ) + + kosmos.fakePowerRepository.updateWakefulness( + rawState = + if (preconditions.isPowerGestureIntercepted) WakefulnessState.AWAKE + else WakefulnessState.ASLEEP, + lastWakeReason = WakeSleepReason.POWER_BUTTON, + lastSleepReason = WakeSleepReason.POWER_BUTTON, + powerButtonLaunchGestureTriggered = preconditions.isPowerGestureIntercepted, + ) + + kosmos.fakeBiometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled( + preconditions.isFaceEnrolledAndEnabled + ) + + runCurrent() + } + + /** Sets up an idle state on the given [on] scene. */ + private fun whenIdle(on: SceneKey) { + kosmos.setSceneTransition(ObservableTransitionState.Idle(on)) + kosmos.sceneInteractor.changeScene(on, "") + } + + data class Preconditions( + val isForceHideHomeAndRecents: Boolean = false, + val isKeyguardShowing: Boolean = true, + val isOccluded: Boolean = false, + val isPowerGestureIntercepted: Boolean = false, + val isShowHomeOverLockscreen: Boolean = false, + val isGesturalMode: Boolean = true, + val isAuthenticationMethodSecure: Boolean = true, + val isFaceEnrolledAndEnabled: Boolean = false, + ) { + override fun toString(): String { + // Only include values set to true: + return buildString { + append("(") + append( + Preconditions::class + .memberProperties + .filter { it.get(this@Preconditions) == true } + .joinToString(", ") { "${it.name}=true" } + ) + append(")") + } + } + + fun assertValid() { + assertWithMessage( + "isForceHideHomeAndRecents means that the bouncer is showing so keyguard must" + + " be showing" + ) + .that(!isForceHideHomeAndRecents || isKeyguardShowing) + .isTrue() + assertWithMessage("Cannot be occluded if the keyguard isn't showing") + .that(!isOccluded || isKeyguardShowing) + .isTrue() + } + } + + data class TestSpec( + val id: Int, + val expectedFlags: Int, + val preconditions: Preconditions, + ) { + override fun toString(): String { + return "id=$id, expected=$expectedFlags, preconditions=$preconditions" + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 2d60fcca58cc..b70dbe240ce0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -151,6 +151,7 @@ import com.android.systemui.log.SessionTracker; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.res.R; +import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeExpansionStateManager; @@ -178,6 +179,8 @@ import com.android.wm.shell.keyguard.KeyguardTransitions; import dagger.Lazy; +import kotlinx.coroutines.CoroutineDispatcher; + import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -187,8 +190,6 @@ import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Consumer; -import kotlinx.coroutines.CoroutineDispatcher; - /** * Mediates requests related to the keyguard. This includes queries about the * state of the keyguard, power management events that effect whether the keyguard @@ -3502,12 +3503,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, + " --> flags=0x" + Integer.toHexString(flags)); } - try { - mStatusBarService.disableForUser(flags, mStatusBarDisableToken, - mContext.getPackageName(), - mSelectedUserInteractor.getSelectedUserId(true)); - } catch (RemoteException e) { - Log.d(TAG, "Failed to set disable flags: " + flags, e); + if (!SceneContainerFlag.isEnabled()) { + try { + mStatusBarService.disableForUser(flags, mStatusBarDisableToken, + mContext.getPackageName(), + mSelectedUserInteractor.getSelectedUserId(true)); + } catch (RemoteException e) { + Log.d(TAG, "Failed to set disable flags: " + flags, e); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt index 323ca871e8b0..08462d79b2fb 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt @@ -25,6 +25,7 @@ import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverM import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule import com.android.systemui.scene.domain.startable.SceneContainerStartable import com.android.systemui.scene.domain.startable.ScrimStartable +import com.android.systemui.scene.domain.startable.StatusBarStartable import com.android.systemui.scene.shared.model.SceneContainerConfig import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shared.flag.DualShade @@ -66,6 +67,11 @@ interface KeyguardlessSceneContainerFrameworkModule { @Binds @IntoMap + @ClassKey(StatusBarStartable::class) + fun statusBarStartable(impl: StatusBarStartable): CoreStartable + + @Binds + @IntoMap @ClassKey(WindowRootViewVisibilityInteractor::class) fun bindWindowRootViewVisibilityInteractor( impl: WindowRootViewVisibilityInteractor diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt index 4691ebaf95b3..17dc9a52f9b7 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt @@ -26,6 +26,7 @@ import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverM import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule import com.android.systemui.scene.domain.startable.SceneContainerStartable import com.android.systemui.scene.domain.startable.ScrimStartable +import com.android.systemui.scene.domain.startable.StatusBarStartable import com.android.systemui.scene.shared.model.SceneContainerConfig import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shared.flag.DualShade @@ -72,6 +73,11 @@ interface SceneContainerFrameworkModule { @Binds @IntoMap + @ClassKey(StatusBarStartable::class) + fun statusBarStartable(impl: StatusBarStartable): CoreStartable + + @Binds + @IntoMap @ClassKey(WindowRootViewVisibilityInteractor::class) fun bindWindowRootViewVisibilityInteractor( impl: WindowRootViewVisibilityInteractor diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt new file mode 100644 index 000000000000..893f030fab4d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt @@ -0,0 +1,180 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.scene.domain.startable + +import android.annotation.SuppressLint +import android.app.StatusBarManager +import android.content.Context +import android.os.Binder +import android.os.IBinder +import android.os.RemoteException +import android.provider.DeviceConfig +import android.util.Log +import com.android.compose.animation.scene.SceneKey +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags +import com.android.internal.statusbar.IStatusBarService +import com.android.systemui.CoreStartable +import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.deviceconfig.domain.interactor.DeviceConfigInteractor +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.navigation.domain.interactor.NavigationInteractor +import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.power.shared.model.WakefulnessModel +import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +@SysUISingleton +class StatusBarStartable +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + @Background private val backgroundDispatcher: CoroutineDispatcher, + @Application private val applicationContext: Context, + private val selectedUserInteractor: SelectedUserInteractor, + private val sceneInteractor: SceneInteractor, + private val deviceEntryInteractor: DeviceEntryInteractor, + private val sceneContainerOcclusionInteractor: SceneContainerOcclusionInteractor, + private val deviceConfigInteractor: DeviceConfigInteractor, + private val navigationInteractor: NavigationInteractor, + private val authenticationInteractor: AuthenticationInteractor, + private val powerInteractor: PowerInteractor, + private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor, + private val statusBarService: IStatusBarService, +) : CoreStartable { + + private val disableToken: IBinder = Binder() + + override fun start() { + if (!SceneContainerFlag.isEnabled) { + return + } + + applicationScope.launch { + combine( + selectedUserInteractor.selectedUser, + sceneInteractor.currentScene, + deviceEntryInteractor.isDeviceEntered, + sceneContainerOcclusionInteractor.invisibleDueToOcclusion, + deviceConfigInteractor.property( + namespace = DeviceConfig.NAMESPACE_SYSTEMUI, + name = SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, + default = true, + ), + navigationInteractor.isGesturalMode, + authenticationInteractor.authenticationMethod, + powerInteractor.detailedWakefulness, + ) { values -> + val selectedUserId = values[0] as Int + val currentScene = values[1] as SceneKey + val isDeviceEntered = values[2] as Boolean + val isOccluded = values[3] as Boolean + val isShowHomeOverLockscreen = values[4] as Boolean + val isGesturalMode = values[5] as Boolean + val authenticationMethod = values[6] as AuthenticationMethodModel + val wakefulnessModel = values[7] as WakefulnessModel + + val isForceHideHomeAndRecents = currentScene == Scenes.Bouncer + val isKeyguardShowing = !isDeviceEntered + val isPowerGestureIntercepted = + with(wakefulnessModel) { + isAwake() && + powerButtonLaunchGestureTriggered && + lastSleepReason == WakeSleepReason.POWER_BUTTON + } + + var flags = StatusBarManager.DISABLE_NONE + + if (isForceHideHomeAndRecents || (isKeyguardShowing && !isOccluded)) { + if (!isShowHomeOverLockscreen || !isGesturalMode) { + flags = flags or StatusBarManager.DISABLE_HOME + } + flags = flags or StatusBarManager.DISABLE_RECENT + } + + if ( + isPowerGestureIntercepted && + isOccluded && + authenticationMethod.isSecure && + deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled() + ) { + flags = flags or StatusBarManager.DISABLE_RECENT + } + + selectedUserId to flags + } + .distinctUntilChanged() + .collect { (selectedUserId, flags) -> + @SuppressLint("WrongConstant", "NonInjectedService") + if (applicationContext.getSystemService(Context.STATUS_BAR_SERVICE) == null) { + Log.w(TAG, "Could not get status bar manager") + return@collect + } + + withContext(backgroundDispatcher) { + try { + statusBarService.disableForUser( + flags, + disableToken, + applicationContext.packageName, + selectedUserId, + ) + } catch (e: RemoteException) { + Log.d(TAG, "Failed to set disable flags: $flags", e) + } + } + } + } + } + + override fun onBootCompleted() { + applicationScope.launch(backgroundDispatcher) { + try { + statusBarService.disableForUser( + StatusBarManager.DISABLE_NONE, + disableToken, + applicationContext.packageName, + selectedUserInteractor.getSelectedUserId(true), + ) + } catch (e: RemoteException) { + Log.d(TAG, "Failed to clear flags", e) + } + } + } + + companion object { + private const val TAG = "StatusBarStartable" + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt new file mode 100644 index 000000000000..ee69c30fe6b9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt @@ -0,0 +1,54 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.scene.domain.startable + +import android.content.applicationContext +import com.android.internal.statusbar.statusBarService +import com.android.systemui.authentication.domain.interactor.authenticationInteractor +import com.android.systemui.deviceconfig.domain.interactor.deviceConfigInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.navigation.domain.interactor.navigationInteractor +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.user.domain.interactor.selectedUserInteractor +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.statusBarStartable by Fixture { + StatusBarStartable( + applicationScope = applicationCoroutineScope, + backgroundDispatcher = testDispatcher, + applicationContext = applicationContext, + selectedUserInteractor = selectedUserInteractor, + sceneInteractor = sceneInteractor, + deviceEntryInteractor = deviceEntryInteractor, + sceneContainerOcclusionInteractor = sceneContainerOcclusionInteractor, + deviceConfigInteractor = deviceConfigInteractor, + navigationInteractor = navigationInteractor, + authenticationInteractor = authenticationInteractor, + powerInteractor = powerInteractor, + deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor, + statusBarService = statusBarService, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt index 1f2ecb7d172d..ed335f9a1834 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt @@ -39,7 +39,7 @@ class FakeUserRepository @Inject constructor() : UserRepository { // User id to represent a non system (human) user id. We presume this is the main user. const val MAIN_USER_ID = 10 - private const val DEFAULT_SELECTED_USER = 0 + const val DEFAULT_SELECTED_USER = 0 private val DEFAULT_SELECTED_USER_INFO = UserInfo( /* id= */ DEFAULT_SELECTED_USER, |