Loading packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright 2023 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.model import com.android.systemui.dagger.qualifiers.DisplayId /** * In-bulk updates multiple flag values and commits the update. * * Example: * ``` * sysuiState.updateFlags( * displayId, * SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != SceneKey.Gone), * SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == SceneKey.Shade), * SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == SceneKey.QuickSettings), * SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == SceneKey.Bouncer), * SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to (sceneKey == SceneKey.Lockscreen), * ) * ``` * * You can inject [displayId] by injecting it using: * ``` * @DisplayId private val displayId: Int`, * ``` */ fun SysUiState.updateFlags( @DisplayId displayId: Int, vararg flagValuePairs: Pair<Int, Boolean>, ) { flagValuePairs.forEach { (flag, enabled) -> setFlag(flag, enabled) } commitUpdate(displayId) } packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt +32 −0 Original line number Diff line number Diff line Loading @@ -20,14 +20,22 @@ import com.android.systemui.CoreStartable import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.DisplayId import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.model.SysUiState import com.android.systemui.model.updateFlags import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.distinctUntilChanged Loading @@ -49,12 +57,15 @@ constructor( private val authenticationInteractor: AuthenticationInteractor, private val keyguardInteractor: KeyguardInteractor, private val featureFlags: FeatureFlags, private val sysUiState: SysUiState, @DisplayId private val displayId: Int, ) : CoreStartable { override fun start() { if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) { hydrateVisibility() automaticallySwitchScenes() hydrateSystemUiState() } } Loading Loading @@ -121,6 +132,27 @@ constructor( } } /** Keeps [SysUiState] up-to-date */ private fun hydrateSystemUiState() { applicationScope.launch { sceneInteractor .currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT) .map { it.key } .distinctUntilChanged() .collect { sceneKey -> sysUiState.updateFlags( displayId, SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != SceneKey.Gone), SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == SceneKey.Shade), SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == SceneKey.QuickSettings), SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == SceneKey.Bouncer), SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to (sceneKey == SceneKey.Lockscreen), ) } } } private fun switchToScene(targetSceneKey: SceneKey) { sceneInteractor.setCurrentScene( containerName = CONTAINER_NAME, Loading packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright 2023 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.model import android.view.Display import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.settings.FakeDisplayTracker import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @SmallTest @RunWith(JUnit4::class) class SysUiStateExtTest : SysuiTestCase() { private val underTest = SysUiState(FakeDisplayTracker(context)) @Test fun updateFlags() { underTest.updateFlags( Display.DEFAULT_DISPLAY, 1 to true, 2 to false, 3 to true, ) assertThat(underTest.flags and 1).isNotEqualTo(0) assertThat(underTest.flags and 2).isEqualTo(0) assertThat(underTest.flags and 3).isNotEqualTo(0) } } packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt +38 −0 Original line number Diff line number Diff line Loading @@ -14,8 +14,11 @@ * limitations under the License. */ @file:OptIn(ExperimentalCoroutinesApi::class) package com.android.systemui.scene.domain.startable import android.view.Display import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue Loading @@ -23,17 +26,24 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.shared.model.WakeSleepReason import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.model.SysUiState import com.android.systemui.scene.SceneTestUtils import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.map import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.times import org.mockito.Mockito.verify @SmallTest @RunWith(JUnit4::class) Loading @@ -53,6 +63,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { utils.keyguardInteractor( repository = keyguardRepository, ) private val sysUiState: SysUiState = mock() private val underTest = SystemUiDefaultSceneContainerStartable( Loading @@ -61,6 +72,8 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { authenticationInteractor = authenticationInteractor, keyguardInteractor = keyguardInteractor, featureFlags = featureFlags, sysUiState = sysUiState, displayId = Display.DEFAULT_DISPLAY, ) @Before Loading Loading @@ -375,6 +388,31 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { assertThat(currentSceneKey).isEqualTo(SceneKey.Shade) } @Test fun hydrateSystemUiState() = testScope.runTest { underTest.start() runCurrent() clearInvocations(sysUiState) listOf( SceneKey.Gone, SceneKey.Lockscreen, SceneKey.Bouncer, SceneKey.Shade, SceneKey.QuickSettings, ) .forEachIndexed { index, sceneKey -> sceneInteractor.setCurrentScene( SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(sceneKey), ) runCurrent() verify(sysUiState, times(index + 1)).commitUpdate(Display.DEFAULT_DISPLAY) } } private fun prepareState( isFeatureEnabled: Boolean = true, isDeviceUnlocked: Boolean = false, Loading Loading
packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright 2023 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.model import com.android.systemui.dagger.qualifiers.DisplayId /** * In-bulk updates multiple flag values and commits the update. * * Example: * ``` * sysuiState.updateFlags( * displayId, * SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != SceneKey.Gone), * SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == SceneKey.Shade), * SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == SceneKey.QuickSettings), * SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == SceneKey.Bouncer), * SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to (sceneKey == SceneKey.Lockscreen), * ) * ``` * * You can inject [displayId] by injecting it using: * ``` * @DisplayId private val displayId: Int`, * ``` */ fun SysUiState.updateFlags( @DisplayId displayId: Int, vararg flagValuePairs: Pair<Int, Boolean>, ) { flagValuePairs.forEach { (flag, enabled) -> setFlag(flag, enabled) } commitUpdate(displayId) }
packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt +32 −0 Original line number Diff line number Diff line Loading @@ -20,14 +20,22 @@ import com.android.systemui.CoreStartable import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.DisplayId import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.model.SysUiState import com.android.systemui.model.updateFlags import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.distinctUntilChanged Loading @@ -49,12 +57,15 @@ constructor( private val authenticationInteractor: AuthenticationInteractor, private val keyguardInteractor: KeyguardInteractor, private val featureFlags: FeatureFlags, private val sysUiState: SysUiState, @DisplayId private val displayId: Int, ) : CoreStartable { override fun start() { if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) { hydrateVisibility() automaticallySwitchScenes() hydrateSystemUiState() } } Loading Loading @@ -121,6 +132,27 @@ constructor( } } /** Keeps [SysUiState] up-to-date */ private fun hydrateSystemUiState() { applicationScope.launch { sceneInteractor .currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT) .map { it.key } .distinctUntilChanged() .collect { sceneKey -> sysUiState.updateFlags( displayId, SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != SceneKey.Gone), SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == SceneKey.Shade), SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == SceneKey.QuickSettings), SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == SceneKey.Bouncer), SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to (sceneKey == SceneKey.Lockscreen), ) } } } private fun switchToScene(targetSceneKey: SceneKey) { sceneInteractor.setCurrentScene( containerName = CONTAINER_NAME, Loading
packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright 2023 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.model import android.view.Display import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.settings.FakeDisplayTracker import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @SmallTest @RunWith(JUnit4::class) class SysUiStateExtTest : SysuiTestCase() { private val underTest = SysUiState(FakeDisplayTracker(context)) @Test fun updateFlags() { underTest.updateFlags( Display.DEFAULT_DISPLAY, 1 to true, 2 to false, 3 to true, ) assertThat(underTest.flags and 1).isNotEqualTo(0) assertThat(underTest.flags and 2).isEqualTo(0) assertThat(underTest.flags and 3).isNotEqualTo(0) } }
packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt +38 −0 Original line number Diff line number Diff line Loading @@ -14,8 +14,11 @@ * limitations under the License. */ @file:OptIn(ExperimentalCoroutinesApi::class) package com.android.systemui.scene.domain.startable import android.view.Display import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue Loading @@ -23,17 +26,24 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.shared.model.WakeSleepReason import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.model.SysUiState import com.android.systemui.scene.SceneTestUtils import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.map import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.times import org.mockito.Mockito.verify @SmallTest @RunWith(JUnit4::class) Loading @@ -53,6 +63,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { utils.keyguardInteractor( repository = keyguardRepository, ) private val sysUiState: SysUiState = mock() private val underTest = SystemUiDefaultSceneContainerStartable( Loading @@ -61,6 +72,8 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { authenticationInteractor = authenticationInteractor, keyguardInteractor = keyguardInteractor, featureFlags = featureFlags, sysUiState = sysUiState, displayId = Display.DEFAULT_DISPLAY, ) @Before Loading Loading @@ -375,6 +388,31 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { assertThat(currentSceneKey).isEqualTo(SceneKey.Shade) } @Test fun hydrateSystemUiState() = testScope.runTest { underTest.start() runCurrent() clearInvocations(sysUiState) listOf( SceneKey.Gone, SceneKey.Lockscreen, SceneKey.Bouncer, SceneKey.Shade, SceneKey.QuickSettings, ) .forEachIndexed { index, sceneKey -> sceneInteractor.setCurrentScene( SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(sceneKey), ) runCurrent() verify(sysUiState, times(index + 1)).commitUpdate(Display.DEFAULT_DISPLAY) } } private fun prepareState( isFeatureEnabled: Boolean = true, isDeviceUnlocked: Boolean = false, Loading