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

Commit 73b22743 authored by Andre Le's avatar Andre Le
Browse files

StatusBarDate: Add DesktopInteractor for isDesktopFeatureSetEnabled

Add an interactor to get if desktop feature set is available. This is
used in shade header and will be used in the status bar date.

Bug: 378545144
Flag: com.android.systemui.status_bar_date
Test: ShadeHeaderViewModelTest, DesktopInteractorTest
Change-Id: Iecbe1b805f439ea8a936b33f6cec18cfec9b3ed5
parent 1ebd6dac
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.desktop.domain.interactor

import android.content.testableContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class DesktopInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val underTest = kosmos.desktopInteractor

    @Test
    fun isDesktopFeatureSetEnabled_false() =
        kosmos.runTest {
            val isDesktopFeatureSetEnabled by collectLastValue(underTest.isDesktopFeatureSetEnabled)

            testableContext.orCreateTestableResources.addOverride(
                R.bool.config_enableDesktopFeatureSet,
                false,
            )

            assertThat(isDesktopFeatureSetEnabled).isFalse()
        }

    @Test
    fun isDesktopFeatureSetEnabled_true() =
        kosmos.runTest {
            val isDesktopFeatureSetEnabled by collectLastValue(underTest.isDesktopFeatureSetEnabled)

            testableContext.orCreateTestableResources.addOverride(
                R.bool.config_enableDesktopFeatureSet,
                true,
            )

            assertThat(isDesktopFeatureSetEnabled).isTrue()
        }
}
+16 −6
Original line number Diff line number Diff line
package com.android.systemui.shade.ui.viewmodel

import android.content.Intent
import android.content.res.Configuration
import android.content.testableContext
import android.provider.AlarmClock
import android.provider.Settings
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
@@ -34,6 +36,7 @@ import com.android.systemui.shade.domain.interactor.enableDualShade
import com.android.systemui.shade.domain.interactor.enableSingleShade
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor
import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.argThat
import com.google.common.truth.Truth.assertThat
@@ -73,8 +76,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
    @Test
    fun onClockClicked_enableDesktopFeatureSetFalse_launchesClock() =
        kosmos.runTest {
            overrideResource(R.bool.config_enableDesktopFeatureSet, false)

            setEnableDesktopFeatureSet(enable = false)
            underTest.onClockClicked()

            verify(activityStarter)
@@ -87,7 +89,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
    @Test
    fun onClockClicked_enableDesktopFeatureSetTrueAndSingleShade_launchesClock() =
        kosmos.runTest {
            overrideResource(R.bool.config_enableDesktopFeatureSet, true)
            setEnableDesktopFeatureSet(enable = true)
            enableSingleShade()

            underTest.onClockClicked()
@@ -102,7 +104,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
    @Test
    fun onClockClicked_enableDesktopFeatureSetTrueAndDualShade_openNotifShade() =
        kosmos.runTest {
            overrideResource(R.bool.config_enableDesktopFeatureSet, true)
            setEnableDesktopFeatureSet(enable = true)
            enableDualShade()
            setDeviceEntered(true)
            val currentScene by collectLastValue(sceneInteractor.currentScene)
@@ -118,7 +120,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
    @Test
    fun onClockClicked_enableDesktopFeatureSetTrueOnNotifShade_closesShade() =
        kosmos.runTest {
            overrideResource(R.bool.config_enableDesktopFeatureSet, true)
            setEnableDesktopFeatureSet(enable = true)
            enableDualShade()
            setDeviceEntered(true)
            setOverlay(Overlays.NotificationsShade)
@@ -134,7 +136,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
    @Test
    fun onClockClicked_enableDesktopFeatureSetTrueOnQSShade_openNotifShade() =
        kosmos.runTest {
            overrideResource(R.bool.config_enableDesktopFeatureSet, true)
            setEnableDesktopFeatureSet(enable = true)
            enableDualShade()
            setDeviceEntered(true)
            setOverlay(Overlays.QuickSettingsShade)
@@ -417,6 +419,14 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
        setScene(if (isEntered) Scenes.Gone else Scenes.Lockscreen)
        assertThat(deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered)
    }

    private fun Kosmos.setEnableDesktopFeatureSet(enable: Boolean) {
        testableContext.orCreateTestableResources.addOverride(
            R.bool.config_enableDesktopFeatureSet,
            enable,
        )
        configurationController.onConfigurationChanged(Configuration())
    }
}

private class IntentMatcherAction(private val action: String) : ArgumentMatcher<Intent> {
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.desktop.domain.interactor

import android.content.res.Resources
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.onConfigChanged
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn

@SysUISingleton
class DesktopInteractor
@Inject
constructor(
    @Main private val resources: Resources,
    @Application private val scope: CoroutineScope,
    configurationController: ConfigurationController,
) {

    /** Whether the desktop feature set is enabled. */
    val isDesktopFeatureSetEnabled: StateFlow<Boolean> =
        configurationController.onConfigChanged
            .map { resources.getBoolean(R.bool.config_enableDesktopFeatureSet) }
            .onStart { emit(resources.getBoolean(R.bool.config_enableDesktopFeatureSet)) }
            .stateIn(
                scope,
                SharingStarted.WhileSubscribed(),
                resources.getBoolean(R.bool.config_enableDesktopFeatureSet),
            )
}
+11 −10
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@

package com.android.systemui.shade.ui.viewmodel

import android.content.Context
import android.content.Intent
import android.provider.Settings
import android.view.ViewGroup
@@ -28,6 +27,7 @@ import androidx.compose.ui.unit.IntRect
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.clock.domain.interactor.ClockInteractor
import com.android.systemui.desktop.domain.interactor.DesktopInteractor
import com.android.systemui.kairos.ExperimentalKairosApi
import com.android.systemui.kairos.KairosNetwork
import com.android.systemui.lifecycle.ExclusiveActivatable
@@ -35,14 +35,12 @@ import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.DualShadeEducationInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.domain.model.DualShadeEducationModel
import com.android.systemui.scene.shared.model.DualShadeEducationElement
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.domain.interactor.PrivacyChipInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
@@ -67,7 +65,6 @@ import kotlinx.coroutines.flow.map
class ShadeHeaderViewModel
@AssistedInject
constructor(
    @ShadeDisplayAware private val context: Context,
    private val activityStarter: ActivityStarter,
    private val sceneInteractor: SceneInteractor,
    private val shadeInteractor: ShadeInteractor,
@@ -83,6 +80,7 @@ constructor(
    val kairosNetwork: KairosNetwork,
    val mobileIconsViewModelKairos: dagger.Lazy<MobileIconsViewModelKairos>,
    private val dualShadeEducationInteractor: DualShadeEducationInteractor,
    private val desktopInteractor: DesktopInteractor,
) : ExclusiveActivatable() {

    private val hydrator = Hydrator("ShadeHeaderViewModel.hydrator")
@@ -178,6 +176,13 @@ constructor(
                },
        )

    private val isDesktopFeatureSetEnabled: Boolean by
        hydrator.hydratedStateOf(
            traceName = "isDesktopFeatureSetEnabled",
            initialValue = desktopInteractor.isDesktopFeatureSetEnabled.value,
            source = desktopInteractor.isDesktopFeatureSetEnabled,
        )

    override suspend fun onActivated(): Nothing {
        coroutineScope {
            launch { hydrator.activate() }
@@ -193,7 +198,7 @@ constructor(

    /** Notifies that the clock was clicked. */
    fun onClockClicked() {
        if (shadeModeInteractor.isDualShade && isDesktopFeatureSetEnabled()) {
        if (shadeModeInteractor.isDualShade && isDesktopFeatureSetEnabled) {
            toggleNotificationShade(
                loggingReason = "ShadeHeaderViewModel.onClockChipClicked",
                launchClockActivityOnCollapse = false,
@@ -210,14 +215,10 @@ constructor(
        }
        toggleNotificationShade(
            loggingReason = "ShadeHeaderViewModel.onNotificationIconChipClicked",
            launchClockActivityOnCollapse = !isDesktopFeatureSetEnabled(),
            launchClockActivityOnCollapse = !isDesktopFeatureSetEnabled,
        )
    }

    private fun isDesktopFeatureSetEnabled(): Boolean {
        return context.resources.getBoolean(R.bool.config_enableDesktopFeatureSet)
    }

    private fun toggleNotificationShade(
        loggingReason: String,
        launchClockActivityOnCollapse: Boolean,
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.desktop.domain.interactor

import android.content.res.mainResources
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.backgroundScope
import com.android.systemui.statusbar.policy.configurationController

val Kosmos.desktopInteractor: DesktopInteractor by
    Kosmos.Fixture {
        DesktopInteractor(
            resources = mainResources,
            scope = backgroundScope,
            configurationController = configurationController,
        )
    }
Loading