1 /*
2  * Copyright (C) 2023 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 @file:OptIn(ExperimentalCoroutinesApi::class)
18 
19 package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
20 
21 import android.os.PowerManager
22 import android.testing.AndroidTestingRunner
23 import androidx.test.filters.SmallTest
24 import com.android.systemui.SysuiTestCase
25 import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
26 import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
27 import com.android.systemui.classifier.FalsingCollectorFake
28 import com.android.systemui.coroutines.collectLastValue
29 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
30 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
31 import com.android.systemui.plugins.statusbar.StatusBarStateController
32 import com.android.systemui.power.data.repository.FakePowerRepository
33 import com.android.systemui.power.domain.interactor.PowerInteractor
34 import com.android.systemui.statusbar.LockscreenShadeTransitionController
35 import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
36 import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
37 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
38 import com.android.systemui.util.mockito.eq
39 import com.android.systemui.util.mockito.whenever
40 import com.google.common.truth.Truth.assertThat
41 import kotlinx.coroutines.ExperimentalCoroutinesApi
42 import kotlinx.coroutines.test.runTest
43 import org.junit.Before
44 import org.junit.Rule
45 import org.junit.Test
46 import org.junit.runner.RunWith
47 import org.mockito.Mock
48 import org.mockito.Mockito
49 import org.mockito.Mockito.verify
50 import org.mockito.junit.MockitoJUnit
51 import org.mockito.junit.MockitoRule
52 
53 @RunWith(AndroidTestingRunner::class)
54 @SmallTest
55 class NotificationShelfViewModelTest : SysuiTestCase() {
56 
57     @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
58 
59     // mocks
60     @Mock private lateinit var keyguardTransitionController: LockscreenShadeTransitionController
61     @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
62     @Mock private lateinit var statusBarStateController: StatusBarStateController
63 
64     // fakes
65     private val keyguardRepository = FakeKeyguardRepository()
66     private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
67     private val a11yRepo = FakeAccessibilityRepository()
68     private val powerRepository = FakePowerRepository()
69     private val powerInteractor by lazy {
70         PowerInteractor(
71             powerRepository,
72             keyguardRepository,
73             FalsingCollectorFake(),
74             screenOffAnimationController,
75             statusBarStateController,
76         )
77     }
78 
79     // real impls
80     private val a11yInteractor = AccessibilityInteractor(a11yRepo)
81     private val activatableViewModel = ActivatableNotificationViewModel(a11yInteractor)
82     private val interactor by lazy {
83         NotificationShelfInteractor(
84             keyguardRepository,
85             deviceEntryFaceAuthRepository,
86             powerInteractor,
87             keyguardTransitionController,
88         )
89     }
90     private val underTest by lazy { NotificationShelfViewModel(interactor, activatableViewModel) }
91 
92     @Before
93     fun setUp() {
94         whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
95     }
96 
97     @Test
98     fun canModifyColorOfNotifications_whenKeyguardNotShowing() = runTest {
99         val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
100 
101         keyguardRepository.setKeyguardShowing(false)
102 
103         assertThat(canModifyNotifColor).isTrue()
104     }
105 
106     @Test
107     fun canModifyColorOfNotifications_whenKeyguardShowingAndNotBypass() = runTest {
108         val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
109 
110         keyguardRepository.setKeyguardShowing(true)
111         deviceEntryFaceAuthRepository.isBypassEnabled.value = false
112 
113         assertThat(canModifyNotifColor).isTrue()
114     }
115 
116     @Test
117     fun cannotModifyColorOfNotifications_whenBypass() = runTest {
118         val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
119 
120         keyguardRepository.setKeyguardShowing(true)
121         deviceEntryFaceAuthRepository.isBypassEnabled.value = true
122 
123         assertThat(canModifyNotifColor).isFalse()
124     }
125 
126     @Test
127     fun isClickable_whenKeyguardShowing() = runTest {
128         val isClickable by collectLastValue(underTest.isClickable)
129 
130         keyguardRepository.setKeyguardShowing(true)
131 
132         assertThat(isClickable).isTrue()
133     }
134 
135     @Test
136     fun isNotClickable_whenKeyguardNotShowing() = runTest {
137         val isClickable by collectLastValue(underTest.isClickable)
138 
139         keyguardRepository.setKeyguardShowing(false)
140 
141         assertThat(isClickable).isFalse()
142     }
143 
144     @Test
145     fun onClicked_goesToLockedShade() {
146         whenever(statusBarStateController.isDozing).thenReturn(true)
147 
148         underTest.onShelfClicked()
149 
150         assertThat(powerRepository.lastWakeReason).isNotNull()
151         assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
152         verify(keyguardTransitionController).goToLockedShade(Mockito.isNull(), eq(true))
153     }
154 }
155