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

Commit 79e3576e authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

[flexiglass] Extracts shadeMode from ShadeInteractor

Creates a smaller ShadeModeInteractor and extract the shadeMode and
isShadeLayoutWide to it then makes ShadeInteractor depend on it and
implement the extracted interface by delegation.

The CL also makes the two SceneResolver implementations that depended on
ShadeInteractor just for shadeMode use ShadeModeInteractor instead.

The second part is what breaks a runtime dependency cycle that was
making the CustomizationProvider content provider fail to be injected
with dependencies, leading to the attached bugs.

Fix: 361328659
Fix: 361382372
Test: unit tests extracted to new file/class
Test: manually verified that the lockscreen shortcuts and lockscreen
preview features in Wallpaper Picker work as intended
Test: manually verified that the exceptions in the AppComponentFactory
logcat tag are gone (were visible when starting sysui and when opening
wallpaper picker)
Flag: com.android.systemui.scene_container

Change-Id: Ic1218557867828ccacdb93384ef34d380acc3cb9
parent e39b6ac8
Loading
Loading
Loading
Loading
+13 −113
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ package com.android.systemui.shade.domain.interactor
import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -38,11 +36,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
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
import com.android.systemui.statusbar.phone.dozeParameters
@@ -73,7 +67,6 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
    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 }
@@ -142,9 +135,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
            userSetupRepository.setUserSetUp(true)

            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NOTIFICATION_SHADE,
                )
                DisableFlagsModel(disable2 = DISABLE2_NOTIFICATION_SHADE)

            val actual by collectLastValue(underTest.isExpandToQsEnabled)

@@ -158,9 +149,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
            userSetupRepository.setUserSetUp(true)

            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_QUICK_SETTINGS,
                )
                DisableFlagsModel(disable2 = DISABLE2_QUICK_SETTINGS)
            val actual by collectLastValue(underTest.isExpandToQsEnabled)

            assertThat(actual).isFalse()
@@ -171,10 +160,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        testScope.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(true)
            userSetupRepository.setUserSetUp(true)
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NONE,
                )
            disableFlagsRepository.disableFlags.value = DisableFlagsModel(disable2 = DISABLE2_NONE)

            keyguardRepository.setIsDozing(true)

@@ -188,10 +174,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        testScope.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(true)
            keyguardRepository.setIsDozing(false)
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NONE,
                )
            disableFlagsRepository.disableFlags.value = DisableFlagsModel(disable2 = DISABLE2_NONE)

            userSetupRepository.setUserSetUp(true)

@@ -205,10 +188,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        testScope.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(true)
            keyguardRepository.setIsDozing(false)
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NONE,
                )
            disableFlagsRepository.disableFlags.value = DisableFlagsModel(disable2 = DISABLE2_NONE)

            userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = false))

@@ -222,10 +202,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        testScope.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(true)
            keyguardRepository.setIsDozing(false)
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NONE,
                )
            disableFlagsRepository.disableFlags.value = DisableFlagsModel(disable2 = DISABLE2_NONE)
            userSetupRepository.setUserSetUp(true)

            val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -250,10 +227,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        testScope.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(true)
            keyguardRepository.setIsDozing(false)
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NONE,
                )
            disableFlagsRepository.disableFlags.value = DisableFlagsModel(disable2 = DISABLE2_NONE)
            userSetupRepository.setUserSetUp(true)

            val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -262,17 +236,12 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {

            // WHEN QS is disabled
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_QUICK_SETTINGS,
                )
                DisableFlagsModel(disable2 = DISABLE2_QUICK_SETTINGS)
            // THEN expand is disabled
            assertThat(actual).isFalse()

            // WHEN QS is enabled
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NONE,
                )
            disableFlagsRepository.disableFlags.value = DisableFlagsModel(disable2 = DISABLE2_NONE)
            // THEN expand is enabled
            assertThat(actual).isTrue()
        }
@@ -282,10 +251,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        testScope.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(true)
            keyguardRepository.setIsDozing(false)
            disableFlagsRepository.disableFlags.value =
                DisableFlagsModel(
                    disable2 = DISABLE2_NONE,
                )
            disableFlagsRepository.disableFlags.value = DisableFlagsModel(disable2 = DISABLE2_NONE)
            userSetupRepository.setUserSetUp(true)

            val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -359,9 +325,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
                )
            )
            keyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(
                    to = DozeStateModel.DOZE_AOD,
                )
                DozeTransitionModel(to = DozeStateModel.DOZE_AOD)
            )
            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
            assertThat(isShadeTouchable).isFalse()
@@ -385,9 +349,7 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
                )
            )
            keyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(
                    to = DozeStateModel.DOZE_PULSING,
                )
                DozeTransitionModel(to = DozeStateModel.DOZE_PULSING)
            )
            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
            assertThat(isShadeTouchable).isTrue()
@@ -450,71 +412,9 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
                lastSleepReason = WakeSleepReason.OTHER,
            )
            keyguardTransitionRepository.sendTransitionStep(
                TransitionStep(
                    transitionState = TransitionState.STARTED,
                )
                TransitionStep(transitionState = TransitionState.STARTED)
            )
            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
            assertThat(isShadeTouchable).isTrue()
        }

    @Test
    @DisableFlags(DualShade.FLAG_NAME)
    fun legacyShadeMode_narrowScreen_singleShade() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(false)

            assertThat(shadeMode).isEqualTo(ShadeMode.Single)
        }

    @Test
    @DisableFlags(DualShade.FLAG_NAME)
    fun legacyShadeMode_wideScreen_splitShade() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(true)

            assertThat(shadeMode).isEqualTo(ShadeMode.Split)
        }

    @Test
    @EnableFlags(DualShade.FLAG_NAME)
    fun shadeMode_wideScreen_isDual() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(true)

            assertThat(shadeMode).isEqualTo(ShadeMode.Dual)
        }

    @Test
    @EnableFlags(DualShade.FLAG_NAME)
    fun shadeMode_narrowScreen_isDual() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(false)

            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)
        }
}
+109 −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.interactor

import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

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

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

    private lateinit var underTest: ShadeModeInteractor

    @Before
    fun setUp() {
        underTest = kosmos.shadeModeInteractor
    }

    @Test
    @DisableFlags(DualShade.FLAG_NAME)
    fun legacyShadeMode_narrowScreen_singleShade() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(false)

            assertThat(shadeMode).isEqualTo(ShadeMode.Single)
        }

    @Test
    @DisableFlags(DualShade.FLAG_NAME)
    fun legacyShadeMode_wideScreen_splitShade() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(true)

            assertThat(shadeMode).isEqualTo(ShadeMode.Split)
        }

    @Test
    @EnableFlags(DualShade.FLAG_NAME)
    fun shadeMode_wideScreen_isDual() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(true)

            assertThat(shadeMode).isEqualTo(ShadeMode.Dual)
        }

    @Test
    @EnableFlags(DualShade.FLAG_NAME)
    fun shadeMode_narrowScreen_isDual() =
        testScope.runTest {
            val shadeMode by collectLastValue(underTest.shadeMode)
            kosmos.shadeRepository.setShadeLayoutWide(false)

            assertThat(shadeMode).isEqualTo(ShadeMode.Dual)
        }

    @Test
    fun getTopEdgeSplitFraction_narrowScreen_splitInHalf() =
        testScope.runTest {
            // Ensure isShadeLayoutWide is collected.
            val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
            kosmos.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)
            kosmos.shadeRepository.setShadeLayoutWide(true)

            assertThat(underTest.getTopEdgeSplitFraction()).isGreaterThan(0.5f)
        }
}
+1 −4
Original line number Diff line number Diff line
@@ -80,10 +80,7 @@ constructor(
        }
        applicationScope.launch {
            val refreshConfig =
                Config(
                    Type.NoTransition,
                    rebuildSections = listOf(smartspaceSection),
                )
                Config(Type.NoTransition, rebuildSections = listOf(smartspaceSection))
            configurationInteractor.onAnyConfigurationChange.collect {
                refreshBlueprint(refreshConfig)
            }
+5 −9
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import dagger.Binds
import dagger.Module
@@ -38,17 +38,17 @@ class NotifShadeSceneFamilyResolver
@Inject
constructor(
    @Application applicationScope: CoroutineScope,
    shadeInteractor: ShadeInteractor,
    shadeModeInteractor: ShadeModeInteractor,
) : SceneResolver {
    override val targetFamily: SceneKey = SceneFamilies.NotifShade

    override val resolvedScene: StateFlow<SceneKey> =
        shadeInteractor.shadeMode
        shadeModeInteractor.shadeMode
            .map(::notifShadeScene)
            .stateIn(
                applicationScope,
                started = SharingStarted.Eagerly,
                initialValue = notifShadeScene(shadeInteractor.shadeMode.value),
                initialValue = notifShadeScene(shadeModeInteractor.shadeMode.value),
            )

    override fun includesScene(scene: SceneKey): Boolean = scene in notifShadeScenes
@@ -61,11 +61,7 @@ constructor(
        }

    companion object {
        val notifShadeScenes =
            setOf(
                Scenes.NotificationsShade,
                Scenes.Shade,
            )
        val notifShadeScenes = setOf(Scenes.NotificationsShade, Scenes.Shade)
    }
}

+5 −9
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import dagger.Binds
import dagger.Module
@@ -38,17 +38,17 @@ class QuickSettingsSceneFamilyResolver
@Inject
constructor(
    @Application applicationScope: CoroutineScope,
    shadeInteractor: ShadeInteractor,
    shadeModeInteractor: ShadeModeInteractor,
) : SceneResolver {
    override val targetFamily: SceneKey = SceneFamilies.QuickSettings

    override val resolvedScene: StateFlow<SceneKey> =
        shadeInteractor.shadeMode
        shadeModeInteractor.shadeMode
            .map(::quickSettingsScene)
            .stateIn(
                applicationScope,
                started = SharingStarted.Eagerly,
                initialValue = quickSettingsScene(shadeInteractor.shadeMode.value),
                initialValue = quickSettingsScene(shadeModeInteractor.shadeMode.value),
            )

    override fun includesScene(scene: SceneKey): Boolean = scene in quickSettingsScenes
@@ -62,11 +62,7 @@ constructor(

    companion object {
        val quickSettingsScenes =
            setOf(
                Scenes.QuickSettings,
                Scenes.QuickSettingsShade,
                Scenes.Shade,
            )
            setOf(Scenes.QuickSettings, Scenes.QuickSettingsShade, Scenes.Shade)
    }
}

Loading