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 package com.android.systemui.keyguard.domain.interactor 18 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import androidx.test.filters.SmallTest 21 import com.android.systemui.RoboPilotTest 22 import com.android.systemui.SysuiTestCase 23 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository 24 import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository 25 import com.android.systemui.keyguard.shared.model.KeyguardState 26 import com.android.systemui.keyguard.shared.model.TransitionState 27 import com.android.systemui.keyguard.shared.model.TransitionStep 28 import com.android.systemui.statusbar.LightRevealEffect 29 import com.android.systemui.statusbar.LightRevealScrim 30 import kotlinx.coroutines.ExperimentalCoroutinesApi 31 import kotlinx.coroutines.flow.launchIn 32 import kotlinx.coroutines.flow.onEach 33 import kotlinx.coroutines.test.TestScope 34 import kotlinx.coroutines.test.UnconfinedTestDispatcher 35 import kotlinx.coroutines.test.runCurrent 36 import kotlinx.coroutines.test.runTest 37 import org.junit.Assert.assertEquals 38 import org.junit.Before 39 import org.junit.Test 40 import org.junit.runner.RunWith 41 import org.mockito.Mockito.anyBoolean 42 import org.mockito.Mockito.never 43 import org.mockito.Mockito.verify 44 import org.mockito.MockitoAnnotations 45 import org.mockito.Spy 46 47 @SmallTest 48 @RoboPilotTest 49 @OptIn(ExperimentalCoroutinesApi::class) 50 @RunWith(AndroidJUnit4::class) 51 class LightRevealScrimInteractorTest : SysuiTestCase() { 52 private val fakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository() 53 54 @Spy private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository() 55 56 private val testScope = TestScope() 57 58 private val keyguardTransitionInteractor = 59 KeyguardTransitionInteractorFactory.create( 60 scope = testScope.backgroundScope, 61 repository = fakeKeyguardTransitionRepository, 62 ) 63 .keyguardTransitionInteractor 64 65 private lateinit var underTest: LightRevealScrimInteractor 66 67 private val reveal1 = 68 object : LightRevealEffect { setRevealAmountOnScrimnull69 override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {} 70 } 71 72 private val reveal2 = 73 object : LightRevealEffect { setRevealAmountOnScrimnull74 override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {} 75 } 76 77 @Before setUpnull78 fun setUp() { 79 MockitoAnnotations.initMocks(this) 80 underTest = 81 LightRevealScrimInteractor( 82 keyguardTransitionInteractor, 83 fakeLightRevealScrimRepository, 84 testScope.backgroundScope 85 ) 86 } 87 88 @Test lightRevealEffect_doesNotChangeDuringKeyguardTransitionnull89 fun lightRevealEffect_doesNotChangeDuringKeyguardTransition() = 90 runTest(UnconfinedTestDispatcher()) { 91 val values = mutableListOf<LightRevealEffect>() 92 val job = underTest.lightRevealEffect.onEach(values::add).launchIn(this) 93 94 fakeLightRevealScrimRepository.setRevealEffect(reveal1) 95 96 // The reveal effect shouldn't emit anything until a keyguard transition starts. 97 assertEquals(values.size, 0) 98 99 // Once it starts, it should emit reveal1. 100 fakeKeyguardTransitionRepository.sendTransitionStep( 101 TransitionStep(transitionState = TransitionState.STARTED) 102 ) 103 assertEquals(values, listOf(reveal1)) 104 105 // Until the next transition starts, reveal2 should not be emitted. 106 fakeLightRevealScrimRepository.setRevealEffect(reveal2) 107 fakeKeyguardTransitionRepository.sendTransitionStep( 108 TransitionStep(transitionState = TransitionState.RUNNING) 109 ) 110 fakeKeyguardTransitionRepository.sendTransitionStep( 111 TransitionStep(transitionState = TransitionState.FINISHED) 112 ) 113 assertEquals(values, listOf(reveal1)) 114 fakeKeyguardTransitionRepository.sendTransitionStep( 115 TransitionStep(transitionState = TransitionState.STARTED) 116 ) 117 assertEquals(values, listOf(reveal1, reveal2)) 118 119 job.cancel() 120 } 121 122 @Test lightRevealEffect_startsAnimationOnlyForDifferentStateTargetsnull123 fun lightRevealEffect_startsAnimationOnlyForDifferentStateTargets() = 124 testScope.runTest { 125 fakeKeyguardTransitionRepository.sendTransitionStep( 126 TransitionStep( 127 transitionState = TransitionState.STARTED, 128 from = KeyguardState.OFF, 129 to = KeyguardState.OFF 130 ) 131 ) 132 runCurrent() 133 verify(fakeLightRevealScrimRepository, never()).startRevealAmountAnimator(anyBoolean()) 134 135 fakeKeyguardTransitionRepository.sendTransitionStep( 136 TransitionStep( 137 transitionState = TransitionState.STARTED, 138 from = KeyguardState.DOZING, 139 to = KeyguardState.LOCKSCREEN 140 ) 141 ) 142 runCurrent() 143 verify(fakeLightRevealScrimRepository).startRevealAmountAnimator(true) 144 145 fakeKeyguardTransitionRepository.sendTransitionStep( 146 TransitionStep( 147 transitionState = TransitionState.STARTED, 148 from = KeyguardState.LOCKSCREEN, 149 to = KeyguardState.DOZING 150 ) 151 ) 152 runCurrent() 153 verify(fakeLightRevealScrimRepository).startRevealAmountAnimator(false) 154 } 155 } 156