Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/AbstractQSFragmentComposeViewModelTest.kt 0 → 100644 +69 −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.qs.composefragment.viewmodel import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.testing.TestLifecycleOwner import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.testDispatcher import com.android.systemui.testKosmos import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestResult import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before @OptIn(ExperimentalCoroutinesApi::class) abstract class AbstractQSFragmentComposeViewModelTest : SysuiTestCase() { protected val kosmos = testKosmos() protected val lifecycleOwner = TestLifecycleOwner( initialState = Lifecycle.State.CREATED, coroutineDispatcher = kosmos.testDispatcher, ) protected val underTest by lazy { kosmos.qsFragmentComposeViewModelFactory.create(lifecycleOwner.lifecycleScope) } @Before fun setUp() { Dispatchers.setMain(kosmos.testDispatcher) } @After fun teardown() { Dispatchers.resetMain() } protected inline fun TestScope.testWithinLifecycle( crossinline block: suspend TestScope.() -> TestResult ): TestResult { return runTest { lifecycleOwner.setCurrentState(Lifecycle.State.RESUMED) lifecycleOwner.lifecycleScope.launch { underTest.activate() } block().also { lifecycleOwner.setCurrentState(Lifecycle.State.DESTROYED) } } } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelForceQSTest.kt 0 → 100644 +98 −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.qs.composefragment.viewmodel import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.sysuiStatusBarStateController import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @SmallTest @RunWith(Parameterized::class) @RunWithLooper class QSFragmentComposeViewModelForceQSTest(private val testData: TestData) : AbstractQSFragmentComposeViewModelTest() { @Test fun forceQs_orRealExpansion() = with(kosmos) { testScope.testWithinLifecycle { val expansionState by collectLastValue(underTest.expansionState) with(testData) { sysuiStatusBarStateController.setState(statusBarState) underTest.isQSExpanded = expanded underTest.isStackScrollerOverscrolling = stackScrollerOverScrolling fakeDeviceEntryRepository.setBypassEnabled(bypassEnabled) underTest.isTransitioningToFullShade = transitioningToFullShade underTest.isInSplitShade = inSplitShade underTest.qsExpansionValue = EXPANSION assertThat(expansionState!!.progress) .isEqualTo(if (expectedForceQS) 1f else EXPANSION) } } } data class TestData( val statusBarState: Int, val expanded: Boolean, val stackScrollerOverScrolling: Boolean, val bypassEnabled: Boolean, val transitioningToFullShade: Boolean, val inSplitShade: Boolean, ) { private val inKeyguard = statusBarState == StatusBarState.KEYGUARD private val showCollapsedOnKeyguard = bypassEnabled || (transitioningToFullShade && !inSplitShade) val expectedForceQS = (expanded || stackScrollerOverScrolling) && (inKeyguard && !showCollapsedOnKeyguard) } companion object { private const val EXPANSION = 0.3f @Parameterized.Parameters(name = "{0}") @JvmStatic fun createTestData(): List<TestData> { return statusBarStates.flatMap { statusBarState -> (0u..31u).map { bitfield -> TestData( statusBarState, expanded = (bitfield or 1u) == 1u, stackScrollerOverScrolling = (bitfield or 2u) == 1u, bypassEnabled = (bitfield or 4u) == 1u, transitioningToFullShade = (bitfield or 8u) == 1u, inSplitShade = (bitfield or 16u) == 1u, ) } } } private val statusBarStates = setOf(StatusBarState.SHADE, StatusBarState.KEYGUARD, StatusBarState.SHADE_LOCKED) } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt +23 −45 Original line number Diff line number Diff line Loading @@ -19,64 +19,28 @@ package com.android.systemui.qs.composefragment.viewmodel import android.app.StatusBarManager import android.content.testableContext import android.testing.TestableLooper.RunWithLooper import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.testing.TestLifecycleOwner import androidx.test.ext.junit.runners.AndroidJUnit4 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.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.qs.fgsManagerController import com.android.systemui.qs.panels.domain.interactor.tileSquishinessInteractor import com.android.systemui.res.R import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository import com.android.systemui.statusbar.sysuiStatusBarStateController import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestResult import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @RunWithLooper @OptIn(ExperimentalCoroutinesApi::class) class QSFragmentComposeViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val lifecycleOwner = TestLifecycleOwner( initialState = Lifecycle.State.CREATED, coroutineDispatcher = kosmos.testDispatcher, ) private val underTest by lazy { kosmos.qsFragmentComposeViewModelFactory.create(lifecycleOwner.lifecycleScope) } @Before fun setUp() { Dispatchers.setMain(kosmos.testDispatcher) } @After fun teardown() { Dispatchers.resetMain() } class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest() { @Test fun qsExpansionValueChanges_correctExpansionState() = Loading Loading @@ -205,16 +169,30 @@ class QSFragmentComposeViewModelTest : SysuiTestCase() { } } private inline fun TestScope.testWithinLifecycle( crossinline block: suspend TestScope.() -> TestResult ): TestResult { return runTest { lifecycleOwner.setCurrentState(Lifecycle.State.RESUMED) block().also { lifecycleOwner.setCurrentState(Lifecycle.State.DESTROYED) } @Test fun squishinessInExpansion_setInInteractor() = with(kosmos) { testScope.testWithinLifecycle { val squishiness by collectLastValue(tileSquishinessInteractor.squishiness) underTest.squishinessFractionValue = 0.3f assertThat(squishiness).isWithin(epsilon).of(0.3f.constrainSquishiness()) underTest.squishinessFractionValue = 0f assertThat(squishiness).isWithin(epsilon).of(0f.constrainSquishiness()) underTest.squishinessFractionValue = 1f assertThat(squishiness).isWithin(epsilon).of(1f.constrainSquishiness()) } } companion object { private const val QS_DISABLE_FLAG = StatusBarManager.DISABLE2_QUICK_SETTINGS private fun Float.constrainSquishiness(): Float { return (0.1f + this * 0.9f).coerceIn(0f, 1f) } private const val epsilon = 0.001f } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt +2 −5 Original line number Diff line number Diff line Loading @@ -22,10 +22,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.testScope import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.fixedColumnsSizeViewModel import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat Loading @@ -44,8 +42,7 @@ class InfiniteGridLayoutTest : SysuiTestCase() { } } private val underTest = with(kosmos) { InfiniteGridLayout(iconTilesViewModel, fixedColumnsSizeViewModel) } private val underTest = kosmos.infiniteGridLayout @Test fun correctPagination_underOnePage_sameOrder() = Loading packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +7 −6 Original line number Diff line number Diff line Loading @@ -180,6 +180,7 @@ constructor( qqsMediaHost.init(MediaHierarchyManager.LOCATION_QQS) qsMediaHost.init(MediaHierarchyManager.LOCATION_QS) setListenerCollections() lifecycleScope.launch { viewModel.activate() } } override fun onCreateView( Loading Loading @@ -331,7 +332,7 @@ constructor( } override fun setOverscrolling(overscrolling: Boolean) { viewModel.stackScrollerOverscrollingValue = overscrolling viewModel.isStackScrollerOverscrolling = overscrolling } override fun setExpanded(qsExpanded: Boolean) { Loading Loading @@ -410,11 +411,11 @@ constructor( qsTransitionFraction: Float, qsSquishinessFraction: Float, ) { super.setTransitionToFullShadeProgress( isTransitioningToFullShade, qsTransitionFraction, qsSquishinessFraction, ) viewModel.isTransitioningToFullShade = isTransitioningToFullShade viewModel.lockscreenToShadeProgressValue = qsTransitionFraction if (isTransitioningToFullShade) { viewModel.squishinessFractionValue = qsSquishinessFraction } } override fun setFancyClipping( Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/AbstractQSFragmentComposeViewModelTest.kt 0 → 100644 +69 −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.qs.composefragment.viewmodel import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.testing.TestLifecycleOwner import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.testDispatcher import com.android.systemui.testKosmos import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestResult import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before @OptIn(ExperimentalCoroutinesApi::class) abstract class AbstractQSFragmentComposeViewModelTest : SysuiTestCase() { protected val kosmos = testKosmos() protected val lifecycleOwner = TestLifecycleOwner( initialState = Lifecycle.State.CREATED, coroutineDispatcher = kosmos.testDispatcher, ) protected val underTest by lazy { kosmos.qsFragmentComposeViewModelFactory.create(lifecycleOwner.lifecycleScope) } @Before fun setUp() { Dispatchers.setMain(kosmos.testDispatcher) } @After fun teardown() { Dispatchers.resetMain() } protected inline fun TestScope.testWithinLifecycle( crossinline block: suspend TestScope.() -> TestResult ): TestResult { return runTest { lifecycleOwner.setCurrentState(Lifecycle.State.RESUMED) lifecycleOwner.lifecycleScope.launch { underTest.activate() } block().also { lifecycleOwner.setCurrentState(Lifecycle.State.DESTROYED) } } } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelForceQSTest.kt 0 → 100644 +98 −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.qs.composefragment.viewmodel import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.sysuiStatusBarStateController import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @SmallTest @RunWith(Parameterized::class) @RunWithLooper class QSFragmentComposeViewModelForceQSTest(private val testData: TestData) : AbstractQSFragmentComposeViewModelTest() { @Test fun forceQs_orRealExpansion() = with(kosmos) { testScope.testWithinLifecycle { val expansionState by collectLastValue(underTest.expansionState) with(testData) { sysuiStatusBarStateController.setState(statusBarState) underTest.isQSExpanded = expanded underTest.isStackScrollerOverscrolling = stackScrollerOverScrolling fakeDeviceEntryRepository.setBypassEnabled(bypassEnabled) underTest.isTransitioningToFullShade = transitioningToFullShade underTest.isInSplitShade = inSplitShade underTest.qsExpansionValue = EXPANSION assertThat(expansionState!!.progress) .isEqualTo(if (expectedForceQS) 1f else EXPANSION) } } } data class TestData( val statusBarState: Int, val expanded: Boolean, val stackScrollerOverScrolling: Boolean, val bypassEnabled: Boolean, val transitioningToFullShade: Boolean, val inSplitShade: Boolean, ) { private val inKeyguard = statusBarState == StatusBarState.KEYGUARD private val showCollapsedOnKeyguard = bypassEnabled || (transitioningToFullShade && !inSplitShade) val expectedForceQS = (expanded || stackScrollerOverScrolling) && (inKeyguard && !showCollapsedOnKeyguard) } companion object { private const val EXPANSION = 0.3f @Parameterized.Parameters(name = "{0}") @JvmStatic fun createTestData(): List<TestData> { return statusBarStates.flatMap { statusBarState -> (0u..31u).map { bitfield -> TestData( statusBarState, expanded = (bitfield or 1u) == 1u, stackScrollerOverScrolling = (bitfield or 2u) == 1u, bypassEnabled = (bitfield or 4u) == 1u, transitioningToFullShade = (bitfield or 8u) == 1u, inSplitShade = (bitfield or 16u) == 1u, ) } } } private val statusBarStates = setOf(StatusBarState.SHADE, StatusBarState.KEYGUARD, StatusBarState.SHADE_LOCKED) } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt +23 −45 Original line number Diff line number Diff line Loading @@ -19,64 +19,28 @@ package com.android.systemui.qs.composefragment.viewmodel import android.app.StatusBarManager import android.content.testableContext import android.testing.TestableLooper.RunWithLooper import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.testing.TestLifecycleOwner import androidx.test.ext.junit.runners.AndroidJUnit4 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.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.qs.fgsManagerController import com.android.systemui.qs.panels.domain.interactor.tileSquishinessInteractor import com.android.systemui.res.R import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository import com.android.systemui.statusbar.sysuiStatusBarStateController import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestResult import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @RunWithLooper @OptIn(ExperimentalCoroutinesApi::class) class QSFragmentComposeViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val lifecycleOwner = TestLifecycleOwner( initialState = Lifecycle.State.CREATED, coroutineDispatcher = kosmos.testDispatcher, ) private val underTest by lazy { kosmos.qsFragmentComposeViewModelFactory.create(lifecycleOwner.lifecycleScope) } @Before fun setUp() { Dispatchers.setMain(kosmos.testDispatcher) } @After fun teardown() { Dispatchers.resetMain() } class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest() { @Test fun qsExpansionValueChanges_correctExpansionState() = Loading Loading @@ -205,16 +169,30 @@ class QSFragmentComposeViewModelTest : SysuiTestCase() { } } private inline fun TestScope.testWithinLifecycle( crossinline block: suspend TestScope.() -> TestResult ): TestResult { return runTest { lifecycleOwner.setCurrentState(Lifecycle.State.RESUMED) block().also { lifecycleOwner.setCurrentState(Lifecycle.State.DESTROYED) } @Test fun squishinessInExpansion_setInInteractor() = with(kosmos) { testScope.testWithinLifecycle { val squishiness by collectLastValue(tileSquishinessInteractor.squishiness) underTest.squishinessFractionValue = 0.3f assertThat(squishiness).isWithin(epsilon).of(0.3f.constrainSquishiness()) underTest.squishinessFractionValue = 0f assertThat(squishiness).isWithin(epsilon).of(0f.constrainSquishiness()) underTest.squishinessFractionValue = 1f assertThat(squishiness).isWithin(epsilon).of(1f.constrainSquishiness()) } } companion object { private const val QS_DISABLE_FLAG = StatusBarManager.DISABLE2_QUICK_SETTINGS private fun Float.constrainSquishiness(): Float { return (0.1f + this * 0.9f).coerceIn(0f, 1f) } private const val epsilon = 0.001f } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt +2 −5 Original line number Diff line number Diff line Loading @@ -22,10 +22,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.testScope import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.fixedColumnsSizeViewModel import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat Loading @@ -44,8 +42,7 @@ class InfiniteGridLayoutTest : SysuiTestCase() { } } private val underTest = with(kosmos) { InfiniteGridLayout(iconTilesViewModel, fixedColumnsSizeViewModel) } private val underTest = kosmos.infiniteGridLayout @Test fun correctPagination_underOnePage_sameOrder() = Loading
packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +7 −6 Original line number Diff line number Diff line Loading @@ -180,6 +180,7 @@ constructor( qqsMediaHost.init(MediaHierarchyManager.LOCATION_QQS) qsMediaHost.init(MediaHierarchyManager.LOCATION_QS) setListenerCollections() lifecycleScope.launch { viewModel.activate() } } override fun onCreateView( Loading Loading @@ -331,7 +332,7 @@ constructor( } override fun setOverscrolling(overscrolling: Boolean) { viewModel.stackScrollerOverscrollingValue = overscrolling viewModel.isStackScrollerOverscrolling = overscrolling } override fun setExpanded(qsExpanded: Boolean) { Loading Loading @@ -410,11 +411,11 @@ constructor( qsTransitionFraction: Float, qsSquishinessFraction: Float, ) { super.setTransitionToFullShadeProgress( isTransitioningToFullShade, qsTransitionFraction, qsSquishinessFraction, ) viewModel.isTransitioningToFullShade = isTransitioningToFullShade viewModel.lockscreenToShadeProgressValue = qsTransitionFraction if (isTransitioningToFullShade) { viewModel.squishinessFractionValue = qsSquishinessFraction } } override fun setFancyClipping( Loading