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.data.repository 19 20 import android.content.BroadcastReceiver 21 import android.content.Intent 22 import android.content.IntentFilter 23 import android.os.PowerManager 24 import androidx.test.ext.junit.runners.AndroidJUnit4 25 import androidx.test.filters.SmallTest 26 import com.android.systemui.SysuiTestCase 27 import com.android.systemui.broadcast.BroadcastDispatcher 28 import com.android.systemui.util.mockito.any 29 import com.android.systemui.util.mockito.argumentCaptor 30 import com.android.systemui.util.mockito.capture 31 import com.android.systemui.util.mockito.eq 32 import com.android.systemui.util.time.FakeSystemClock 33 import com.google.common.truth.Truth.assertThat 34 import kotlinx.coroutines.Dispatchers 35 import kotlinx.coroutines.flow.launchIn 36 import kotlinx.coroutines.flow.onEach 37 import kotlinx.coroutines.runBlocking 38 import org.junit.Before 39 import org.junit.Test 40 import org.junit.runner.RunWith 41 import org.mockito.ArgumentCaptor 42 import org.mockito.Captor 43 import org.mockito.Mock 44 import org.mockito.Mockito.anyInt 45 import org.mockito.Mockito.isNull 46 import org.mockito.Mockito.verify 47 import org.mockito.Mockito.`when` as whenever 48 import org.mockito.MockitoAnnotations 49 50 @SmallTest 51 @RunWith(AndroidJUnit4::class) 52 class PowerRepositoryImplTest : SysuiTestCase() { 53 54 private val systemClock = FakeSystemClock() 55 56 @Mock private lateinit var manager: PowerManager 57 @Mock private lateinit var dispatcher: BroadcastDispatcher 58 @Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver> 59 @Captor private lateinit var filterCaptor: ArgumentCaptor<IntentFilter> 60 61 private lateinit var underTest: PowerRepositoryImpl 62 63 private var isInteractive = true 64 65 @Before setUpnull66 fun setUp() { 67 MockitoAnnotations.initMocks(this) 68 isInteractive = true 69 whenever(manager.isInteractive).then { isInteractive } 70 71 underTest = 72 PowerRepositoryImpl( 73 manager, 74 context.applicationContext, 75 systemClock, 76 dispatcher, 77 ) 78 } 79 80 @Test isInteractive_registersForBroadcastsnull81 fun isInteractive_registersForBroadcasts() = 82 runBlocking(IMMEDIATE) { 83 val job = underTest.isInteractive.onEach {}.launchIn(this) 84 85 verifyRegistered() 86 assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_ON)).isTrue() 87 assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_OFF)).isTrue() 88 89 job.cancel() 90 } 91 92 @Test isInteractive_unregistersFromBroadcastsnull93 fun isInteractive_unregistersFromBroadcasts() = 94 runBlocking(IMMEDIATE) { 95 val job = underTest.isInteractive.onEach {}.launchIn(this) 96 verifyRegistered() 97 98 job.cancel() 99 100 verify(dispatcher).unregisterReceiver(receiverCaptor.value) 101 } 102 103 @Test isInteractive_emitsInitialTrueValueIfScreenWasOnnull104 fun isInteractive_emitsInitialTrueValueIfScreenWasOn() = 105 runBlocking(IMMEDIATE) { 106 isInteractive = true 107 var value: Boolean? = null 108 val job = underTest.isInteractive.onEach { value = it }.launchIn(this) 109 110 verifyRegistered() 111 112 assertThat(value).isTrue() 113 job.cancel() 114 } 115 116 @Test isInteractive_emitsInitialFalseValueIfScreenWasOffnull117 fun isInteractive_emitsInitialFalseValueIfScreenWasOff() = 118 runBlocking(IMMEDIATE) { 119 isInteractive = false 120 var value: Boolean? = null 121 val job = underTest.isInteractive.onEach { value = it }.launchIn(this) 122 123 verifyRegistered() 124 125 assertThat(value).isFalse() 126 job.cancel() 127 } 128 129 @Test isInteractive_emitsTrueWhenTheScreenTurnsOnnull130 fun isInteractive_emitsTrueWhenTheScreenTurnsOn() = 131 runBlocking(IMMEDIATE) { 132 var value: Boolean? = null 133 val job = underTest.isInteractive.onEach { value = it }.launchIn(this) 134 verifyRegistered() 135 136 isInteractive = true 137 receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON)) 138 139 assertThat(value).isTrue() 140 job.cancel() 141 } 142 143 @Test isInteractive_emitsFalseWhenTheScreenTurnsOffnull144 fun isInteractive_emitsFalseWhenTheScreenTurnsOff() = 145 runBlocking(IMMEDIATE) { 146 var value: Boolean? = null 147 val job = underTest.isInteractive.onEach { value = it }.launchIn(this) 148 verifyRegistered() 149 150 isInteractive = false 151 receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF)) 152 153 assertThat(value).isFalse() 154 job.cancel() 155 } 156 157 @Test isInteractive_emitsCorrectlyOverTimenull158 fun isInteractive_emitsCorrectlyOverTime() = 159 runBlocking(IMMEDIATE) { 160 val values = mutableListOf<Boolean>() 161 val job = underTest.isInteractive.onEach(values::add).launchIn(this) 162 verifyRegistered() 163 164 isInteractive = false 165 receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF)) 166 isInteractive = true 167 receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON)) 168 isInteractive = false 169 receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF)) 170 171 assertThat(values).isEqualTo(listOf(true, false, true, false)) 172 job.cancel() 173 } 174 175 @Test wakeUp_notifiesPowerManagernull176 fun wakeUp_notifiesPowerManager() { 177 systemClock.setUptimeMillis(345000) 178 179 underTest.wakeUp("fakeWhy", PowerManager.WAKE_REASON_GESTURE) 180 181 val reasonCaptor = argumentCaptor<String>() 182 verify(manager) 183 .wakeUp(eq(345000L), eq(PowerManager.WAKE_REASON_GESTURE), capture(reasonCaptor)) 184 assertThat(reasonCaptor.value).contains("fakeWhy") 185 } 186 187 @Test wakeUp_usesApplicationPackageNamenull188 fun wakeUp_usesApplicationPackageName() { 189 underTest.wakeUp("fakeWhy", PowerManager.WAKE_REASON_GESTURE) 190 191 val reasonCaptor = argumentCaptor<String>() 192 verify(manager).wakeUp(any(), any(), capture(reasonCaptor)) 193 assertThat(reasonCaptor.value).contains(context.applicationContext.packageName) 194 } 195 196 @Test userActivity_notifiesPowerManagernull197 fun userActivity_notifiesPowerManager() { 198 systemClock.setUptimeMillis(345000) 199 200 underTest.userTouch() 201 202 val flagsCaptor = argumentCaptor<Int>() 203 verify(manager) 204 .userActivity( 205 eq(345000L), 206 eq(PowerManager.USER_ACTIVITY_EVENT_TOUCH), 207 capture(flagsCaptor) 208 ) 209 assertThat(flagsCaptor.value).isNotEqualTo(PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) 210 assertThat(flagsCaptor.value).isNotEqualTo(PowerManager.USER_ACTIVITY_FLAG_INDIRECT) 211 } 212 213 @Test userActivity_notifiesPowerManager_noChangeLightsTruenull214 fun userActivity_notifiesPowerManager_noChangeLightsTrue() { 215 systemClock.setUptimeMillis(345000) 216 217 underTest.userTouch(noChangeLights = true) 218 219 val flagsCaptor = argumentCaptor<Int>() 220 verify(manager) 221 .userActivity( 222 eq(345000L), 223 eq(PowerManager.USER_ACTIVITY_EVENT_TOUCH), 224 capture(flagsCaptor) 225 ) 226 assertThat(flagsCaptor.value).isEqualTo(PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) 227 } 228 verifyRegisterednull229 private fun verifyRegistered() { 230 // We must verify with all arguments, even those that are optional because they have default 231 // values because Mockito is forcing us to. Once we can use mockito-kotlin, we should be 232 // able to remove this. 233 verify(dispatcher) 234 .registerReceiver( 235 capture(receiverCaptor), 236 capture(filterCaptor), 237 isNull(), 238 isNull(), 239 anyInt(), 240 isNull(), 241 ) 242 } 243 244 companion object { 245 private val IMMEDIATE = Dispatchers.Main.immediate 246 } 247 } 248