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