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

Commit 94d9720e authored by Lucas Silva's avatar Lucas Silva
Browse files

Automatically enter hub from lockscreen when applicable

Depending on the user's chosen "when to start" setting, we will
automatically open the hub when the conditions are met.

Flag: com.android.systemui.glanceable_hub_v2
Test: atest CommunalInteractorTest
Test: atest CommunalSettingsRepositoryImplTest
Bug: 383208131
Change-Id: I077ad623dd5c1fe61962ea983faf38007892329f
parent 382e19e7
Loading
Loading
Loading
Loading
+128 −94
Original line number Diff line number Diff line
@@ -38,19 +38,19 @@ import com.android.systemui.communal.data.model.DisabledReason
import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl.Companion.GLANCEABLE_HUB_BACKGROUND_SETTING
import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.communal.shared.model.WhenToDream
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -62,9 +62,11 @@ import platform.test.runner.parameterized.Parameters
@RunWith(ParameterizedAndroidJunit4::class)
class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiTestCase() {
    private val kosmos =
        testKosmos().apply { mainResources = mContext.orCreateTestableResources.resources }
    private val testScope = kosmos.testScope
    private lateinit var underTest: CommunalSettingsRepository
        testKosmos()
            .apply { mainResources = mContext.orCreateTestableResources.resources }
            .useUnconfinedTestDispatcher()

    private val Kosmos.underTest by Kosmos.Fixture { communalSettingsRepository }

    init {
        mSetFlagsRule.setFlagsParameterization(flags!!)
@@ -76,30 +78,32 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
        setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_FEATURES_NONE)
        setKeyguardFeaturesDisabled(SECONDARY_USER, KEYGUARD_DISABLE_FEATURES_NONE)
        setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_FEATURES_NONE)
        underTest = kosmos.communalSettingsRepository
    }

    @EnableFlags(FLAG_COMMUNAL_HUB)
    @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
    @Test
    fun getFlagEnabled_bothEnabled() {
        kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
    fun getFlagEnabled_bothEnabled() =
        kosmos.runTest {
            fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)

            assertThat(underTest.getFlagEnabled()).isTrue()
        }

    @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
    @Test
    fun getFlagEnabled_bothDisabled() {
        kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
    fun getFlagEnabled_bothDisabled() =
        kosmos.runTest {
            fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)

            assertThat(underTest.getFlagEnabled()).isFalse()
        }

    @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
    @Test
    fun getFlagEnabled_onlyClassicFlagEnabled() {
        kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
    fun getFlagEnabled_onlyClassicFlagEnabled() =
        kosmos.runTest {
            fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)

            assertThat(underTest.getFlagEnabled()).isFalse()
        }
@@ -107,8 +111,9 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_COMMUNAL_HUB)
    @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
    @Test
    fun getFlagEnabled_onlyTrunkFlagEnabled() {
        kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
    fun getFlagEnabled_onlyTrunkFlagEnabled() =
        kosmos.runTest {
            fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)

            assertThat(underTest.getFlagEnabled()).isFalse()
        }
@@ -116,7 +121,8 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    @DisableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun getFlagEnabled_mobileConfigEnabled() {
    fun getFlagEnabled_mobileConfigEnabled() =
        kosmos.runTest {
            mContext.orCreateTestableResources.addOverride(
                com.android.internal.R.bool.config_glanceableHubEnabled,
                true,
@@ -127,7 +133,8 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT

    @DisableFlags(FLAG_GLANCEABLE_HUB_V2, FLAG_COMMUNAL_HUB)
    @Test
    fun getFlagEnabled_onlyMobileConfigEnabled() {
    fun getFlagEnabled_onlyMobileConfigEnabled() =
        kosmos.runTest {
            mContext.orCreateTestableResources.addOverride(
                com.android.internal.R.bool.config_glanceableHubEnabled,
                true,
@@ -139,7 +146,8 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    @DisableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun getFlagEnabled_onlyMobileFlagEnabled() {
    fun getFlagEnabled_onlyMobileFlagEnabled() =
        kosmos.runTest {
            mContext.orCreateTestableResources.addOverride(
                com.android.internal.R.bool.config_glanceableHubEnabled,
                false,
@@ -151,7 +159,8 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    @DisableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun getFlagEnabled_oldFlagIgnored() {
    fun getFlagEnabled_oldFlagIgnored() =
        kosmos.runTest {
            // New config flag enabled.
            mContext.orCreateTestableResources.addOverride(
                com.android.internal.R.bool.config_glanceableHubEnabled,
@@ -159,7 +168,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
            )

            // Old config flag disabled.
        kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
            fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)

            assertThat(underTest.getFlagEnabled()).isTrue()
        }
@@ -167,7 +176,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun secondaryUserIsInvalid() =
        testScope.runTest {
        kosmos.runTest {
            val enabledState by collectLastValue(underTest.getEnabledState(SECONDARY_USER))

            assertThat(enabledState?.enabled).isFalse()
@@ -187,7 +196,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
    @Test
    fun communalHubFlagIsDisabled() =
        testScope.runTest {
        kosmos.runTest {
            val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
            assertThat(enabledState?.enabled).isFalse()
            assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG)
@@ -196,35 +205,23 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun hubIsDisabledByUser() =
        testScope.runTest {
            kosmos.fakeSettings.putIntForUser(
                Settings.Secure.GLANCEABLE_HUB_ENABLED,
                0,
                PRIMARY_USER.id,
            )
        kosmos.runTest {
            fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id)
            val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
            assertThat(enabledState?.enabled).isFalse()
            assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_USER_SETTING)

            kosmos.fakeSettings.putIntForUser(
                Settings.Secure.GLANCEABLE_HUB_ENABLED,
                1,
                SECONDARY_USER.id,
            )
            fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, SECONDARY_USER.id)
            assertThat(enabledState?.enabled).isFalse()

            kosmos.fakeSettings.putIntForUser(
                Settings.Secure.GLANCEABLE_HUB_ENABLED,
                1,
                PRIMARY_USER.id,
            )
            fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, PRIMARY_USER.id)
            assertThat(enabledState?.enabled).isTrue()
        }

    @EnableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun hubIsDisabledByDevicePolicy() =
        testScope.runTest {
        kosmos.runTest {
            val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
            assertThat(enabledState?.enabled).isTrue()

@@ -236,7 +233,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() =
        testScope.runTest {
        kosmos.runTest {
            val widgetsAllowedForWorkProfile by
                collectLastValue(underTest.getAllowedByDevicePolicy(WORK_PROFILE))
            assertThat(widgetsAllowedForWorkProfile).isTrue()
@@ -248,7 +245,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() =
        testScope.runTest {
        kosmos.runTest {
            val enabledStateForPrimaryUser by
                collectLastValue(underTest.getEnabledState(PRIMARY_USER))
            assertThat(enabledStateForPrimaryUser?.enabled).isTrue()
@@ -260,15 +257,11 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @EnableFlags(FLAG_COMMUNAL_HUB)
    @Test
    fun hubIsDisabledByUserAndDevicePolicy() =
        testScope.runTest {
        kosmos.runTest {
            val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
            assertThat(enabledState?.enabled).isTrue()

            kosmos.fakeSettings.putIntForUser(
                Settings.Secure.GLANCEABLE_HUB_ENABLED,
                0,
                PRIMARY_USER.id,
            )
            fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id)
            setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL)

            assertThat(enabledState?.enabled).isFalse()
@@ -282,17 +275,17 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
    @Test
    @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND)
    fun backgroundType_defaultValue() =
        testScope.runTest {
        kosmos.runTest {
            val backgroundType by collectLastValue(underTest.getBackground(PRIMARY_USER))
            assertThat(backgroundType).isEqualTo(CommunalBackgroundType.ANIMATED)
        }

    @Test
    fun backgroundType_verifyAllValues() =
        testScope.runTest {
        kosmos.runTest {
            val backgroundType by collectLastValue(underTest.getBackground(PRIMARY_USER))
            for (type in CommunalBackgroundType.entries) {
                kosmos.fakeSettings.putIntForUser(
                fakeSettings.putIntForUser(
                    GLANCEABLE_HUB_BACKGROUND_SETTING,
                    type.value,
                    PRIMARY_USER.id,
@@ -308,30 +301,71 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT

    @Test
    fun screensaverDisabledByUser() =
        testScope.runTest {
        kosmos.runTest {
            val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER))

            kosmos.fakeSettings.putIntForUser(
                Settings.Secure.SCREENSAVER_ENABLED,
                0,
                PRIMARY_USER.id,
            )
            fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 0, PRIMARY_USER.id)

            assertThat(enabledState).isFalse()
        }

    @Test
    fun screensaverEnabledByUser() =
        testScope.runTest {
        kosmos.runTest {
            val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER))

            kosmos.fakeSettings.putIntForUser(
                Settings.Secure.SCREENSAVER_ENABLED,
            fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 1, PRIMARY_USER.id)

            assertThat(enabledState).isTrue()
        }

    @Test
    fun whenToDream_charging() =
        kosmos.runTest {
            val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))

            fakeSettings.putIntForUser(
                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
                1,
                PRIMARY_USER.id,
            )

            assertThat(enabledState).isTrue()
            assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_CHARGING)
        }

    @Test
    fun whenToDream_docked() =
        kosmos.runTest {
            val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))

            fakeSettings.putIntForUser(
                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
                1,
                PRIMARY_USER.id,
            )

            assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_DOCKED)
        }

    @Test
    fun whenToDream_postured() =
        kosmos.runTest {
            val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))

            fakeSettings.putIntForUser(
                Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
                1,
                PRIMARY_USER.id,
            )

            assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_POSTURED)
        }

    @Test
    fun whenToDream_default() =
        kosmos.runTest {
            val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))
            assertThat(whenToDreamState).isEqualTo(WhenToDream.NEVER)
        }

    private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
+244 −256

File changed.

Preview size limit exceeded, changes collapsed.

+12 −28
Original line number Diff line number Diff line
@@ -21,19 +21,17 @@ import android.app.admin.devicePolicyManager
import android.content.Intent
import android.content.pm.UserInfo
import android.os.UserManager
import android.os.userManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.fakeUserRepository
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
@@ -48,34 +46,20 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class CommunalSettingsInteractorTest : SysuiTestCase() {

    private lateinit var userManager: UserManager
    private lateinit var userRepository: FakeUserRepository
    private lateinit var userTracker: FakeUserTracker
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()

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

    private lateinit var underTest: CommunalSettingsInteractor
    private val Kosmos.underTest by Kosmos.Fixture { communalSettingsInteractor }

    @Before
    fun setUp() {
        userManager = kosmos.userManager
        userRepository = kosmos.fakeUserRepository
        userTracker = kosmos.fakeUserTracker

        val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
        userRepository.setUserInfos(userInfos)
        userTracker.set(
            userInfos = userInfos,
            selectedUserIndex = 0,
        )

        underTest = kosmos.communalSettingsInteractor
        kosmos.fakeUserRepository.setUserInfos(userInfos)
        kosmos.fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
    }

    @Test
    fun filterUsers_dontFilteredUsersWhenAllAreAllowed() =
        testScope.runTest {
        kosmos.runTest {
            // If no users have any keyguard features disabled...
            val disallowedUser by
                collectLastValue(underTest.workProfileUserDisallowedByDevicePolicy)
@@ -85,11 +69,11 @@ class CommunalSettingsInteractorTest : SysuiTestCase() {

    @Test
    fun filterUsers_filterWorkProfileUserWhenDisallowed() =
        testScope.runTest {
        kosmos.runTest {
            // If the work profile user has keyguard widgets disabled...
            setKeyguardFeaturesDisabled(
                USER_INFO_WORK,
                DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
                DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL,
            )
            // ...then the disallowed user match the work profile
            val disallowedUser by
@@ -102,7 +86,7 @@ class CommunalSettingsInteractorTest : SysuiTestCase() {
        whenever(
                kosmos.devicePolicyManager.getKeyguardDisabledFeatures(
                    anyOrNull(),
                    ArgumentMatchers.eq(user.id)
                    ArgumentMatchers.eq(user.id),
                )
            )
            .thenReturn(disabledFlags)
+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.common.data

import com.android.systemui.common.data.repository.BatteryRepository
import com.android.systemui.common.data.repository.BatteryRepositoryImpl
import com.android.systemui.common.data.repository.PackageChangeRepository
import com.android.systemui.common.data.repository.PackageChangeRepositoryImpl
import dagger.Binds
@@ -27,4 +29,6 @@ abstract class CommonDataLayerModule {
    abstract fun bindPackageChangeRepository(
        impl: PackageChangeRepositoryImpl
    ): PackageChangeRepository

    @Binds abstract fun bindBatteryRepository(impl: BatteryRepositoryImpl): BatteryRepository
}
+44 −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.common.data.repository

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.util.kotlin.isDevicePluggedIn
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn

interface BatteryRepository {
    val isDevicePluggedIn: Flow<Boolean>
}

@SysUISingleton
class BatteryRepositoryImpl
@Inject
constructor(@Background bgScope: CoroutineScope, batteryController: BatteryController) :
    BatteryRepository {

    /** Returns {@code true} if the device is currently plugged in or wireless charging. */
    override val isDevicePluggedIn: Flow<Boolean> =
        batteryController
            .isDevicePluggedIn()
            .stateIn(bgScope, SharingStarted.WhileSubscribed(), batteryController.isPluggedIn)
}
Loading