1 /*
2  * Copyright (C) 2022 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 
18 package com.android.systemui.power.domain.interactor
19 
20 import android.os.PowerManager
21 import androidx.test.ext.junit.runners.AndroidJUnit4
22 import androidx.test.filters.SmallTest
23 import com.android.systemui.SysuiTestCase
24 import com.android.systemui.classifier.FalsingCollector
25 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
26 import com.android.systemui.power.shared.model.WakeSleepReason
27 import com.android.systemui.power.shared.model.WakefulnessState
28 import com.android.systemui.plugins.statusbar.StatusBarStateController
29 import com.android.systemui.power.data.repository.FakePowerRepository
30 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
31 import com.android.systemui.util.mockito.whenever
32 import com.google.common.truth.Truth.assertThat
33 import junit.framework.Assert.assertFalse
34 import junit.framework.Assert.assertTrue
35 import kotlin.test.assertEquals
36 import kotlinx.coroutines.Dispatchers
37 import kotlinx.coroutines.flow.launchIn
38 import kotlinx.coroutines.flow.onEach
39 import kotlinx.coroutines.runBlocking
40 import org.junit.Before
41 import org.junit.Test
42 import org.junit.runner.RunWith
43 import org.mockito.Mock
44 import org.mockito.Mockito.verify
45 import org.mockito.MockitoAnnotations
46 
47 @SmallTest
48 @RunWith(AndroidJUnit4::class)
49 class PowerInteractorTest : SysuiTestCase() {
50 
51     private lateinit var underTest: PowerInteractor
52     private lateinit var repository: FakePowerRepository
53     private val keyguardRepository = FakeKeyguardRepository()
54     @Mock private lateinit var falsingCollector: FalsingCollector
55     @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
56     @Mock private lateinit var statusBarStateController: StatusBarStateController
57 
58     @Before
setUpnull59     fun setUp() {
60         MockitoAnnotations.initMocks(this)
61 
62         repository = FakePowerRepository()
63         underTest =
64             PowerInteractor(
65                 repository,
66                 falsingCollector,
67                 screenOffAnimationController,
68                 statusBarStateController,
69             )
70     }
71 
72     @Test
isInteractive_screenTurnsOffnull73     fun isInteractive_screenTurnsOff() =
74         runBlocking(IMMEDIATE) {
75             repository.setInteractive(true)
76             var value: Boolean? = null
77             val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
78 
79             repository.setInteractive(false)
80 
81             assertThat(value).isFalse()
82             job.cancel()
83         }
84 
85     @Test
isInteractive_becomesInteractivenull86     fun isInteractive_becomesInteractive() =
87         runBlocking(IMMEDIATE) {
88             repository.setInteractive(false)
89             var value: Boolean? = null
90             val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
91 
92             repository.setInteractive(true)
93 
94             assertThat(value).isTrue()
95             job.cancel()
96         }
97 
98     @Test
wakeUpIfDozing_notDozing_notWokennull99     fun wakeUpIfDozing_notDozing_notWoken() {
100         whenever(statusBarStateController.isDozing).thenReturn(false)
101         whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
102 
103         underTest.wakeUpIfDozing("why", PowerManager.WAKE_REASON_TAP)
104 
105         assertThat(repository.lastWakeWhy).isNull()
106         assertThat(repository.lastWakeReason).isNull()
107     }
108 
109     @Test
wakeUpIfDozing_notAllowed_notWokennull110     fun wakeUpIfDozing_notAllowed_notWoken() {
111         whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(false)
112         whenever(statusBarStateController.isDozing).thenReturn(true)
113 
114         underTest.wakeUpIfDozing("why", PowerManager.WAKE_REASON_TAP)
115 
116         assertThat(repository.lastWakeWhy).isNull()
117         assertThat(repository.lastWakeReason).isNull()
118     }
119 
120     @Test
wakeUpIfDozing_dozingAndAllowed_wokenAndFalsingNotifiednull121     fun wakeUpIfDozing_dozingAndAllowed_wokenAndFalsingNotified() {
122         whenever(statusBarStateController.isDozing).thenReturn(true)
123         whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
124 
125         underTest.wakeUpIfDozing("testReason", PowerManager.WAKE_REASON_GESTURE)
126 
127         assertThat(repository.lastWakeWhy).isEqualTo("testReason")
128         assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
129         verify(falsingCollector).onScreenOnFromTouch()
130     }
131 
132     @Test
wakeUpForFullScreenIntent_notGoingToSleepAndNotDozing_notWokennull133     fun wakeUpForFullScreenIntent_notGoingToSleepAndNotDozing_notWoken() {
134         underTest.onFinishedWakingUp()
135         whenever(statusBarStateController.isDozing).thenReturn(false)
136 
137         underTest.wakeUpForFullScreenIntent()
138 
139         assertThat(repository.lastWakeWhy).isNull()
140         assertThat(repository.lastWakeReason).isNull()
141     }
142 
143     @Test
wakeUpForFullScreenIntent_startingToSleep_wokennull144     fun wakeUpForFullScreenIntent_startingToSleep_woken() {
145         underTest.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
146         whenever(statusBarStateController.isDozing).thenReturn(false)
147 
148         underTest.wakeUpForFullScreenIntent()
149 
150         assertThat(repository.lastWakeWhy).isNotNull()
151         assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_APPLICATION)
152     }
153 
154     @Test
wakeUpForFullScreenIntent_dozing_wokennull155     fun wakeUpForFullScreenIntent_dozing_woken() {
156         whenever(statusBarStateController.isDozing).thenReturn(true)
157         underTest.onFinishedWakingUp()
158         underTest.wakeUpForFullScreenIntent()
159 
160         assertThat(repository.lastWakeWhy).isNotNull()
161         assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_APPLICATION)
162     }
163 
164     @Test
wakeUpIfDreaming_dreaming_wokennull165     fun wakeUpIfDreaming_dreaming_woken() {
166         // GIVEN device is dreaming
167         whenever(statusBarStateController.isDreaming).thenReturn(true)
168 
169         // WHEN wakeUpIfDreaming is called
170         underTest.wakeUpIfDreaming("testReason", PowerManager.WAKE_REASON_GESTURE)
171 
172         // THEN device is woken up
173         assertThat(repository.lastWakeWhy).isEqualTo("testReason")
174         assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
175     }
176 
177     @Test
wakeUpIfDreaming_notDreaming_notWokennull178     fun wakeUpIfDreaming_notDreaming_notWoken() {
179         // GIVEN device is not dreaming
180         whenever(statusBarStateController.isDreaming).thenReturn(false)
181 
182         // WHEN wakeUpIfDreaming is called
183         underTest.wakeUpIfDreaming("why", PowerManager.WAKE_REASON_TAP)
184 
185         // THEN device is not woken
186         assertThat(repository.lastWakeWhy).isNull()
187         assertThat(repository.lastWakeReason).isNull()
188     }
189 
190     @Test
onStartedGoingToSleep_clearsPowerButtonLaunchGestureTriggerednull191     fun onStartedGoingToSleep_clearsPowerButtonLaunchGestureTriggered() {
192         underTest.onStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON, true)
193 
194         assertTrue(repository.wakefulness.value.powerButtonLaunchGestureTriggered)
195 
196         underTest.onFinishedWakingUp()
197 
198         assertTrue(repository.wakefulness.value.powerButtonLaunchGestureTriggered)
199 
200         underTest.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON)
201 
202         assertFalse(repository.wakefulness.value.powerButtonLaunchGestureTriggered)
203     }
204 
205     @Test
onCameraLaunchGestureDetected_maintainsAllOtherStatenull206     fun onCameraLaunchGestureDetected_maintainsAllOtherState() {
207         underTest.onStartedWakingUp(
208             PowerManager.WAKE_REASON_POWER_BUTTON,
209             /*powerButtonLaunchGestureTriggeredDuringSleep= */ false
210         )
211         underTest.onFinishedWakingUp()
212         underTest.onCameraLaunchGestureDetected()
213 
214         assertEquals(WakefulnessState.AWAKE, repository.wakefulness.value.internalWakefulnessState)
215         assertEquals(WakeSleepReason.POWER_BUTTON, repository.wakefulness.value.lastWakeReason)
216         assertTrue(repository.wakefulness.value.powerButtonLaunchGestureTriggered)
217     }
218 
219     @Test
onCameraLaunchGestureDetected_stillTrue_ifGestureNotDetectedOnWakingUpnull220     fun onCameraLaunchGestureDetected_stillTrue_ifGestureNotDetectedOnWakingUp() {
221         underTest.onCameraLaunchGestureDetected()
222         // Ensure that the 'false' here does not clear the direct launch detection call earlier.
223         // This state should only be reset onStartedGoingToSleep.
224         underTest.onFinishedGoingToSleep(/*powerButtonLaunchGestureTriggeredDuringSleep= */ false)
225         underTest.onStartedWakingUp(
226             PowerManager.WAKE_REASON_POWER_BUTTON,
227             /*powerButtonLaunchGestureTriggeredDuringSleep= */ false
228         )
229         underTest.onFinishedWakingUp()
230 
231         assertEquals(WakefulnessState.AWAKE, repository.wakefulness.value.internalWakefulnessState)
232         assertEquals(WakeSleepReason.POWER_BUTTON, repository.wakefulness.value.lastWakeReason)
233         assertTrue(repository.wakefulness.value.powerButtonLaunchGestureTriggered)
234     }
235 
236     @Test
cameraLaunchDetectedOnGoingToSleep_stillTrue_ifGestureNotDetectedOnWakingUpnull237     fun cameraLaunchDetectedOnGoingToSleep_stillTrue_ifGestureNotDetectedOnWakingUp() {
238         underTest.onFinishedGoingToSleep(/*powerButtonLaunchGestureTriggeredDuringSleep= */ true)
239         // Ensure that the 'false' here does not clear the direct launch detection call earlier.
240         // This state should only be reset onStartedGoingToSleep.
241         underTest.onStartedWakingUp(
242             PowerManager.WAKE_REASON_POWER_BUTTON,
243             /*powerButtonLaunchGestureTriggeredDuringSleep= */ false
244         )
245         underTest.onFinishedWakingUp()
246 
247         assertEquals(WakefulnessState.AWAKE, repository.wakefulness.value.internalWakefulnessState)
248         assertEquals(WakeSleepReason.POWER_BUTTON, repository.wakefulness.value.lastWakeReason)
249         assertTrue(repository.wakefulness.value.powerButtonLaunchGestureTriggered)
250     }
251 
252     companion object {
253         private val IMMEDIATE = Dispatchers.Main.immediate
254     }
255 }
256