diff options
46 files changed, 1150 insertions, 701 deletions
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 72ae76a45cac..f628a420d8fa 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -312,6 +312,9 @@ <!-- Permission necessary to change car audio volume through CarAudioManager --> <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" /> + <!-- To detect when projecting to Android Auto --> + <uses-permission android:name="android.permission.READ_PROJECTION_STATE" /> + <!-- Permission to control Android Debug Bridge (ADB) --> <uses-permission android:name="android.permission.MANAGE_DEBUGGING" /> diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt index ed73d89db2c7..6a25069a4e5e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt @@ -73,12 +73,12 @@ class CommunalOngoingContentStartableTest : SysuiTestCase() { assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() - kosmos.setCommunalEnabled(true) + setCommunalEnabled(true) assertThat(fakeCommunalMediaRepository.isListening()).isTrue() assertThat(fakeCommunalSmartspaceRepository.isListening()).isTrue() - kosmos.setCommunalEnabled(false) + setCommunalEnabled(false) assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() @@ -93,13 +93,13 @@ class CommunalOngoingContentStartableTest : SysuiTestCase() { assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() - kosmos.setCommunalEnabled(true) + setCommunalEnabled(true) // Media listening does not start when UMO is disabled. assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isTrue() - kosmos.setCommunalEnabled(false) + setCommunalEnabled(false) assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryImplTest.kt new file mode 100644 index 000000000000..f9b29e9bc5b5 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryImplTest.kt @@ -0,0 +1,120 @@ +/* + * 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.communal.data.repository + +import android.app.UiModeManager +import android.app.UiModeManager.OnProjectionStateChangedListener +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.backgroundScope +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.launchIn +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CarProjectionRepositoryImplTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val capturedListeners = mutableListOf<OnProjectionStateChangedListener>() + + private val Kosmos.uiModeManager by + Kosmos.Fixture<UiModeManager> { + mock { + on { + addOnProjectionStateChangedListener( + eq(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE), + any(), + any(), + ) + } doAnswer + { + val listener = it.getArgument<OnProjectionStateChangedListener>(2) + capturedListeners.add(listener) + Unit + } + + on { removeOnProjectionStateChangedListener(any()) } doAnswer + { + val listener = it.getArgument<OnProjectionStateChangedListener>(0) + capturedListeners.remove(listener) + Unit + } + + on { activeProjectionTypes } doReturn UiModeManager.PROJECTION_TYPE_NONE + } + } + + private val Kosmos.underTest by + Kosmos.Fixture { + CarProjectionRepositoryImpl( + uiModeManager = uiModeManager, + bgDispatcher = testDispatcher, + ) + } + + @Test + fun testProjectionActiveUpdatesAfterCallback() = + kosmos.runTest { + val projectionActive by collectLastValue(underTest.projectionActive) + assertThat(projectionActive).isFalse() + + setActiveProjectionType(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) + assertThat(projectionActive).isTrue() + + setActiveProjectionType(UiModeManager.PROJECTION_TYPE_NONE) + assertThat(projectionActive).isFalse() + } + + @Test + fun testProjectionInitialValueTrue() = + kosmos.runTest { + setActiveProjectionType(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) + + val projectionActive by collectLastValue(underTest.projectionActive) + assertThat(projectionActive).isTrue() + } + + @Test + fun testUnsubscribeWhenCancelled() = + kosmos.runTest { + val job = underTest.projectionActive.launchIn(backgroundScope) + assertThat(capturedListeners).hasSize(1) + + job.cancel() + assertThat(capturedListeners).isEmpty() + } + + private fun Kosmos.setActiveProjectionType(@UiModeManager.ProjectionType projectionType: Int) { + uiModeManager.stub { on { activeProjectionTypes } doReturn projectionType } + capturedListeners.forEach { it.onProjectionStateChanged(projectionType, emptySet()) } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt index 5c983656225e..09d44a5e18d9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt @@ -34,9 +34,7 @@ import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher -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.communal.shared.model.WhenToDream import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED @@ -202,63 +200,6 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @EnableFlags(FLAG_COMMUNAL_HUB) @Test - fun secondaryUserIsInvalid() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(SECONDARY_USER)) - - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_INVALID_USER) - } - - @EnableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) - @Test - fun classicFlagIsDisabled() = - kosmos.runTest { - setCommunalV2Enabled(false) - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG) - } - - @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) - @Test - fun communalHubFlagIsDisabled() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG) - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsDisabledByUser() = - 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) - - fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, SECONDARY_USER.id) - assertThat(enabledState?.enabled).isFalse() - - fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, PRIMARY_USER.id) - assertThat(enabledState?.enabled).isTrue() - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsDisabledByDevicePolicy() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isTrue() - - setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL) - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_DEVICE_POLICY) - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() = kosmos.runTest { val widgetsAllowedForWorkProfile by @@ -269,36 +210,6 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT assertThat(widgetsAllowedForWorkProfile).isFalse() } - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() = - kosmos.runTest { - val enabledStateForPrimaryUser by - collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledStateForPrimaryUser?.enabled).isTrue() - - setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) - assertThat(enabledStateForPrimaryUser?.enabled).isTrue() - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsDisabledByUserAndDevicePolicy() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isTrue() - - fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id) - setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL) - - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState) - .containsExactly( - DisabledReason.DISABLED_REASON_DEVICE_POLICY, - DisabledReason.DISABLED_REASON_USER_SETTING, - ) - } - @Test @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) fun backgroundType_defaultValue() = @@ -327,26 +238,6 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT } @Test - fun screensaverDisabledByUser() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) - - fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 0, PRIMARY_USER.id) - - assertThat(enabledState).isFalse() - } - - @Test - fun screensaverEnabledByUser() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) - - 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)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorTest.kt new file mode 100644 index 000000000000..fc4cd43577b1 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorTest.kt @@ -0,0 +1,49 @@ +/* + * 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.communal.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.carProjectionRepository +import com.android.systemui.communal.data.repository.fake +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.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CarProjectionInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val Kosmos.underTest by Kosmos.Fixture { carProjectionInteractor } + + @Test + fun testProjectionActive() = + kosmos.runTest { + val projectionActive by collectLastValue(underTest.projectionActive) + assertThat(projectionActive).isFalse() + + carProjectionRepository.fake.setProjectionActive(true) + assertThat(projectionActive).isTrue() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt new file mode 100644 index 000000000000..f4a1c90a5471 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt @@ -0,0 +1,173 @@ +/* + * 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.communal.domain.interactor + +import android.provider.Settings +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.data.repository.batteryRepository +import com.android.systemui.common.data.repository.fake +import com.android.systemui.communal.data.model.FEATURE_AUTO_OPEN +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.posturing.data.repository.fake +import com.android.systemui.communal.posturing.data.repository.posturingRepository +import com.android.systemui.communal.posturing.shared.model.PosturedState +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.fakeDockManager +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.testKosmos +import com.android.systemui.user.data.repository.FakeUserRepository.Companion.MAIN_USER_ID +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.util.settings.fakeSettings +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CommunalAutoOpenInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val Kosmos.underTest by Kosmos.Fixture { communalAutoOpenInteractor } + + @Before + fun setUp() { + runBlocking { kosmos.fakeUserRepository.asMainUser() } + with(kosmos.fakeSettings) { + putBoolForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, false, MAIN_USER_ID) + putBoolForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, false, MAIN_USER_ID) + putBoolForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, false, MAIN_USER_ID) + } + } + + @Test + fun testStartWhileCharging() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + true, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(false) + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + + batteryRepository.fake.setDevicePluggedIn(true) + assertThat(shouldAutoOpen).isTrue() + assertThat(suppressionReason).isNull() + } + + @Test + fun testStartWhileDocked() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + true, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(true) + fakeDockManager.setIsDocked(false) + + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + + fakeDockManager.setIsDocked(true) + fakeDockManager.setDockEvent(DockManager.STATE_DOCKED) + assertThat(shouldAutoOpen).isTrue() + assertThat(suppressionReason).isNull() + } + + @Test + fun testStartWhilePostured() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + true, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(true) + posturingRepository.fake.setPosturedState(PosturedState.NotPostured) + + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + + posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) + assertThat(shouldAutoOpen).isTrue() + assertThat(suppressionReason).isNull() + } + + @Test + fun testStartNever() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + false, + MAIN_USER_ID, + ) + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + false, + MAIN_USER_ID, + ) + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + false, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(true) + posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) + fakeDockManager.setIsDocked(true) + + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt deleted file mode 100644 index beec184b80e7..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.communal.domain.interactor - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.systemui.Flags.FLAG_COMMUNAL_HUB -import com.android.systemui.SysuiTestCase -import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository -import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository -import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository -import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository -import com.android.systemui.kosmos.testScope -import com.android.systemui.testKosmos -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** - * This class is a variation of the [CommunalInteractorTest] for cases where communal is disabled. - */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class CommunalInteractorCommunalDisabledTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - - private lateinit var communalRepository: FakeCommunalSceneRepository - private lateinit var widgetRepository: FakeCommunalWidgetRepository - private lateinit var keyguardRepository: FakeKeyguardRepository - - private lateinit var underTest: CommunalInteractor - - @Before - fun setUp() { - communalRepository = kosmos.fakeCommunalSceneRepository - widgetRepository = kosmos.fakeCommunalWidgetRepository - keyguardRepository = kosmos.fakeKeyguardRepository - - mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB) - - underTest = kosmos.communalInteractor - } - - @Test - fun isCommunalEnabled_false() = - testScope.runTest { assertThat(underTest.isCommunalEnabled.value).isFalse() } - - @Test - fun isCommunalAvailable_whenStorageUnlock_false() = - testScope.runTest { - val isCommunalAvailable by collectLastValue(underTest.isCommunalAvailable) - - assertThat(isCommunalAvailable).isFalse() - - keyguardRepository.setIsEncryptedOrLockdown(false) - runCurrent() - - assertThat(isCommunalAvailable).isFalse() - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index 8424746f3db5..b65ecf46dcca 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -21,7 +21,6 @@ import android.app.admin.DevicePolicyManager import android.app.admin.devicePolicyManager import android.content.Intent import android.content.pm.UserInfo -import android.content.res.mainResources import android.os.UserHandle import android.os.UserManager import android.os.userManager @@ -39,9 +38,8 @@ import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.common.data.repository.batteryRepository -import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.model.CommunalSmartspaceTimer +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository @@ -50,14 +48,9 @@ import com.android.systemui.communal.data.repository.fakeCommunalTutorialReposit import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel -import com.android.systemui.communal.posturing.data.repository.fake -import com.android.systemui.communal.posturing.data.repository.posturingRepository -import com.android.systemui.communal.posturing.shared.model.PosturedState import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.EditModeState -import com.android.systemui.dock.DockManager -import com.android.systemui.dock.fakeDockManager import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic @@ -75,19 +68,16 @@ import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.fakeUserTracker import com.android.systemui.statusbar.phone.fakeManagedProfileController import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture 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 kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.advanceTimeBy -import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -98,10 +88,6 @@ import org.mockito.Mockito.verify import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters -/** - * This class of test cases assume that communal is enabled. For disabled cases, see - * [CommunalInteractorCommunalDisabledTest]. - */ @SmallTest @RunWith(ParameterizedAndroidJunit4::class) class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @@ -109,10 +95,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN) private val secondaryUser = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0) - private val kosmos = - testKosmos() - .apply { mainResources = mContext.orCreateTestableResources.resources } - .useUnconfinedTestDispatcher() + private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val Kosmos.underTest by Kosmos.Fixture { communalInteractor } @@ -128,104 +111,40 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true) mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB) - - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault, - false, - ) - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault, - false, - ) - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault, - false, - ) - } - - @After - fun tearDown() { - mContext.orCreateTestableResources.removeOverride( - com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault - ) - mContext.orCreateTestableResources.removeOverride( - com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault - ) - mContext.orCreateTestableResources.removeOverride( - com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault - ) } @Test fun communalEnabled_true() = kosmos.runTest { - fakeUserRepository.setSelectedUserInfo(mainUser) + communalSettingsInteractor.setSuppressionReasons(emptyList()) assertThat(underTest.isCommunalEnabled.value).isTrue() } @Test - fun isCommunalAvailable_mainUserUnlockedAndMainUser_true() = + fun isCommunalAvailable_whenKeyguardShowing_true() = kosmos.runTest { - val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - - assertThat(isAvailable).isTrue() - } + communalSettingsInteractor.setSuppressionReasons(emptyList()) + fakeKeyguardRepository.setKeyguardShowing(false) - @Test - fun isCommunalAvailable_mainUserLockedAndMainUser_false() = - kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, false) - fakeUserRepository.setSelectedUserInfo(mainUser) fakeKeyguardRepository.setKeyguardShowing(true) - - assertThat(isAvailable).isFalse() + assertThat(isAvailable).isTrue() } @Test - fun isCommunalAvailable_mainUserUnlockedAndSecondaryUser_false() = + fun isCommunalAvailable_suppressed() = kosmos.runTest { - val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(secondaryUser) + communalSettingsInteractor.setSuppressionReasons(emptyList()) fakeKeyguardRepository.setKeyguardShowing(true) - assertThat(isAvailable).isFalse() - } - - @Test - fun isCommunalAvailable_whenKeyguardShowing_true() = - kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - assertThat(isAvailable).isTrue() - } - - @Test - fun isCommunalAvailable_communalDisabled_false() = - kosmos.runTest { - mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) - val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, false) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) + communalSettingsInteractor.setSuppressionReasons( + listOf(SuppressionReason.ReasonUnknown()) + ) assertThat(isAvailable).isFalse() } @@ -1280,66 +1199,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { .inOrder() } - @Test - fun showCommunalWhileCharging() = - kosmos.runTest { - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, - 1, - mainUser.id, - ) - - val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) - batteryRepository.fake.setDevicePluggedIn(false) - assertThat(shouldShowCommunal).isFalse() - - batteryRepository.fake.setDevicePluggedIn(true) - assertThat(shouldShowCommunal).isTrue() - } - - @Test - fun showCommunalWhilePosturedAndCharging() = - kosmos.runTest { - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, - 1, - mainUser.id, - ) - - val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) - batteryRepository.fake.setDevicePluggedIn(true) - posturingRepository.fake.setPosturedState(PosturedState.NotPostured) - assertThat(shouldShowCommunal).isFalse() - - posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) - assertThat(shouldShowCommunal).isTrue() - } - - @Test - fun showCommunalWhileDocked() = - kosmos.runTest { - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 1, mainUser.id) - - batteryRepository.fake.setDevicePluggedIn(true) - fakeDockManager.setIsDocked(false) - - val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) - assertThat(shouldShowCommunal).isFalse() - - fakeDockManager.setIsDocked(true) - fakeDockManager.setDockEvent(DockManager.STATE_DOCKED) - assertThat(shouldShowCommunal).isTrue() - } - private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) .thenReturn(disabledFlags) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt index 8dc7a331dc2d..b8dbc9f77076 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt @@ -32,9 +32,9 @@ import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_DIRECT_EDIT_MODE import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository -import com.android.systemui.common.data.repository.batteryRepository -import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.model.CommunalSmartspaceTimer +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository import com.android.systemui.communal.data.repository.FakeCommunalSmartspaceRepository @@ -50,6 +50,7 @@ import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.communal.domain.interactor.communalTutorialInteractor +import com.android.systemui.communal.domain.interactor.setCommunalEnabled import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.log.CommunalMetricsLogger @@ -101,7 +102,6 @@ import com.android.systemui.statusbar.KeyguardIndicationController import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.advanceTimeBy @@ -128,7 +128,9 @@ import platform.test.runner.parameterized.Parameters @RunWith(ParameterizedAndroidJunit4::class) class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost + @Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler + @Mock private lateinit var metricsLogger: CommunalMetricsLogger private val kosmos = testKosmos() @@ -212,11 +214,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun tutorial_tutorialNotCompletedAndKeyguardVisible_showTutorialContent() = testScope.runTest { - // Keyguard showing, storage unlocked, main user, and tutorial not started. keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - userRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - setIsMainUser(true) + kosmos.setCommunalEnabled(true) tutorialRepository.setTutorialSettingState( Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED ) @@ -951,21 +950,16 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { fun swipeToCommunal() = kosmos.runTest { setCommunalV2ConfigEnabled(true) - val mainUser = fakeUserRepository.asMainUser() - fakeKeyguardRepository.setKeyguardShowing(true) - fakeUserRepository.setUserUnlocked(mainUser.id, true) - fakeUserTracker.set(userInfos = listOf(mainUser), selectedUserIndex = 0) - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, - 1, - mainUser.id, + // Suppress manual opening + communalSettingsInteractor.setSuppressionReasons( + listOf(SuppressionReason.ReasonUnknown(FEATURE_MANUAL_OPEN)) ) val viewModel = createViewModel() val swipeToHubEnabled by collectLastValue(viewModel.swipeToHubEnabled) assertThat(swipeToHubEnabled).isFalse() - batteryRepository.fake.setDevicePluggedIn(true) + communalSettingsInteractor.setSuppressionReasons(emptyList()) assertThat(swipeToHubEnabled).isTrue() keyguardTransitionRepository.sendTransitionStep( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt index c15f797aad5d..df10d058c5d1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.communal.widgets import android.content.pm.UserInfo -import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_COMMUNAL_HUB @@ -25,6 +24,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor +import com.android.systemui.communal.domain.interactor.setCommunalEnabled import com.android.systemui.communal.shared.model.FakeGlanceableHubMultiUserHelper import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper import com.android.systemui.coroutines.collectLastValue @@ -37,11 +37,9 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.settings.fakeUserTracker import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.FakeUserRepository.Companion.MAIN_USER_ID import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.user.domain.interactor.userLockedInteractor import com.android.systemui.util.mockito.whenever -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.test.runCurrent @@ -282,22 +280,12 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() { } } - private suspend fun setCommunalAvailable( - available: Boolean, - setKeyguardShowing: Boolean = true, - ) = + private fun setCommunalAvailable(available: Boolean, setKeyguardShowing: Boolean = true) = with(kosmos) { - fakeUserRepository.setUserUnlocked(MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO) + setCommunalEnabled(available) if (setKeyguardShowing) { fakeKeyguardRepository.setKeyguardShowing(true) } - val settingsValue = if (available) 1 else 0 - fakeSettings.putIntForUser( - Settings.Secure.GLANCEABLE_HUB_ENABLED, - settingsValue, - MAIN_USER_INFO.id, - ) } private companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt index 6c4325adced4..046d92d58978 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt @@ -35,7 +35,6 @@ package com.android.systemui.keyguard.domain.interactor import android.os.PowerManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags @@ -43,8 +42,6 @@ import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository -import com.android.systemui.common.data.repository.batteryRepository -import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.setCommunalV2Available @@ -72,7 +69,6 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth import junit.framework.Assert.assertEquals import kotlinx.coroutines.runBlocking @@ -433,9 +429,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() { @EnableFlags(FLAG_GLANCEABLE_HUB_V2) fun testTransitionToGlanceableHub_onWakeUpFromAod() = kosmos.runTest { - val user = setCommunalV2Available(true) - fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, user.id) - batteryRepository.fake.setDevicePluggedIn(true) + setCommunalV2Available(true) val currentScene by collectLastValue(communalSceneInteractor.currentScene) fakeCommunalSceneRepository.changeScene(CommunalScenes.Blank) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt index 9be786fab34d..096c3dafd01c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt @@ -193,6 +193,7 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT @Test @EnableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR) + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) fun testTransitionToLockscreen_onWake_canNotDream_glanceableHubAvailable() = kosmos.runTest { whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(false) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index 8df70ef0fd2e..7d5e9a5ed178 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -33,7 +33,7 @@ import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepositor import com.android.systemui.communal.domain.interactor.CommunalSceneTransitionInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSceneTransitionInteractor -import com.android.systemui.communal.domain.interactor.setCommunalAvailable +import com.android.systemui.communal.domain.interactor.setCommunalV2Available import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled import com.android.systemui.communal.shared.model.CommunalScenes @@ -1004,16 +1004,15 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest @BrokenWithSceneContainer(339465026) fun occludedToGlanceableHub_communalKtfRefactor() = testScope.runTest { - // GIVEN a device on lockscreen and communal is available - keyguardRepository.setKeyguardShowing(true) - kosmos.setCommunalAvailable(true) - runCurrent() - // GIVEN a prior transition has run to OCCLUDED from GLANCEABLE_HUB runTransitionAndSetWakefulness(KeyguardState.GLANCEABLE_HUB, KeyguardState.OCCLUDED) keyguardRepository.setKeyguardOccluded(true) runCurrent() + // GIVEN a device on lockscreen and communal is available + kosmos.setCommunalV2Available(true) + runCurrent() + // WHEN occlusion ends keyguardRepository.setKeyguardOccluded(false) runCurrent() diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSuppressionStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSuppressionStartable.kt new file mode 100644 index 000000000000..6a611ec5b647 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSuppressionStartable.kt @@ -0,0 +1,66 @@ +/* + * 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.communal + +import com.android.systemui.CoreStartable +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.log.dagger.CommunalTableLog +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +@SysUISingleton +class CommunalSuppressionStartable +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + @Background private val bgDispatcher: CoroutineDispatcher, + private val suppressionFlows: Set<@JvmSuppressWildcards Flow<SuppressionReason?>>, + private val communalSettingsInteractor: CommunalSettingsInteractor, + @CommunalTableLog private val tableLogBuffer: TableLogBuffer, +) : CoreStartable { + override fun start() { + getSuppressionReasons() + .onEach { reasons -> communalSettingsInteractor.setSuppressionReasons(reasons) } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "suppressionReasons", + initialValue = emptyList(), + ) + .flowOn(bgDispatcher) + .launchIn(applicationScope) + } + + private fun getSuppressionReasons(): Flow<List<SuppressionReason>> { + if (!communalSettingsInteractor.isCommunalFlagEnabled()) { + return flowOf(listOf(SuppressionReason.ReasonFlagDisabled)) + } + return combine(suppressionFlows) { reasons -> reasons.filterNotNull() } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt index bb3be531aa8a..a31c0bd35453 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt @@ -29,6 +29,7 @@ import com.android.systemui.communal.data.repository.CommunalSmartspaceRepositor import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule import com.android.systemui.communal.domain.interactor.CommunalSceneTransitionInteractor +import com.android.systemui.communal.domain.suppression.dagger.CommunalSuppressionModule import com.android.systemui.communal.shared.log.CommunalMetricsLogger import com.android.systemui.communal.shared.log.CommunalStatsLogProxyImpl import com.android.systemui.communal.shared.model.CommunalScenes @@ -70,6 +71,7 @@ import kotlinx.coroutines.CoroutineScope CommunalSmartspaceRepositoryModule::class, CommunalStartableModule::class, GlanceableHubWidgetManagerModule::class, + CommunalSuppressionModule::class, ] ) interface CommunalModule { diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt index 7358aa7b3fcd..a4f75e81b6ae 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt @@ -22,6 +22,7 @@ import com.android.systemui.communal.CommunalDreamStartable import com.android.systemui.communal.CommunalMetricsStartable import com.android.systemui.communal.CommunalOngoingContentStartable import com.android.systemui.communal.CommunalSceneStartable +import com.android.systemui.communal.CommunalSuppressionStartable import com.android.systemui.communal.DevicePosturingListener import com.android.systemui.communal.log.CommunalLoggerStartable import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable @@ -73,4 +74,9 @@ interface CommunalStartableModule { @IntoMap @ClassKey(DevicePosturingListener::class) fun bindDevicePosturingistener(impl: DevicePosturingListener): CoreStartable + + @Binds + @IntoMap + @ClassKey(CommunalSuppressionStartable::class) + fun bindCommunalSuppressionStartable(impl: CommunalSuppressionStartable): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalEnabledState.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalEnabledState.kt deleted file mode 100644 index 83a5bdb14ebd..000000000000 --- a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalEnabledState.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.communal.data.model - -import com.android.systemui.log.table.Diffable -import com.android.systemui.log.table.TableRowLogger -import java.util.EnumSet - -/** Reasons that communal is disabled, primarily for logging. */ -enum class DisabledReason(val loggingString: String) { - /** Communal should be disabled due to invalid current user */ - DISABLED_REASON_INVALID_USER("invalidUser"), - /** Communal should be disabled due to the flag being off */ - DISABLED_REASON_FLAG("flag"), - /** Communal should be disabled because the user has turned off the setting */ - DISABLED_REASON_USER_SETTING("userSetting"), - /** Communal is disabled by the device policy app */ - DISABLED_REASON_DEVICE_POLICY("devicePolicy"), -} - -/** - * Model representing the reasons communal hub should be disabled. Allows logging reasons separately - * for debugging. - */ -@JvmInline -value class CommunalEnabledState( - private val disabledReasons: EnumSet<DisabledReason> = - EnumSet.noneOf(DisabledReason::class.java) -) : Diffable<CommunalEnabledState>, Set<DisabledReason> by disabledReasons { - - /** Creates [CommunalEnabledState] with a single reason for being disabled */ - constructor(reason: DisabledReason) : this(EnumSet.of(reason)) - - /** Checks if there are any reasons communal should be disabled. If none, returns true. */ - val enabled: Boolean - get() = isEmpty() - - override fun logDiffs(prevVal: CommunalEnabledState, row: TableRowLogger) { - for (reason in DisabledReason.entries) { - val newVal = contains(reason) - if (newVal != prevVal.contains(reason)) { - row.logChange( - columnName = reason.loggingString, - value = newVal, - ) - } - } - } - - override fun logFull(row: TableRowLogger) { - for (reason in DisabledReason.entries) { - row.logChange(columnName = reason.loggingString, value = contains(reason)) - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalFeature.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalFeature.kt new file mode 100644 index 000000000000..5fb1c4e84eef --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalFeature.kt @@ -0,0 +1,41 @@ +/* + * 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.communal.data.model + +import android.annotation.IntDef + +@Retention(AnnotationRetention.SOURCE) +@IntDef( + flag = true, + prefix = ["FEATURE_"], + value = [FEATURE_AUTO_OPEN, FEATURE_MANUAL_OPEN, FEATURE_ENABLED, FEATURE_ALL], +) +annotation class CommunalFeature + +/** If we should automatically open the hub */ +const val FEATURE_AUTO_OPEN: Int = 1 + +/** If the user is allowed to manually open the hub */ +const val FEATURE_MANUAL_OPEN: Int = 1 shl 1 + +/** + * If the hub should be considered enabled. If not, it may be cleaned up entirely to reduce memory + * footprint. + */ +const val FEATURE_ENABLED: Int = 1 shl 2 + +const val FEATURE_ALL: Int = FEATURE_ENABLED or FEATURE_MANUAL_OPEN or FEATURE_AUTO_OPEN diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/SuppressionReason.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/SuppressionReason.kt new file mode 100644 index 000000000000..de05bed7ef57 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/SuppressionReason.kt @@ -0,0 +1,63 @@ +/* + * 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.communal.data.model + +sealed interface SuppressionReason { + @CommunalFeature val suppressedFeatures: Int + + /** Whether this reason suppresses a particular feature. */ + fun isSuppressed(@CommunalFeature feature: Int): Boolean { + return (suppressedFeatures and feature) != 0 + } + + /** Suppress hub automatically opening due to Android Auto projection */ + data object ReasonCarProjection : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_AUTO_OPEN + } + + /** Suppress hub due to the "When to dream" conditions not being met */ + data class ReasonWhenToAutoShow(override val suppressedFeatures: Int) : SuppressionReason + + /** Suppress hub due to device policy */ + data object ReasonDevicePolicy : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to the user disabling the setting */ + data object ReasonSettingDisabled : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to the user being locked */ + data object ReasonUserLocked : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due the a secondary user being active */ + data object ReasonSecondaryUser : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to the flag being disabled */ + data object ReasonFlagDisabled : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to an unknown reason, used as initial state and in tests */ + data class ReasonUnknown(override val suppressedFeatures: Int = FEATURE_ALL) : + SuppressionReason +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CarProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CarProjectionRepository.kt new file mode 100644 index 000000000000..4fe641a78d4b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CarProjectionRepository.kt @@ -0,0 +1,71 @@ +/* + * 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.communal.data.repository + +import android.app.UiModeManager +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.kotlin.emitOnStart +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.asExecutor +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext + +interface CarProjectionRepository { + /** Whether car projection is active. */ + val projectionActive: Flow<Boolean> + + /** + * Checks the system for the current car projection state. + * + * @return True if projection is active, false otherwise. + */ + suspend fun isProjectionActive(): Boolean +} + +@SysUISingleton +class CarProjectionRepositoryImpl +@Inject +constructor( + private val uiModeManager: UiModeManager, + @Background private val bgDispatcher: CoroutineDispatcher, +) : CarProjectionRepository { + override val projectionActive: Flow<Boolean> = + conflatedCallbackFlow { + val listener = + UiModeManager.OnProjectionStateChangedListener { _, _ -> trySend(Unit) } + uiModeManager.addOnProjectionStateChangedListener( + UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, + bgDispatcher.asExecutor(), + listener, + ) + awaitClose { uiModeManager.removeOnProjectionStateChangedListener(listener) } + } + .emitOnStart() + .map { isProjectionActive() } + .flowOn(bgDispatcher) + + override suspend fun isProjectionActive(): Boolean = + withContext(bgDispatcher) { + (uiModeManager.activeProjectionTypes and UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) != 0 + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt index 7f137f3b976b..0d590db97860 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt @@ -22,4 +22,6 @@ import dagger.Module @Module interface CommunalRepositoryModule { @Binds fun communalRepository(impl: CommunalSceneRepositoryImpl): CommunalSceneRepository + + @Binds fun carProjectionRepository(impl: CarProjectionRepositoryImpl): CarProjectionRepository } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt index 4c291a0c5a2e..6f688d172843 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt @@ -26,12 +26,9 @@ import android.provider.Settings import com.android.systemui.Flags.communalHub import com.android.systemui.Flags.glanceableHubV2 import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.communal.data.model.CommunalEnabledState -import com.android.systemui.communal.data.model.DisabledReason -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_DEVICE_POLICY -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_FLAG -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_INVALID_USER -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_USER_SETTING +import com.android.systemui.communal.data.model.CommunalFeature +import com.android.systemui.communal.data.model.FEATURE_ALL +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryModule.Companion.DEFAULT_BACKGROUND_TYPE import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.WhenToDream @@ -43,22 +40,23 @@ import com.android.systemui.flags.Flags import com.android.systemui.util.kotlin.emitOnStart import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow -import java.util.EnumSet import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onStart interface CommunalSettingsRepository { - /** A [CommunalEnabledState] for the specified user. */ - fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState> + /** Whether a particular feature is enabled */ + fun isEnabled(@CommunalFeature feature: Int): Flow<Boolean> - fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean> + /** + * Suppresses the hub with the given reasons. If there are no reasons, the hub will not be + * suppressed. + */ + fun setSuppressionReasons(reasons: List<SuppressionReason>) /** * Returns a [WhenToDream] for the specified user, indicating what state the device should be in @@ -66,6 +64,9 @@ interface CommunalSettingsRepository { */ fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream> + /** Returns whether glanceable hub is enabled by the current user. */ + fun getSettingEnabledByUser(user: UserInfo): Flow<Boolean> + /** * Returns true if any glanceable hub functionality should be enabled via configs and flags. * @@ -123,6 +124,19 @@ constructor( resources.getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault) } + private val _suppressionReasons = + MutableStateFlow<List<SuppressionReason>>( + // Suppress hub by default until we get an initial update. + listOf(SuppressionReason.ReasonUnknown(FEATURE_ALL)) + ) + + override fun isEnabled(@CommunalFeature feature: Int): Flow<Boolean> = + _suppressionReasons.map { reasons -> reasons.none { it.isSuppressed(feature) } } + + override fun setSuppressionReasons(reasons: List<SuppressionReason>) { + _suppressionReasons.value = reasons + } + override fun getFlagEnabled(): Boolean { return if (getV2FlagEnabled()) { true @@ -138,44 +152,6 @@ constructor( glanceableHubV2() } - override fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState> { - if (!user.isMain) { - return flowOf(CommunalEnabledState(DISABLED_REASON_INVALID_USER)) - } - if (!getFlagEnabled()) { - return flowOf(CommunalEnabledState(DISABLED_REASON_FLAG)) - } - return combine( - getEnabledByUser(user).mapToReason(DISABLED_REASON_USER_SETTING), - getAllowedByDevicePolicy(user).mapToReason(DISABLED_REASON_DEVICE_POLICY), - ) { reasons -> - reasons.filterNotNull() - } - .map { reasons -> - if (reasons.isEmpty()) { - EnumSet.noneOf(DisabledReason::class.java) - } else { - EnumSet.copyOf(reasons) - } - } - .map { reasons -> CommunalEnabledState(reasons) } - .flowOn(bgDispatcher) - } - - override fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean> = - secureSettings - .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.SCREENSAVER_ENABLED)) - // Force an update - .onStart { emit(Unit) } - .map { - secureSettings.getIntForUser( - Settings.Secure.SCREENSAVER_ENABLED, - SCREENSAVER_ENABLED_SETTING_DEFAULT, - user.id, - ) == 1 - } - .flowOn(bgDispatcher) - override fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream> = secureSettings .observerFlow( @@ -247,11 +223,11 @@ constructor( ?: defaultBackgroundType } - private fun getEnabledByUser(user: UserInfo): Flow<Boolean> = + override fun getSettingEnabledByUser(user: UserInfo): Flow<Boolean> = secureSettings .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.GLANCEABLE_HUB_ENABLED)) // Force an update - .onStart { emit(Unit) } + .emitOnStart() .map { secureSettings.getIntForUser( Settings.Secure.GLANCEABLE_HUB_ENABLED, @@ -259,17 +235,13 @@ constructor( user.id, ) == 1 } + .flowOn(bgDispatcher) companion object { const val GLANCEABLE_HUB_BACKGROUND_SETTING = "glanceable_hub_background" private const val ENABLED_SETTING_DEFAULT = 1 - private const val SCREENSAVER_ENABLED_SETTING_DEFAULT = 0 } } private fun DevicePolicyManager.areKeyguardWidgetsAllowed(userId: Int): Boolean = (getKeyguardDisabledFeatures(null, userId) and KEYGUARD_DISABLE_WIDGETS_ALL) == 0 - -private fun Flow<Boolean>.mapToReason(reason: DisabledReason) = map { enabled -> - if (enabled) null else reason -} diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractor.kt new file mode 100644 index 000000000000..17b61e1c6fdf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractor.kt @@ -0,0 +1,27 @@ +/* + * 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.communal.domain.interactor + +import com.android.systemui.communal.data.repository.CarProjectionRepository +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +@SysUISingleton +class CarProjectionInteractor @Inject constructor(repository: CarProjectionRepository) { + /** Whether car projection is active. */ + val projectionActive = repository.projectionActive +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt new file mode 100644 index 000000000000..51df3338a18e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt @@ -0,0 +1,79 @@ +/* + * 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.communal.domain.interactor + +import com.android.systemui.common.domain.interactor.BatteryInteractor +import com.android.systemui.communal.dagger.CommunalModule.Companion.SWIPE_TO_HUB +import com.android.systemui.communal.data.model.FEATURE_AUTO_OPEN +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor +import com.android.systemui.communal.shared.model.WhenToDream +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.retrieveIsDocked +import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated +import javax.inject.Inject +import javax.inject.Named +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +@SysUISingleton +class CommunalAutoOpenInteractor +@Inject +constructor( + communalSettingsInteractor: CommunalSettingsInteractor, + @Background private val backgroundContext: CoroutineContext, + private val batteryInteractor: BatteryInteractor, + private val posturingInteractor: PosturingInteractor, + private val dockManager: DockManager, + @Named(SWIPE_TO_HUB) private val allowSwipeAlways: Boolean, +) { + val shouldAutoOpen: Flow<Boolean> = + communalSettingsInteractor.whenToDream + .flatMapLatestConflated { whenToDream -> + when (whenToDream) { + WhenToDream.WHILE_CHARGING -> batteryInteractor.isDevicePluggedIn + WhenToDream.WHILE_DOCKED -> { + allOf(batteryInteractor.isDevicePluggedIn, dockManager.retrieveIsDocked()) + } + WhenToDream.WHILE_POSTURED -> { + allOf(batteryInteractor.isDevicePluggedIn, posturingInteractor.postured) + } + WhenToDream.NEVER -> flowOf(false) + } + } + .flowOn(backgroundContext) + + val suppressionReason: Flow<SuppressionReason?> = + shouldAutoOpen.map { conditionMet -> + if (conditionMet) { + null + } else { + var suppressedFeatures = FEATURE_AUTO_OPEN + if (!allowSwipeAlways) { + suppressedFeatures = suppressedFeatures or FEATURE_MANUAL_OPEN + } + SuppressionReason.ReasonWhenToAutoShow(suppressedFeatures) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 564628d3f52f..684c52ad45f3 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -30,13 +30,11 @@ import com.android.compose.animation.scene.TransitionKey import com.android.systemui.Flags.communalResponsiveGrid import com.android.systemui.Flags.glanceableHubBlurredBackground import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.common.domain.interactor.BatteryInteractor import com.android.systemui.communal.data.repository.CommunalMediaRepository import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository import com.android.systemui.communal.data.repository.CommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent -import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.FULL @@ -45,14 +43,11 @@ import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize. import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.CommunalWidgetContentModel import com.android.systemui.communal.shared.model.EditModeState -import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.communal.widgets.EditWidgetsActivityStarter import com.android.systemui.communal.widgets.WidgetConfigurator import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.dock.DockManager -import com.android.systemui.dock.retrieveIsDocked import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge @@ -69,11 +64,8 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.ManagedProfileController -import com.android.systemui.user.domain.interactor.UserLockedInteractor import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf -import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.util.kotlin.emitOnStart -import com.android.systemui.util.kotlin.isDevicePluggedIn import javax.inject.Inject import kotlin.time.Duration.Companion.minutes import kotlinx.coroutines.CoroutineDispatcher @@ -125,10 +117,6 @@ constructor( @CommunalLog logBuffer: LogBuffer, @CommunalTableLog tableLogBuffer: TableLogBuffer, private val managedProfileController: ManagedProfileController, - private val batteryInteractor: BatteryInteractor, - private val dockManager: DockManager, - private val posturingInteractor: PosturingInteractor, - private val userLockedInteractor: UserLockedInteractor, ) { private val logger = Logger(logBuffer, "CommunalInteractor") @@ -162,11 +150,7 @@ constructor( /** Whether communal features are enabled and available. */ val isCommunalAvailable: Flow<Boolean> = - allOf( - communalSettingsInteractor.isCommunalEnabled, - userLockedInteractor.isUserUnlocked(userManager.mainUser), - keyguardInteractor.isKeyguardShowing, - ) + allOf(communalSettingsInteractor.isCommunalEnabled, keyguardInteractor.isKeyguardShowing) .distinctUntilChanged() .onEach { available -> logger.i({ "Communal is ${if (bool1) "" else "un"}available" }) { @@ -184,37 +168,6 @@ constructor( replay = 1, ) - /** - * Whether communal hub should be shown automatically, depending on the user's [WhenToDream] - * state. - */ - val shouldShowCommunal: StateFlow<Boolean> = - allOf( - isCommunalAvailable, - communalSettingsInteractor.whenToDream - .flatMapLatest { whenToDream -> - when (whenToDream) { - WhenToDream.NEVER -> flowOf(false) - - WhenToDream.WHILE_CHARGING -> batteryInteractor.isDevicePluggedIn - - WhenToDream.WHILE_DOCKED -> - allOf( - batteryInteractor.isDevicePluggedIn, - dockManager.retrieveIsDocked(), - ) - - WhenToDream.WHILE_POSTURED -> - allOf( - batteryInteractor.isDevicePluggedIn, - posturingInteractor.postured, - ) - } - } - .flowOn(bgDispatcher), - ) - .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) - private val _isDisclaimerDismissed = MutableStateFlow(false) val isDisclaimerDismissed: Flow<Boolean> = _isDisclaimerDismissed.asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt index a0b1261df346..ae89b39175c1 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt @@ -18,17 +18,18 @@ package com.android.systemui.communal.domain.interactor import android.content.pm.UserInfo import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow -import com.android.systemui.communal.data.model.CommunalEnabledState +import com.android.systemui.communal.data.model.FEATURE_AUTO_OPEN +import com.android.systemui.communal.data.model.FEATURE_ENABLED +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.CommunalSettingsRepository import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.log.dagger.CommunalTableLog -import com.android.systemui.log.table.TableLogBuffer -import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.settings.UserTracker import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import java.util.concurrent.Executor import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -53,33 +54,43 @@ constructor( private val repository: CommunalSettingsRepository, userInteractor: SelectedUserInteractor, private val userTracker: UserTracker, - @CommunalTableLog tableLogBuffer: TableLogBuffer, ) { - /** Whether or not communal is enabled for the currently selected user. */ + /** Whether communal is enabled at all. */ val isCommunalEnabled: StateFlow<Boolean> = - userInteractor.selectedUserInfo - .flatMapLatest { user -> repository.getEnabledState(user) } - .logDiffsForTable( - tableLogBuffer = tableLogBuffer, - columnPrefix = "disabledReason", - initialValue = CommunalEnabledState(), - ) - .map { model -> model.enabled } - // Start this eagerly since the value is accessed synchronously in many places. + repository + .isEnabled(FEATURE_ENABLED) .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) - /** Whether or not screensaver (dreams) is enabled for the currently selected user. */ - val isScreensaverEnabled: Flow<Boolean> = - userInteractor.selectedUserInfo.flatMapLatest { user -> - repository.getScreensaverEnabledState(user) - } + /** Whether manually opening the hub is enabled */ + val manualOpenEnabled: StateFlow<Boolean> = + repository + .isEnabled(FEATURE_MANUAL_OPEN) + .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) + + /** Whether auto-opening the hub is enabled */ + val autoOpenEnabled: StateFlow<Boolean> = + repository + .isEnabled(FEATURE_AUTO_OPEN) + .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) /** When to dream for the currently selected user. */ val whenToDream: Flow<WhenToDream> = - userInteractor.selectedUserInfo.flatMapLatest { user -> + userInteractor.selectedUserInfo.flatMapLatestConflated { user -> repository.getWhenToDreamState(user) } + /** Whether communal hub is allowed by device policy for the current user */ + val allowedForCurrentUserByDevicePolicy: Flow<Boolean> = + userInteractor.selectedUserInfo.flatMapLatestConflated { user -> + repository.getAllowedByDevicePolicy(user) + } + + /** Whether the hub is enabled for the current user */ + val settingEnabledForCurrentUser: Flow<Boolean> = + userInteractor.selectedUserInfo.flatMapLatestConflated { user -> + repository.getSettingEnabledByUser(user) + } + /** * Returns true if any glanceable hub functionality should be enabled via configs and flags. * @@ -109,6 +120,14 @@ constructor( */ fun isV2FlagEnabled(): Boolean = repository.getV2FlagEnabled() + /** + * Suppresses the hub with the given reasons. If there are no reasons, the hub will not be + * suppressed. + */ + fun setSuppressionReasons(reasons: List<SuppressionReason>) { + repository.setSuppressionReasons(reasons) + } + /** The type of background to use for the hub. Used to experiment with different backgrounds */ val communalBackground: Flow<CommunalBackgroundType> = userInteractor.selectedUserInfo diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/FlowExt.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/FlowExt.kt new file mode 100644 index 000000000000..a10e90f09cc2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/FlowExt.kt @@ -0,0 +1,24 @@ +/* + * 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.communal.domain.suppression + +import com.android.systemui.communal.data.model.SuppressionReason +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +fun Flow<Boolean>.mapToReasonIfNotAllowed(reason: SuppressionReason): Flow<SuppressionReason?> = + this.map { allowed -> if (allowed) null else reason } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/dagger/CommunalSuppressionModule.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/dagger/CommunalSuppressionModule.kt new file mode 100644 index 000000000000..c62d77eee287 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/dagger/CommunalSuppressionModule.kt @@ -0,0 +1,103 @@ +/* + * 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.communal.domain.suppression.dagger + +import com.android.systemui.Flags.glanceableHubV2 +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.domain.interactor.CarProjectionInteractor +import com.android.systemui.communal.domain.interactor.CommunalAutoOpenInteractor +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.domain.suppression.mapToReasonIfNotAllowed +import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import com.android.systemui.user.domain.interactor.UserLockedInteractor +import com.android.systemui.util.kotlin.BooleanFlowOperators.not +import dagger.Module +import dagger.Provides +import dagger.multibindings.IntoSet +import dagger.multibindings.Multibinds +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map + +@Module +interface CommunalSuppressionModule { + /** + * A set of reasons why communal may be suppressed. Ensures that this can be injected even if + * it's empty. + */ + @Multibinds fun suppressorSet(): Set<Flow<SuppressionReason?>> + + companion object { + @Provides + @IntoSet + fun provideCarProjectionSuppressor( + interactor: CarProjectionInteractor + ): Flow<SuppressionReason?> { + if (!glanceableHubV2()) { + return flowOf(null) + } + return not(interactor.projectionActive) + .mapToReasonIfNotAllowed(SuppressionReason.ReasonCarProjection) + } + + @Provides + @IntoSet + fun provideDevicePolicySuppressor( + interactor: CommunalSettingsInteractor + ): Flow<SuppressionReason?> { + return interactor.allowedForCurrentUserByDevicePolicy.mapToReasonIfNotAllowed( + SuppressionReason.ReasonDevicePolicy + ) + } + + @Provides + @IntoSet + fun provideSettingDisabledSuppressor( + interactor: CommunalSettingsInteractor + ): Flow<SuppressionReason?> { + return interactor.settingEnabledForCurrentUser.mapToReasonIfNotAllowed( + SuppressionReason.ReasonSettingDisabled + ) + } + + @Provides + @IntoSet + fun bindUserLockedSuppressor(interactor: UserLockedInteractor): Flow<SuppressionReason?> { + return interactor.currentUserUnlocked.mapToReasonIfNotAllowed( + SuppressionReason.ReasonUserLocked + ) + } + + @Provides + @IntoSet + fun provideAutoOpenSuppressor( + interactor: CommunalAutoOpenInteractor + ): Flow<SuppressionReason?> { + return interactor.suppressionReason + } + + @Provides + @IntoSet + fun provideMainUserSuppressor( + interactor: SelectedUserInteractor + ): Flow<SuppressionReason?> { + return interactor.selectedUserInfo + .map { it.isMain } + .mapToReasonIfNotAllowed(SuppressionReason.ReasonSecondaryUser) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 62a98d7a48ea..857fa5cac3e2 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -369,12 +369,10 @@ constructor( val swipeToHubEnabled: Flow<Boolean> by lazy { val inAllowedDeviceState = - if (swipeToHub) { - MutableStateFlow(true) - } else if (v2FlagEnabled()) { - communalInteractor.shouldShowCommunal + if (v2FlagEnabled()) { + communalSettingsInteractor.manualOpenEnabled } else { - MutableStateFlow(false) + MutableStateFlow(swipeToHub) } if (v2FlagEnabled()) { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt index a7c078f235b4..36b75c6fc6b8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt @@ -61,7 +61,7 @@ constructor( fun startTransitionFromDream() { val showGlanceableHub = if (communalSettingsInteractor.isV2FlagEnabled()) { - communalInteractor.shouldShowCommunal.value + communalSettingsInteractor.autoOpenEnabled.value } else { communalInteractor.isCommunalEnabled.value && !keyguardUpdateMonitor.isEncryptedOrLockdown(userTracker.userId) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt index ef06a85bd0d9..54af8f5b9806 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt @@ -20,7 +20,6 @@ import android.animation.ValueAnimator import android.util.Log import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.model.CommunalScenes @@ -60,7 +59,6 @@ constructor( private val wakeToGoneInteractor: KeyguardWakeDirectlyToGoneInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, private val communalSceneInteractor: CommunalSceneInteractor, - private val communalInteractor: CommunalInteractor, ) : TransitionInteractor( fromState = KeyguardState.AOD, @@ -110,7 +108,7 @@ constructor( val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value val biometricUnlockMode = keyguardInteractor.biometricUnlockState.value.mode val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value - val shouldShowCommunal = communalInteractor.shouldShowCommunal.value + val shouldShowCommunal = communalSettingsInteractor.autoOpenEnabled.value if (!maybeHandleInsecurePowerGesture()) { val shouldTransitionToLockscreen = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index 6f5f662d6fa3..1fc41085f772 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -153,7 +153,7 @@ constructor( .filterRelevantKeyguardStateAnd { isAwake -> isAwake } .sample( communalInteractor.isCommunalAvailable, - communalInteractor.shouldShowCommunal, + communalSettingsInteractor.autoOpenEnabled, ) .collect { (_, isCommunalAvailable, shouldShowCommunal) -> val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value @@ -209,7 +209,7 @@ constructor( powerInteractor.detailedWakefulness .filterRelevantKeyguardStateAnd { it.isAwake() } .sample( - communalInteractor.shouldShowCommunal, + communalSettingsInteractor.autoOpenEnabled, communalInteractor.isCommunalAvailable, keyguardInteractor.biometricUnlockState, wakeToGoneInteractor.canWakeDirectlyToGone, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index 0fb98ffa4a30..3b1b6fcc45f2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -115,7 +115,7 @@ constructor( powerInteractor.isAwake .debounce(50L) .filterRelevantKeyguardStateAnd { isAwake -> isAwake } - .sample(communalInteractor.shouldShowCommunal) + .sample(communalSettingsInteractor.autoOpenEnabled) .collect { shouldShowCommunal -> if (shouldShowCommunal) { // This case handles tapping the power button to transition through diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index a01dc02bbd9f..f8c7a86687dd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -20,7 +20,6 @@ import android.animation.ValueAnimator import android.util.MathUtils import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.model.CommunalScenes @@ -69,7 +68,6 @@ constructor( private val shadeRepository: ShadeRepository, powerInteractor: PowerInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, - private val communalInteractor: CommunalInteractor, private val communalSceneInteractor: CommunalSceneInteractor, private val swipeToDismissInteractor: SwipeToDismissInteractor, keyguardOcclusionInteractor: KeyguardOcclusionInteractor, @@ -355,7 +353,7 @@ constructor( private fun listenForLockscreenToGlanceableHubV2() { scope.launch { - communalInteractor.shouldShowCommunal + communalSettingsInteractor.autoOpenEnabled .filterRelevantKeyguardStateAnd { shouldShow -> shouldShow } .collect { communalSceneInteractor.changeScene( diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt index 3bd8af690763..6657c428a594 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt @@ -20,6 +20,7 @@ import android.os.UserHandle import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.user.data.repository.UserRepository +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow @@ -31,7 +32,14 @@ class UserLockedInteractor constructor( @Background val backgroundDispatcher: CoroutineDispatcher, val userRepository: UserRepository, + val selectedUserInteractor: SelectedUserInteractor, ) { + /** Whether the current user is unlocked */ + val currentUserUnlocked: Flow<Boolean> = + selectedUserInteractor.selectedUserInfo.flatMapLatestConflated { user -> + isUserUnlocked(user.userHandle) + } + fun isUserUnlocked(userHandle: UserHandle?): Flow<Boolean> = userRepository.isUserUnlocked(userHandle).flowOn(backgroundDispatcher) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryKosmos.kt new file mode 100644 index 000000000000..130c2987912e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.communal.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.carProjectionRepository by + Kosmos.Fixture<CarProjectionRepository> { FakeCarProjectionRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCarProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCarProjectionRepository.kt new file mode 100644 index 000000000000..4042342923ea --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCarProjectionRepository.kt @@ -0,0 +1,37 @@ +/* + * 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.communal.data.repository + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeCarProjectionRepository : CarProjectionRepository { + private val _projectionActive = MutableStateFlow(false) + override val projectionActive: Flow<Boolean> = _projectionActive.asStateFlow() + + override suspend fun isProjectionActive(): Boolean { + return _projectionActive.value + } + + fun setProjectionActive(active: Boolean) { + _projectionActive.value = active + } +} + +val CarProjectionRepository.fake + get() = this as FakeCarProjectionRepository diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorKosmos.kt new file mode 100644 index 000000000000..23bbe36203e6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.communal.domain.interactor + +import com.android.systemui.communal.data.repository.carProjectionRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.carProjectionInteractor by Fixture { CarProjectionInteractor(carProjectionRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorKosmos.kt new file mode 100644 index 000000000000..5735cf82cca0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorKosmos.kt @@ -0,0 +1,35 @@ +/* + * 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.communal.domain.interactor + +import com.android.systemui.common.domain.interactor.batteryInteractor +import com.android.systemui.communal.posturing.domain.interactor.posturingInteractor +import com.android.systemui.dock.dockManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.backgroundCoroutineContext + +val Kosmos.communalAutoOpenInteractor by Fixture { + CommunalAutoOpenInteractor( + communalSettingsInteractor = communalSettingsInteractor, + backgroundContext = backgroundCoroutineContext, + batteryInteractor = batteryInteractor, + posturingInteractor = posturingInteractor, + dockManager = dockManager, + allowSwipeAlways = false, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index b8b2ec5a58ae..316fcbb85b26 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -16,17 +16,14 @@ package com.android.systemui.communal.domain.interactor -import android.content.pm.UserInfo import android.content.testableContext import android.os.userManager import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.common.domain.interactor.batteryInteractor +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.communalMediaRepository import com.android.systemui.communal.data.repository.communalSmartspaceRepository import com.android.systemui.communal.data.repository.communalWidgetRepository -import com.android.systemui.communal.posturing.domain.interactor.posturingInteractor import com.android.systemui.communal.widgets.EditWidgetsActivityStarter -import com.android.systemui.dock.dockManager import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository @@ -39,13 +36,9 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.activityStarter -import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.settings.userTracker import com.android.systemui.statusbar.phone.fakeManagedProfileController -import com.android.systemui.user.data.repository.FakeUserRepository -import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.user.domain.interactor.userLockedInteractor import com.android.systemui.util.mockito.mock val Kosmos.communalInteractor by Fixture { @@ -70,10 +63,6 @@ val Kosmos.communalInteractor by Fixture { logBuffer = logcatLogBuffer("CommunalInteractor"), tableLogBuffer = mock(), managedProfileController = fakeManagedProfileController, - batteryInteractor = batteryInteractor, - dockManager = dockManager, - posturingInteractor = posturingInteractor, - userLockedInteractor = userLockedInteractor, ) } @@ -86,28 +75,28 @@ fun Kosmos.setCommunalV2ConfigEnabled(enabled: Boolean) { ) } -suspend fun Kosmos.setCommunalEnabled(enabled: Boolean): UserInfo { +fun Kosmos.setCommunalEnabled(enabled: Boolean) { fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, enabled) - return if (enabled) { - fakeUserRepository.asMainUser() - } else { - fakeUserRepository.asDefaultUser() - } + val suppressionReasons = + if (enabled) { + emptyList() + } else { + listOf(SuppressionReason.ReasonUnknown()) + } + communalSettingsInteractor.setSuppressionReasons(suppressionReasons) } -suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean): UserInfo { +fun Kosmos.setCommunalV2Enabled(enabled: Boolean) { setCommunalV2ConfigEnabled(enabled) return setCommunalEnabled(enabled) } -suspend fun Kosmos.setCommunalAvailable(available: Boolean): UserInfo { - val user = setCommunalEnabled(available) +fun Kosmos.setCommunalAvailable(available: Boolean) { + setCommunalEnabled(available) fakeKeyguardRepository.setKeyguardShowing(available) - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, available) - return user } -suspend fun Kosmos.setCommunalV2Available(available: Boolean): UserInfo { +fun Kosmos.setCommunalV2Available(available: Boolean) { setCommunalV2ConfigEnabled(available) - return setCommunalAvailable(available) + setCommunalAvailable(available) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt index fb983f7c605f..d2fbb515e686 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt @@ -24,7 +24,6 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.settings.userTracker import com.android.systemui.user.domain.interactor.selectedUserInteractor -import com.android.systemui.util.mockito.mock val Kosmos.communalSettingsInteractor by Fixture { CommunalSettingsInteractor( @@ -34,6 +33,5 @@ val Kosmos.communalSettingsInteractor by Fixture { repository = communalSettingsRepository, userInteractor = selectedUserInteractor, userTracker = userTracker, - tableLogBuffer = mock(), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java deleted file mode 100644 index b99310bcbe38..000000000000 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2018 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.dock; - -/** - * A rudimentary fake for DockManager. - */ -public class DockManagerFake implements DockManager { - DockEventListener mCallback; - AlignmentStateListener mAlignmentListener; - private boolean mDocked; - - @Override - public void addListener(DockEventListener callback) { - this.mCallback = callback; - } - - @Override - public void removeListener(DockEventListener callback) { - this.mCallback = null; - } - - @Override - public void addAlignmentStateListener(AlignmentStateListener listener) { - mAlignmentListener = listener; - } - - @Override - public void removeAlignmentStateListener(AlignmentStateListener listener) { - mAlignmentListener = listener; - } - - @Override - public boolean isDocked() { - return mDocked; - } - - /** Sets the docked state */ - public void setIsDocked(boolean docked) { - mDocked = docked; - } - - @Override - public boolean isHidden() { - return false; - } - - /** Notifies callbacks of dock state change */ - public void setDockEvent(int event) { - mCallback.onEvent(event); - } -} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.kt new file mode 100644 index 000000000000..6a43c40612a7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.kt @@ -0,0 +1,61 @@ +/* + * 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.dock + +import com.android.systemui.dock.DockManager.AlignmentStateListener + +/** A rudimentary fake for DockManager. */ +class DockManagerFake : DockManager { + private val callbacks = mutableSetOf<DockManager.DockEventListener>() + private val alignmentListeners = mutableSetOf<AlignmentStateListener>() + private var docked = false + + override fun addListener(callback: DockManager.DockEventListener) { + callbacks.add(callback) + } + + override fun removeListener(callback: DockManager.DockEventListener) { + callbacks.remove(callback) + } + + override fun addAlignmentStateListener(listener: AlignmentStateListener) { + alignmentListeners.add(listener) + } + + override fun removeAlignmentStateListener(listener: AlignmentStateListener) { + alignmentListeners.remove(listener) + } + + override fun isDocked(): Boolean { + return docked + } + + /** Sets the docked state */ + fun setIsDocked(docked: Boolean) { + this.docked = docked + } + + override fun isHidden(): Boolean { + return false + } + + /** Notifies callbacks of dock state change */ + fun setDockEvent(event: Int) { + for (callback in callbacks) { + callback.onEvent(event) + } + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt index bdfa875f5429..9b0a9830dcc4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt @@ -16,7 +16,6 @@ package com.android.systemui.keyguard.domain.interactor -import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.deviceentry.data.repository.deviceEntryRepository @@ -43,6 +42,5 @@ val Kosmos.fromAodTransitionInteractor by wakeToGoneInteractor = keyguardWakeDirectlyToGoneInteractor, communalSettingsInteractor = communalSettingsInteractor, communalSceneInteractor = communalSceneInteractor, - communalInteractor = communalInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt index 985044c80f18..511bede7349b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt @@ -16,7 +16,6 @@ package com.android.systemui.keyguard.domain.interactor -import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository @@ -42,7 +41,6 @@ var Kosmos.fromLockscreenTransitionInteractor by communalSettingsInteractor = communalSettingsInteractor, swipeToDismissInteractor = swipeToDismissInteractor, keyguardOcclusionInteractor = keyguardOcclusionInteractor, - communalInteractor = communalInteractor, communalSceneInteractor = communalSceneInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt index 933c351679a4..6bb908a6ef07 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt @@ -22,5 +22,9 @@ import com.android.systemui.user.data.repository.userRepository val Kosmos.userLockedInteractor by Kosmos.Fixture { - UserLockedInteractor(backgroundDispatcher = testDispatcher, userRepository = userRepository) + UserLockedInteractor( + backgroundDispatcher = testDispatcher, + userRepository = userRepository, + selectedUserInteractor = selectedUserInteractor, + ) } |