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

Commit 55e4b4a0 authored by Justin Weir's avatar Justin Weir Committed by Android (Google) Code Review
Browse files

Merge "Make QS switch to Split Shade on unfold" into main

parents 9e17c632 b4318f1d
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.qs.ui.viewmodel

import android.platform.test.annotations.DisableFlags
import android.testing.TestableLooper.RunWithLooper
import androidx.lifecycle.LifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -26,20 +27,26 @@ 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.lifecycle.activateIn
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
import com.android.systemui.media.controls.shared.model.MediaData
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.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -51,6 +58,7 @@ import org.mockito.Mockito.verify
@RunWith(AndroidJUnit4::class)
@RunWithLooper
@EnableSceneContainer
@DisableFlags(com.android.systemui.Flags.FLAG_DUAL_SHADE)
class QuickSettingsSceneContentViewModelTest : SysuiTestCase() {

    private val kosmos = testKosmos()
@@ -64,6 +72,8 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() {
    private val footerActionsController = mock<FooterActionsController>()

    private val sceneContainerStartable = kosmos.sceneContainerStartable
    private val sceneInteractor by lazy { kosmos.sceneInteractor }
    private val shadeInteractor by lazy { kosmos.shadeInteractor }

    private lateinit var underTest: QuickSettingsSceneContentViewModel

@@ -80,7 +90,10 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() {
                footerActionsViewModelFactory = footerActionsViewModelFactory,
                footerActionsController = footerActionsController,
                mediaCarouselInteractor = kosmos.mediaCarouselInteractor,
                shadeInteractor = shadeInteractor,
                sceneInteractor = sceneInteractor,
            )
        underTest.activateIn(testScope)
    }

    @Test
@@ -122,4 +135,16 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() {

            assertThat(isMediaVisible).isTrue()
        }

    @Test
    fun shadeModeChange_switchToShadeScene() =
        testScope.runTest {
            val scene by collectLastValue(sceneInteractor.currentScene)

            // switch to split shade
            kosmos.shadeRepository.setShadeLayoutWide(true)
            runCurrent()

            assertThat(scene).isEqualTo(Scenes.Shade)
        }
}
+24 −1
Original line number Diff line number Diff line
@@ -17,16 +17,24 @@
package com.android.systemui.qs.ui.viewmodel

import androidx.lifecycle.LifecycleOwner
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.qs.FooterActionsController
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
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
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

/**
 * Models UI state needed for rendering the content of the quick settings scene.
@@ -43,7 +51,9 @@ constructor(
    private val footerActionsViewModelFactory: FooterActionsViewModel.Factory,
    private val footerActionsController: FooterActionsController,
    val mediaCarouselInteractor: MediaCarouselInteractor,
) {
    private val shadeInteractor: ShadeInteractor,
    private val sceneInteractor: SceneInteractor,
) : ExclusiveActivatable() {

    val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasAnyMediaOrRecommendation

@@ -56,6 +66,19 @@ constructor(
        return footerActionsViewModelFactory.create(lifecycleOwner)
    }

    override suspend fun onActivated(): Nothing {
        coroutineScope {
            launch {
                shadeInteractor.shadeMode.collect { shadeMode ->
                    if (shadeMode == ShadeMode.Split) {
                        sceneInteractor.snapToScene(Scenes.Shade, "Unfold while on QS")
                    }
                }
            }
            awaitCancellation()
        }
    }

    @AssistedFactory
    interface Factory {
        fun create(): QuickSettingsSceneContentViewModel
+13 −18
Original line number Diff line number Diff line
@@ -58,29 +58,20 @@ constructor(

    fun onSceneChange(from: SceneKey, to: SceneKey) {
        check(from != to) { "from == to, from=${from.debugName}, to=${to.debugName}" }
        when (stackOperation(from, to)) {
            Clear -> {
                _backStack.value = sceneStackOf()
            }
            Push -> {
                _backStack.update { s -> s.push(from) }
            }
            Pop -> {
                _backStack.update { s ->
                    checkNotNull(s.pop()) { "Cannot pop ${from.debugName} when stack is empty" }
                        .also {
                            val popped = s.peek()
                            check(popped == to) {
                                "Expected to pop ${to.debugName} but instead popped ${popped?.debugName}"
                            }
                        }
                }

        _backStack.update { stack ->
            when (stackOperation(from, to, stack)) {
                null -> stack
                Clear -> sceneStackOf()
                Push -> stack.push(from)
                Pop ->
                    checkNotNull(stack.pop()) { "Cannot pop ${from.debugName} when stack is empty" }
            }
        }
        logger.logSceneBackStack(backStack.value.asIterable())
    }

    private fun stackOperation(from: SceneKey, to: SceneKey): StackOperation {
    private fun stackOperation(from: SceneKey, to: SceneKey, stack: SceneStack): StackOperation? {
        val fromDistance =
            checkNotNull(sceneContainerConfig.navigationDistances[from]) {
                "No distance mapping for scene \"${from.debugName}\"!"
@@ -93,6 +84,7 @@ constructor(
        return when {
            toDistance == 0 -> Clear
            toDistance > fromDistance -> Push
            stack.peek() != to -> null
            toDistance < fromDistance -> Pop
            else ->
                error(
@@ -103,7 +95,10 @@ constructor(
    }

    private sealed interface StackOperation

    private data object Clear : StackOperation

    private data object Push : StackOperation

    private data object Pop : StackOperation
}