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 17 package com.android.systemui.unfold.progress 18 19 import com.android.systemui.unfold.UnfoldTransitionProgressProvider 20 import com.android.systemui.util.leak.ReferenceTestUtils.waitForCondition 21 import com.google.common.truth.Truth.assertThat 22 import com.google.common.truth.Truth.assertWithMessage 23 24 /** Listener usable by tests with some handy assertions. */ 25 class TestUnfoldProgressListener : UnfoldTransitionProgressProvider.TransitionProgressListener { 26 27 private val recordings: MutableList<UnfoldTransitionRecording> = arrayListOf() 28 private var currentRecording: UnfoldTransitionRecording? = null 29 var lastCallbackThread: Thread? = null 30 private set 31 onTransitionStartednull32 override fun onTransitionStarted() { 33 lastCallbackThread = Thread.currentThread() 34 assertWithMessage("Trying to start a transition when it is already in progress") 35 .that(currentRecording) 36 .isNull() 37 38 currentRecording = UnfoldTransitionRecording() 39 } 40 onTransitionProgressnull41 override fun onTransitionProgress(progress: Float) { 42 lastCallbackThread = Thread.currentThread() 43 assertWithMessage("Received transition progress event when it's not started") 44 .that(currentRecording) 45 .isNotNull() 46 currentRecording!!.addProgress(progress) 47 } 48 onTransitionFinishingnull49 override fun onTransitionFinishing() { 50 lastCallbackThread = Thread.currentThread() 51 assertWithMessage("Received transition finishing event when it's not started") 52 .that(currentRecording) 53 .isNotNull() 54 currentRecording!!.onFinishing() 55 } 56 onTransitionFinishednull57 override fun onTransitionFinished() { 58 lastCallbackThread = Thread.currentThread() 59 assertWithMessage("Received transition finish event when it's not started") 60 .that(currentRecording) 61 .isNotNull() 62 recordings += currentRecording!! 63 currentRecording = null 64 } 65 ensureTransitionFinishednull66 fun ensureTransitionFinished(): UnfoldTransitionRecording { 67 waitForCondition { recordings.size == 1 } 68 return recordings.first() 69 } 70 assertStartednull71 fun assertStarted() { 72 assertWithMessage("Transition didn't start").that(currentRecording).isNotNull() 73 } 74 assertNotStartednull75 fun assertNotStarted() { 76 assertWithMessage("Transition started").that(currentRecording).isNull() 77 } 78 assertLastProgressnull79 fun assertLastProgress(progress: Float) { 80 currentRecording?.assertLastProgress(progress) ?: error("unfold not in progress.") 81 } 82 clearnull83 fun clear() { 84 currentRecording = null 85 recordings.clear() 86 } 87 88 class UnfoldTransitionRecording { 89 private val progressHistory: MutableList<Float> = arrayListOf() 90 private var finishingInvocations: Int = 0 91 addProgressnull92 fun addProgress(progress: Float) { 93 assertThat(progress).isAtMost(1.0f) 94 assertThat(progress).isAtLeast(0.0f) 95 96 progressHistory += progress 97 } 98 onFinishingnull99 fun onFinishing() { 100 finishingInvocations++ 101 } 102 assertIncreasingProgressnull103 fun assertIncreasingProgress() { 104 assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) 105 assertThat(progressHistory).isInOrder() 106 } 107 assertDecreasingProgressnull108 fun assertDecreasingProgress() { 109 assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) 110 assertThat(progressHistory).isInOrder(Comparator.reverseOrder<Float>()) 111 } 112 assertFinishedWithUnfoldnull113 fun assertFinishedWithUnfold() { 114 assertThat(progressHistory).isNotEmpty() 115 assertThat(progressHistory.last()).isEqualTo(1.0f) 116 } 117 assertFinishedWithFoldnull118 fun assertFinishedWithFold() { 119 assertThat(progressHistory).isNotEmpty() 120 assertThat(progressHistory.last()).isEqualTo(0.0f) 121 } 122 assertHasFoldAnimationAtTheEndnull123 fun assertHasFoldAnimationAtTheEnd() { 124 // Check that there are at least a few decreasing events at the end 125 assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) 126 assertThat(progressHistory.takeLast(MIN_ANIMATION_EVENTS)) 127 .isInOrder(Comparator.reverseOrder<Float>()) 128 assertThat(progressHistory.last()).isEqualTo(0.0f) 129 } 130 assertHasSingleFinishingEventnull131 fun assertHasSingleFinishingEvent() { 132 assertWithMessage( 133 "onTransitionFinishing callback should be invoked exactly " + "one time" 134 ) 135 .that(finishingInvocations) 136 .isEqualTo(1) 137 } 138 assertLastProgressnull139 fun assertLastProgress(progress: Float) { 140 waitForCondition { progress == progressHistory.lastOrNull() } 141 } 142 } 143 144 private companion object { 145 private const val MIN_ANIMATION_EVENTS = 5 146 } 147 } 148