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

Commit c4a4dd79 authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

[Flexiglas] Split shade - domain layer

Domain layer changes to support the split shade.

Split shade is the single panel shade that's shown for large screens and
unfolded devices where quick settings is one the left and notifications
is on the right.

The most interesting part of this CL is the use of the new
ShadeStartable to hydrate the value of isSplitShade in the repository.

Bug: 328473018
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Test: unit tests, integration tests - included with this CL
Test: see followup CLs on this chain for manual testing details
Change-Id: I1952c3b6d392e4d7e3ff71990e23530141821560
parent 277c5beb
Loading
Loading
Loading
Loading
+44 −26
Original line number Diff line number Diff line
@@ -29,9 +29,11 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.userRepository
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
@@ -45,19 +47,20 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    val kosmos = testKosmos()
    val testComponent = kosmos.testScope
    val configurationRepository = kosmos.fakeConfigurationRepository
    val keyguardRepository = kosmos.fakeKeyguardRepository
    val keyguardTransitionRepository = kosmos.keyguardTransitionRepository
    val sceneInteractor = kosmos.sceneInteractor
    val userRepository = kosmos.userRepository
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val configurationRepository = kosmos.fakeConfigurationRepository
    private val keyguardRepository = kosmos.fakeKeyguardRepository
    private val keyguardTransitionRepository = kosmos.keyguardTransitionRepository
    private val sceneInteractor = kosmos.sceneInteractor
    private val userRepository = kosmos.userRepository
    private val shadeRepository = kosmos.shadeRepository

    val underTest = kosmos.shadeInteractorSceneContainerImpl
    private val underTest = kosmos.shadeInteractorSceneContainerImpl

    @Test
    fun qsExpansionWhenInSplitShadeAndQsExpanded() =
        testComponent.runTest {
        testScope.runTest {
            val actual by collectLastValue(underTest.qsExpansion)

            // WHEN split shade is enabled and QS is expanded
@@ -84,7 +87,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun qsExpansionWhenNotInSplitShadeAndQsExpanded() =
        testComponent.runTest {
        testScope.runTest {
            val actual by collectLastValue(underTest.qsExpansion)

            // WHEN split shade is not enabled and QS is expanded
@@ -112,7 +115,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun qsFullscreen_falseWhenTransitioning() =
        testComponent.runTest {
        testScope.runTest {
            val actual by collectLastValue(underTest.isQsFullscreen)

            // WHEN scene transition active
@@ -136,7 +139,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun qsFullscreen_falseWhenIdleNotQS() =
        testComponent.runTest {
        testScope.runTest {
            val actual by collectLastValue(underTest.isQsFullscreen)

            // WHEN Idle but not on QuickSettings scene
@@ -154,7 +157,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun qsFullscreen_trueWhenIdleQS() =
        testComponent.runTest {
        testScope.runTest {
            val actual by collectLastValue(underTest.isQsFullscreen)

            // WHEN Idle on QuickSettings scene
@@ -172,7 +175,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun lockscreenShadeExpansion_idle_onScene() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an expansion flow based on transitions to and from a scene
            val key = Scenes.Shade
            val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -189,7 +192,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun lockscreenShadeExpansion_idle_onDifferentScene() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an expansion flow based on transitions to and from a scene
            val expansion = underTest.sceneBasedExpansion(sceneInteractor, Scenes.Shade)
            val expansionAmount by collectLastValue(expansion)
@@ -207,7 +210,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun lockscreenShadeExpansion_transitioning_toScene() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an expansion flow based on transitions to and from a scene
            val key = Scenes.QuickSettings
            val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -245,7 +248,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun lockscreenShadeExpansion_transitioning_fromScene() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an expansion flow based on transitions to and from a scene
            val key = Scenes.QuickSettings
            val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -282,7 +285,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {
        }

    fun isQsBypassingShade_goneToQs() =
        testComponent.runTest {
        testScope.runTest {
            val actual by collectLastValue(underTest.isQsBypassingShade)

            // WHEN transitioning from QS directly to Gone
@@ -305,7 +308,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {
        }

    fun isQsBypassingShade_shadeToQs() =
        testComponent.runTest {
        testScope.runTest {
            val actual by collectLastValue(underTest.isQsBypassingShade)

            // WHEN transitioning from QS to Shade
@@ -329,7 +332,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun lockscreenShadeExpansion_transitioning_toAndFromDifferentScenes() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an expansion flow based on transitions to and from a scene
            val expansion = underTest.sceneBasedExpansion(sceneInteractor, Scenes.QuickSettings)
            val expansionAmount by collectLastValue(expansion)
@@ -366,7 +369,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun userInteracting_idle() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = Scenes.Shade
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -383,7 +386,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun userInteracting_transitioning_toScene_programmatic() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = Scenes.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -421,7 +424,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun userInteracting_transitioning_toScene_userInputDriven() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = Scenes.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -459,7 +462,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun userInteracting_transitioning_fromScene_programmatic() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = Scenes.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -497,7 +500,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun userInteracting_transitioning_fromScene_userInputDriven() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = Scenes.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -535,7 +538,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {

    @Test
    fun userInteracting_transitioning_toAndFromDifferentScenes() =
        testComponent.runTest {
        testScope.runTest {
            // GIVEN an interacting flow based on transitions to and from a scene
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, Scenes.Shade)
            val interacting by collectLastValue(interactingFlow)
@@ -557,4 +560,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {
            // THEN interacting is false
            Truth.assertThat(interacting).isFalse()
        }

    @Test
    fun isSplitShade() =
        testScope.runTest {
            val isSplitShade by collectLastValue(underTest.isSplitShade)

            shadeRepository.setSplitShade(true)
            assertThat(isSplitShade).isTrue()

            shadeRepository.setSplitShade(false)
            assertThat(isSplitShade).isFalse()

            shadeRepository.setSplitShade(true)
            assertThat(isSplitShade).isTrue()
        }
}
+61 −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.startable

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.testScope
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

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

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val shadeInteractor = kosmos.shadeInteractor
    private val fakeConfigurationRepository = kosmos.fakeConfigurationRepository

    private val underTest = kosmos.shadeStartable

    @Test
    fun hydrateSplitShade() =
        testScope.runTest {
            overrideResource(R.bool.config_use_split_notification_shade, false)
            val isSplitShade by collectLastValue(shadeInteractor.isSplitShade)

            underTest.start()
            assertThat(isSplitShade).isFalse()

            overrideResource(R.bool.config_use_split_notification_shade, true)
            fakeConfigurationRepository.onAnyConfigurationChange()
            assertThat(isSplitShade).isTrue()

            overrideResource(R.bool.config_use_split_notification_shade, false)
            fakeConfigurationRepository.onAnyConfigurationChange()
            assertThat(isSplitShade).isFalse()
        }
}
+6 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.shade

import com.android.systemui.CoreStartable
import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.shade.domain.startable.ShadeStartable
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -34,4 +35,9 @@ internal abstract class StartShadeModule {
    @IntoMap
    @ClassKey(AuthRippleController::class)
    abstract fun bindAuthRippleController(controller: AuthRippleController): CoreStartable

    @Binds
    @IntoMap
    @ClassKey(ShadeStartable::class)
    abstract fun provideShadeStartable(startable: ShadeStartable): CoreStartable
}
+3 −0
Original line number Diff line number Diff line
@@ -102,6 +102,9 @@ interface BaseShadeInteractor {
     * animating.
     */
    val isUserInteractingWithQs: Flow<Boolean>

    /** Whether the current configuration requires the split shade to be shown. */
    val isSplitShade: StateFlow<Boolean>
}

fun createAnyExpansionFlow(
+1 −0
Original line number Diff line number Diff line
@@ -42,4 +42,5 @@ class ShadeInteractorEmptyImpl @Inject constructor() : ShadeInteractor {
    override val isUserInteracting: StateFlow<Boolean> = inactiveFlowBoolean
    override val isShadeTouchable: Flow<Boolean> = inactiveFlowBoolean
    override val isExpandToQsEnabled: Flow<Boolean> = inactiveFlowBoolean
    override val isSplitShade: StateFlow<Boolean> = inactiveFlowBoolean
}
Loading