Loading packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt 0 → 100644 +108 −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.shade.domain.interactor import android.content.applicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.kosmos.testScope import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags import com.android.systemui.scene.shared.model.ObservableTransitionState import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.shared.recents.utilities.Utilities import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Assume import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class ShadeBackActionInteractorImplTest : SysuiTestCase() { val kosmos = testKosmos().apply { fakeSceneContainerFlags.enabled = true } val testScope = kosmos.testScope val sceneInteractor = kosmos.sceneInteractor val deviceEntryRepository = kosmos.fakeDeviceEntryRepository val underTest = kosmos.shadeBackActionInteractor @Before fun ignoreSplitShade() { Assume.assumeFalse(Utilities.isLargeScreen(kosmos.applicationContext)) } @Test fun animateCollapseQs_notOnQs() = testScope.runTest { setScene(SceneKey.Shade) underTest.animateCollapseQs(true) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Shade) } @Test fun animateCollapseQs_fullyCollapse_entered() = testScope.runTest { enterDevice() setScene(SceneKey.QuickSettings) underTest.animateCollapseQs(true) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Gone) } @Test fun animateCollapseQs_fullyCollapse_locked() = testScope.runTest { deviceEntryRepository.setUnlocked(false) setScene(SceneKey.QuickSettings) underTest.animateCollapseQs(true) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Lockscreen) } @Test fun animateCollapseQs_notFullyCollapse() = testScope.runTest { setScene(SceneKey.QuickSettings) underTest.animateCollapseQs(false) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Shade) } private fun enterDevice() { deviceEntryRepository.setUnlocked(true) testScope.runCurrent() setScene(SceneKey.Gone) } private fun setScene(key: SceneKey) { sceneInteractor.changeScene(SceneModel(key), "test") sceneInteractor.setTransitionState( MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) ) testScope.runCurrent() } } packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt +10 −10 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor import com.android.systemui.shade.QuickSettingsController import com.android.systemui.shade.ShadeController import com.android.systemui.shade.ShadeViewController import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager Loading Loading @@ -64,8 +64,8 @@ constructor( } override fun onBackProgressed(backEvent: BackEvent) { if (shouldBackBeHandled() && shadeViewController.canBeCollapsed()) { shadeViewController.onBackProgressed(backEvent.progress) if (shouldBackBeHandled() && shadeBackActionInteractor.canBeCollapsed()) { shadeBackActionInteractor.onBackProgressed(backEvent.progress) } } } Loading @@ -77,12 +77,12 @@ constructor( get() = notificationShadeWindowController.windowRootView?.viewRootImpl?.onBackInvokedDispatcher private lateinit var shadeViewController: ShadeViewController private lateinit var shadeBackActionInteractor: ShadeBackActionInteractor private lateinit var qsController: QuickSettingsController fun setup(qsController: QuickSettingsController, svController: ShadeViewController) { fun setup(qsController: QuickSettingsController, svController: ShadeBackActionInteractor) { this.qsController = qsController this.shadeViewController = svController this.shadeBackActionInteractor = svController } override fun start() { Loading Loading @@ -114,16 +114,16 @@ constructor( return true } if (qsController.expanded) { shadeViewController.animateCollapseQs(false) shadeBackActionInteractor.animateCollapseQs(false) return true } if (shadeViewController.closeUserSwitcherIfOpen()) { if (shadeBackActionInteractor.closeUserSwitcherIfOpen()) { return true } if (shouldBackBeHandled()) { if (shadeViewController.canBeCollapsed()) { if (shadeBackActionInteractor.canBeCollapsed()) { // this is the Shade dismiss animation, so make sure QQS closes when it ends. shadeViewController.onBackPressed() shadeBackActionInteractor.onBackPressed() shadeController.animateCollapseShade() } return true Loading packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt +5 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.shade.data.repository.ShadeRepositoryImpl import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorEmptyImpl import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractorEmptyImpl import dagger.Binds Loading @@ -33,6 +34,10 @@ abstract class ShadeEmptyImplModule { @SysUISingleton abstract fun bindsShadeViewController(svc: ShadeViewControllerEmptyImpl): ShadeViewController @Binds @SysUISingleton abstract fun bindsShadeBack(sbai: ShadeViewControllerEmptyImpl): ShadeBackActionInteractor @Binds @SysUISingleton abstract fun bindsShadeController(sc: ShadeControllerEmptyImpl): ShadeController Loading packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt +16 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import com.android.systemui.shade.domain.interactor.BaseShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorSceneContainerImpl import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractorImpl import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl Loading Loading @@ -78,6 +80,20 @@ abstract class ShadeModule { sceneContainerOff.get() } } @Provides @SysUISingleton fun provideShadeBackActionInteractor( sceneContainerFlags: SceneContainerFlags, sceneContainerOn: Provider<ShadeBackActionInteractorImpl>, sceneContainerOff: Provider<NotificationPanelViewController> ): ShadeBackActionInteractor { return if (sceneContainerFlags.isEnabled()) { sceneContainerOn.get() } else { sceneContainerOff.get() } } } @Binds Loading packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt +2 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.shade import android.view.ViewPropertyAnimator import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.statusbar.GestureRecorder import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.HeadsUpManager Loading @@ -25,7 +26,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager * this class. If any method in this class is needed outside of CentralSurfacesImpl, it must be * pulled up into ShadeViewController. */ interface ShadeSurface : ShadeViewController { interface ShadeSurface : ShadeViewController, ShadeBackActionInteractor { /** Initialize objects instead of injecting to avoid circular dependencies. */ fun initDependencies( centralSurfaces: CentralSurfaces, Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt 0 → 100644 +108 −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.shade.domain.interactor import android.content.applicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.kosmos.testScope import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags import com.android.systemui.scene.shared.model.ObservableTransitionState import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.shared.recents.utilities.Utilities import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Assume import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class ShadeBackActionInteractorImplTest : SysuiTestCase() { val kosmos = testKosmos().apply { fakeSceneContainerFlags.enabled = true } val testScope = kosmos.testScope val sceneInteractor = kosmos.sceneInteractor val deviceEntryRepository = kosmos.fakeDeviceEntryRepository val underTest = kosmos.shadeBackActionInteractor @Before fun ignoreSplitShade() { Assume.assumeFalse(Utilities.isLargeScreen(kosmos.applicationContext)) } @Test fun animateCollapseQs_notOnQs() = testScope.runTest { setScene(SceneKey.Shade) underTest.animateCollapseQs(true) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Shade) } @Test fun animateCollapseQs_fullyCollapse_entered() = testScope.runTest { enterDevice() setScene(SceneKey.QuickSettings) underTest.animateCollapseQs(true) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Gone) } @Test fun animateCollapseQs_fullyCollapse_locked() = testScope.runTest { deviceEntryRepository.setUnlocked(false) setScene(SceneKey.QuickSettings) underTest.animateCollapseQs(true) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Lockscreen) } @Test fun animateCollapseQs_notFullyCollapse() = testScope.runTest { setScene(SceneKey.QuickSettings) underTest.animateCollapseQs(false) runCurrent() assertThat(sceneInteractor.desiredScene.value.key).isEqualTo(SceneKey.Shade) } private fun enterDevice() { deviceEntryRepository.setUnlocked(true) testScope.runCurrent() setScene(SceneKey.Gone) } private fun setScene(key: SceneKey) { sceneInteractor.changeScene(SceneModel(key), "test") sceneInteractor.setTransitionState( MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) ) testScope.runCurrent() } }
packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt +10 −10 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor import com.android.systemui.shade.QuickSettingsController import com.android.systemui.shade.ShadeController import com.android.systemui.shade.ShadeViewController import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager Loading Loading @@ -64,8 +64,8 @@ constructor( } override fun onBackProgressed(backEvent: BackEvent) { if (shouldBackBeHandled() && shadeViewController.canBeCollapsed()) { shadeViewController.onBackProgressed(backEvent.progress) if (shouldBackBeHandled() && shadeBackActionInteractor.canBeCollapsed()) { shadeBackActionInteractor.onBackProgressed(backEvent.progress) } } } Loading @@ -77,12 +77,12 @@ constructor( get() = notificationShadeWindowController.windowRootView?.viewRootImpl?.onBackInvokedDispatcher private lateinit var shadeViewController: ShadeViewController private lateinit var shadeBackActionInteractor: ShadeBackActionInteractor private lateinit var qsController: QuickSettingsController fun setup(qsController: QuickSettingsController, svController: ShadeViewController) { fun setup(qsController: QuickSettingsController, svController: ShadeBackActionInteractor) { this.qsController = qsController this.shadeViewController = svController this.shadeBackActionInteractor = svController } override fun start() { Loading Loading @@ -114,16 +114,16 @@ constructor( return true } if (qsController.expanded) { shadeViewController.animateCollapseQs(false) shadeBackActionInteractor.animateCollapseQs(false) return true } if (shadeViewController.closeUserSwitcherIfOpen()) { if (shadeBackActionInteractor.closeUserSwitcherIfOpen()) { return true } if (shouldBackBeHandled()) { if (shadeViewController.canBeCollapsed()) { if (shadeBackActionInteractor.canBeCollapsed()) { // this is the Shade dismiss animation, so make sure QQS closes when it ends. shadeViewController.onBackPressed() shadeBackActionInteractor.onBackPressed() shadeController.animateCollapseShade() } return true Loading
packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt +5 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.shade.data.repository.ShadeRepositoryImpl import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorEmptyImpl import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractorEmptyImpl import dagger.Binds Loading @@ -33,6 +34,10 @@ abstract class ShadeEmptyImplModule { @SysUISingleton abstract fun bindsShadeViewController(svc: ShadeViewControllerEmptyImpl): ShadeViewController @Binds @SysUISingleton abstract fun bindsShadeBack(sbai: ShadeViewControllerEmptyImpl): ShadeBackActionInteractor @Binds @SysUISingleton abstract fun bindsShadeController(sc: ShadeControllerEmptyImpl): ShadeController Loading
packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt +16 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import com.android.systemui.shade.domain.interactor.BaseShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorSceneContainerImpl import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractorImpl import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl Loading Loading @@ -78,6 +80,20 @@ abstract class ShadeModule { sceneContainerOff.get() } } @Provides @SysUISingleton fun provideShadeBackActionInteractor( sceneContainerFlags: SceneContainerFlags, sceneContainerOn: Provider<ShadeBackActionInteractorImpl>, sceneContainerOff: Provider<NotificationPanelViewController> ): ShadeBackActionInteractor { return if (sceneContainerFlags.isEnabled()) { sceneContainerOn.get() } else { sceneContainerOff.get() } } } @Binds Loading
packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt +2 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.shade import android.view.ViewPropertyAnimator import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor import com.android.systemui.statusbar.GestureRecorder import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.HeadsUpManager Loading @@ -25,7 +26,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager * this class. If any method in this class is needed outside of CentralSurfacesImpl, it must be * pulled up into ShadeViewController. */ interface ShadeSurface : ShadeViewController { interface ShadeSurface : ShadeViewController, ShadeBackActionInteractor { /** Initialize objects instead of injecting to avoid circular dependencies. */ fun initDependencies( centralSurfaces: CentralSurfaces, Loading