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 package com.android.quickstep.util.unfold 17 18 import android.os.Handler 19 import android.testing.AndroidTestingRunner 20 import android.testing.TestableLooper 21 import android.testing.TestableLooper.RunWithLooper 22 import android.util.Log 23 import androidx.test.filters.SmallTest 24 import com.android.systemui.unfold.UnfoldTransitionProgressProvider 25 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener 26 import org.junit.After 27 import org.junit.Before 28 import org.junit.Test 29 import org.junit.runner.RunWith 30 import org.mockito.kotlin.any 31 import org.mockito.kotlin.inOrder 32 import org.mockito.kotlin.mock 33 import org.mockito.kotlin.never 34 import org.mockito.kotlin.verify 35 36 @SmallTest 37 @RunWith(AndroidTestingRunner::class) 38 @RunWithLooper 39 class PreemptiveUnfoldTransitionProgressProviderTest { 40 41 private lateinit var testableLooper: TestableLooper 42 private lateinit var source: TransitionProgressListener 43 private lateinit var handler: Handler 44 private lateinit var oldWtfHandler: Log.TerribleFailureHandler 45 private val listener: TransitionProgressListener = mock() 46 private val testWtfHandler: Log.TerribleFailureHandler = mock() 47 48 private lateinit var provider: PreemptiveUnfoldTransitionProgressProvider 49 50 @Before beforenull51 fun before() { 52 testableLooper = TestableLooper.get(this) 53 handler = Handler(testableLooper.looper) 54 55 val testSource = createSource() 56 source = testSource as TransitionProgressListener 57 58 oldWtfHandler = Log.setWtfHandler(testWtfHandler) 59 60 provider = PreemptiveUnfoldTransitionProgressProvider(testSource, handler) 61 provider.init() 62 provider.addCallback(listener) 63 } 64 65 @After afternull66 fun after() { 67 Log.setWtfHandler(oldWtfHandler) 68 } 69 70 @Test preemptiveStartInitialProgressNull_transitionStartsnull71 fun preemptiveStartInitialProgressNull_transitionStarts() { 72 provider.preemptivelyStartTransition(initialProgress = null) 73 74 verify(listener).onTransitionStarted() 75 verify(listener, never()).onTransitionProgress(any()) 76 } 77 78 @Test preemptiveStartWithInitialProgress_startsAnimationAndSendsProgressnull79 fun preemptiveStartWithInitialProgress_startsAnimationAndSendsProgress() { 80 provider.preemptivelyStartTransition(initialProgress = 0.5f) 81 82 verify(listener).onTransitionStarted() 83 verify(listener).onTransitionProgress(0.5f) 84 } 85 86 @Test preemptiveStartAndCancel_finishesAnimationnull87 fun preemptiveStartAndCancel_finishesAnimation() { 88 provider.preemptivelyStartTransition() 89 provider.cancelPreemptiveStart() 90 91 inOrder(listener) { 92 verify(listener).onTransitionStarted() 93 verify(listener).onTransitionFinished() 94 } 95 } 96 97 @Test preemptiveStartAndThenSourceStartsTransition_transitionStartsnull98 fun preemptiveStartAndThenSourceStartsTransition_transitionStarts() { 99 provider.preemptivelyStartTransition() 100 source.onTransitionStarted() 101 102 verify(listener).onTransitionStarted() 103 } 104 105 @Test preemptiveStartAndThenSourceStartsAndFinishesTransition_transitionFinishesnull106 fun preemptiveStartAndThenSourceStartsAndFinishesTransition_transitionFinishes() { 107 provider.preemptivelyStartTransition() 108 109 source.onTransitionStarted() 110 source.onTransitionFinished() 111 112 inOrder(listener) { 113 verify(listener).onTransitionStarted() 114 verify(listener).onTransitionFinished() 115 } 116 } 117 118 @Test preemptiveStartAndThenSourceStartsAnimationAndSendsProgress_sendsProgressnull119 fun preemptiveStartAndThenSourceStartsAnimationAndSendsProgress_sendsProgress() { 120 provider.preemptivelyStartTransition() 121 122 source.onTransitionStarted() 123 source.onTransitionProgress(0.4f) 124 125 verify(listener).onTransitionProgress(0.4f) 126 } 127 128 @Test preemptiveStartAndThenSourceSendsProgress_sendsProgressnull129 fun preemptiveStartAndThenSourceSendsProgress_sendsProgress() { 130 provider.preemptivelyStartTransition() 131 132 source.onTransitionProgress(0.4f) 133 134 verify(listener).onTransitionProgress(0.4f) 135 } 136 137 @Test preemptiveStartAfterTransitionRunning_transitionStartednull138 fun preemptiveStartAfterTransitionRunning_transitionStarted() { 139 source.onTransitionStarted() 140 141 provider.preemptivelyStartTransition() 142 143 verify(listener).onTransitionStarted() 144 } 145 146 @Test preemptiveStartAfterTransitionRunningAndThenFinished_transitionFinishesnull147 fun preemptiveStartAfterTransitionRunningAndThenFinished_transitionFinishes() { 148 source.onTransitionStarted() 149 150 provider.preemptivelyStartTransition() 151 source.onTransitionFinished() 152 153 inOrder(listener) { 154 verify(listener).onTransitionStarted() 155 verify(listener).onTransitionFinished() 156 } 157 } 158 159 @Test preemptiveStart_transitionDoesNotFinishAfterTimeout_finishesTransitionnull160 fun preemptiveStart_transitionDoesNotFinishAfterTimeout_finishesTransition() { 161 provider.preemptivelyStartTransition() 162 163 testableLooper.moveTimeForward(PREEMPTIVE_UNFOLD_TIMEOUT_MS + 1) 164 testableLooper.processAllMessages() 165 166 inOrder(listener) { 167 verify(listener).onTransitionStarted() 168 verify(listener).onTransitionFinished() 169 } 170 } 171 172 @Test preemptiveStart_transitionFinishAfterTimeout_logsWtfnull173 fun preemptiveStart_transitionFinishAfterTimeout_logsWtf() { 174 provider.preemptivelyStartTransition() 175 176 testableLooper.moveTimeForward(PREEMPTIVE_UNFOLD_TIMEOUT_MS + 1) 177 testableLooper.processAllMessages() 178 179 verify(testWtfHandler).onTerribleFailure(any(), any(), any()) 180 } 181 182 @Test preemptiveStart_transitionDoesNotFinishBeforeTimeout_doesNotFinishTransitionnull183 fun preemptiveStart_transitionDoesNotFinishBeforeTimeout_doesNotFinishTransition() { 184 provider.preemptivelyStartTransition() 185 186 testableLooper.moveTimeForward(PREEMPTIVE_UNFOLD_TIMEOUT_MS - 1) 187 testableLooper.processAllMessages() 188 189 verify(listener).onTransitionStarted() 190 } 191 192 @Test preemptiveStart_transitionStarted_timeoutHappened_doesNotFinishTransitionnull193 fun preemptiveStart_transitionStarted_timeoutHappened_doesNotFinishTransition() { 194 provider.preemptivelyStartTransition() 195 196 source.onTransitionStarted() 197 testableLooper.moveTimeForward(PREEMPTIVE_UNFOLD_TIMEOUT_MS + 1) 198 testableLooper.processAllMessages() 199 200 verify(listener).onTransitionStarted() 201 } 202 203 @Test noPreemptiveStart_transitionStarted_startsTransitionnull204 fun noPreemptiveStart_transitionStarted_startsTransition() { 205 source.onTransitionStarted() 206 207 verify(listener).onTransitionStarted() 208 } 209 210 @Test noPreemptiveStart_transitionProgress_sendsProgressnull211 fun noPreemptiveStart_transitionProgress_sendsProgress() { 212 source.onTransitionStarted() 213 214 source.onTransitionProgress(0.5f) 215 216 verify(listener).onTransitionProgress(0.5f) 217 } 218 219 @Test noPreemptiveStart_transitionFinishes_finishesTransitionnull220 fun noPreemptiveStart_transitionFinishes_finishesTransition() { 221 source.onTransitionStarted() 222 source.onTransitionProgress(0.5f) 223 224 source.onTransitionFinished() 225 226 inOrder(listener) { 227 verify(listener).onTransitionStarted() 228 verify(listener).onTransitionFinished() 229 } 230 } 231 createSourcenull232 private fun createSource(): UnfoldTransitionProgressProvider = 233 object : TransitionProgressListener, UnfoldTransitionProgressProvider { 234 235 private val listeners = arrayListOf<TransitionProgressListener>() 236 237 override fun addCallback(listener: TransitionProgressListener) { 238 listeners += listener 239 } 240 241 override fun removeCallback(listener: TransitionProgressListener) { 242 listeners -= listener 243 } 244 245 override fun destroy() {} 246 247 override fun onTransitionStarted() = 248 listeners.forEach(TransitionProgressListener::onTransitionStarted) 249 250 override fun onTransitionFinishing() = 251 listeners.forEach(TransitionProgressListener::onTransitionFinishing) 252 253 override fun onTransitionFinished() = 254 listeners.forEach(TransitionProgressListener::onTransitionFinished) 255 256 override fun onTransitionProgress(progress: Float) = 257 listeners.forEach { it.onTransitionProgress(progress) } 258 } 259 } 260