1 /*
2 * Copyright 2024 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.cts.input
18
19 import android.view.Display
20 import android.view.InputDevice
21 import android.view.MotionEvent
22
23 const val DEFAULT_DEVICE_ID = -1
24
isFromSourcenull25 private fun isFromSource(source: Int, test: Int): Boolean {
26 return (source and test) == test
27 }
28
29 class MotionEventBuilder(val action: Int, val source: Int) {
30 private var deviceId = DEFAULT_DEVICE_ID
31 private var downTime = System.currentTimeMillis()
32 private var eventTime = downTime
33 private var displayId = Display.DEFAULT_DISPLAY
34 private var actionButton = 0
35 private var metaState = 0
36 private var buttonState = 0
37 private var xPrecision = 0f
38 private var yPrecision = 0f
39 private var flags = 0
40 private var rawXCursorPosition: Float? = null
41 private var rawYCursorPosition: Float? = null
42 private var classification = MotionEvent.CLASSIFICATION_NONE
43 private val edgeFlags = 0
44 private val pointers = mutableListOf<PointerBuilder>()
45
46 // Builder methods
<lambda>null47 fun deviceId(deviceId: Int) = apply { this.deviceId = deviceId }
downTimenull48 fun downTime(downTime: Long) = apply { this.downTime = downTime }
<lambda>null49 fun eventTime(eventTime: Long) = apply { this.eventTime = eventTime }
<lambda>null50 fun displayId(displayId: Int) = apply { this.displayId = displayId }
<lambda>null51 fun actionButton(actionButton: Int) = apply { this.actionButton = actionButton }
<lambda>null52 fun metaState(metaState: Int) = apply { this.metaState = metaState }
<lambda>null53 fun buttonState(buttonState: Int) = apply { this.buttonState = buttonState }
<lambda>null54 fun xPrecision(xPrecision: Float) = apply { this.xPrecision = xPrecision}
<lambda>null55 fun yPrecision(yPrecision: Float) = apply { this.yPrecision = yPrecision}
<lambda>null56 fun addFlag(flags: Int) = apply { this.flags = this.flags or flags }
<lambda>null57 fun rawXCursorPosition(rawXCursorPosition: Float?) = apply {
58 this.rawXCursorPosition = rawXCursorPosition
59 }
<lambda>null60 fun rawYCursorPosition(rawYCursorPosition: Float?) = apply {
61 this.rawYCursorPosition = rawYCursorPosition
62 }
<lambda>null63 fun pointer(pointer: PointerBuilder) = apply { pointers.add(pointer) }
<lambda>null64 fun classification(classification: Int) = apply { this.classification = classification }
65
buildnull66 fun build(): MotionEvent {
67 val pointerProperties = pointers.map { it.buildProperties() }
68 val pointerCoords = pointers.map { it.buildCoords() }
69
70 // If the mouse cursor position is not explicitly specified, use the X and Y coordinates of
71 // the first pointer, if this is a mouse event.
72 if (isFromSource(source, InputDevice.SOURCE_MOUSE) &&
73 (rawXCursorPosition == null || rawYCursorPosition == null)) {
74 rawXCursorPosition = pointerCoords[0].x
75 rawYCursorPosition = pointerCoords[0].y
76 }
77
78 return MotionEvent.obtain(
79 downTime, eventTime, action, pointerProperties.size, pointerProperties.toTypedArray(),
80 pointerCoords.toTypedArray(), metaState, buttonState, xPrecision, yPrecision, deviceId,
81 edgeFlags, source, displayId, flags, classification
82 )!!
83 }
84 }
85