Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +5 −1 Original line number Diff line number Diff line Loading @@ -128,7 +128,11 @@ fun SceneContainer( } }, ) { SceneTransitionLayout(state = state, modifier = modifier.fillMaxSize()) { SceneTransitionLayout( state = state, modifier = modifier.fillMaxSize(), swipeSourceDetector = viewModel.edgeDetector, ) { sceneByKey.forEach { (sceneKey, scene) -> scene( key = sceneKey, Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +4 −0 Original line number Diff line number Diff line Loading @@ -379,6 +379,10 @@ sealed class UserAction { return this to UserActionResult(toScene = scene) } infix fun to(overlay: OverlayKey): Pair<UserAction, UserActionResult> { return this to UserActionResult(toOverlay = overlay) } /** Resolve this into a [Resolved] user action given [layoutDirection]. */ internal abstract fun resolve(layoutDirection: LayoutDirection): Resolved Loading packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt +54 −0 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package com.android.systemui.scene.ui.viewmodel import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.MotionEvent import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.DefaultEdgeDetector import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.domain.interactor.falsingInteractor import com.android.systemui.classifier.fakeFalsingManager Loading @@ -37,6 +40,10 @@ import com.android.systemui.scene.shared.logger.sceneLogger import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.shade.data.repository.fakeShadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever Loading @@ -60,6 +67,7 @@ class SceneContainerViewModelTest : SysuiTestCase() { private val testScope by lazy { kosmos.testScope } private val sceneInteractor by lazy { kosmos.sceneInteractor } private val fakeSceneDataSource by lazy { kosmos.fakeSceneDataSource } private val fakeShadeRepository by lazy { kosmos.fakeShadeRepository } private val sceneContainerConfig by lazy { kosmos.sceneContainerConfig } private val falsingManager by lazy { kosmos.fakeFalsingManager } Loading @@ -75,6 +83,8 @@ class SceneContainerViewModelTest : SysuiTestCase() { sceneInteractor = sceneInteractor, falsingInteractor = kosmos.falsingInteractor, powerInteractor = kosmos.powerInteractor, shadeInteractor = kosmos.shadeInteractor, splitEdgeDetector = kosmos.splitEdgeDetector, logger = kosmos.sceneLogger, motionEventHandlerReceiver = { motionEventHandler -> this@SceneContainerViewModelTest.motionEventHandler = motionEventHandler Loading Loading @@ -287,4 +297,48 @@ class SceneContainerViewModelTest : SysuiTestCase() { assertThat(actionableContentKey).isEqualTo(Overlays.QuickSettingsShade) } @Test @DisableFlags(DualShade.FLAG_NAME) fun edgeDetector_singleShade_usesDefaultEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(false) assertThat(shadeMode).isEqualTo(ShadeMode.Single) assertThat(underTest.edgeDetector).isEqualTo(DefaultEdgeDetector) } @Test @DisableFlags(DualShade.FLAG_NAME) fun edgeDetector_splitShade_usesDefaultEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(true) assertThat(shadeMode).isEqualTo(ShadeMode.Split) assertThat(underTest.edgeDetector).isEqualTo(DefaultEdgeDetector) } @Test @EnableFlags(DualShade.FLAG_NAME) fun edgeDetector_dualShade_narrowScreen_usesSplitEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(false) assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(underTest.edgeDetector).isEqualTo(kosmos.splitEdgeDetector) } @Test @EnableFlags(DualShade.FLAG_NAME) fun edgeDetector_dualShade_wideScreen_usesSplitEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(true) assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(underTest.edgeDetector).isEqualTo(kosmos.splitEdgeDetector) } } packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SplitEdgeDetectorTest.kt 0 → 100644 +274 −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.scene.ui.viewmodel import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Bottom import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.End import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Left import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Right import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Start import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopEnd import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopLeft import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopRight import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopStart import com.google.common.truth.Truth.assertThat import kotlin.test.assertFailsWith import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class SplitEdgeDetectorTest : SysuiTestCase() { private val edgeSize = 40 private val screenWidth = 800 private val screenHeight = 600 private var edgeSplitFraction = 0.7f private val underTest = SplitEdgeDetector( topEdgeSplitFraction = { edgeSplitFraction }, edgeSize = edgeSize.dp, ) @Test fun source_noEdge_detectsNothing() { val detectedEdge = swipeVerticallyFrom( x = screenWidth / 2, y = screenHeight / 2, ) assertThat(detectedEdge).isNull() } @Test fun source_swipeVerticallyOnTopLeft_detectsTopLeft() { val detectedEdge = swipeVerticallyFrom( x = 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopLeft) } @Test fun source_swipeHorizontallyOnTopLeft_detectsLeft() { val detectedEdge = swipeHorizontallyFrom( x = 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(Left) } @Test fun source_swipeVerticallyOnTopRight_detectsTopRight() { val detectedEdge = swipeVerticallyFrom( x = screenWidth - 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopRight) } @Test fun source_swipeHorizontallyOnTopRight_detectsRight() { val detectedEdge = swipeHorizontallyFrom( x = screenWidth - 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(Right) } @Test fun source_swipeVerticallyToLeftOfSplit_detectsTopLeft() { val detectedEdge = swipeVerticallyFrom( x = (screenWidth * edgeSplitFraction).toInt() - 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopLeft) } @Test fun source_swipeVerticallyToRightOfSplit_detectsTopRight() { val detectedEdge = swipeVerticallyFrom( x = (screenWidth * edgeSplitFraction).toInt() + 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopRight) } @Test fun source_edgeSplitFractionUpdatesDynamically() { val middleX = (screenWidth * 0.5f).toInt() val topY = 0 // Split closer to the right; middle of screen is considered "left". edgeSplitFraction = 0.6f assertThat(swipeVerticallyFrom(x = middleX, y = topY)).isEqualTo(TopLeft) // Split closer to the left; middle of screen is considered "right". edgeSplitFraction = 0.4f assertThat(swipeVerticallyFrom(x = middleX, y = topY)).isEqualTo(TopRight) // Illegal fraction. edgeSplitFraction = 1.2f assertFailsWith<IllegalArgumentException> { swipeVerticallyFrom(x = middleX, y = topY) } // Illegal fraction. edgeSplitFraction = -0.3f assertFailsWith<IllegalArgumentException> { swipeVerticallyFrom(x = middleX, y = topY) } } @Test fun source_swipeVerticallyOnBottom_detectsBottom() { val detectedEdge = swipeVerticallyFrom( x = screenWidth / 3, y = screenHeight - (edgeSize / 2), ) assertThat(detectedEdge).isEqualTo(Bottom) } @Test fun source_swipeHorizontallyOnBottom_detectsNothing() { val detectedEdge = swipeHorizontallyFrom( x = screenWidth / 3, y = screenHeight - (edgeSize - 1), ) assertThat(detectedEdge).isNull() } @Test fun source_swipeHorizontallyOnLeft_detectsLeft() { val detectedEdge = swipeHorizontallyFrom( x = edgeSize - 1, y = screenHeight / 2, ) assertThat(detectedEdge).isEqualTo(Left) } @Test fun source_swipeVerticallyOnLeft_detectsNothing() { val detectedEdge = swipeVerticallyFrom( x = edgeSize - 1, y = screenHeight / 2, ) assertThat(detectedEdge).isNull() } @Test fun source_swipeHorizontallyOnRight_detectsRight() { val detectedEdge = swipeHorizontallyFrom( x = screenWidth - edgeSize + 1, y = screenHeight / 2, ) assertThat(detectedEdge).isEqualTo(Right) } @Test fun source_swipeVerticallyOnRight_detectsNothing() { val detectedEdge = swipeVerticallyFrom( x = screenWidth - edgeSize + 1, y = screenHeight / 2, ) assertThat(detectedEdge).isNull() } @Test fun resolve_startInLtr_resolvesLeft() { val resolvedEdge = Start.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Left) } @Test fun resolve_startInRtl_resolvesRight() { val resolvedEdge = Start.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Right) } @Test fun resolve_endInLtr_resolvesRight() { val resolvedEdge = End.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Right) } @Test fun resolve_endInRtl_resolvesLeft() { val resolvedEdge = End.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Left) } @Test fun resolve_topStartInLtr_resolvesTopLeft() { val resolvedEdge = TopStart.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopLeft) } @Test fun resolve_topStartInRtl_resolvesTopRight() { val resolvedEdge = TopStart.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopRight) } @Test fun resolve_topEndInLtr_resolvesTopRight() { val resolvedEdge = TopEnd.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopRight) } @Test fun resolve_topEndInRtl_resolvesTopLeft() { val resolvedEdge = TopEnd.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopLeft) } private fun swipeVerticallyFrom(x: Int, y: Int): SceneContainerEdge? { return swipeFrom(x, y, Orientation.Vertical) } private fun swipeHorizontallyFrom(x: Int, y: Int): SceneContainerEdge? { return swipeFrom(x, y, Orientation.Horizontal) } private fun swipeFrom(x: Int, y: Int, orientation: Orientation): SceneContainerEdge? { return underTest.source( layoutSize = IntSize(width = screenWidth, height = screenHeight), position = IntOffset(x, y), density = Density(1f), orientation = orientation, ) } } packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt +33 −13 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.parameterizeSceneContainerFlag import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository Loading @@ -39,6 +38,7 @@ import com.android.systemui.kosmos.testScope 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.shade.data.repository.fakeShadeRepository import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.shadeTestUtil import com.android.systemui.shade.shared.flag.DualShade Loading Loading @@ -66,18 +66,18 @@ import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() { val kosmos = testKosmos() val testScope = kosmos.testScope val configurationRepository by lazy { kosmos.fakeConfigurationRepository } val deviceProvisioningRepository by lazy { kosmos.fakeDeviceProvisioningRepository } val disableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository } val keyguardRepository by lazy { kosmos.fakeKeyguardRepository } val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } val powerRepository by lazy { kosmos.fakePowerRepository } val shadeTestUtil by lazy { kosmos.shadeTestUtil } val userRepository by lazy { kosmos.fakeUserRepository } val userSetupRepository by lazy { kosmos.fakeUserSetupRepository } val dozeParameters by lazy { kosmos.dozeParameters } private val kosmos = testKosmos() private val testScope = kosmos.testScope private val deviceProvisioningRepository by lazy { kosmos.fakeDeviceProvisioningRepository } private val disableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository } private val keyguardRepository by lazy { kosmos.fakeKeyguardRepository } private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } private val powerRepository by lazy { kosmos.fakePowerRepository } private val shadeRepository by lazy { kosmos.fakeShadeRepository } private val shadeTestUtil by lazy { kosmos.shadeTestUtil } private val userRepository by lazy { kosmos.fakeUserRepository } private val userSetupRepository by lazy { kosmos.fakeUserSetupRepository } private val dozeParameters by lazy { kosmos.dozeParameters } lateinit var underTest: ShadeInteractorImpl Loading Loading @@ -497,4 +497,24 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(shadeMode).isEqualTo(ShadeMode.Dual) } @Test fun getTopEdgeSplitFraction_narrowScreen_splitInHalf() = testScope.runTest { // Ensure isShadeLayoutWide is collected. val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide) shadeRepository.setShadeLayoutWide(false) assertThat(underTest.getTopEdgeSplitFraction()).isEqualTo(0.5f) } @Test fun getTopEdgeSplitFraction_wideScreen_leftSideLarger() = testScope.runTest { // Ensure isShadeLayoutWide is collected. val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide) shadeRepository.setShadeLayoutWide(true) assertThat(underTest.getTopEdgeSplitFraction()).isGreaterThan(0.5f) } } Loading
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +5 −1 Original line number Diff line number Diff line Loading @@ -128,7 +128,11 @@ fun SceneContainer( } }, ) { SceneTransitionLayout(state = state, modifier = modifier.fillMaxSize()) { SceneTransitionLayout( state = state, modifier = modifier.fillMaxSize(), swipeSourceDetector = viewModel.edgeDetector, ) { sceneByKey.forEach { (sceneKey, scene) -> scene( key = sceneKey, Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +4 −0 Original line number Diff line number Diff line Loading @@ -379,6 +379,10 @@ sealed class UserAction { return this to UserActionResult(toScene = scene) } infix fun to(overlay: OverlayKey): Pair<UserAction, UserActionResult> { return this to UserActionResult(toOverlay = overlay) } /** Resolve this into a [Resolved] user action given [layoutDirection]. */ internal abstract fun resolve(layoutDirection: LayoutDirection): Resolved Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt +54 −0 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package com.android.systemui.scene.ui.viewmodel import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.MotionEvent import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.DefaultEdgeDetector import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.domain.interactor.falsingInteractor import com.android.systemui.classifier.fakeFalsingManager Loading @@ -37,6 +40,10 @@ import com.android.systemui.scene.shared.logger.sceneLogger import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.shade.data.repository.fakeShadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever Loading @@ -60,6 +67,7 @@ class SceneContainerViewModelTest : SysuiTestCase() { private val testScope by lazy { kosmos.testScope } private val sceneInteractor by lazy { kosmos.sceneInteractor } private val fakeSceneDataSource by lazy { kosmos.fakeSceneDataSource } private val fakeShadeRepository by lazy { kosmos.fakeShadeRepository } private val sceneContainerConfig by lazy { kosmos.sceneContainerConfig } private val falsingManager by lazy { kosmos.fakeFalsingManager } Loading @@ -75,6 +83,8 @@ class SceneContainerViewModelTest : SysuiTestCase() { sceneInteractor = sceneInteractor, falsingInteractor = kosmos.falsingInteractor, powerInteractor = kosmos.powerInteractor, shadeInteractor = kosmos.shadeInteractor, splitEdgeDetector = kosmos.splitEdgeDetector, logger = kosmos.sceneLogger, motionEventHandlerReceiver = { motionEventHandler -> this@SceneContainerViewModelTest.motionEventHandler = motionEventHandler Loading Loading @@ -287,4 +297,48 @@ class SceneContainerViewModelTest : SysuiTestCase() { assertThat(actionableContentKey).isEqualTo(Overlays.QuickSettingsShade) } @Test @DisableFlags(DualShade.FLAG_NAME) fun edgeDetector_singleShade_usesDefaultEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(false) assertThat(shadeMode).isEqualTo(ShadeMode.Single) assertThat(underTest.edgeDetector).isEqualTo(DefaultEdgeDetector) } @Test @DisableFlags(DualShade.FLAG_NAME) fun edgeDetector_splitShade_usesDefaultEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(true) assertThat(shadeMode).isEqualTo(ShadeMode.Split) assertThat(underTest.edgeDetector).isEqualTo(DefaultEdgeDetector) } @Test @EnableFlags(DualShade.FLAG_NAME) fun edgeDetector_dualShade_narrowScreen_usesSplitEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(false) assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(underTest.edgeDetector).isEqualTo(kosmos.splitEdgeDetector) } @Test @EnableFlags(DualShade.FLAG_NAME) fun edgeDetector_dualShade_wideScreen_usesSplitEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) fakeShadeRepository.setShadeLayoutWide(true) assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(underTest.edgeDetector).isEqualTo(kosmos.splitEdgeDetector) } }
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SplitEdgeDetectorTest.kt 0 → 100644 +274 −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.scene.ui.viewmodel import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Bottom import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.End import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Left import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Right import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.Start import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopEnd import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopLeft import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopRight import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge.TopStart import com.google.common.truth.Truth.assertThat import kotlin.test.assertFailsWith import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class SplitEdgeDetectorTest : SysuiTestCase() { private val edgeSize = 40 private val screenWidth = 800 private val screenHeight = 600 private var edgeSplitFraction = 0.7f private val underTest = SplitEdgeDetector( topEdgeSplitFraction = { edgeSplitFraction }, edgeSize = edgeSize.dp, ) @Test fun source_noEdge_detectsNothing() { val detectedEdge = swipeVerticallyFrom( x = screenWidth / 2, y = screenHeight / 2, ) assertThat(detectedEdge).isNull() } @Test fun source_swipeVerticallyOnTopLeft_detectsTopLeft() { val detectedEdge = swipeVerticallyFrom( x = 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopLeft) } @Test fun source_swipeHorizontallyOnTopLeft_detectsLeft() { val detectedEdge = swipeHorizontallyFrom( x = 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(Left) } @Test fun source_swipeVerticallyOnTopRight_detectsTopRight() { val detectedEdge = swipeVerticallyFrom( x = screenWidth - 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopRight) } @Test fun source_swipeHorizontallyOnTopRight_detectsRight() { val detectedEdge = swipeHorizontallyFrom( x = screenWidth - 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(Right) } @Test fun source_swipeVerticallyToLeftOfSplit_detectsTopLeft() { val detectedEdge = swipeVerticallyFrom( x = (screenWidth * edgeSplitFraction).toInt() - 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopLeft) } @Test fun source_swipeVerticallyToRightOfSplit_detectsTopRight() { val detectedEdge = swipeVerticallyFrom( x = (screenWidth * edgeSplitFraction).toInt() + 1, y = edgeSize - 1, ) assertThat(detectedEdge).isEqualTo(TopRight) } @Test fun source_edgeSplitFractionUpdatesDynamically() { val middleX = (screenWidth * 0.5f).toInt() val topY = 0 // Split closer to the right; middle of screen is considered "left". edgeSplitFraction = 0.6f assertThat(swipeVerticallyFrom(x = middleX, y = topY)).isEqualTo(TopLeft) // Split closer to the left; middle of screen is considered "right". edgeSplitFraction = 0.4f assertThat(swipeVerticallyFrom(x = middleX, y = topY)).isEqualTo(TopRight) // Illegal fraction. edgeSplitFraction = 1.2f assertFailsWith<IllegalArgumentException> { swipeVerticallyFrom(x = middleX, y = topY) } // Illegal fraction. edgeSplitFraction = -0.3f assertFailsWith<IllegalArgumentException> { swipeVerticallyFrom(x = middleX, y = topY) } } @Test fun source_swipeVerticallyOnBottom_detectsBottom() { val detectedEdge = swipeVerticallyFrom( x = screenWidth / 3, y = screenHeight - (edgeSize / 2), ) assertThat(detectedEdge).isEqualTo(Bottom) } @Test fun source_swipeHorizontallyOnBottom_detectsNothing() { val detectedEdge = swipeHorizontallyFrom( x = screenWidth / 3, y = screenHeight - (edgeSize - 1), ) assertThat(detectedEdge).isNull() } @Test fun source_swipeHorizontallyOnLeft_detectsLeft() { val detectedEdge = swipeHorizontallyFrom( x = edgeSize - 1, y = screenHeight / 2, ) assertThat(detectedEdge).isEqualTo(Left) } @Test fun source_swipeVerticallyOnLeft_detectsNothing() { val detectedEdge = swipeVerticallyFrom( x = edgeSize - 1, y = screenHeight / 2, ) assertThat(detectedEdge).isNull() } @Test fun source_swipeHorizontallyOnRight_detectsRight() { val detectedEdge = swipeHorizontallyFrom( x = screenWidth - edgeSize + 1, y = screenHeight / 2, ) assertThat(detectedEdge).isEqualTo(Right) } @Test fun source_swipeVerticallyOnRight_detectsNothing() { val detectedEdge = swipeVerticallyFrom( x = screenWidth - edgeSize + 1, y = screenHeight / 2, ) assertThat(detectedEdge).isNull() } @Test fun resolve_startInLtr_resolvesLeft() { val resolvedEdge = Start.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Left) } @Test fun resolve_startInRtl_resolvesRight() { val resolvedEdge = Start.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Right) } @Test fun resolve_endInLtr_resolvesRight() { val resolvedEdge = End.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Right) } @Test fun resolve_endInRtl_resolvesLeft() { val resolvedEdge = End.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.Left) } @Test fun resolve_topStartInLtr_resolvesTopLeft() { val resolvedEdge = TopStart.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopLeft) } @Test fun resolve_topStartInRtl_resolvesTopRight() { val resolvedEdge = TopStart.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopRight) } @Test fun resolve_topEndInLtr_resolvesTopRight() { val resolvedEdge = TopEnd.resolve(LayoutDirection.Ltr) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopRight) } @Test fun resolve_topEndInRtl_resolvesTopLeft() { val resolvedEdge = TopEnd.resolve(LayoutDirection.Rtl) assertThat(resolvedEdge).isEqualTo(SceneContainerEdge.Resolved.TopLeft) } private fun swipeVerticallyFrom(x: Int, y: Int): SceneContainerEdge? { return swipeFrom(x, y, Orientation.Vertical) } private fun swipeHorizontallyFrom(x: Int, y: Int): SceneContainerEdge? { return swipeFrom(x, y, Orientation.Horizontal) } private fun swipeFrom(x: Int, y: Int, orientation: Orientation): SceneContainerEdge? { return underTest.source( layoutSize = IntSize(width = screenWidth, height = screenHeight), position = IntOffset(x, y), density = Density(1f), orientation = orientation, ) } }
packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt +33 −13 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.parameterizeSceneContainerFlag import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository Loading @@ -39,6 +38,7 @@ import com.android.systemui.kosmos.testScope 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.shade.data.repository.fakeShadeRepository import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.shadeTestUtil import com.android.systemui.shade.shared.flag.DualShade Loading Loading @@ -66,18 +66,18 @@ import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() { val kosmos = testKosmos() val testScope = kosmos.testScope val configurationRepository by lazy { kosmos.fakeConfigurationRepository } val deviceProvisioningRepository by lazy { kosmos.fakeDeviceProvisioningRepository } val disableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository } val keyguardRepository by lazy { kosmos.fakeKeyguardRepository } val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } val powerRepository by lazy { kosmos.fakePowerRepository } val shadeTestUtil by lazy { kosmos.shadeTestUtil } val userRepository by lazy { kosmos.fakeUserRepository } val userSetupRepository by lazy { kosmos.fakeUserSetupRepository } val dozeParameters by lazy { kosmos.dozeParameters } private val kosmos = testKosmos() private val testScope = kosmos.testScope private val deviceProvisioningRepository by lazy { kosmos.fakeDeviceProvisioningRepository } private val disableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository } private val keyguardRepository by lazy { kosmos.fakeKeyguardRepository } private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } private val powerRepository by lazy { kosmos.fakePowerRepository } private val shadeRepository by lazy { kosmos.fakeShadeRepository } private val shadeTestUtil by lazy { kosmos.shadeTestUtil } private val userRepository by lazy { kosmos.fakeUserRepository } private val userSetupRepository by lazy { kosmos.fakeUserSetupRepository } private val dozeParameters by lazy { kosmos.dozeParameters } lateinit var underTest: ShadeInteractorImpl Loading Loading @@ -497,4 +497,24 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(shadeMode).isEqualTo(ShadeMode.Dual) } @Test fun getTopEdgeSplitFraction_narrowScreen_splitInHalf() = testScope.runTest { // Ensure isShadeLayoutWide is collected. val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide) shadeRepository.setShadeLayoutWide(false) assertThat(underTest.getTopEdgeSplitFraction()).isEqualTo(0.5f) } @Test fun getTopEdgeSplitFraction_wideScreen_leftSideLarger() = testScope.runTest { // Ensure isShadeLayoutWide is collected. val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide) shadeRepository.setShadeLayoutWide(true) assertThat(underTest.getTopEdgeSplitFraction()).isGreaterThan(0.5f) } }