summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ioana Alexandru <aioana@google.com> 2023-11-07 17:07:10 +0100
committer Ioana Alexandru <aioana@google.com> 2023-11-14 15:59:04 +0100
commit810d2e3155e1bdfaed67b491b0c29ec2b58b66d8 (patch)
tree10f07c1d449b125c159bade0dc100f3a956a8432
parent5cfe5d02a59a0c6ecd0b906a346b77c3dbf0a114 (diff)
Introduce ZenModeRepository & Interactor.
This code isn't used yet, but usages will be flagged. Interactor tests are based on ZenModeControllerImplTest. Bug: 293167744 Bug: 308591859 Test: atest ZenModeRepositoryImplTest ZenModeInteractorTest Flag: NONE Change-Id: Ie714e049d4d0cfe1968e757460a78def9df00f4d
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepository.kt77
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepositoryImplTest.kt91
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt172
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeZenModeRepository.kt43
7 files changed, 448 insertions, 2 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index 818ba9512e15..3304b9827fd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -71,6 +71,7 @@ import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepository;
import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepositoryImpl;
import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepositoryModule;
+import com.android.systemui.statusbar.policy.data.repository.ZenModeRepositoryModule;
import dagger.Binds;
import dagger.Module;
@@ -81,7 +82,7 @@ import java.util.concurrent.Executor;
import javax.inject.Named;
/** Dagger Module for code in the statusbar.policy package. */
-@Module(includes = { DeviceProvisioningRepositoryModule.class })
+@Module(includes = { DeviceProvisioningRepositoryModule.class, ZenModeRepositoryModule.class })
public interface StatusBarPolicyModule {
String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepository.kt
new file mode 100644
index 000000000000..94ab58ae5a3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepository.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy.data.repository
+
+import android.app.NotificationManager
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.statusbar.policy.ZenModeController
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * A repository that holds information about the status and configuration of Zen Mode (or Do Not
+ * Disturb/DND Mode).
+ */
+interface ZenModeRepository {
+ val zenMode: Flow<Int>
+ val consolidatedNotificationPolicy: Flow<NotificationManager.Policy?>
+}
+
+class ZenModeRepositoryImpl
+@Inject
+constructor(
+ private val zenModeController: ZenModeController,
+) : ZenModeRepository {
+ // TODO(b/308591859): ZenModeController should use flows instead of callbacks. The
+ // conflatedCallbackFlows here should be replaced eventually, see:
+ // https://docs.google.com/document/d/1gAiuYupwUAFdbxkDXa29A4aFNu7XoCd7sCIk31WTnHU/edit?resourcekey=0-J4ZBiUhLhhQnNobAcI2vIw
+
+ override val zenMode: Flow<Int> = conflatedCallbackFlow {
+ val callback =
+ object : ZenModeController.Callback {
+ override fun onZenChanged(zen: Int) {
+ trySend(zen)
+ }
+ }
+ zenModeController.addCallback(callback)
+ trySend(zenModeController.zen)
+
+ awaitClose { zenModeController.removeCallback(callback) }
+ }
+
+ override val consolidatedNotificationPolicy: Flow<NotificationManager.Policy?> =
+ conflatedCallbackFlow {
+ val callback =
+ object : ZenModeController.Callback {
+ override fun onConsolidatedPolicyChanged(policy: NotificationManager.Policy?) {
+ trySend(policy)
+ }
+ }
+ zenModeController.addCallback(callback)
+ trySend(zenModeController.consolidatedPolicy)
+
+ awaitClose { zenModeController.removeCallback(callback) }
+ }
+}
+
+@Module
+interface ZenModeRepositoryModule {
+ @Binds fun bindImpl(impl: ZenModeRepositoryImpl): ZenModeRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
new file mode 100644
index 000000000000..ae31851cb8f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy.domain.interactor
+
+import android.provider.Settings
+import com.android.systemui.statusbar.policy.data.repository.ZenModeRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+/**
+ * An interactor that performs business logic related to the status and configuration of Zen Mode
+ * (or Do Not Disturb/DND Mode).
+ */
+class ZenModeInteractor @Inject constructor(repository: ZenModeRepository) {
+ val isZenModeEnabled: Flow<Boolean> =
+ repository.zenMode
+ .map {
+ when (it) {
+ Settings.Global.ZEN_MODE_ALARMS -> true
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS -> true
+ Settings.Global.ZEN_MODE_NO_INTERRUPTIONS -> true
+ Settings.Global.ZEN_MODE_OFF -> false
+ else -> false
+ }
+ }
+ .distinctUntilChanged()
+
+ val areNotificationsHiddenInShade: Flow<Boolean> =
+ combine(isZenModeEnabled, repository.consolidatedNotificationPolicy) { dndEnabled, policy ->
+ if (!dndEnabled) {
+ false
+ } else {
+ val showInNotificationList = policy?.showInNotificationList() ?: true
+ !showInNotificationList
+ }
+ }
+ .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepositoryImplTest.kt
new file mode 100644
index 000000000000..004f67934e86
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepositoryImplTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.policy.data.repository
+
+import android.app.NotificationManager
+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.coroutines.collectLastValue
+import com.android.systemui.statusbar.policy.ZenModeController
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ZenModeRepositoryImplTest : SysuiTestCase() {
+ @Mock lateinit var zenModeController: ZenModeController
+
+ lateinit var underTest: ZenModeRepositoryImpl
+
+ private val testPolicy = NotificationManager.Policy(0, 1, 0)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ underTest = ZenModeRepositoryImpl(zenModeController)
+ }
+
+ @Test
+ fun zenMode_reflectsCurrentControllerState() = runTest {
+ whenever(zenModeController.zen).thenReturn(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS)
+ val zenMode by collectLastValue(underTest.zenMode)
+ assertThat(zenMode).isEqualTo(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS)
+ }
+
+ @Test
+ fun zenMode_updatesWhenControllerStateChanges() = runTest {
+ val zenMode by collectLastValue(underTest.zenMode)
+ runCurrent()
+ whenever(zenModeController.zen).thenReturn(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ withArgCaptor { Mockito.verify(zenModeController).addCallback(capture()) }
+ .onZenChanged(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ assertThat(zenMode).isEqualTo(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ }
+
+ @Test
+ fun policy_reflectsCurrentControllerState() {
+ runTest {
+ whenever(zenModeController.consolidatedPolicy).thenReturn(testPolicy)
+ val policy by collectLastValue(underTest.consolidatedNotificationPolicy)
+ assertThat(policy).isEqualTo(testPolicy)
+ }
+ }
+
+ @Test
+ fun policy_updatesWhenControllerStateChanges() = runTest {
+ val policy by collectLastValue(underTest.consolidatedNotificationPolicy)
+ runCurrent()
+ whenever(zenModeController.consolidatedPolicy).thenReturn(testPolicy)
+ withArgCaptor { Mockito.verify(zenModeController).addCallback(capture()) }
+ .onConsolidatedPolicyChanged(testPolicy)
+ assertThat(policy).isEqualTo(testPolicy)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
new file mode 100644
index 000000000000..78e79718e166
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy.domain.interactor
+
+import android.app.NotificationManager.Policy
+import android.provider.Settings
+import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
+import com.android.SysUITestModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.data.repository.FakeZenModeRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import org.junit.Test
+
+@SmallTest
+class ZenModeInteractorTest : SysuiTestCase() {
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<ZenModeInteractor> {
+
+ val repository: FakeZenModeRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(@BindsInstance test: SysuiTestCase): TestComponent
+ }
+ }
+
+ private val testComponent: TestComponent =
+ DaggerZenModeInteractorTest_TestComponent.factory().create(test = this)
+
+ @Test
+ fun testIsZenModeEnabled_off() =
+ testComponent.runTest {
+ val enabled by collectLastValue(underTest.isZenModeEnabled)
+
+ repository.zenMode.value = Settings.Global.ZEN_MODE_OFF
+ runCurrent()
+
+ assertThat(enabled).isFalse()
+ }
+
+ @Test
+ fun testIsZenModeEnabled_alarms() =
+ testComponent.runTest {
+ val enabled by collectLastValue(underTest.isZenModeEnabled)
+
+ repository.zenMode.value = Settings.Global.ZEN_MODE_ALARMS
+ runCurrent()
+
+ assertThat(enabled).isTrue()
+ }
+
+ @Test
+ fun testIsZenModeEnabled_importantInterruptions() =
+ testComponent.runTest {
+ val enabled by collectLastValue(underTest.isZenModeEnabled)
+
+ repository.zenMode.value = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ runCurrent()
+
+ assertThat(enabled).isTrue()
+ }
+
+ @Test
+ fun testIsZenModeEnabled_noInterruptions() =
+ testComponent.runTest {
+ val enabled by collectLastValue(underTest.isZenModeEnabled)
+
+ repository.zenMode.value = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
+ runCurrent()
+
+ assertThat(enabled).isTrue()
+ }
+
+ @Test
+ fun testIsZenModeEnabled_unknown() =
+ testComponent.runTest {
+ val enabled by collectLastValue(underTest.isZenModeEnabled)
+
+ repository.zenMode.value = 4 // this should fail if we ever add another zen mode type
+ runCurrent()
+
+ assertThat(enabled).isFalse()
+ }
+
+ @Test
+ fun testAreNotificationsHiddenInShade_noPolicy() =
+ testComponent.runTest {
+ val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
+
+ repository.consolidatedNotificationPolicy.value = null
+ repository.zenMode.value = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ runCurrent()
+
+ assertThat(hidden).isFalse()
+ }
+
+ @Test
+ fun testAreNotificationsHiddenInShade_zenOffShadeSuppressed() =
+ testComponent.runTest {
+ val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
+
+ repository.consolidatedNotificationPolicy.value =
+ policyWithSuppressedVisualEffects(Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST)
+ repository.zenMode.value = Settings.Global.ZEN_MODE_OFF
+ runCurrent()
+
+ assertThat(hidden).isFalse()
+ }
+
+ @Test
+ fun testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() =
+ testComponent.runTest {
+ val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
+
+ repository.consolidatedNotificationPolicy.value =
+ policyWithSuppressedVisualEffects(Policy.SUPPRESSED_EFFECT_STATUS_BAR)
+ repository.zenMode.value = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ runCurrent()
+
+ assertThat(hidden).isFalse()
+ }
+
+ @Test
+ fun testAreNotificationsHiddenInShade_zenOnShadeSuppressed() =
+ testComponent.runTest {
+ val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
+
+ repository.consolidatedNotificationPolicy.value =
+ policyWithSuppressedVisualEffects(Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST)
+ repository.zenMode.value = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ runCurrent()
+
+ assertThat(hidden).isTrue()
+ }
+}
+
+fun policyWithSuppressedVisualEffects(suppressedVisualEffects: Int) =
+ Policy(
+ /* priorityCategories = */ 0,
+ /* priorityCallSenders = */ 0,
+ /* priorityMessageSenders = */ 0,
+ /* suppressedVisualEffects = */ suppressedVisualEffects
+ )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
index 5aece1bbbd31..16dab40d6edc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
@@ -16,7 +16,14 @@
package com.android.systemui.statusbar.policy.data
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepositoryModule
+import com.android.systemui.statusbar.policy.data.repository.FakeZenModeRepositoryModule
import dagger.Module
-@Module(includes = [FakeDeviceProvisioningRepositoryModule::class])
+@Module(
+ includes =
+ [
+ FakeDeviceProvisioningRepositoryModule::class,
+ FakeZenModeRepositoryModule::class,
+ ]
+)
object FakeStatusBarPolicyDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeZenModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeZenModeRepository.kt
new file mode 100644
index 000000000000..405993073b68
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeZenModeRepository.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy.data.repository
+
+import android.app.NotificationManager
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+@SysUISingleton
+class FakeZenModeRepository @Inject constructor() : ZenModeRepository {
+ override val zenMode: MutableStateFlow<Int> = MutableStateFlow(Settings.Global.ZEN_MODE_OFF)
+ override val consolidatedNotificationPolicy: MutableStateFlow<NotificationManager.Policy?> =
+ MutableStateFlow(
+ NotificationManager.Policy(
+ /* priorityCategories = */ 0,
+ /* priorityCallSenders = */ 0,
+ /* priorityMessageSenders = */ 0,
+ )
+ )
+}
+
+@Module
+interface FakeZenModeRepositoryModule {
+ @Binds fun bindFake(fake: FakeZenModeRepository): ZenModeRepository
+}