1package com.xtremelabs.robolectric.shadows;
2
3import android.view.MotionEvent;
4import com.xtremelabs.robolectric.Robolectric;
5import com.xtremelabs.robolectric.internal.Implementation;
6import com.xtremelabs.robolectric.internal.Implements;
7import com.xtremelabs.robolectric.internal.RealObject;
8
9import java.lang.reflect.Constructor;
10
11/**
12 * Shadow for {@code MotionEvent} that uses reflection to create {@code MotionEvent} objects, which cannot otherwise
13 * be constructed.
14 */
15@SuppressWarnings({"UnusedDeclaration"})
16@Implements(MotionEvent.class)
17public class ShadowMotionEvent {
18    @RealObject private MotionEvent realObject;
19
20    private int action;
21    private float[] x = new float[2];
22    private float[] y = new float[2];
23    private int pointerCount = 1;
24    private long downTime;
25    private long eventTime;
26    private int[] pointerIds = new int[2];
27    private int pointerIndex;
28
29    @Implementation
30    public static MotionEvent obtain(long downTime, long eventTime, int action, float x, float y, int metaState) {
31        try {
32            Constructor<MotionEvent> constructor = MotionEvent.class.getDeclaredConstructor();
33            constructor.setAccessible(true);
34            MotionEvent motionEvent = constructor.newInstance();
35            ShadowMotionEvent shadowMotionEvent = (ShadowMotionEvent) Robolectric.shadowOf_(motionEvent);
36            shadowMotionEvent.x[0] = x;
37            shadowMotionEvent.y[0] = y;
38            shadowMotionEvent.action = action;
39            shadowMotionEvent.downTime = downTime;
40            shadowMotionEvent.eventTime = eventTime;
41            return motionEvent;
42        } catch (Exception e) {
43            throw new RuntimeException(e);
44        }
45    }
46
47    @Implementation
48    public static MotionEvent obtain(MotionEvent motionEvent) {
49        return obtain(motionEvent.getDownTime(), motionEvent.getEventTime(), motionEvent.getAction(), motionEvent.getX(), motionEvent.getY(), motionEvent.getMetaState());
50    }
51
52    @Implementation
53    public int getAction() {
54        return action | (pointerIndex << MotionEvent.ACTION_POINTER_ID_SHIFT);
55    }
56
57    @Implementation
58    public float getRawX() {
59        return getX();
60    }
61
62    @Implementation
63    public float getRawY() {
64        return getY();
65    }
66
67    @Implementation
68    public final float getX() {
69        return getX(0);
70    }
71
72    @Implementation
73    public final float getY() {
74        return getY(0);
75    }
76
77    @Implementation
78    public final float getX(int pointerIndex) {
79        return x[pointerIndex];
80    }
81
82    @Implementation
83    public final float getY(int pointerIndex) {
84        return y[pointerIndex];
85    }
86
87    @Implementation
88    public final int getPointerCount() {
89    	return pointerCount;
90    }
91
92    @Implementation
93    public final long getEventTime() {
94        return eventTime;
95    }
96
97    @Implementation
98    public final long getDownTime() {
99        return downTime;
100    }
101
102    @Implementation
103    public final int getPointerId(int index) {
104        return pointerIds[index];
105    }
106
107    @Implementation
108    public final int findPointerIndex(int id) {
109        for (int i = 0; i < pointerIds.length; i++) {
110            int pointerId = pointerIds[i];
111
112            if (pointerId == id) {
113                return i;
114            }
115        }
116        return -1;
117    }
118
119    @Implementation
120    public final int getActionMasked() {
121        return action;
122    }
123
124    @Implementation
125    public final int getActionIndex() {
126        return pointerIndex;
127    }
128
129    @Implementation
130    public final float getPressure(int pointerIndex) {
131        return 1.0f;
132    }
133
134    @Implementation
135    public final void setLocation(float x, float y) {
136        this.x[0] = x;
137        this.y[0] = y;
138    }
139
140    public MotionEvent setPointer2(float x, float y) {
141        this.x[1] = x;
142        this.y[1] = y;
143        pointerCount = 2;
144        return realObject;
145    }
146
147    public void setPointerIndex(int pointerIndex) {
148        this.pointerIndex = pointerIndex;
149    }
150
151    public void setPointerIds(int index0PointerId, int index1PointerId) {
152        pointerIds[0] = index0PointerId;
153        pointerIds[1] = index1PointerId;
154    }
155}
156