• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.notification.emptyshade.ui.viewmodel
18 
19 import android.app.Flags
20 import android.app.NotificationManager.Policy
21 import android.content.res.Configuration
22 import android.os.LocaleList
23 import android.platform.test.annotations.DisableFlags
24 import android.platform.test.annotations.EnableFlags
25 import android.platform.test.flag.junit.FlagsParameterization
26 import android.provider.Settings
27 import android.service.notification.ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST
28 import androidx.test.filters.SmallTest
29 import com.android.settingslib.notification.data.repository.updateNotificationPolicy
30 import com.android.settingslib.notification.modes.TestModeBuilder
31 import com.android.systemui.SysuiTestCase
32 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
33 import com.android.systemui.coroutines.collectLastValue
34 import com.android.systemui.flags.andSceneContainer
35 import com.android.systemui.kosmos.testScope
36 import com.android.systemui.shared.settings.data.repository.fakeSecureSettingsRepository
37 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
38 import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
39 import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
40 import com.android.systemui.testKosmos
41 import com.google.common.truth.Truth.assertThat
42 import java.util.Locale
43 import kotlinx.coroutines.test.runCurrent
44 import kotlinx.coroutines.test.runTest
45 import org.junit.After
46 import org.junit.Before
47 import org.junit.Test
48 import org.junit.runner.RunWith
49 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
50 import platform.test.runner.parameterized.Parameters
51 
52 @RunWith(ParameterizedAndroidJunit4::class)
53 @SmallTest
54 class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
55     private val kosmos = testKosmos()
56     private val testScope = kosmos.testScope
57     private val zenModeRepository = kosmos.zenModeRepository
58     private val activeNotificationListRepository = kosmos.activeNotificationListRepository
59     private val fakeSecureSettingsRepository = kosmos.fakeSecureSettingsRepository
60     private val fakeConfigurationRepository = kosmos.fakeConfigurationRepository
61 
62     /** Backup of the current locales, to be restored at the end of the test if they are changed. */
63     private lateinit var originalLocales: LocaleList
64 
<lambda>null65     private val underTest by lazy { kosmos.emptyShadeViewModel }
66 
67     companion object {
68         @JvmStatic
69         @Parameters(name = "{0}")
getParamsnull70         fun getParams(): List<FlagsParameterization> {
71             return FlagsParameterization.allCombinationsOf().andSceneContainer()
72         }
73     }
74 
75     init {
76         mSetFlagsRule.setFlagsParameterization(flags)
77     }
78 
79     @Before
setUpnull80     fun setUp() {
81         originalLocales = context.resources.configuration.locales
82         updateLocales(LocaleList(Locale.US))
83     }
84 
85     @After
tearDownnull86     fun tearDown() {
87         // Make sure we restore the original locale even if a test fails after changing it
88         updateLocales(originalLocales)
89     }
90 
91     @Test
areNotificationsHiddenInShade_truenull92     fun areNotificationsHiddenInShade_true() =
93         testScope.runTest {
94             val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
95 
96             zenModeRepository.updateNotificationPolicy(
97                 suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
98             )
99             zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
100             runCurrent()
101 
102             assertThat(hidden).isTrue()
103         }
104 
105     @Test
areNotificationsHiddenInShade_falsenull106     fun areNotificationsHiddenInShade_false() =
107         testScope.runTest {
108             val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
109 
110             zenModeRepository.updateNotificationPolicy(
111                 suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
112             )
113             zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
114             runCurrent()
115 
116             assertThat(hidden).isFalse()
117         }
118 
119     @Test
hasFilteredOutSeenNotifications_truenull120     fun hasFilteredOutSeenNotifications_true() =
121         testScope.runTest {
122             val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)
123 
124             activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
125             runCurrent()
126 
127             assertThat(hasFilteredNotifs).isTrue()
128         }
129 
130     @Test
hasFilteredOutSeenNotifications_falsenull131     fun hasFilteredOutSeenNotifications_false() =
132         testScope.runTest {
133             val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)
134 
135             activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
136             runCurrent()
137 
138             assertThat(hasFilteredNotifs).isFalse()
139         }
140 
141     @Test
142     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
143     @DisableFlags(Flags.FLAG_MODES_UI)
text_changesWhenNotifsHiddenInShadenull144     fun text_changesWhenNotifsHiddenInShade() =
145         testScope.runTest {
146             val text by collectLastValue(underTest.text)
147 
148             zenModeRepository.updateNotificationPolicy(
149                 suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
150             )
151             zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
152             runCurrent()
153 
154             assertThat(text).isEqualTo("No notifications")
155 
156             zenModeRepository.updateNotificationPolicy(
157                 suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
158             )
159             zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
160             runCurrent()
161 
162             assertThat(text).isEqualTo("Notifications paused by Do Not Disturb")
163         }
164 
165     @Test
166     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
text_changesWhenLocaleChangesnull167     fun text_changesWhenLocaleChanges() =
168         testScope.runTest {
169             val text by collectLastValue(underTest.text)
170 
171             zenModeRepository.updateNotificationPolicy(
172                 suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
173             )
174             zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
175             runCurrent()
176 
177             assertThat(text).isEqualTo("No notifications")
178 
179             updateLocales(LocaleList(Locale.GERMAN))
180             runCurrent()
181 
182             assertThat(text).isEqualTo("Keine Benachrichtigungen")
183 
184             // Make sure we restore the original locales
185             updateLocales(originalLocales)
186         }
187 
188     @Test
189     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
text_reflectsModesHidingNotificationsnull190     fun text_reflectsModesHidingNotifications() =
191         testScope.runTest {
192             val text by collectLastValue(underTest.text)
193 
194             assertThat(text).isEqualTo("No notifications")
195 
196             zenModeRepository.addMode(
197                 TestModeBuilder()
198                     .setId("Do not disturb")
199                     .setName("Do not disturb")
200                     .setActive(true)
201                     .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
202                     .build()
203             )
204             runCurrent()
205             assertThat(text).isEqualTo("Notifications paused by Do not disturb")
206 
207             zenModeRepository.addMode(
208                 TestModeBuilder()
209                     .setId("Work")
210                     .setName("Work")
211                     .setActive(true)
212                     .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
213                     .build()
214             )
215             runCurrent()
216             assertThat(text).isEqualTo("Notifications paused by Do not disturb and one other mode")
217 
218             zenModeRepository.addMode(
219                 TestModeBuilder()
220                     .setId("Gym")
221                     .setName("Gym")
222                     .setActive(true)
223                     .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
224                     .build()
225             )
226             runCurrent()
227             assertThat(text).isEqualTo("Notifications paused by Do not disturb and 2 other modes")
228 
229             zenModeRepository.deactivateMode("Do not disturb")
230             zenModeRepository.deactivateMode("Work")
231             runCurrent()
232             assertThat(text).isEqualTo("Notifications paused by Gym")
233         }
234 
235     @Test
236     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
footer_isVisibleWhenSeenNotifsAreFilteredOutnull237     fun footer_isVisibleWhenSeenNotifsAreFilteredOut() =
238         testScope.runTest {
239             val footerVisible by collectLastValue(underTest.footer.isVisible)
240 
241             activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
242             runCurrent()
243 
244             assertThat(footerVisible).isFalse()
245 
246             activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
247             runCurrent()
248 
249             assertThat(footerVisible).isTrue()
250         }
251 
252     @Test
253     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
onClick_whenHistoryDisabled_leadsToSettingsPagenull254     fun onClick_whenHistoryDisabled_leadsToSettingsPage() =
255         testScope.runTest {
256             val onClick by collectLastValue(underTest.onClick)
257             runCurrent()
258 
259             fakeSecureSettingsRepository.setInt(Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0)
260 
261             assertThat(onClick?.targetIntent?.action)
262                 .isEqualTo(Settings.ACTION_NOTIFICATION_SETTINGS)
263             assertThat(onClick?.backStack).isEmpty()
264         }
265 
266     @Test
267     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
onClick_whenHistoryEnabled_leadsToHistoryPagenull268     fun onClick_whenHistoryEnabled_leadsToHistoryPage() =
269         testScope.runTest {
270             val onClick by collectLastValue(underTest.onClick)
271             runCurrent()
272 
273             fakeSecureSettingsRepository.setInt(Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1)
274 
275             assertThat(onClick?.targetIntent?.action)
276                 .isEqualTo(Settings.ACTION_NOTIFICATION_HISTORY)
277             assertThat(onClick?.backStack?.map { it.action })
278                 .containsExactly(Settings.ACTION_NOTIFICATION_SETTINGS)
279         }
280 
281     @Test
282     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
onClick_whenOneModeHidingNotifications_leadsToModeSettingsnull283     fun onClick_whenOneModeHidingNotifications_leadsToModeSettings() =
284         testScope.runTest {
285             val onClick by collectLastValue(underTest.onClick)
286             runCurrent()
287 
288             zenModeRepository.addMode(
289                 TestModeBuilder()
290                     .setId("ID")
291                     .setActive(true)
292                     .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
293                     .build()
294             )
295             runCurrent()
296 
297             assertThat(onClick?.targetIntent?.action)
298                 .isEqualTo(Settings.ACTION_AUTOMATIC_ZEN_RULE_SETTINGS)
299             assertThat(
300                     onClick?.targetIntent?.extras?.getString(Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID)
301                 )
302                 .isEqualTo("ID")
303             assertThat(onClick?.backStack?.map { it.action })
304                 .containsExactly(Settings.ACTION_ZEN_MODE_SETTINGS)
305         }
306 
307     @Test
308     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
onClick_whenMultipleModesHidingNotifications_leadsToGeneralModesSettingsnull309     fun onClick_whenMultipleModesHidingNotifications_leadsToGeneralModesSettings() =
310         testScope.runTest {
311             val onClick by collectLastValue(underTest.onClick)
312             runCurrent()
313 
314             zenModeRepository.addMode(
315                 TestModeBuilder()
316                     .setActive(true)
317                     .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
318                     .build()
319             )
320             zenModeRepository.addMode(
321                 TestModeBuilder()
322                     .setActive(true)
323                     .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
324                     .build()
325             )
326             runCurrent()
327 
328             assertThat(onClick?.targetIntent?.action).isEqualTo(Settings.ACTION_ZEN_MODE_SETTINGS)
329             assertThat(onClick?.backStack).isEmpty()
330         }
331 
updateLocalesnull332     private fun updateLocales(locales: LocaleList) {
333         val configuration = Configuration()
334         configuration.setLocales(locales)
335         context.resources.updateConfiguration(configuration, context.resources.displayMetrics)
336         fakeConfigurationRepository.onConfigurationChange(configuration)
337     }
338 }
339