Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a68f81f authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Fixes infinite back nav between QS and bouncer." into main

parents e81739a8 0da90b84
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.testKosmos
@@ -67,10 +68,13 @@ class BouncerViewModelTest : SysuiTestCase() {
    private val testScope = kosmos.testScope
    private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
    private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
    private val sceneContainerStartable = kosmos.sceneContainerStartable

    private lateinit var underTest: BouncerViewModel

    @Before
    fun setUp() {
        sceneContainerStartable.start()
        underTest = kosmos.bouncerViewModel
    }

+11 −3
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
@@ -38,6 +39,8 @@ import com.android.systemui.qs.FooterActionsController
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneContainerStartable
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel
@@ -58,6 +61,7 @@ import org.mockito.Mockito.verify

@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableSceneContainer
class QuickSettingsSceneViewModelTest : SysuiTestCase() {

    private val kosmos = testKosmos()
@@ -71,6 +75,8 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
    private val footerActionsController = mock<FooterActionsController>()

    private val sceneInteractor = kosmos.sceneInteractor
    private val sceneBackInteractor = kosmos.sceneBackInteractor
    private val sceneContainerStartable = kosmos.sceneContainerStartable

    private lateinit var underTest: QuickSettingsSceneViewModel

@@ -79,6 +85,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
    fun setUp() {
        kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false)

        sceneContainerStartable.start()
        underTest =
            QuickSettingsSceneViewModel(
                applicationScope = testScope.backgroundScope,
@@ -89,7 +96,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
                notifications = kosmos.notificationsPlaceholderViewModel,
                footerActionsViewModelFactory = footerActionsViewModelFactory,
                footerActionsController = footerActionsController,
                sceneInteractor = sceneInteractor,
                sceneBackInteractor = sceneBackInteractor,
            )
    }

@@ -127,11 +134,12 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
            val destinations by collectLastValue(underTest.destinationScenes)

            val currentScene by collectLastValue(sceneInteractor.currentScene)
            val previousScene by collectLastValue(sceneInteractor.previousScene())
            val backScene by collectLastValue(sceneBackInteractor.backScene)
            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
            sceneInteractor.changeScene(Scenes.QuickSettings, "reason")
            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
            assertThat(previousScene).isEqualTo(Scenes.Lockscreen)
            assertThat(backScene).isEqualTo(Scenes.Lockscreen)

            assertThat(destinations)
                .isEqualTo(
                    mapOf(
+0 −19
Original line number Diff line number Diff line
@@ -140,23 +140,4 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
                    ObservableTransitionState.Idle(kosmos.sceneContainerConfig.initialSceneKey)
                )
        }

    @Test
    fun previousScene() =
        testScope.runTest {
            val underTest = kosmos.sceneContainerRepository
            val currentScene by collectLastValue(underTest.currentScene)
            val previousScene by collectLastValue(underTest.previousScene)

            assertThat(previousScene).isNull()

            val firstScene = currentScene
            underTest.changeScene(Scenes.Shade)
            assertThat(previousScene).isEqualTo(firstScene)
            assertThat(currentScene).isEqualTo(Scenes.Shade)

            underTest.changeScene(Scenes.QuickSettings)
            assertThat(previousScene).isEqualTo(Scenes.Shade)
            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
        }
}
+206 −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.
 */

@file:OptIn(ExperimentalCoroutinesApi::class)

package com.android.systemui.scene.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.domain.interactor.AuthenticationResult
import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class SceneBackInteractorTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val sceneInteractor = kosmos.sceneInteractor
    private val sceneContainerStartable = kosmos.sceneContainerStartable
    private val authenticationInteractor = kosmos.authenticationInteractor

    private val underTest = kosmos.sceneBackInteractor

    @Test
    @EnableSceneContainer
    fun navigateToQs_thenBouncer_thenBack_whileLocked() =
        testScope.runTest {
            sceneContainerStartable.start()

            assertRoute(
                RouteNode(Scenes.Lockscreen, null),
                RouteNode(Scenes.Shade, Scenes.Lockscreen),
                RouteNode(Scenes.QuickSettings, Scenes.Shade),
                RouteNode(Scenes.Bouncer, Scenes.QuickSettings),
                RouteNode(Scenes.QuickSettings, Scenes.Shade),
                RouteNode(Scenes.Shade, Scenes.Lockscreen),
                RouteNode(Scenes.Lockscreen, null),
            )
        }

    @Test
    @EnableSceneContainer
    fun navigateToQs_thenBouncer_thenUnlock() =
        testScope.runTest {
            sceneContainerStartable.start()

            assertRoute(
                RouteNode(Scenes.Lockscreen, null),
                RouteNode(Scenes.Shade, Scenes.Lockscreen),
                RouteNode(Scenes.QuickSettings, Scenes.Shade),
                RouteNode(Scenes.Bouncer, Scenes.QuickSettings, unlockDevice = true),
                RouteNode(Scenes.Gone, null),
            )
        }

    @Test
    @EnableSceneContainer
    fun navigateToQs_skippingShade_thenBouncer_thenBack_whileLocked() =
        testScope.runTest {
            sceneContainerStartable.start()

            assertRoute(
                RouteNode(Scenes.Lockscreen, null),
                RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
                RouteNode(Scenes.Bouncer, Scenes.QuickSettings),
                RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
                RouteNode(Scenes.Lockscreen, null),
            )
        }

    @Test
    @EnableSceneContainer
    fun navigateToBouncer_thenBack_whileLocked() =
        testScope.runTest {
            sceneContainerStartable.start()

            assertRoute(
                RouteNode(Scenes.Lockscreen, null),
                RouteNode(Scenes.Bouncer, Scenes.Lockscreen),
                RouteNode(Scenes.Lockscreen, null),
            )
        }

    @Test
    @EnableSceneContainer
    fun navigateToQs_skippingShade_thenBouncer_thenBack_thenShade_whileLocked() =
        testScope.runTest {
            sceneContainerStartable.start()

            assertRoute(
                RouteNode(Scenes.Lockscreen, null),
                RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
                RouteNode(Scenes.Bouncer, Scenes.QuickSettings),
                RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
                RouteNode(Scenes.Lockscreen, null),
                RouteNode(Scenes.Shade, Scenes.Lockscreen),
            )
        }

    @Test
    @EnableSceneContainer
    fun navigateToQs_thenBack_whileUnlocked() =
        testScope.runTest {
            sceneContainerStartable.start()
            unlockDevice()

            assertRoute(
                RouteNode(Scenes.Gone, null),
                RouteNode(Scenes.Shade, Scenes.Gone),
                RouteNode(Scenes.QuickSettings, Scenes.Shade),
                RouteNode(Scenes.Shade, Scenes.Gone),
                RouteNode(Scenes.Gone, null),
            )
        }

    @Test
    @EnableSceneContainer
    fun navigateToQs_skippingShade_thenBack_whileUnlocked() =
        testScope.runTest {
            sceneContainerStartable.start()
            unlockDevice()

            assertRoute(
                RouteNode(Scenes.Gone, null),
                RouteNode(Scenes.QuickSettings, Scenes.Gone),
                RouteNode(Scenes.Gone, null),
            )
        }

    @Test
    @EnableSceneContainer
    fun navigateToQs_skippingShade_thenBack_thenShade_whileUnlocked() =
        testScope.runTest {
            sceneContainerStartable.start()
            unlockDevice()

            assertRoute(
                RouteNode(Scenes.Gone, null),
                RouteNode(Scenes.QuickSettings, Scenes.Gone),
                RouteNode(Scenes.Gone, null),
                RouteNode(Scenes.Shade, Scenes.Gone),
            )
        }

    private suspend fun TestScope.assertRoute(vararg route: RouteNode) {
        val currentScene by collectLastValue(sceneInteractor.currentScene)
        val backScene by collectLastValue(underTest.backScene)

        route.forEachIndexed { index, node ->
            sceneInteractor.changeScene(node.changeSceneTo, "")
            assertWithMessage("node at index $index currentScene mismatch")
                .that(currentScene)
                .isEqualTo(node.changeSceneTo)
            assertWithMessage("node at index $index backScene mismatch")
                .that(backScene)
                .isEqualTo(node.expectedBackScene)
            if (node.unlockDevice) {
                unlockDevice()
            }
        }
    }

    private suspend fun TestScope.unlockDevice() {
        val currentScene by collectLastValue(sceneInteractor.currentScene)
        runCurrent()
        assertThat(authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
            .isEqualTo(AuthenticationResult.SUCCEEDED)
        assertThat(currentScene).isEqualTo(Scenes.Gone)
    }

    private data class RouteNode(
        val changeSceneTo: SceneKey,
        val expectedBackScene: SceneKey? = null,
        val unlockDevice: Boolean = false,
    )
}
+0 −30
Original line number Diff line number Diff line
@@ -291,34 +291,4 @@ class SceneInteractorTest : SysuiTestCase() {

            assertThat(isVisible).isFalse()
        }

    @Test
    fun previousScene() =
        testScope.runTest {
            val currentScene by collectLastValue(underTest.currentScene)
            val previousScene by collectLastValue(underTest.previousScene())
            assertThat(previousScene).isNull()

            val firstScene = currentScene
            underTest.changeScene(toScene = Scenes.Shade, "reason")
            assertThat(previousScene).isEqualTo(firstScene)

            underTest.changeScene(toScene = Scenes.QuickSettings, "reason")
            assertThat(previousScene).isEqualTo(Scenes.Shade)
        }

    @Test
    fun previousScene_withIgnoredScene() =
        testScope.runTest {
            val currentScene by collectLastValue(underTest.currentScene)
            val previousScene by collectLastValue(underTest.previousScene(ignored = Scenes.Shade))
            assertThat(previousScene).isNull()

            val firstScene = currentScene
            underTest.changeScene(toScene = Scenes.Shade, "reason")
            assertThat(previousScene).isEqualTo(firstScene)

            underTest.changeScene(toScene = Scenes.QuickSettings, "reason")
            assertThat(previousScene).isNull()
        }
}
Loading