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