Loading packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt→packages/SystemUI/multivalentTests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt +23 −54 Original line number Diff line number Diff line Loading @@ -27,7 +27,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.keyguard.userActivityNotifier import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor Loading @@ -35,10 +38,8 @@ import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading @@ -55,6 +56,7 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class PowerRepositoryImplTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val systemClock = FakeSystemClock() val manager: PowerManager = kosmos.powerManager Loading @@ -76,94 +78,66 @@ class PowerRepositoryImplTest : SysuiTestCase() { PowerRepositoryImpl( manager, context.applicationContext, kosmos.testScope.backgroundScope, systemClock, dispatcher, kosmos.userActivityNotifier, ) } @Test fun isInteractive_registersForBroadcasts() = runBlocking(IMMEDIATE) { val job = underTest.isInteractive.onEach {}.launchIn(this) verifyRegistered() assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_ON)).isTrue() assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_OFF)).isTrue() job.cancel() } @Test fun isInteractive_unregistersFromBroadcasts() = runBlocking(IMMEDIATE) { val job = underTest.isInteractive.onEach {}.launchIn(this) verifyRegistered() job.cancel() verify(dispatcher).unregisterReceiver(receiverCaptor.value) } @Test fun isInteractive_emitsInitialTrueValueIfScreenWasOn() = runBlocking(IMMEDIATE) { testScope.runTest { isInteractive = true var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() assertThat(value).isTrue() job.cancel() } @Test fun isInteractive_emitsInitialFalseValueIfScreenWasOff() = runBlocking(IMMEDIATE) { testScope.runTest { isInteractive = false var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() assertThat(value).isFalse() job.cancel() } @Test fun isInteractive_emitsTrueWhenTheScreenTurnsOn() = runBlocking(IMMEDIATE) { var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) testScope.runTest { val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() isInteractive = true receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON)) assertThat(value).isTrue() job.cancel() } @Test fun isInteractive_emitsFalseWhenTheScreenTurnsOff() = runBlocking(IMMEDIATE) { var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) testScope.runTest { val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() isInteractive = false receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF)) assertThat(value).isFalse() job.cancel() } @Test fun isInteractive_emitsCorrectlyOverTime() = runBlocking(IMMEDIATE) { val values = mutableListOf<Boolean>() val job = underTest.isInteractive.onEach(values::add).launchIn(this) testScope.runTest { val values by collectValues(underTest.isInteractive) runCurrent() verifyRegistered() isInteractive = false Loading @@ -173,8 +147,7 @@ class PowerRepositoryImplTest : SysuiTestCase() { isInteractive = false receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF)) assertThat(values).isEqualTo(listOf(true, false, true, false)) job.cancel() assertThat(values).isEqualTo(listOf(false, true, false)) } @Test Loading Loading @@ -247,8 +220,4 @@ class PowerRepositoryImplTest : SysuiTestCase() { isNull(), ) } companion object { private val IMMEDIATE = Dispatchers.Main.immediate } } packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt +28 −23 Original line number Diff line number Diff line Loading @@ -37,16 +37,18 @@ import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.util.time.SystemClock import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.stateIn /** Defines interface for classes that act as source of truth for power-related data. */ interface PowerRepository { /** Whether the device is interactive. Starts with the current state. */ val isInteractive: Flow<Boolean> val isInteractive: StateFlow<Boolean> /** * Whether the device is awake or asleep. [WakefulnessState.AWAKE] means the screen is fully Loading Loading @@ -103,6 +105,7 @@ class PowerRepositoryImpl constructor( private val manager: PowerManager, @Application private val applicationContext: Context, @Application private val scope: CoroutineScope, private val systemClock: SystemClock, dispatcher: BroadcastDispatcher, private val userActivityNotifier: UserActivityNotifier, Loading @@ -110,7 +113,8 @@ constructor( override val dozeScreenState = MutableStateFlow(DozeScreenStateModel.UNKNOWN) override val isInteractive: Flow<Boolean> = conflatedCallbackFlow { override val isInteractive: StateFlow<Boolean> = conflatedCallbackFlow { fun send() { trySendWithFailureLogging(manager.isInteractive, TAG) } Loading @@ -133,6 +137,7 @@ constructor( awaitClose { dispatcher.unregisterReceiver(receiver) } } .stateIn(scope, SharingStarted.Eagerly, false) private val _wakefulness = MutableStateFlow(WakefulnessModel()) override val wakefulness = _wakefulness.asStateFlow() Loading packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt +1 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.statusbar.phone.ScreenOffAnimationController import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collect Loading @@ -53,7 +52,7 @@ constructor( private val cameraGestureHelper: Provider<CameraGestureHelper?>, ) { /** Whether the screen is on or off. */ val isInteractive: Flow<Boolean> = repository.isInteractive val isInteractive: StateFlow<Boolean> = repository.isInteractive /** * Whether we're awake or asleep, along with additional information about why we're awake/asleep Loading packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt +2 −2 Original line number Diff line number Diff line Loading @@ -27,14 +27,14 @@ import com.android.systemui.power.shared.model.WakefulnessState import dagger.Binds import dagger.Module import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @SysUISingleton class FakePowerRepository @Inject constructor() : PowerRepository { private val _isInteractive = MutableStateFlow(true) override val isInteractive: Flow<Boolean> = _isInteractive.asStateFlow() override val isInteractive: StateFlow<Boolean> = _isInteractive.asStateFlow() private val _wakefulness = MutableStateFlow(WakefulnessModel()) override val wakefulness = _wakefulness.asStateFlow() Loading Loading
packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt→packages/SystemUI/multivalentTests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt +23 −54 Original line number Diff line number Diff line Loading @@ -27,7 +27,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.keyguard.userActivityNotifier import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor Loading @@ -35,10 +38,8 @@ import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading @@ -55,6 +56,7 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class PowerRepositoryImplTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val systemClock = FakeSystemClock() val manager: PowerManager = kosmos.powerManager Loading @@ -76,94 +78,66 @@ class PowerRepositoryImplTest : SysuiTestCase() { PowerRepositoryImpl( manager, context.applicationContext, kosmos.testScope.backgroundScope, systemClock, dispatcher, kosmos.userActivityNotifier, ) } @Test fun isInteractive_registersForBroadcasts() = runBlocking(IMMEDIATE) { val job = underTest.isInteractive.onEach {}.launchIn(this) verifyRegistered() assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_ON)).isTrue() assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_OFF)).isTrue() job.cancel() } @Test fun isInteractive_unregistersFromBroadcasts() = runBlocking(IMMEDIATE) { val job = underTest.isInteractive.onEach {}.launchIn(this) verifyRegistered() job.cancel() verify(dispatcher).unregisterReceiver(receiverCaptor.value) } @Test fun isInteractive_emitsInitialTrueValueIfScreenWasOn() = runBlocking(IMMEDIATE) { testScope.runTest { isInteractive = true var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() assertThat(value).isTrue() job.cancel() } @Test fun isInteractive_emitsInitialFalseValueIfScreenWasOff() = runBlocking(IMMEDIATE) { testScope.runTest { isInteractive = false var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() assertThat(value).isFalse() job.cancel() } @Test fun isInteractive_emitsTrueWhenTheScreenTurnsOn() = runBlocking(IMMEDIATE) { var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) testScope.runTest { val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() isInteractive = true receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON)) assertThat(value).isTrue() job.cancel() } @Test fun isInteractive_emitsFalseWhenTheScreenTurnsOff() = runBlocking(IMMEDIATE) { var value: Boolean? = null val job = underTest.isInteractive.onEach { value = it }.launchIn(this) testScope.runTest { val value by collectLastValue(underTest.isInteractive) runCurrent() verifyRegistered() isInteractive = false receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF)) assertThat(value).isFalse() job.cancel() } @Test fun isInteractive_emitsCorrectlyOverTime() = runBlocking(IMMEDIATE) { val values = mutableListOf<Boolean>() val job = underTest.isInteractive.onEach(values::add).launchIn(this) testScope.runTest { val values by collectValues(underTest.isInteractive) runCurrent() verifyRegistered() isInteractive = false Loading @@ -173,8 +147,7 @@ class PowerRepositoryImplTest : SysuiTestCase() { isInteractive = false receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF)) assertThat(values).isEqualTo(listOf(true, false, true, false)) job.cancel() assertThat(values).isEqualTo(listOf(false, true, false)) } @Test Loading Loading @@ -247,8 +220,4 @@ class PowerRepositoryImplTest : SysuiTestCase() { isNull(), ) } companion object { private val IMMEDIATE = Dispatchers.Main.immediate } }
packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt +28 −23 Original line number Diff line number Diff line Loading @@ -37,16 +37,18 @@ import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.util.time.SystemClock import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.stateIn /** Defines interface for classes that act as source of truth for power-related data. */ interface PowerRepository { /** Whether the device is interactive. Starts with the current state. */ val isInteractive: Flow<Boolean> val isInteractive: StateFlow<Boolean> /** * Whether the device is awake or asleep. [WakefulnessState.AWAKE] means the screen is fully Loading Loading @@ -103,6 +105,7 @@ class PowerRepositoryImpl constructor( private val manager: PowerManager, @Application private val applicationContext: Context, @Application private val scope: CoroutineScope, private val systemClock: SystemClock, dispatcher: BroadcastDispatcher, private val userActivityNotifier: UserActivityNotifier, Loading @@ -110,7 +113,8 @@ constructor( override val dozeScreenState = MutableStateFlow(DozeScreenStateModel.UNKNOWN) override val isInteractive: Flow<Boolean> = conflatedCallbackFlow { override val isInteractive: StateFlow<Boolean> = conflatedCallbackFlow { fun send() { trySendWithFailureLogging(manager.isInteractive, TAG) } Loading @@ -133,6 +137,7 @@ constructor( awaitClose { dispatcher.unregisterReceiver(receiver) } } .stateIn(scope, SharingStarted.Eagerly, false) private val _wakefulness = MutableStateFlow(WakefulnessModel()) override val wakefulness = _wakefulness.asStateFlow() Loading
packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt +1 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.statusbar.phone.ScreenOffAnimationController import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collect Loading @@ -53,7 +52,7 @@ constructor( private val cameraGestureHelper: Provider<CameraGestureHelper?>, ) { /** Whether the screen is on or off. */ val isInteractive: Flow<Boolean> = repository.isInteractive val isInteractive: StateFlow<Boolean> = repository.isInteractive /** * Whether we're awake or asleep, along with additional information about why we're awake/asleep Loading
packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt +2 −2 Original line number Diff line number Diff line Loading @@ -27,14 +27,14 @@ import com.android.systemui.power.shared.model.WakefulnessState import dagger.Binds import dagger.Module import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @SysUISingleton class FakePowerRepository @Inject constructor() : PowerRepository { private val _isInteractive = MutableStateFlow(true) override val isInteractive: Flow<Boolean> = _isInteractive.asStateFlow() override val isInteractive: StateFlow<Boolean> = _isInteractive.asStateFlow() private val _wakefulness = MutableStateFlow(WakefulnessModel()) override val wakefulness = _wakefulness.asStateFlow() Loading