Add VelocityTracker Benchmark tests for Planar Axes
Bug: 268413323
Test: atest VelocityTrackerBenchmarkTest
Change-Id: I359b7916fc28f534c7ff0805fd9d15765976c02a
diff --git a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
index 324fcc6..13269eb 100644
--- a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
+++ b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
@@ -23,33 +23,133 @@
import androidx.test.filters.LargeTest
import androidx.test.runner.AndroidJUnit4
+import java.time.Duration
+
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-private fun createScrollMotionEvent(scrollAmount: Float, eventTimeMs: Long): MotionEvent {
- val props = MotionEvent.PointerProperties()
- props.id = 0
- val coords = MotionEvent.PointerCoords()
- coords.setAxisValue(MotionEvent.AXIS_SCROLL, scrollAmount)
- return MotionEvent.obtain(
- /*downTime=*/0,
- eventTimeMs,
- MotionEvent.ACTION_SCROLL,
- /*pointerCount=*/1,
- arrayOf(props),
- arrayOf(coords),
- /*metaState=*/0,
- /*buttonState=*/0,
- /*xPrecision=*/0f,
- /*yPrecision=*/0f,
- /*deviceId=*/1,
- /*edgeFlags=*/0,
- InputDevice.SOURCE_ROTARY_ENCODER,
- /*flags=*/0
- )
+/**
+ * Helper class to maintain [MotionEvent]s for tests.
+ *
+ * This is primarily used to create [MotionEvent]s for tests, in a way where a sequence of
+ * [MotionEvent]s created in multiple test runs are exactly the same, as long as [reset] is called
+ * between consecutive sequences of [MotionEvent]s.
+ *
+ * Furthermore, it also contains convenience methods to run any queries/verifications of the
+ * generated [MotionEvent]s.
+ */
+abstract class MotionState {
+ /** Current time, in ms. */
+ protected var currentTime = START_TIME
+
+ /** Resets the state of this instance. */
+ open fun reset() {
+ currentTime = START_TIME
+ }
+
+ /** Creates a [MotionEvent]. */
+ abstract fun createMotionEvent(): MotionEvent
+
+ /** Asserts that the current velocity is not zero, just for verifying there's motion. */
+ abstract fun assertNonZeroVelocity(velocityTracker: VelocityTracker)
+
+ companion object {
+ /** Arbitrarily chosen start time. */
+ val START_TIME = Duration.ofMillis(100)
+ /**
+ * A small enough time jump, which won't be considered by the tracker as big enough to
+ * deduce that a pointer has stopped.
+ */
+ val DEFAULT_TIME_JUMP = Duration.ofMillis(2)
+ }
+}
+
+/** An implementation of [MotionState] for [MotionEvent.AXIS_SCROLL]. */
+private class ScrollMotionState : MotionState() {
+ override fun createMotionEvent(): MotionEvent {
+ val props = MotionEvent.PointerProperties()
+ props.id = 0
+ val coords = MotionEvent.PointerCoords()
+ coords.setAxisValue(MotionEvent.AXIS_SCROLL, DEFAULT_SCROLL_AMOUNT)
+ val motionEvent = MotionEvent.obtain(
+ /*downTime=*/0,
+ currentTime.toMillis(),
+ MotionEvent.ACTION_SCROLL,
+ /*pointerCount=*/1,
+ arrayOf(props),
+ arrayOf(coords),
+ /*metaState=*/0,
+ /*buttonState=*/0,
+ /*xPrecision=*/0f,
+ /*yPrecision=*/0f,
+ /*deviceId=*/1,
+ /*edgeFlags=*/0,
+ InputDevice.SOURCE_ROTARY_ENCODER,
+ /*flags=*/0
+ )
+
+ currentTime = currentTime.plus(DEFAULT_TIME_JUMP)
+
+ return motionEvent
+ }
+
+ override fun assertNonZeroVelocity(velocityTracker: VelocityTracker) {
+ Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) != 0f)
+ }
+
+ companion object {
+ private val DEFAULT_SCROLL_AMOUNT: Float = 30f
+ }
+}
+
+/** An implementation of [MotionState] for [MotionEvent.AXIS_X] and [MotionEvent.AXIS_Y]. */
+private class PlanarMotionState : MotionState() {
+ private var x: Float = DEFAULT_X
+ private var y: Float = DEFAULT_Y
+ private var downEventCreated = false
+
+ override fun createMotionEvent(): MotionEvent {
+ val action: Int = if (downEventCreated) MotionEvent.ACTION_MOVE else MotionEvent.ACTION_DOWN
+ val motionEvent = MotionEvent.obtain(
+ /*downTime=*/START_TIME.toMillis(),
+ currentTime.toMillis(),
+ action,
+ x,
+ y,
+ /*metaState=*/0)
+
+ if (downEventCreated) {
+ x += INCREMENT
+ y += INCREMENT
+ } else {
+ downEventCreated = true
+ }
+ currentTime = currentTime.plus(DEFAULT_TIME_JUMP)
+
+ return motionEvent
+ }
+
+ override fun assertNonZeroVelocity(velocityTracker: VelocityTracker) {
+ Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_X) != 0f)
+ Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_Y) != 0f)
+ }
+
+ override fun reset() {
+ super.reset()
+ x = DEFAULT_X
+ y = DEFAULT_Y
+ downEventCreated = false
+ }
+
+ companion object {
+ /** Arbitrarily chosen constants. No need to have varying velocity for now. */
+ private val DEFAULT_X: Float = 2f
+ private val DEFAULT_Y: Float = 4f
+ private val INCREMENT: Float = 0.7f
+ }
}
/**
@@ -72,65 +172,80 @@
@Test
fun addMovement_axisScroll() {
+ testAddMovement(ScrollMotionState())
+ }
+
+ @Test
+ fun computeCurrentVelocity_computeAfterAllAdditions_axisScroll() {
+ testComputeCurrentVelocity_computeAfterAllAdditions(ScrollMotionState())
+ }
+
+ @Test
+ fun computeCurrentVelocity_computeAfterEachAdd_axisScroll() {
+ testComputeCurrentVelocity_computeAfterEachAdd(ScrollMotionState())
+ }
+
+ @Test
+ fun addMovementTest_planarAxes() {
+ testAddMovement(PlanarMotionState())
+ }
+
+ @Test
+ fun computeCurrentVelocity_computeAfterAllAdditions_planarAxes() {
+ testComputeCurrentVelocity_computeAfterAllAdditions(PlanarMotionState())
+ }
+
+ private fun testAddMovement(motionState: MotionState) {
val state = perfStatusReporter.getBenchmarkState()
while (state.keepRunning()) {
state.pauseTiming()
- var eventTimeMs: Long = 100
- val scrollAmount = 30f
for (i in 0 until TEST_NUM_DATAPOINTS) {
+ val motionEvent = motionState.createMotionEvent()
state.resumeTiming()
- velocityTracker.addMovement(createScrollMotionEvent(scrollAmount, eventTimeMs))
+ velocityTracker.addMovement(motionEvent)
state.pauseTiming()
- eventTimeMs += 2
}
velocityTracker.computeCurrentVelocity(1000)
- Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) > 0)
+ motionState.assertNonZeroVelocity(velocityTracker)
// Clear the tracker for the next run
velocityTracker.clear()
+ motionState.reset()
state.resumeTiming()
}
}
- @Test
- fun computeCurrentVelocity_constantVelocity_axisScroll_computeAfterAllAdditions() {
+ private fun testComputeCurrentVelocity_computeAfterAllAdditions(motionState: MotionState) {
val state = perfStatusReporter.getBenchmarkState()
while (state.keepRunning()) {
// Add the data points
state.pauseTiming()
- var eventTimeMs: Long = 100
- val scrollAmount = 30f
for (i in 0 until TEST_NUM_DATAPOINTS) {
- velocityTracker.addMovement(createScrollMotionEvent(scrollAmount, eventTimeMs))
- eventTimeMs += 2
+ velocityTracker.addMovement(motionState.createMotionEvent())
}
// Do the velocity computation
state.resumeTiming()
velocityTracker.computeCurrentVelocity(1000)
- // Clear the tracker for the next run
state.pauseTiming()
- Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) > 0)
+ motionState.assertNonZeroVelocity(velocityTracker)
+ // Clear the tracker for the next run
velocityTracker.clear()
state.resumeTiming()
}
}
- @Test
- fun computeCurrentVelocity_constantVelocity_axisScroll_computeAfterEachAdd() {
+ private fun testComputeCurrentVelocity_computeAfterEachAdd(motionState: MotionState) {
val state = perfStatusReporter.getBenchmarkState()
while (state.keepRunning()) {
state.pauseTiming()
- var eventTimeMs: Long = 100
- val scrollAmount = 30f
for (i in 0 until TEST_NUM_DATAPOINTS) {
- velocityTracker.addMovement(createScrollMotionEvent(scrollAmount, eventTimeMs))
+ velocityTracker.addMovement(motionState.createMotionEvent())
state.resumeTiming()
velocityTracker.computeCurrentVelocity(1000)
state.pauseTiming()
- eventTimeMs += 2
}
- Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) > 0)
+ motionState.assertNonZeroVelocity(velocityTracker)
// Clear the tracker for the next run
velocityTracker.clear()
state.resumeTiming()