MotionEventCompat.java revision dc5487a46b75572fa9120b22e89487c0178ff0a0
1/*
2 * Copyright (C) 2011 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
17package android.support.v4.view;
18
19import android.view.MotionEvent;
20import android.view.View;
21
22/**
23 * Helper for accessing features in {@link MotionEvent} introduced
24 * after API level 4 in a backwards compatible fashion.
25 */
26public class MotionEventCompat {
27    /**
28     * Interface for the full API.
29     */
30    interface MotionEventVersionImpl {
31        public int findPointerIndex(MotionEvent event, int pointerId);
32        public int getPointerId(MotionEvent event, int pointerIndex);
33        public float getX(MotionEvent event, int pointerIndex);
34        public float getY(MotionEvent event, int pointerIndex);
35    }
36
37    /**
38     * Interface implementation that doesn't use anything about v4 APIs.
39     */
40    static class BaseMotionEventVersionImpl implements MotionEventVersionImpl {
41        @Override
42        public int findPointerIndex(MotionEvent event, int pointerId) {
43            if (pointerId == 0) {
44                // id 0 == index 0 and vice versa.
45                return 0;
46            }
47            return -1;
48        }
49        @Override
50        public int getPointerId(MotionEvent event, int pointerIndex) {
51            if (pointerIndex == 0) {
52                // index 0 == id 0 and vice versa.
53                return 0;
54            }
55            throw new IndexOutOfBoundsException("Pre-Eclair does not support multiple pointers");
56        }
57        @Override
58        public float getX(MotionEvent event, int pointerIndex) {
59            if (pointerIndex == 0) {
60                return event.getX();
61            }
62            throw new IndexOutOfBoundsException("Pre-Eclair does not support multiple pointers");
63        }
64        @Override
65        public float getY(MotionEvent event, int pointerIndex) {
66            if (pointerIndex == 0) {
67                return event.getY();
68            }
69            throw new IndexOutOfBoundsException("Pre-Eclair does not support multiple pointers");
70        }
71    }
72
73    /**
74     * Interface implementation for devices with at least v11 APIs.
75     */
76    static class EclairMotionEventVersionImpl implements MotionEventVersionImpl {
77        @Override
78        public int findPointerIndex(MotionEvent event, int pointerId) {
79            return MotionEventCompatEclair.findPointerIndex(event, pointerId);
80        }
81        @Override
82        public int getPointerId(MotionEvent event, int pointerIndex) {
83            return MotionEventCompatEclair.getPointerId(event, pointerIndex);
84        }
85        @Override
86        public float getX(MotionEvent event, int pointerIndex) {
87            return MotionEventCompatEclair.getX(event, pointerIndex);
88        }
89        @Override
90        public float getY(MotionEvent event, int pointerIndex) {
91            return MotionEventCompatEclair.getY(event, pointerIndex);
92        }
93    }
94
95    /**
96     * Select the correct implementation to use for the current platform.
97     */
98    static final MotionEventVersionImpl IMPL;
99    static {
100        if (android.os.Build.VERSION.SDK_INT >= 5) {
101            IMPL = new EclairMotionEventVersionImpl();
102        } else {
103            IMPL = new BaseMotionEventVersionImpl();
104        }
105    }
106
107    // -------------------------------------------------------------------
108
109    /**
110     * Synonym for {@link MotionEvent#ACTION_MASK}.
111     */
112    public static final int ACTION_MASK = 0xff;
113
114    /**
115     * Synonym for {@link MotionEvent#ACTION_POINTER_DOWN}.
116     */
117    public static final int ACTION_POINTER_DOWN = 5;
118
119    /**
120     * Synonym for {@link MotionEvent#ACTION_POINTER_UP}.
121     */
122    public static final int ACTION_POINTER_UP = 6;
123
124    /**
125     * Synonym for {@link MotionEvent#ACTION_HOVER_MOVE}.
126     */
127    public static final int ACTION_HOVER_MOVE = 7;
128
129    /**
130     * Synonym for {@link MotionEvent#ACTION_SCROLL}.
131     */
132    public static final int ACTION_SCROLL = 8;
133
134    /**
135     * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_MASK}.
136     */
137    public static final int ACTION_POINTER_INDEX_MASK  = 0xff00;
138
139    /**
140     * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_SHIFT}.
141     */
142    public static final int ACTION_POINTER_INDEX_SHIFT = 8;
143
144    /**
145     * Constant for {@link #getActionMasked}: The pointer is not down but has entered the
146     * boundaries of a window or view.
147     * <p>
148     * This action is always delivered to the window or view under the pointer.
149     * </p><p>
150     * This action is not a touch event so it is delivered to
151     * {@link View#onGenericMotionEvent(MotionEvent)} rather than
152     * {@link View#onTouchEvent(MotionEvent)}.
153     * </p>
154     */
155    public static final int ACTION_HOVER_ENTER = 9;
156
157    /**
158     * Constant for {@link #getActionMasked}: The pointer is not down but has exited the
159     * boundaries of a window or view.
160     * <p>
161     * This action is always delivered to the window or view that was previously under the pointer.
162     * </p><p>
163     * This action is not a touch event so it is delivered to
164     * {@link View#onGenericMotionEvent(MotionEvent)} rather than
165     * {@link View#onTouchEvent(MotionEvent)}.
166     * </p>
167     */
168    public static final int ACTION_HOVER_EXIT = 10;
169
170    /**
171     * Call {@link MotionEvent#getAction}, returning only the {@link #ACTION_MASK}
172     * portion.
173     */
174    public static int getActionMasked(MotionEvent event) {
175        return event.getAction() & ACTION_MASK;
176    }
177
178    /**
179     * Call {@link MotionEvent#getAction}, returning only the pointer index
180     * portion
181     */
182    public static int getActionIndex(MotionEvent event) {
183        return (event.getAction() & ACTION_POINTER_INDEX_MASK)
184                >> ACTION_POINTER_INDEX_SHIFT;
185    }
186
187    /**
188     * Call {@link MotionEvent#findPointerIndex(int)}.
189     * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device,
190     * does nothing and returns -1.
191     */
192    public static int findPointerIndex(MotionEvent event, int pointerId) {
193        return IMPL.findPointerIndex(event, pointerId);
194    }
195
196    /**
197     * Call {@link MotionEvent#getPointerId(int)}.
198     * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device,
199     * {@link IndexOutOfBoundsException} is thrown.
200     */
201    public static int getPointerId(MotionEvent event, int pointerIndex) {
202        return IMPL.getPointerId(event, pointerIndex);
203    }
204
205    /**
206     * Call {@link MotionEvent#getX(int)}.
207     * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device,
208     * {@link IndexOutOfBoundsException} is thrown.
209     */
210    public static float getX(MotionEvent event, int pointerIndex) {
211        return IMPL.getX(event, pointerIndex);
212    }
213
214    /**
215     * Call {@link MotionEvent#getY(int)}.
216     * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device,
217     * {@link IndexOutOfBoundsException} is thrown.
218     */
219    public static float getY(MotionEvent event, int pointerIndex) {
220        return IMPL.getY(event, pointerIndex);
221    }
222}
223