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

Commit 2194a344 authored by Andre Le's avatar Andre Le Committed by Android (Google) Code Review
Browse files

Merge "StatusBarDate: Add DesktopInteractor for isDesktopFeatureSetEnabled" into main

parents e119cb34 73b22743
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