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.inputeventmatchers 18 19 import android.graphics.Point 20 import android.graphics.PointF 21 import android.view.KeyEvent 22 import android.view.KeyEvent.keyCodeToString 23 import android.view.MotionEvent 24 import kotlin.math.abs 25 import org.hamcrest.Description 26 import org.hamcrest.Matcher 27 import org.hamcrest.TypeSafeMatcher 28 29 private const val EPSILON = 0.001f 30 withCoordsnull31fun withCoords(pt: PointF): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 32 override fun describeTo(description: Description) { 33 description.appendText("With coords = $pt") 34 } 35 36 override fun matchesSafely(event: MotionEvent): Boolean { 37 return (abs(event.x - pt.x) < EPSILON) && 38 (abs(event.y - pt.y) < EPSILON) 39 } 40 } 41 withPointerCountnull42fun withPointerCount(count: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 43 override fun describeTo(description: Description) { 44 description.appendText("With pointer count = $count") 45 } 46 47 override fun matchesSafely(event: MotionEvent): Boolean { 48 return event.pointerCount == count 49 } 50 } 51 withCoordsnull52fun withCoords(pt: Point): Matcher<MotionEvent> = withCoords(PointF(pt)) 53 54 fun withCoordsForPointerIndex(index: Int, pt: PointF): Matcher<MotionEvent> = 55 object : TypeSafeMatcher<MotionEvent>() { 56 override fun describeTo(description: Description) { 57 description.appendText("With coords = $pt for pointer index = $index") 58 } 59 60 override fun matchesSafely(event: MotionEvent): Boolean { 61 return (abs(event.getX(index)) - pt.x < EPSILON) && 62 (abs(event.getY(index)) - pt.y < EPSILON) 63 } 64 } 65 withRawCoordsnull66fun withRawCoords(pt: PointF): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 67 override fun describeTo(description: Description) { 68 description.appendText("With coords = $pt") 69 } 70 71 override fun matchesSafely(event: MotionEvent): Boolean { 72 return (abs(event.rawX) - pt.x < EPSILON) && 73 (abs(event.rawY) - pt.y < EPSILON) 74 } 75 76 override fun describeMismatchSafely(event: MotionEvent, mismatchDescription: Description) { 77 mismatchDescription.appendText("Got raw coords = {${event.getRawX()}, ${event.getRawY()}}") 78 } 79 } 80 withMotionActionnull81fun withMotionAction(action: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 82 override fun describeTo(description: Description) { 83 description.appendText("With action = ${MotionEvent.actionToString(action)}") 84 } 85 86 override fun matchesSafely(event: MotionEvent): Boolean { 87 if (action == MotionEvent.ACTION_CANCEL) { 88 if (event.flags and MotionEvent.FLAG_CANCELED != MotionEvent.FLAG_CANCELED) { 89 return false 90 } 91 } 92 return event.action == action 93 } 94 } 95 withMotionActionnull96fun withMotionAction(action: Int, index: Int): Matcher<MotionEvent> = 97 object : TypeSafeMatcher<MotionEvent>() { 98 override fun describeTo(description: Description) { 99 description.appendText( 100 "With action = ${MotionEvent.actionToString(action)}, index = $index" 101 ) 102 } 103 104 override fun matchesSafely(event: MotionEvent): Boolean { 105 if (action != MotionEvent.ACTION_POINTER_DOWN && action != MotionEvent.ACTION_POINTER_UP) { 106 throw Exception( 107 "Matcher should only be used with ACTION_POINTER_DOWN or ACTION_POINTER_UP" 108 ) 109 } 110 return event.actionMasked == action && event.actionIndex == index 111 } 112 } 113 withRawCoordsnull114fun withRawCoords(pt: Point): Matcher<MotionEvent> { 115 return withRawCoords(PointF(pt)) 116 } 117 withSourcenull118fun withSource(source: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 119 override fun describeTo(description: Description) { 120 description.appendText("With source = $source") 121 } 122 123 override fun matchesSafely(event: MotionEvent): Boolean { 124 return event.getSource() == source 125 } 126 } 127 withDeviceIdnull128fun withDeviceId(deviceId: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 129 override fun describeTo(description: Description) { 130 description.appendText("With deviceId = $deviceId") 131 } 132 133 override fun matchesSafely(event: MotionEvent): Boolean { 134 return event.getDeviceId() == deviceId 135 } 136 } 137 withEventTimenull138fun withEventTime(eventTime: Long): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 139 override fun describeTo(description: Description) { 140 description.appendText("With eventTime = $eventTime") 141 } 142 143 override fun matchesSafely(event: MotionEvent): Boolean { 144 return event.getEventTime() == eventTime 145 } 146 } 147 withFlagsnull148fun withFlags(flags: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 149 override fun describeTo(description: Description) { 150 description.appendText("With flags = $flags") 151 } 152 153 override fun matchesSafely(event: MotionEvent): Boolean { 154 return event.flags and flags == flags 155 } 156 } 157 withToolTypenull158fun withToolType(toolType: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 159 override fun describeTo(description: Description) { 160 description.appendText("With tool type = $toolType") 161 } 162 163 override fun matchesSafely(event: MotionEvent): Boolean { 164 for (p in 0..<event.getPointerCount()) { 165 if (event.getToolType(p) != toolType) { 166 return false 167 } 168 } 169 return true 170 } 171 } 172 withKeyCodenull173fun withKeyCode(keyCode: Int): Matcher<KeyEvent> = object : TypeSafeMatcher<KeyEvent>() { 174 override fun describeTo(description: Description) { 175 description.appendText("With key code = " + keyCodeToString(keyCode)) 176 } 177 178 override fun matchesSafely(event: KeyEvent): Boolean { 179 return event.keyCode == keyCode 180 } 181 } 182 withEdgeFlagsnull183fun withEdgeFlags(edgeFlags: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 184 override fun describeTo(description: Description) { 185 description.appendText("With edge flags = 0x${edgeFlags.toString(16)}") 186 } 187 188 override fun matchesSafely(event: MotionEvent): Boolean { 189 return (event.edgeFlags and edgeFlags) == edgeFlags 190 } 191 } 192 withDownTimenull193fun withDownTime(downTime: Long): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 194 override fun describeTo(description: Description) { 195 description.appendText("With down time = $downTime") 196 } 197 198 override fun matchesSafely(event: MotionEvent): Boolean { 199 return event.downTime == downTime 200 } 201 } 202 withMetaStatenull203fun withMetaState(metaState: Int): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 204 override fun describeTo(description: Description) { 205 description.appendText("With meta state = 0x${metaState.toString(16)}") 206 } 207 208 override fun matchesSafely(event: MotionEvent): Boolean { 209 return event.metaState == metaState 210 } 211 } 212 withPressurenull213fun withPressure(pressure: Float): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 214 override fun describeTo(description: Description) { 215 description.appendText("With pressure = $pressure") 216 } 217 218 override fun matchesSafely(event: MotionEvent): Boolean { 219 return abs(event.pressure - pressure) < EPSILON 220 } 221 } 222 withSizenull223fun withSize(size: Float): Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 224 override fun describeTo(description: Description) { 225 description.appendText("With size = $size") 226 } 227 228 override fun matchesSafely(event: MotionEvent): Boolean { 229 return abs(event.size - size) < EPSILON 230 } 231 } 232 withXPrecisionnull233fun withXPrecision(xPrecision: Float): 234 Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 235 override fun describeTo(description: Description) { 236 description.appendText("With xPrecision = $xPrecision") 237 } 238 239 override fun matchesSafely(event: MotionEvent): Boolean { 240 return abs(event.xPrecision - xPrecision) < EPSILON 241 } 242 } 243 withYPrecisionnull244fun withYPrecision(yPrecision: Float): 245 Matcher<MotionEvent> = object : TypeSafeMatcher<MotionEvent>() { 246 override fun describeTo(description: Description) { 247 description.appendText("With yPrecision = $yPrecision") 248 } 249 250 override fun matchesSafely(event: MotionEvent): Boolean { 251 return abs(event.yPrecision - yPrecision) < EPSILON 252 } 253 } 254