1 /* 2 * Copyright (C) 2008 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 android.view.cts; 18 19 import static android.view.cts.MotionEventUtils.withCoords; 20 import static android.view.cts.MotionEventUtils.withProperties; 21 22 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withDeviceId; 23 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withDownTime; 24 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withEdgeFlags; 25 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withEventTime; 26 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withMetaState; 27 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withMotionAction; 28 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withPressure; 29 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withRawCoords; 30 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withSize; 31 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withXPrecision; 32 import static com.android.cts.input.inputeventmatchers.InputEventMatchersKt.withYPrecision; 33 34 import static org.hamcrest.CoreMatchers.allOf; 35 import static org.hamcrest.CoreMatchers.is; 36 import static org.hamcrest.CoreMatchers.notNullValue; 37 import static org.hamcrest.MatcherAssert.assertThat; 38 import static org.junit.Assert.assertEquals; 39 import static org.junit.Assert.assertFalse; 40 import static org.junit.Assert.assertNotNull; 41 import static org.junit.Assert.assertNotSame; 42 import static org.junit.Assert.assertTrue; 43 import static org.junit.Assert.fail; 44 45 import android.graphics.Matrix; 46 import android.graphics.PointF; 47 import android.os.Parcel; 48 import android.os.Parcelable; 49 import android.os.SystemClock; 50 import android.platform.test.annotations.AppModeSdkSandbox; 51 import android.text.TextUtils; 52 import android.view.InputDevice; 53 import android.view.KeyEvent; 54 import android.view.MotionEvent; 55 import android.view.MotionEvent.PointerCoords; 56 import android.view.MotionEvent.PointerProperties; 57 import android.view.cts.MotionEventUtils.PointerCoordsBuilder; 58 import android.view.cts.MotionEventUtils.PointerPropertiesBuilder; 59 import android.view.cts.util.NativeHeapLeakDetector; 60 61 import androidx.test.filters.SmallTest; 62 import androidx.test.runner.AndroidJUnit4; 63 64 import com.android.cts.input.inputeventmatchers.InputEventMatchersKt; 65 66 import org.junit.After; 67 import org.junit.Before; 68 import org.junit.Test; 69 import org.junit.runner.RunWith; 70 71 import java.util.LinkedHashSet; 72 import java.util.Set; 73 74 /** 75 * Test {@link MotionEvent}. 76 */ 77 @SmallTest 78 @RunWith(AndroidJUnit4.class) 79 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 80 public class MotionEventTest { 81 private MotionEvent mMotionEvent1; 82 private MotionEvent mMotionEvent2; 83 private MotionEvent mMotionEventDynamic; 84 private long mDownTime; 85 private long mEventTime; 86 private long mEventTimeNano; 87 private static final int NS_PER_MS = 1_000_000; 88 private static final float X_3F = 3.0f; 89 private static final float Y_4F = 4.0f; 90 private static final int META_STATE = KeyEvent.META_SHIFT_ON; 91 private static final float PRESSURE_1F = 1.0f; 92 private static final float SIZE_1F = 1.0f; 93 private static final float X_PRECISION_3F = 3.0f; 94 private static final float Y_PRECISION_4F = 4.0f; 95 private static final int DEVICE_ID_1 = 1; 96 private static final int EDGE_FLAGS = MotionEvent.EDGE_TOP; 97 private static final float DELTA = 0.01f; 98 private static final float RAW_COORD_TOLERANCE = 0.001f; 99 100 // Underestimated from ~528 B to breach threshold when leaked 101 private static final int APPROX_MOTION_EVENT_SIZE_BYTES = 500; 102 private static final int NUM_MOTION_EVENT_ALLOCATIONS = 103 NativeHeapLeakDetector.MEMORY_LEAK_THRESHOLD_KB * 1024 / APPROX_MOTION_EVENT_SIZE_BYTES; 104 nativeMotionEventTest(MotionEvent event)105 private static native void nativeMotionEventTest(MotionEvent event); 106 obtainNativeMotionEventCopyFromJava(MotionEvent event)107 private static native void obtainNativeMotionEventCopyFromJava(MotionEvent event); 108 obtainMotionEventCopyFromNative(MotionEvent event)109 private static native MotionEvent obtainMotionEventCopyFromNative(MotionEvent event); 110 111 static { 112 System.loadLibrary("ctsview_jni"); 113 } 114 115 @Before setup()116 public void setup() { 117 mDownTime = SystemClock.uptimeMillis(); 118 mEventTime = SystemClock.uptimeMillis(); 119 mEventTimeNano = mEventTime * NS_PER_MS; 120 mMotionEvent1 = MotionEvent.obtain(mDownTime, mEventTime, 121 MotionEvent.ACTION_MOVE, X_3F, Y_4F, META_STATE); 122 mMotionEvent2 = MotionEvent.obtain(mDownTime, mEventTime, 123 MotionEvent.ACTION_MOVE, X_3F, Y_4F, PRESSURE_1F, SIZE_1F, META_STATE, 124 X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS); 125 } 126 127 @After teardown()128 public void teardown() { 129 if (null != mMotionEvent1) { 130 mMotionEvent1.recycle(); 131 } 132 if (null != mMotionEvent2) { 133 mMotionEvent2.recycle(); 134 } 135 if (null != mMotionEventDynamic) { 136 mMotionEventDynamic.recycle(); 137 } 138 } 139 140 @Test testObtainBasic()141 public void testObtainBasic() { 142 mMotionEvent1 = MotionEvent.obtain(mDownTime, mEventTime, 143 MotionEvent.ACTION_DOWN, X_3F, Y_4F, META_STATE); 144 assertNotNull(mMotionEvent1); 145 assertEquals(mDownTime, mMotionEvent1.getDownTime()); 146 assertEquals(mEventTime, mMotionEvent1.getEventTime()); 147 assertEquals(mEventTimeNano, mMotionEvent1.getEventTimeNanos()); 148 assertEquals(MotionEvent.ACTION_DOWN, mMotionEvent1.getAction()); 149 assertEquals(X_3F, mMotionEvent1.getX(), DELTA); 150 assertEquals(Y_4F, mMotionEvent1.getY(), DELTA); 151 assertEquals(X_3F, mMotionEvent1.getRawX(), DELTA); 152 assertEquals(Y_4F, mMotionEvent1.getRawY(), DELTA); 153 assertEquals(META_STATE, mMotionEvent1.getMetaState()); 154 assertEquals(0, mMotionEvent1.getDeviceId()); 155 assertEquals(0, mMotionEvent1.getEdgeFlags()); 156 assertEquals(PRESSURE_1F, mMotionEvent1.getPressure(), DELTA); 157 assertEquals(SIZE_1F, mMotionEvent1.getSize(), DELTA); 158 assertEquals(1.0f, mMotionEvent1.getXPrecision(), DELTA); 159 assertEquals(1.0f, mMotionEvent1.getYPrecision(), DELTA); 160 } 161 162 @Test testObtainFromMotionEvent()163 public void testObtainFromMotionEvent() { 164 mMotionEventDynamic = MotionEvent.obtain(mMotionEvent2); 165 assertNotNull(mMotionEventDynamic); 166 assertEquals(mMotionEvent2.getDownTime(), mMotionEventDynamic.getDownTime()); 167 assertEquals(mMotionEvent2.getEventTime(), mMotionEventDynamic.getEventTime()); 168 assertEquals(mMotionEvent2.getEventTimeNanos(), mMotionEventDynamic.getEventTimeNanos()); 169 assertEquals(mMotionEvent2.getAction(), mMotionEventDynamic.getAction()); 170 assertEquals(mMotionEvent2.getX(), mMotionEventDynamic.getX(), DELTA); 171 assertEquals(mMotionEvent2.getY(), mMotionEventDynamic.getY(), DELTA); 172 assertEquals(mMotionEvent2.getX(), mMotionEventDynamic.getRawX(), DELTA); 173 assertEquals(mMotionEvent2.getY(), mMotionEventDynamic.getRawY(), DELTA); 174 assertEquals(mMotionEvent2.getMetaState(), mMotionEventDynamic.getMetaState()); 175 assertEquals(mMotionEvent2.getDeviceId(), mMotionEventDynamic.getDeviceId()); 176 assertEquals(mMotionEvent2.getEdgeFlags(), mMotionEventDynamic.getEdgeFlags()); 177 assertEquals(mMotionEvent2.getPressure(), mMotionEventDynamic.getPressure(), DELTA); 178 assertEquals(mMotionEvent2.getSize(), mMotionEventDynamic.getSize(), DELTA); 179 assertEquals(mMotionEvent2.getXPrecision(), mMotionEventDynamic.getXPrecision(), DELTA); 180 assertEquals(mMotionEvent2.getYPrecision(), mMotionEventDynamic.getYPrecision(), DELTA); 181 } 182 183 @Test testObtainAllFields()184 public void testObtainAllFields() { 185 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 186 MotionEvent.ACTION_DOWN, X_3F, Y_4F, PRESSURE_1F, SIZE_1F, META_STATE, 187 X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS); 188 assertNotNull(mMotionEventDynamic); 189 assertEquals(mDownTime, mMotionEventDynamic.getDownTime()); 190 assertEquals(mEventTime, mMotionEventDynamic.getEventTime()); 191 assertEquals(mEventTimeNano, mMotionEventDynamic.getEventTimeNanos()); 192 assertEquals(MotionEvent.ACTION_DOWN, mMotionEventDynamic.getAction()); 193 assertEquals(X_3F, mMotionEventDynamic.getX(), DELTA); 194 assertEquals(Y_4F, mMotionEventDynamic.getY(), DELTA); 195 assertEquals(X_3F, mMotionEventDynamic.getRawX(), DELTA); 196 assertEquals(Y_4F, mMotionEventDynamic.getRawY(), DELTA); 197 assertEquals(META_STATE, mMotionEventDynamic.getMetaState()); 198 assertEquals(DEVICE_ID_1, mMotionEventDynamic.getDeviceId()); 199 assertEquals(EDGE_FLAGS, mMotionEventDynamic.getEdgeFlags()); 200 assertEquals(PRESSURE_1F, mMotionEventDynamic.getPressure(), DELTA); 201 assertEquals(SIZE_1F, mMotionEventDynamic.getSize(), DELTA); 202 assertEquals(X_PRECISION_3F, mMotionEventDynamic.getXPrecision(), DELTA); 203 assertEquals(Y_PRECISION_4F, mMotionEventDynamic.getYPrecision(), DELTA); 204 } 205 206 @Test testObtainFromPropertyArrays()207 public void testObtainFromPropertyArrays() { 208 PointerCoordsBuilder coordsBuilder0 = 209 withCoords(X_3F, Y_4F).withPressure(PRESSURE_1F).withSize(SIZE_1F). 210 withTool(1.2f, 1.4f).withGenericAxis1(2.6f); 211 PointerCoordsBuilder coordsBuilder1 = 212 withCoords(X_3F + 1.0f, Y_4F - 2.0f).withPressure(PRESSURE_1F + 0.2f). 213 withSize(SIZE_1F + 0.5f).withTouch(2.2f, 0.6f).withGenericAxis1(2.6f); 214 215 PointerPropertiesBuilder propertiesBuilder0 = 216 withProperties(0, MotionEvent.TOOL_TYPE_FINGER); 217 PointerPropertiesBuilder propertiesBuilder1 = 218 withProperties(1, MotionEvent.TOOL_TYPE_FINGER); 219 220 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 221 MotionEvent.ACTION_MOVE, 2, 222 new PointerProperties[] { propertiesBuilder0.build(), propertiesBuilder1.build() }, 223 new PointerCoords[] { coordsBuilder0.build(), coordsBuilder1.build() }, 224 META_STATE, 0, X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS, 225 InputDevice.SOURCE_TOUCHSCREEN, 0); 226 227 // We expect to have data for two pointers 228 assertEquals(2, mMotionEventDynamic.getPointerCount()); 229 assertEquals(0, mMotionEventDynamic.getPointerId(0)); 230 assertEquals(1, mMotionEventDynamic.getPointerId(1)); 231 assertEquals(0, mMotionEventDynamic.getFlags()); 232 verifyCurrentPointerData(mMotionEventDynamic, 233 new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 }, 234 new PointerCoordsBuilder[] { coordsBuilder0, coordsBuilder1 }); 235 } 236 237 @Test testObtainWithClassification()238 public void testObtainWithClassification() { 239 PointerCoordsBuilder coordsBuilder = 240 withCoords(X_3F, Y_4F).withPressure(PRESSURE_1F).withSize(SIZE_1F) 241 .withTool(1.2f, 1.4f).withGenericAxis1(2.6f); 242 PointerPropertiesBuilder propertiesBuilder = 243 withProperties(0, MotionEvent.TOOL_TYPE_FINGER); 244 245 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 246 MotionEvent.ACTION_MOVE, 1, 247 new PointerProperties[] { propertiesBuilder.build() }, 248 new PointerCoords[] { coordsBuilder.build() }, 249 META_STATE, 0, X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS, 250 InputDevice.SOURCE_TOUCHSCREEN, 0, 0, MotionEvent.CLASSIFICATION_DEEP_PRESS); 251 assertEquals(MotionEvent.CLASSIFICATION_DEEP_PRESS, 252 mMotionEventDynamic.getClassification()); 253 } 254 255 @Test testObtainNoHistory()256 public void testObtainNoHistory() { 257 // Add two batch to one of our events 258 mMotionEvent2.addBatch(mEventTime + 10, X_3F + 5.0f, Y_4F + 5.0f, 0.5f, 0.5f, 0); 259 mMotionEvent2.addBatch(mEventTime + 20, X_3F + 10.0f, Y_4F + 15.0f, 2.0f, 3.0f, 0); 260 // The newly added batch should be the "new" values of the event 261 withCoords(X_3F + 10.0f, Y_4F + 15.0f).withPressure(2.0f).withSize(3.0f). 262 verifyMatches(mMotionEvent2); 263 assertEquals(mEventTime + 20, mMotionEvent2.getEventTime()); 264 assertEquals((mEventTime + 20) * NS_PER_MS, mMotionEvent2.getEventTimeNanos()); 265 // We should have history with 2 entries 266 assertEquals(2, mMotionEvent2.getHistorySize()); 267 // The previous data should be history at index 1 268 withCoords(X_3F + 5.0f, Y_4F + 5.0f).withPressure(0.5f).withSize(0.5f). 269 verifyMatchesHistorical(mMotionEvent2, 1); 270 assertEquals(mEventTime + 10, mMotionEvent2.getHistoricalEventTime(1)); 271 assertEquals((mEventTime + 10) * NS_PER_MS, mMotionEvent2.getHistoricalEventTimeNanos(1)); 272 // And the original data should be history at index 0 273 withCoords(X_3F, Y_4F).withPressure(1.0f).withSize(1.0f). 274 verifyMatchesHistorical(mMotionEvent2, 0); 275 assertEquals(mEventTime, mMotionEvent2.getHistoricalEventTime(0)); 276 assertEquals(mEventTimeNano, mMotionEvent2.getHistoricalEventTimeNanos(0)); 277 278 assertEquals(2, mMotionEvent2.getHistorySize()); 279 280 mMotionEventDynamic = MotionEvent.obtainNoHistory(mMotionEvent2); 281 // The newly obtained event should have the matching current content 282 withCoords(X_3F + 10.0f, Y_4F + 15.0f).withPressure(2.0f).withSize(3.0f). 283 verifyMatches(mMotionEvent2); 284 // And no history 285 assertEquals(0, mMotionEventDynamic.getHistorySize()); 286 } 287 288 @Test testFlagCanceled()289 public void testFlagCanceled() { 290 final long eventTime = SystemClock.uptimeMillis(); 291 MotionEvent event = MotionEvent.obtain(eventTime, eventTime, MotionEvent.ACTION_CANCEL, 292 /*x=*/ 0, /*y=*/ 0, 0); 293 assertEquals(MotionEvent.FLAG_CANCELED, event.getFlags() & MotionEvent.FLAG_CANCELED); 294 } 295 296 @Test testAccessAction()297 public void testAccessAction() { 298 assertEquals(MotionEvent.ACTION_MOVE, mMotionEvent1.getAction()); 299 300 mMotionEvent1.setAction(MotionEvent.ACTION_UP); 301 assertEquals(MotionEvent.ACTION_UP, mMotionEvent1.getAction()); 302 303 mMotionEvent1.setAction(MotionEvent.ACTION_MOVE); 304 assertEquals(MotionEvent.ACTION_MOVE, mMotionEvent1.getAction()); 305 306 mMotionEvent1.setAction(MotionEvent.ACTION_CANCEL); 307 assertEquals(MotionEvent.ACTION_CANCEL, mMotionEvent1.getAction()); 308 assertEquals(MotionEvent.FLAG_CANCELED, 309 mMotionEvent1.getFlags() & MotionEvent.FLAG_CANCELED); 310 311 mMotionEvent1.setAction(MotionEvent.ACTION_DOWN); 312 assertEquals(MotionEvent.ACTION_DOWN, mMotionEvent1.getAction()); 313 assertEquals(0, mMotionEvent1.getFlags() & MotionEvent.FLAG_CANCELED); 314 } 315 316 @Test testDescribeContents()317 public void testDescribeContents() { 318 // make sure this method never throw any exception. 319 mMotionEvent2.describeContents(); 320 } 321 322 @Test testAccessEdgeFlags()323 public void testAccessEdgeFlags() { 324 assertEquals(EDGE_FLAGS, mMotionEvent2.getEdgeFlags()); 325 326 int edgeFlags = 10; 327 mMotionEvent2.setEdgeFlags(edgeFlags); 328 assertEquals(edgeFlags, mMotionEvent2.getEdgeFlags()); 329 } 330 331 @Test testWriteToParcel()332 public void testWriteToParcel() { 333 Parcel parcel = Parcel.obtain(); 334 mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 335 parcel.setDataPosition(0); 336 337 MotionEvent motionEvent = MotionEvent.CREATOR.createFromParcel(parcel); 338 assertEquals(mMotionEvent2.getRawY(), motionEvent.getRawY(), DELTA); 339 assertEquals(mMotionEvent2.getRawX(), motionEvent.getRawX(), DELTA); 340 assertEquals(mMotionEvent2.getY(), motionEvent.getY(), DELTA); 341 assertEquals(mMotionEvent2.getX(), motionEvent.getX(), DELTA); 342 assertEquals(mMotionEvent2.getAction(), motionEvent.getAction()); 343 assertEquals(mMotionEvent2.getDownTime(), motionEvent.getDownTime()); 344 assertEquals(mMotionEvent2.getEventTime(), motionEvent.getEventTime()); 345 assertEquals(mMotionEvent2.getEventTimeNanos(), motionEvent.getEventTimeNanos()); 346 assertEquals(mMotionEvent2.getEdgeFlags(), motionEvent.getEdgeFlags()); 347 assertEquals(mMotionEvent2.getDeviceId(), motionEvent.getDeviceId()); 348 } 349 350 @Test testReadFromParcelWithInvalidPointerCountSize()351 public void testReadFromParcelWithInvalidPointerCountSize() { 352 Parcel parcel = Parcel.obtain(); 353 mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 354 355 // Move to pointer id count. 356 parcel.setDataPosition(4); 357 // Use a very large pointer count, which should make this parcel invalid. 358 parcel.writeInt(117); 359 360 parcel.setDataPosition(0); 361 try { 362 MotionEvent.CREATOR.createFromParcel(parcel); 363 fail("deserialized invalid parcel"); 364 } catch (RuntimeException e) { 365 // Expected. 366 } 367 } 368 369 @Test testReadFromParcelWithInvalidSampleSize()370 public void testReadFromParcelWithInvalidSampleSize() { 371 Parcel parcel = Parcel.obtain(); 372 mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 373 374 // Move to sample count. 375 parcel.setDataPosition(2 * 4); 376 parcel.writeInt(0x000f0000); 377 378 parcel.setDataPosition(0); 379 try { 380 MotionEvent.CREATOR.createFromParcel(parcel); 381 fail("deserialized invalid parcel"); 382 } catch (RuntimeException e) { 383 // Expected. 384 } 385 } 386 387 @SuppressWarnings("ReturnValueIgnored") 388 @Test testToString()389 public void testToString() { 390 // make sure this method never throw exception. 391 mMotionEvent2.toString(); 392 } 393 394 @Test testOffsetLocationForPointerSource()395 public void testOffsetLocationForPointerSource() { 396 assertEquals(X_3F, mMotionEvent2.getX(), DELTA); 397 assertEquals(Y_4F, mMotionEvent2.getY(), DELTA); 398 mMotionEvent2.setSource(InputDevice.SOURCE_TOUCHSCREEN); 399 400 float offsetX = 1.0f; 401 float offsetY = 1.0f; 402 mMotionEvent2.offsetLocation(offsetX, offsetY); 403 withCoords(X_3F + offsetX, Y_4F + offsetY) 404 .withPressure(PRESSURE_1F) 405 .withSize(SIZE_1F) 406 .verifyMatches(mMotionEvent2); 407 } 408 409 @Test testNoLocationOffsetForNonPointerSource()410 public void testNoLocationOffsetForNonPointerSource() { 411 assertEquals(X_3F, mMotionEvent2.getX(), DELTA); 412 assertEquals(Y_4F, mMotionEvent2.getY(), DELTA); 413 mMotionEvent2.setSource(InputDevice.SOURCE_TOUCHPAD); 414 415 float offsetX = 1.0f; 416 float offsetY = 1.0f; 417 mMotionEvent2.offsetLocation(offsetX, offsetY); 418 withCoords(X_3F, Y_4F) 419 .withPressure(PRESSURE_1F) 420 .withSize(SIZE_1F) 421 .verifyMatches(mMotionEvent2); 422 } 423 424 @Test testSetLocation()425 public void testSetLocation() { 426 assertEquals(X_3F, mMotionEvent2.getX(), DELTA); 427 assertEquals(Y_4F, mMotionEvent2.getY(), DELTA); 428 mMotionEvent2.setSource(InputDevice.SOURCE_TOUCHSCREEN); 429 430 mMotionEvent2.setLocation(0.0f, 0.0f); 431 withCoords(0.0f, 0.0f).withPressure(PRESSURE_1F).withSize(SIZE_1F). 432 verifyMatches(mMotionEvent2); 433 434 mMotionEvent2.setLocation(2.0f, 2.0f); 435 withCoords(2.0f, 2.0f).withPressure(PRESSURE_1F).withSize(SIZE_1F). 436 verifyMatches(mMotionEvent2); 437 } 438 439 @Test testGetHistoricalData()440 public void testGetHistoricalData() { 441 assertEquals(0, mMotionEvent2.getHistorySize()); 442 443 mMotionEvent2.addBatch(mEventTime + 10, X_3F + 5.0f, Y_4F + 5.0f, 0.5f, 0.5f, 0); 444 // The newly added batch should be the "new" values of the event 445 withCoords(X_3F + 5.0f, Y_4F + 5.0f).withPressure(0.5f).withSize(0.5f). 446 verifyMatches(mMotionEvent2); 447 assertEquals(mEventTime + 10, mMotionEvent2.getEventTime()); 448 assertEquals((mEventTime + 10) * NS_PER_MS, mMotionEvent2.getEventTimeNanos()); 449 // We should have history with 1 entry 450 assertEquals(1, mMotionEvent2.getHistorySize()); 451 // And the previous / original data should be history at index 0 452 assertEquals(1, mMotionEvent2.getHistorySize()); 453 withCoords(X_3F, Y_4F).withPressure(1.0f).withSize(1.0f). 454 verifyMatchesHistorical(mMotionEvent2, 0); 455 assertEquals(mEventTime, mMotionEvent2.getHistoricalEventTime(0)); 456 assertEquals(mEventTimeNano, mMotionEvent2.getHistoricalEventTimeNanos(0)); 457 458 // Add another update batch to our event 459 mMotionEvent2.addBatch(mEventTime + 20, X_3F + 10.0f, Y_4F + 15.0f, 2.0f, 3.0f, 0); 460 // The newly added batch should be the "new" values of the event 461 withCoords(X_3F + 10.0f, Y_4F + 15.0f).withPressure(2.0f).withSize(3.0f). 462 verifyMatches(mMotionEvent2); 463 assertEquals(mEventTime + 20, mMotionEvent2.getEventTime()); 464 assertEquals((mEventTime + 20) * NS_PER_MS, mMotionEvent2.getEventTimeNanos()); 465 // We should have history with 2 entries 466 assertEquals(2, mMotionEvent2.getHistorySize()); 467 // The previous data should be history at index 1 468 withCoords(X_3F + 5.0f, Y_4F + 5.0f).withPressure(0.5f).withSize(0.5f). 469 verifyMatchesHistorical(mMotionEvent2, 1); 470 assertEquals(mEventTime + 10, mMotionEvent2.getHistoricalEventTime(1)); 471 assertEquals((mEventTime + 10) * NS_PER_MS, mMotionEvent2.getHistoricalEventTimeNanos(1)); 472 // And the original data should be history at index 0 473 withCoords(X_3F, Y_4F).withPressure(1.0f).withSize(1.0f). 474 verifyMatchesHistorical(mMotionEvent2, 0); 475 assertEquals(mEventTime, mMotionEvent2.getHistoricalEventTime(0)); 476 assertEquals(mEventTimeNano, mMotionEvent2.getHistoricalEventTimeNanos(0)); 477 } 478 verifyCurrentPointerData(MotionEvent motionEvent, PointerPropertiesBuilder[] pointerPropertiesBuilders, PointerCoordsBuilder[] pointerCoordsBuilders)479 private static void verifyCurrentPointerData(MotionEvent motionEvent, 480 PointerPropertiesBuilder[] pointerPropertiesBuilders, 481 PointerCoordsBuilder[] pointerCoordsBuilders) { 482 assertNotNull(motionEvent); 483 assertNotNull(pointerPropertiesBuilders); 484 assertNotNull(pointerCoordsBuilders); 485 final int pointerCount = motionEvent.getPointerCount(); 486 assertEquals(pointerCount, pointerPropertiesBuilders.length); 487 assertEquals(pointerCount, pointerCoordsBuilders.length); 488 489 // Test that we have the expected data fetched via MotionEvent.getPointerCoords API 490 for (int i = 0; i < pointerCount; i++) { 491 pointerCoordsBuilders[i].verifyMatchesPointerCoords(motionEvent, i); 492 } 493 494 // Test that we have the expected data fetched via per-field MotionEvent getter APIs 495 for (int i = 0; i < pointerCount; i++) { 496 pointerCoordsBuilders[i].verifyMatches(motionEvent, i); 497 } 498 499 // Test that we have the expected data fetched via MotionEvent.getPointerProperties API 500 for (int i = 0; i < pointerCount; i++) { 501 pointerPropertiesBuilders[i].verifyMatchesPointerProperties(motionEvent, i); 502 } 503 504 // Test that we have the expected data fetched via per-field MotionEvent getter APIs 505 for (int i = 0; i < pointerCount; i++) { 506 pointerPropertiesBuilders[i].verifyMatches(motionEvent, i); 507 } 508 } 509 verifyHistoricalPointerData(MotionEvent motionEvent, PointerCoordsBuilder[] pointerCoordsBuilders, int pos)510 private static void verifyHistoricalPointerData(MotionEvent motionEvent, 511 PointerCoordsBuilder[] pointerCoordsBuilders, int pos) { 512 assertNotNull(motionEvent); 513 assertNotNull(pointerCoordsBuilders); 514 final int pointerCount = motionEvent.getPointerCount(); 515 assertEquals(pointerCount, pointerCoordsBuilders.length); 516 517 // Test that we have the expected data fetched via MotionEvent.getHistoricalPointerCoords 518 // API 519 for (int i = 0; i < pointerCount; i++) { 520 pointerCoordsBuilders[i].verifyMatchesHistoricalPointerCoords(motionEvent, i, pos); 521 } 522 523 // Test that we have the expected data fetched via per-field MotionEvent getter APIs 524 for (int i = 0; i < pointerCount; i++) { 525 pointerCoordsBuilders[i].verifyMatchesHistorical(motionEvent, i, pos); 526 } 527 } 528 529 @Test testGetCurrentDataWithTwoPointers()530 public void testGetCurrentDataWithTwoPointers() { 531 PointerCoordsBuilder coordsBuilder0 = 532 withCoords(10.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 533 1.4f).withGenericAxis1(4.4f); 534 PointerCoordsBuilder coordsBuilder1 = 535 withCoords(30.0f, 40.0f).withPressure(1.4f).withSize(3.0f).withTouch(2.2f, 536 0.6f).withGenericAxis1(6.6f); 537 538 PointerPropertiesBuilder propertiesBuilder0 = 539 withProperties(0, MotionEvent.TOOL_TYPE_FINGER); 540 PointerPropertiesBuilder propertiesBuilder1 = 541 withProperties(1, MotionEvent.TOOL_TYPE_FINGER); 542 543 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 544 MotionEvent.ACTION_MOVE, 2, 545 new PointerProperties[] { propertiesBuilder0.build(), propertiesBuilder1.build() }, 546 new PointerCoords[] { coordsBuilder0.build(), coordsBuilder1.build() }, 547 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0); 548 549 // We expect to have data for two pointers 550 assertEquals(2, mMotionEventDynamic.getPointerCount()); 551 assertEquals(0, mMotionEventDynamic.getPointerId(0)); 552 assertEquals(1, mMotionEventDynamic.getPointerId(1)); 553 assertEquals(0, mMotionEventDynamic.getFlags()); 554 verifyCurrentPointerData(mMotionEventDynamic, 555 new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 }, 556 new PointerCoordsBuilder[] { coordsBuilder0, coordsBuilder1 }); 557 } 558 559 /** 560 * Verify we can get raw coordinates for specific pointers using MotionEvent#getRawX(int) and 561 * MotionEvent#getRawY(int). Also verity MotionEvent#getRawX() and MotionEvent#getRawY() 562 * returns the raw coordinates of pointer with pointer index 0. 563 */ 564 @Test testGetRawCoordsWithTwoPointers()565 public void testGetRawCoordsWithTwoPointers() { 566 PointerCoordsBuilder coordsBuilder0 = 567 withCoords(10.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 568 1.4f).withGenericAxis1(4.4f); 569 PointerCoordsBuilder coordsBuilder1 = 570 withCoords(30.0f, 40.0f).withPressure(1.4f).withSize(3.0f).withTouch(2.2f, 571 0.6f).withGenericAxis1(6.6f); 572 573 PointerPropertiesBuilder propertiesBuilder0 = 574 withProperties(0, MotionEvent.TOOL_TYPE_FINGER); 575 PointerPropertiesBuilder propertiesBuilder1 = 576 withProperties(1, MotionEvent.TOOL_TYPE_FINGER); 577 578 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 579 MotionEvent.ACTION_MOVE, 2, 580 new PointerProperties[] { propertiesBuilder0.build(), propertiesBuilder1.build() }, 581 new PointerCoords[] { coordsBuilder0.build(), coordsBuilder1.build() }, 582 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0); 583 584 assertEquals(10.0f, mMotionEventDynamic.getRawX(), RAW_COORD_TOLERANCE); 585 assertEquals(20.0f, mMotionEventDynamic.getRawY(), RAW_COORD_TOLERANCE); 586 587 // Assert that getRawX returns the results for the first pointer index. 588 assertEquals(mMotionEventDynamic.getRawX(), mMotionEventDynamic.getRawX(0), 589 RAW_COORD_TOLERANCE); 590 assertEquals(mMotionEventDynamic.getRawY(), mMotionEventDynamic.getRawY(0), 591 RAW_COORD_TOLERANCE); 592 593 assertEquals(30.0f, mMotionEventDynamic.getRawX(1), RAW_COORD_TOLERANCE); 594 assertEquals(40.0f, mMotionEventDynamic.getRawY(1), RAW_COORD_TOLERANCE); 595 } 596 597 598 @Test testGetHistoricalDataWithTwoPointers()599 public void testGetHistoricalDataWithTwoPointers() { 600 // PHASE 1 - construct the initial data for the event 601 PointerCoordsBuilder coordsBuilderInitial0 = 602 withCoords(10.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 1.4f). 603 withTouch(0.7f, 0.6f).withOrientation(2.0f).withGenericAxis1(4.4f); 604 PointerCoordsBuilder coordsBuilderInitial1 = 605 withCoords(30.0f, 40.0f).withPressure(1.4f).withSize(3.0f).withTool(1.3f, 1.7f). 606 withTouch(2.7f, 3.6f).withOrientation(1.0f).withGenericAxis1(5.4f); 607 608 PointerPropertiesBuilder propertiesBuilder0 = 609 withProperties(0, MotionEvent.TOOL_TYPE_FINGER); 610 PointerPropertiesBuilder propertiesBuilder1 = 611 withProperties(1, MotionEvent.TOOL_TYPE_FINGER); 612 613 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 614 MotionEvent.ACTION_MOVE, 2, 615 new PointerProperties[] { propertiesBuilder0.build(), propertiesBuilder1.build() }, 616 new PointerCoords[] { 617 coordsBuilderInitial0.build(), coordsBuilderInitial1.build() }, 618 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0); 619 620 // We expect to have data for two pointers 621 assertEquals(2, mMotionEventDynamic.getPointerCount()); 622 assertEquals(0, mMotionEventDynamic.getPointerId(0)); 623 assertEquals(1, mMotionEventDynamic.getPointerId(1)); 624 assertEquals(0, mMotionEventDynamic.getFlags()); 625 verifyCurrentPointerData(mMotionEventDynamic, 626 new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 }, 627 new PointerCoordsBuilder[] { coordsBuilderInitial0, coordsBuilderInitial1 }); 628 629 // PHASE 2 - add a new batch of data to our event 630 PointerCoordsBuilder coordsBuilderNext0 = 631 withCoords(15.0f, 25.0f).withPressure(1.6f).withSize(2.2f).withTool(1.2f, 1.4f). 632 withTouch(1.0f, 0.9f).withOrientation(2.2f).withGenericAxis1(7.4f); 633 PointerCoordsBuilder coordsBuilderNext1 = 634 withCoords(35.0f, 45.0f).withPressure(1.8f).withSize(3.2f).withTool(1.2f, 1.4f). 635 withTouch(0.7f, 0.6f).withOrientation(2.9f).withGenericAxis1(8.4f); 636 637 mMotionEventDynamic.addBatch(mEventTime + 10, 638 new PointerCoords[] { coordsBuilderNext0.build(), coordsBuilderNext1.build() }, 0); 639 // We still expect to have data for two pointers 640 assertEquals(2, mMotionEventDynamic.getPointerCount()); 641 assertEquals(0, mMotionEventDynamic.getPointerId(0)); 642 assertEquals(1, mMotionEventDynamic.getPointerId(1)); 643 assertEquals(0, mMotionEventDynamic.getFlags()); 644 645 // The newly added batch should be the "new" values of the event 646 verifyCurrentPointerData(mMotionEventDynamic, 647 new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 }, 648 new PointerCoordsBuilder[] { coordsBuilderNext0, coordsBuilderNext1 }); 649 assertEquals(mEventTime + 10, mMotionEventDynamic.getEventTime()); 650 assertEquals((mEventTime + 10) * NS_PER_MS, mMotionEventDynamic.getEventTimeNanos()); 651 // We should have history with 1 entry 652 assertEquals(1, mMotionEventDynamic.getHistorySize()); 653 // And the previous / original data should be history at index 0 654 assertEquals(1, mMotionEventDynamic.getHistorySize()); 655 verifyHistoricalPointerData(mMotionEventDynamic, 656 new PointerCoordsBuilder[] { coordsBuilderInitial0, coordsBuilderInitial1 }, 657 0); 658 659 // PHASE 3 - add one more new batch of data to our event 660 PointerCoordsBuilder coordsBuilderLast0 = 661 withCoords(18.0f, 28.0f).withPressure(1.1f).withSize(2.9f).withTool(1.5f, 1.9f). 662 withTouch(1.2f, 5.0f).withOrientation(3.1f).withGenericAxis1(1.4f); 663 PointerCoordsBuilder coordsBuilderLast1 = 664 withCoords(38.0f, 48.0f).withPressure(1.2f).withSize(2.5f).withTool(0.2f, 0.4f). 665 withTouch(2.7f, 4.6f).withOrientation(0.2f).withGenericAxis1(5.4f); 666 667 mMotionEventDynamic.addBatch(mEventTime + 20, 668 new PointerCoords[] { coordsBuilderLast0.build(), coordsBuilderLast1.build() }, 0); 669 // We still expect to have data for two pointers 670 assertEquals(2, mMotionEventDynamic.getPointerCount()); 671 assertEquals(0, mMotionEventDynamic.getPointerId(0)); 672 assertEquals(1, mMotionEventDynamic.getPointerId(1)); 673 assertEquals(0, mMotionEventDynamic.getFlags()); 674 675 // The newly added batch should be the "new" values of the event 676 verifyCurrentPointerData(mMotionEventDynamic, 677 new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 }, 678 new PointerCoordsBuilder[] { coordsBuilderLast0, coordsBuilderLast1 }); 679 assertEquals(mEventTime + 20, mMotionEventDynamic.getEventTime()); 680 assertEquals((mEventTime + 20) * NS_PER_MS, mMotionEventDynamic.getEventTimeNanos()); 681 // We should have history with 2 entries 682 assertEquals(2, mMotionEventDynamic.getHistorySize()); 683 // The previous data should be history at index 1 684 verifyHistoricalPointerData(mMotionEventDynamic, 685 new PointerCoordsBuilder[] { coordsBuilderNext0, coordsBuilderNext1 }, 686 1); 687 assertEquals(mEventTime + 10, mMotionEventDynamic.getHistoricalEventTime(1)); 688 assertEquals((mEventTime + 10) * NS_PER_MS, 689 mMotionEventDynamic.getHistoricalEventTimeNanos(1)); 690 // And the original data should be history at index 0 691 verifyHistoricalPointerData(mMotionEventDynamic, 692 new PointerCoordsBuilder[] { coordsBuilderInitial0, coordsBuilderInitial1 }, 693 0); 694 assertEquals(mEventTime, mMotionEventDynamic.getHistoricalEventTime(0)); 695 assertEquals(mEventTimeNano, mMotionEventDynamic.getHistoricalEventTimeNanos(0)); 696 } 697 698 @Test testGetHistorySize()699 public void testGetHistorySize() { 700 long eventTime = SystemClock.uptimeMillis(); 701 float x = 10.0f; 702 float y = 20.0f; 703 float pressure = 1.0f; 704 float size = 1.0f; 705 706 mMotionEvent2.setAction(MotionEvent.ACTION_DOWN); 707 assertEquals(0, mMotionEvent2.getHistorySize()); 708 709 mMotionEvent2.setAction(MotionEvent.ACTION_MOVE); 710 mMotionEvent2.addBatch(eventTime, x, y, pressure, size, 0); 711 assertEquals(1, mMotionEvent2.getHistorySize()); 712 } 713 714 @Test testRecycle()715 public void testRecycle() { 716 mMotionEvent2.setAction(MotionEvent.ACTION_MOVE); 717 assertEquals(0, mMotionEvent2.getHistorySize()); 718 mMotionEvent2.addBatch(mEventTime, 10.0f, 5.0f, 1.0f, 0.0f, 0); 719 assertEquals(1, mMotionEvent2.getHistorySize()); 720 721 mMotionEvent2.recycle(); 722 723 try { 724 mMotionEvent2.recycle(); 725 fail("recycle() should throw an exception when the event has already been recycled."); 726 } catch (RuntimeException ex) { 727 } 728 729 mMotionEvent2 = null; // since it was recycled, don't try to recycle again in tear down 730 } 731 732 @Test(expected=IllegalArgumentException.class) testTransformShouldThrowWhenMatrixIsNull()733 public void testTransformShouldThrowWhenMatrixIsNull() { 734 // transform() should throw an exception when matrix is null 735 mMotionEvent1.transform(null); 736 } 737 738 @Test testTransformShouldApplyMatrixToPointsAndPreserveRawPosition()739 public void testTransformShouldApplyMatrixToPointsAndPreserveRawPosition() { 740 // Generate some points on a circle, then assign each point to a pointer. 741 // The location of pointer 'i' is a point on a circle of radius ROTATION centered at (3,2) 742 // at an angle of ARC * i degrees clockwise relative to the Y axis. 743 // The geometrical representation is irrelevant to the test, it's just easy to generate 744 // and check rotation. We set the orientation to the same angle. 745 // Coordinate system: down is increasing Y, right is increasing X. 746 final float PI_180 = (float) (Math.PI / 180); 747 final float RADIUS = 10; 748 final float ARC = 36; 749 final float ROTATION = ARC * 2; 750 751 final int pointerCount = 11; 752 final int[] pointerIds = new int[pointerCount]; 753 final PointerCoords[] pointerCoords = new PointerCoords[pointerCount]; 754 final PointerCoords[] originalRawCoords = new PointerCoords[pointerCount]; 755 for (int i = 0; i < pointerCount; i++) { 756 final PointerCoords c = new PointerCoords(); 757 final float angle = (float) (i * ARC * PI_180); 758 pointerIds[i] = i; 759 pointerCoords[i] = c; 760 c.x = (float) (Math.sin(angle) * RADIUS + 3); 761 c.y = (float) (- Math.cos(angle) * RADIUS + 2); 762 c.orientation = angle; 763 originalRawCoords[i] = new PointerCoords(c); 764 } 765 final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 766 pointerCount, pointerIds, pointerCoords, 0, 0, 0, 0, 0, 767 InputDevice.SOURCE_TOUCHSCREEN, 0); 768 dump("Original points.", event); 769 770 // Check original raw X and Y assumption. 771 for (int i = 0; i < pointerCount; i++) { 772 assertEquals(originalRawCoords[i].x, event.getRawX(i), RAW_COORD_TOLERANCE); 773 assertEquals(originalRawCoords[i].y, event.getRawY(i), RAW_COORD_TOLERANCE); 774 } 775 776 // Now translate the motion event so the circle's origin is at (0,0). 777 event.offsetLocation(-3, -2); 778 dump("Translated points.", event); 779 780 // Offsetting the location should preserve the raw X and Y of all pointers. 781 for (int i = 0; i < pointerCount; i++) { 782 assertEquals(originalRawCoords[i].x, event.getRawX(i), RAW_COORD_TOLERANCE); 783 assertEquals(originalRawCoords[i].y, event.getRawY(i), RAW_COORD_TOLERANCE); 784 } 785 786 // Apply a rotation about the origin by ROTATION degrees clockwise. 787 Matrix matrix = new Matrix(); 788 matrix.setRotate(ROTATION); 789 event.transform(matrix); 790 dump("Rotated points.", event); 791 792 // Check the points. 793 for (int i = 0; i < pointerCount; i++) { 794 final PointerCoords c = pointerCoords[i]; 795 event.getPointerCoords(i, c); 796 797 final float angle = (float) ((i * ARC + ROTATION) * PI_180); 798 assertEquals(Math.sin(angle) * RADIUS, c.x, RAW_COORD_TOLERANCE); 799 assertEquals(-Math.cos(angle) * RADIUS, c.y, RAW_COORD_TOLERANCE); 800 assertEquals(Math.tan(angle), Math.tan(c.orientation), 0.1); 801 802 // Applying the transformation should preserve the raw X and Y of all pointers. 803 assertEquals(originalRawCoords[i].x, event.getRawX(i), RAW_COORD_TOLERANCE); 804 assertEquals(originalRawCoords[i].y, event.getRawY(i), RAW_COORD_TOLERANCE); 805 } 806 } 807 dump(String label, MotionEvent ev)808 private void dump(String label, MotionEvent ev) { 809 if (false) { 810 StringBuilder msg = new StringBuilder(); 811 msg.append(label).append("\n"); 812 813 msg.append(" Raw: (").append(ev.getRawX()).append(",").append(ev.getRawY()).append(")\n"); 814 int pointerCount = ev.getPointerCount(); 815 for (int i = 0; i < pointerCount; i++) { 816 msg.append(" Pointer[").append(i).append("]: (") 817 .append(ev.getX(i)).append(",").append(ev.getY(i)).append("), orientation=") 818 .append(ev.getOrientation(i) * 180 / Math.PI).append(" deg\n"); 819 } 820 821 android.util.Log.i("TEST", msg.toString()); 822 } 823 } 824 825 @Test testPointerCoordsDefaultConstructor()826 public void testPointerCoordsDefaultConstructor() { 827 PointerCoords coords = new PointerCoords(); 828 829 assertEquals(0f, coords.x, 0.0f); 830 assertEquals(0f, coords.y, 0.0f); 831 assertEquals(0f, coords.pressure, 0.0f); 832 assertEquals(0f, coords.size, 0.0f); 833 assertEquals(0f, coords.touchMajor, 0.0f); 834 assertEquals(0f, coords.touchMinor, 0.0f); 835 assertEquals(0f, coords.toolMajor, 0.0f); 836 assertEquals(0f, coords.toolMinor, 0.0f); 837 assertEquals(0f, coords.orientation, 0.0f); 838 } 839 840 @Test testPointerCoordsCopyConstructor()841 public void testPointerCoordsCopyConstructor() { 842 PointerCoords coords = new PointerCoords(); 843 coords.x = 1; 844 coords.y = 2; 845 coords.pressure = 3; 846 coords.size = 4; 847 coords.touchMajor = 5; 848 coords.touchMinor = 6; 849 coords.toolMajor = 7; 850 coords.toolMinor = 8; 851 coords.orientation = 9; 852 coords.setAxisValue(MotionEvent.AXIS_GENERIC_1, 10); 853 854 PointerCoords copy = new PointerCoords(coords); 855 assertEquals(1f, copy.x, 0.0f); 856 assertEquals(2f, copy.y, 0.0f); 857 assertEquals(3f, copy.pressure, 0.0f); 858 assertEquals(4f, copy.size, 0.0f); 859 assertEquals(5f, copy.touchMajor, 0.0f); 860 assertEquals(6f, copy.touchMinor, 0.0f); 861 assertEquals(7f, copy.toolMajor, 0.0f); 862 assertEquals(8f, copy.toolMinor, 0.0f); 863 assertEquals(9f, copy.orientation, 0.0f); 864 assertEquals(10f, coords.getAxisValue(MotionEvent.AXIS_GENERIC_1), 0.0f); 865 } 866 867 @Test testPointerCoordsCopyFrom()868 public void testPointerCoordsCopyFrom() { 869 PointerCoords coords = new PointerCoords(); 870 coords.x = 1; 871 coords.y = 2; 872 coords.pressure = 3; 873 coords.size = 4; 874 coords.touchMajor = 5; 875 coords.touchMinor = 6; 876 coords.toolMajor = 7; 877 coords.toolMinor = 8; 878 coords.orientation = 9; 879 coords.setAxisValue(MotionEvent.AXIS_GENERIC_1, 10); 880 881 PointerCoords copy = new PointerCoords(); 882 copy.copyFrom(coords); 883 assertEquals(1f, copy.x, 0.0f); 884 assertEquals(2f, copy.y, 0.0f); 885 assertEquals(3f, copy.pressure, 0.0f); 886 assertEquals(4f, copy.size, 0.0f); 887 assertEquals(5f, copy.touchMajor, 0.0f); 888 assertEquals(6f, copy.touchMinor, 0.0f); 889 assertEquals(7f, copy.toolMajor, 0.0f); 890 assertEquals(8f, copy.toolMinor, 0.0f); 891 assertEquals(9f, copy.orientation, 0.0f); 892 assertEquals(10f, coords.getAxisValue(MotionEvent.AXIS_GENERIC_1), 0.0f); 893 } 894 895 @Test testPointerPropertiesDefaultConstructor()896 public void testPointerPropertiesDefaultConstructor() { 897 PointerProperties properties = new PointerProperties(); 898 899 assertEquals(MotionEvent.INVALID_POINTER_ID, properties.id); 900 assertEquals(MotionEvent.TOOL_TYPE_UNKNOWN, properties.toolType); 901 } 902 903 @Test testPointerPropertiesCopyConstructor()904 public void testPointerPropertiesCopyConstructor() { 905 PointerProperties properties = new PointerProperties(); 906 properties.id = 1; 907 properties.toolType = MotionEvent.TOOL_TYPE_MOUSE; 908 909 PointerProperties copy = new PointerProperties(properties); 910 assertEquals(1, copy.id); 911 assertEquals(MotionEvent.TOOL_TYPE_MOUSE, copy.toolType); 912 } 913 914 @Test testPointerPropertiesCopyFrom()915 public void testPointerPropertiesCopyFrom() { 916 PointerProperties properties = new PointerProperties(); 917 properties.id = 1; 918 properties.toolType = MotionEvent.TOOL_TYPE_MOUSE; 919 920 PointerProperties copy = new PointerProperties(); 921 copy.copyFrom(properties); 922 assertEquals(1, copy.id); 923 assertEquals(MotionEvent.TOOL_TYPE_MOUSE, copy.toolType); 924 } 925 926 @Test testActionToString()927 public void testActionToString() { 928 final int[] actions = { 929 MotionEvent.ACTION_DOWN, 930 MotionEvent.ACTION_UP, 931 MotionEvent.ACTION_MOVE, 932 MotionEvent.ACTION_CANCEL, 933 MotionEvent.ACTION_OUTSIDE, 934 MotionEvent.ACTION_HOVER_MOVE, 935 MotionEvent.ACTION_SCROLL, 936 MotionEvent.ACTION_HOVER_ENTER, 937 MotionEvent.ACTION_HOVER_EXIT, 938 MotionEvent.ACTION_BUTTON_PRESS, 939 MotionEvent.ACTION_BUTTON_RELEASE 940 }; 941 942 // There is no hard guarantee on the actual return result on any specific action 943 // from MotionEvent.actionToString. Verify that we are not crashing on those calls 944 // and that the return result on each is not empty 945 for (int i = 0; i < actions.length; i++) { 946 assertFalse(TextUtils.isEmpty(MotionEvent.actionToString(actions[i]))); 947 } 948 949 final int[] pointerActions = { 950 MotionEvent.ACTION_POINTER_UP, 951 MotionEvent.ACTION_POINTER_DOWN 952 }; 953 954 for (int i = 0; i < pointerActions.length; i++) { 955 for (int pointer = 0; pointer < 5; pointer++) { 956 int pointerAction = 957 pointerActions[i] | pointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT; 958 assertFalse(TextUtils.isEmpty(MotionEvent.actionToString(pointerAction))); 959 } 960 } 961 } 962 963 @Test testAxisFromToString()964 public void testAxisFromToString() { 965 final int[] axes = { 966 MotionEvent.AXIS_X, 967 MotionEvent.AXIS_Y, 968 MotionEvent.AXIS_PRESSURE, 969 MotionEvent.AXIS_SIZE, 970 MotionEvent.AXIS_TOUCH_MAJOR, 971 MotionEvent.AXIS_TOUCH_MINOR, 972 MotionEvent.AXIS_TOOL_MAJOR, 973 MotionEvent.AXIS_TOOL_MINOR, 974 MotionEvent.AXIS_ORIENTATION, 975 MotionEvent.AXIS_VSCROLL, 976 MotionEvent.AXIS_HSCROLL, 977 MotionEvent.AXIS_Z, 978 MotionEvent.AXIS_RX, 979 MotionEvent.AXIS_RY, 980 MotionEvent.AXIS_RZ, 981 MotionEvent.AXIS_HAT_X, 982 MotionEvent.AXIS_HAT_Y, 983 MotionEvent.AXIS_LTRIGGER, 984 MotionEvent.AXIS_RTRIGGER, 985 MotionEvent.AXIS_THROTTLE, 986 MotionEvent.AXIS_RUDDER, 987 MotionEvent.AXIS_WHEEL, 988 MotionEvent.AXIS_GAS, 989 MotionEvent.AXIS_BRAKE, 990 MotionEvent.AXIS_DISTANCE, 991 MotionEvent.AXIS_TILT, 992 MotionEvent.AXIS_SCROLL, 993 MotionEvent.AXIS_RELATIVE_X, 994 MotionEvent.AXIS_RELATIVE_Y, 995 MotionEvent.AXIS_GENERIC_1, 996 MotionEvent.AXIS_GENERIC_2, 997 MotionEvent.AXIS_GENERIC_3, 998 MotionEvent.AXIS_GENERIC_4, 999 MotionEvent.AXIS_GENERIC_5, 1000 MotionEvent.AXIS_GENERIC_6, 1001 MotionEvent.AXIS_GENERIC_7, 1002 MotionEvent.AXIS_GENERIC_8, 1003 MotionEvent.AXIS_GENERIC_9, 1004 MotionEvent.AXIS_GENERIC_10, 1005 MotionEvent.AXIS_GENERIC_11, 1006 MotionEvent.AXIS_GENERIC_12, 1007 MotionEvent.AXIS_GENERIC_13, 1008 MotionEvent.AXIS_GENERIC_14, 1009 MotionEvent.AXIS_GENERIC_15, 1010 MotionEvent.AXIS_GENERIC_16, 1011 MotionEvent.AXIS_GESTURE_X_OFFSET, 1012 MotionEvent.AXIS_GESTURE_Y_OFFSET, 1013 MotionEvent.AXIS_GESTURE_SCROLL_X_DISTANCE, 1014 MotionEvent.AXIS_GESTURE_SCROLL_Y_DISTANCE, 1015 MotionEvent.AXIS_GESTURE_PINCH_SCALE_FACTOR, 1016 }; 1017 1018 // There is no hard guarantee on the actual return result on any specific axis 1019 // from MotionEvent.axisToString. Verify that we are not crashing on those calls 1020 // and that the return result on each is not empty. However, we do expect the two-way 1021 // call chain of to/from to get us back to the original integer value. 1022 for (int i = 0; i < axes.length; i++) { 1023 String axisToString = MotionEvent.axisToString(axes[i]); 1024 assertFalse(TextUtils.isEmpty(axisToString)); 1025 assertEquals(axes[i], MotionEvent.axisFromString(axisToString)); 1026 } 1027 } 1028 1029 @Test testGetActionButton()1030 public void testGetActionButton() { 1031 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 1032 MotionEvent.ACTION_BUTTON_PRESS, X_3F, Y_4F, 0); 1033 mMotionEventDynamic.setActionButton(MotionEvent.BUTTON_STYLUS_PRIMARY); 1034 assertEquals(MotionEvent.BUTTON_STYLUS_PRIMARY, mMotionEventDynamic.getActionButton()); 1035 mMotionEventDynamic.recycle(); 1036 1037 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 1038 MotionEvent.ACTION_BUTTON_PRESS, X_3F, Y_4F, 0); 1039 mMotionEventDynamic.setActionButton(MotionEvent.BUTTON_SECONDARY); 1040 assertEquals(MotionEvent.BUTTON_SECONDARY, mMotionEventDynamic.getActionButton()); 1041 } 1042 1043 @Test testIsButtonPressed()1044 public void testIsButtonPressed() { 1045 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 1046 MotionEvent.ACTION_DOWN, X_3F, Y_4F, 0); 1047 mMotionEventDynamic.setSource(InputDevice.SOURCE_MOUSE); 1048 1049 mMotionEventDynamic.setButtonState( 1050 MotionEvent.BUTTON_PRIMARY | MotionEvent.BUTTON_STYLUS_PRIMARY); 1051 assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_PRIMARY)); 1052 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_SECONDARY)); 1053 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_TERTIARY)); 1054 assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)); 1055 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)); 1056 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_BACK)); 1057 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_FORWARD)); 1058 1059 mMotionEventDynamic.setButtonState(MotionEvent.BUTTON_PRIMARY); 1060 assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_PRIMARY)); 1061 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_SECONDARY)); 1062 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_TERTIARY)); 1063 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)); 1064 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)); 1065 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_BACK)); 1066 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_FORWARD)); 1067 1068 mMotionEventDynamic.setButtonState( 1069 MotionEvent.BUTTON_FORWARD | MotionEvent.BUTTON_TERTIARY); 1070 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_PRIMARY)); 1071 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_SECONDARY)); 1072 assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_TERTIARY)); 1073 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)); 1074 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)); 1075 assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_BACK)); 1076 assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_FORWARD)); 1077 } 1078 1079 @Test testClassificationConstantsAreUnique()1080 public void testClassificationConstantsAreUnique() { 1081 Set<Integer> values = new LinkedHashSet<>(); 1082 values.add(MotionEvent.CLASSIFICATION_NONE); 1083 values.add(MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE); 1084 values.add(MotionEvent.CLASSIFICATION_DEEP_PRESS); 1085 assertEquals(3, values.size()); 1086 } 1087 1088 /** 1089 * The motion events 1 and 2 were created using one of the obtain methods. 1090 * As a result, they should not have any classification. 1091 * Only events generated by the framework are allowed to have classification other than NONE. 1092 */ 1093 @Test testGetClassification()1094 public void testGetClassification() { 1095 assertEquals(MotionEvent.CLASSIFICATION_NONE, mMotionEvent1.getClassification()); 1096 assertEquals(MotionEvent.CLASSIFICATION_NONE, mMotionEvent2.getClassification()); 1097 } 1098 1099 @Test testNativeConverter()1100 public void testNativeConverter() { 1101 final MotionEvent event = MotionEvent.obtain(mDownTime, mEventTime, 1102 MotionEvent.ACTION_BUTTON_PRESS, X_3F, Y_4F, META_STATE); 1103 event.setActionButton(MotionEvent.BUTTON_PRIMARY); 1104 nativeMotionEventTest(event); 1105 } 1106 1107 @Test testNativeToJavaConverter()1108 public void testNativeToJavaConverter() { 1109 final MotionEvent javaMotionEvent = MotionEvent.obtain(mDownTime, mEventTime, 1110 MotionEvent.ACTION_DOWN, X_3F, Y_4F, PRESSURE_1F, SIZE_1F, META_STATE, 1111 X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS); 1112 final MotionEvent motionEventFromNative = obtainMotionEventCopyFromNative(javaMotionEvent); 1113 assertNotSame(javaMotionEvent, motionEventFromNative); 1114 assertThat(motionEventFromNative, allOf( 1115 is(notNullValue()), 1116 withEventTime(javaMotionEvent.getEventTime()), 1117 withDownTime(javaMotionEvent.getDownTime()), 1118 withMotionAction(javaMotionEvent.getAction()), 1119 InputEventMatchersKt.withCoords( 1120 new PointF(javaMotionEvent.getX(), javaMotionEvent.getY()) 1121 ), 1122 withRawCoords(new PointF(javaMotionEvent.getRawX(), javaMotionEvent.getRawY())), 1123 withDeviceId(javaMotionEvent.getDeviceId()), 1124 withEdgeFlags(javaMotionEvent.getEdgeFlags()), 1125 withMetaState(javaMotionEvent.getMetaState()), 1126 withPressure(javaMotionEvent.getPressure()), 1127 withSize(javaMotionEvent.getSize()), 1128 withXPrecision(javaMotionEvent.getXPrecision()), 1129 withYPrecision(javaMotionEvent.getYPrecision()) 1130 )); 1131 assertEquals( 1132 javaMotionEvent.getEventTimeNanos(), 1133 motionEventFromNative.getEventTimeNanos() 1134 ); 1135 } 1136 1137 @Test testNativeToJavaConverterMemoryLeak()1138 public void testNativeToJavaConverterMemoryLeak() { 1139 final MotionEvent javaMotionEvent = 1140 MotionEvent.obtain( 1141 mDownTime, mEventTime, MotionEvent.ACTION_DOWN, X_3F, Y_4F, META_STATE); 1142 1143 try (NativeHeapLeakDetector d = new NativeHeapLeakDetector()) { 1144 for (int iteration = 0; iteration < NUM_MOTION_EVENT_ALLOCATIONS; ++iteration) { 1145 obtainMotionEventCopyFromNative(javaMotionEvent); 1146 } 1147 } 1148 } 1149 1150 @Test testNativeToJavaConverterMemoryLeakRecylingObjects()1151 public void testNativeToJavaConverterMemoryLeakRecylingObjects() { 1152 final MotionEvent javaMotionEvent = 1153 MotionEvent.obtain( 1154 mDownTime, mEventTime, MotionEvent.ACTION_DOWN, X_3F, Y_4F, META_STATE); 1155 1156 try (NativeHeapLeakDetector d = new NativeHeapLeakDetector()) { 1157 for (int iteration = 0; iteration < NUM_MOTION_EVENT_ALLOCATIONS; ++iteration) { 1158 obtainMotionEventCopyFromNative(javaMotionEvent).recycle(); 1159 } 1160 } 1161 } 1162 1163 @Test testJavaToNativeConverterMemoryLeak()1164 public void testJavaToNativeConverterMemoryLeak() { 1165 final MotionEvent event = 1166 MotionEvent.obtain( 1167 mDownTime, 1168 mEventTime, 1169 MotionEvent.ACTION_BUTTON_PRESS, 1170 X_3F, 1171 Y_4F, 1172 META_STATE); 1173 1174 try (NativeHeapLeakDetector d = new NativeHeapLeakDetector()) { 1175 for (int iteration = 0; iteration < NUM_MOTION_EVENT_ALLOCATIONS; ++iteration) { 1176 obtainNativeMotionEventCopyFromJava(event); 1177 } 1178 } 1179 } 1180 1181 @Test testAddBatchWithTransform()1182 public void testAddBatchWithTransform() { 1183 PointerCoordsBuilder coordsBuilder0 = 1184 withCoords(10.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 1185 1.4f).withGenericAxis1(4.4f).withOrientation(1.0f); 1186 PointerCoordsBuilder coordsBuilder1 = 1187 withCoords(30.0f, 40.0f).withPressure(1.4f).withSize(3.0f).withTouch(2.2f, 1188 0.6f).withGenericAxis1(6.6f).withOrientation(-1.0f); 1189 1190 PointerPropertiesBuilder propertiesBuilder0 = 1191 withProperties(0, MotionEvent.TOOL_TYPE_FINGER); 1192 PointerPropertiesBuilder propertiesBuilder1 = 1193 withProperties(1, MotionEvent.TOOL_TYPE_FINGER); 1194 1195 mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime, 1196 MotionEvent.ACTION_MOVE, 2, 1197 new PointerProperties[]{propertiesBuilder0.build(), propertiesBuilder1.build()}, 1198 new PointerCoords[]{coordsBuilder0.build(), coordsBuilder1.build()}, 1199 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0); 1200 1201 // Apply an arbitrary transform to the event. 1202 Matrix matrix = new Matrix(); 1203 matrix.setRotate(90); 1204 mMotionEventDynamic.transform(matrix); 1205 1206 // Add a new batch to our event. 1207 PointerCoordsBuilder coordsBuilderNext0 = withCoords(15.0f, 25.0f).withPressure(1.6f) 1208 .withSize(2.2f).withTool(1.2f, 1.4f).withTouch(1.0f, 0.9f) 1209 .withOrientation(2.2f).withGenericAxis1(7.4f); 1210 PointerCoordsBuilder coordsBuilderNext1 = withCoords(35.0f, 45.0f).withPressure(1.8f) 1211 .withSize(3.2f).withTool(1.2f, 1.4f).withTouch(0.7f, 0.6f) 1212 .withOrientation(2.9f).withGenericAxis1(8.4f); 1213 1214 mMotionEventDynamic.addBatch(mEventTime + 20, 1215 new PointerCoords[]{coordsBuilderNext0.build(), coordsBuilderNext1.build()}, 0); 1216 1217 assertEquals(1, mMotionEventDynamic.getHistorySize()); 1218 assertEquals(2, mMotionEventDynamic.getPointerCount()); 1219 1220 // The added batch should be our "new" values for our event, because the batch was added 1221 // after the event was transformed. 1222 verifyCurrentPointerData(mMotionEventDynamic, 1223 new PointerPropertiesBuilder[]{propertiesBuilder0, propertiesBuilder1}, 1224 new PointerCoordsBuilder[]{coordsBuilderNext0, coordsBuilderNext1}); 1225 1226 // Undo the transformation. 1227 Matrix inverseMatrix = new Matrix(); 1228 assertTrue(matrix.invert(inverseMatrix)); 1229 mMotionEventDynamic.transform(inverseMatrix); 1230 1231 // Now, the "old" values should match what they were initially set to. 1232 verifyHistoricalPointerData(mMotionEventDynamic, 1233 new PointerCoordsBuilder[]{coordsBuilder0, coordsBuilder1}, 0); 1234 } 1235 } 1236