1 /* <lambda>null2 * Copyright 2021 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 androidx.compose.ui.test.injectionscope.touch 18 19 import androidx.compose.foundation.layout.Box 20 import androidx.compose.foundation.layout.fillMaxSize 21 import androidx.compose.ui.Modifier 22 import androidx.compose.ui.geometry.Offset 23 import androidx.compose.ui.test.TouchInjectionScope 24 import androidx.compose.ui.test.junit4.createComposeRule 25 import androidx.compose.ui.test.onNodeWithTag 26 import androidx.compose.ui.test.performTouchInput 27 import androidx.compose.ui.test.swipe 28 import androidx.compose.ui.test.util.ClickableTestBox 29 import androidx.compose.ui.test.util.SinglePointerInputRecorder 30 import androidx.compose.ui.test.util.areSampledFromCurve 31 import androidx.compose.ui.test.util.assertOnlyLastEventIsUp 32 import androidx.compose.ui.test.util.assertSinglePointer 33 import androidx.compose.ui.test.util.assertUpSameAsLastMove 34 import androidx.compose.ui.test.util.downEvents 35 import androidx.compose.ui.test.util.hasSameTimeBetweenEvents 36 import androidx.compose.ui.test.util.recordedDurationMillis 37 import androidx.test.filters.MediumTest 38 import com.google.common.truth.Truth.assertThat 39 import org.junit.Before 40 import org.junit.Rule 41 import org.junit.Test 42 import org.junit.runner.RunWith 43 import org.junit.runners.Parameterized 44 45 /** Test for [TouchInjectionScope.swipe] along a curve with key times */ 46 @MediumTest 47 @RunWith(Parameterized::class) 48 class SwipeCurveWithKeyTimesTest(private val config: TestConfig) { 49 data class TestConfig(val keyTimes: List<Long>) 50 51 companion object { 52 private const val tag = "widget" 53 private const val duration = 100L 54 55 @JvmStatic 56 @Parameterized.Parameters(name = "{0}") 57 fun createTestSet(): List<TestConfig> = 58 listOf( 59 TestConfig(emptyList()), 60 TestConfig(listOf(0)), 61 TestConfig(listOf(1)), 62 TestConfig(listOf(50)), 63 TestConfig(listOf(51)), 64 TestConfig(listOf(duration - 1)), 65 TestConfig(listOf(duration)), 66 TestConfig(listOf(33, 66)), 67 TestConfig(listOf(45, 46, 47)), 68 TestConfig(listOf(45, 55, 65)), 69 ) 70 } 71 72 @get:Rule val rule = createComposeRule() 73 74 private val recorder = SinglePointerInputRecorder() 75 76 private fun curve(t: Long) = Offset(t + 10f, t + 10f) 77 78 @Before 79 fun setContent() { 80 rule.setContent { 81 Box(Modifier.fillMaxSize()) { ClickableTestBox(modifier = recorder, tag = tag) } 82 } 83 } 84 85 @Test 86 fun swipe() { 87 rule.onNodeWithTag(tag).performTouchInput { 88 swipe(curve = ::curve, duration, config.keyTimes) 89 } 90 91 rule.runOnIdle { 92 recorder.apply { 93 assertThat(events.size).isAtLeast(3) 94 assertOnlyLastEventIsUp() 95 assertUpSameAsLastMove() 96 assertSinglePointer() 97 98 val t0 = events[0].timestamp 99 100 // All key times have been sampled 101 assertThat(events.map { it.timestamp - t0 }) 102 .containsAtLeastElementsIn(config.keyTimes) 103 104 // The duration of the gesture is as expected 105 assertThat(recordedDurationMillis).isEqualTo(duration) 106 // And each event is sampled from the curve 107 downEvents.areSampledFromCurve(::curve) 108 109 // All events between two key times are evenly spaced in time 110 (listOf(0L) + config.keyTimes + listOf(duration)) 111 .distinct() 112 .zipWithNext { a, b -> downEvents.filter { (it.timestamp - t0) in a..b } } 113 .forEach { it.hasSameTimeBetweenEvents() } 114 } 115 } 116 } 117 } 118