/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v4.view; import android.view.MotionEvent; /** * Helper for accessing features in {@link MotionEvent} introduced * after API level 4 in a backwards compatible fashion. */ public class MotionEventCompat { /** * Interface for the full API. */ interface MotionEventVersionImpl { public int findPointerIndex(MotionEvent event, int pointerId); public int getPointerId(MotionEvent event, int pointerIndex); public float getX(MotionEvent event, int pointerIndex); public float getY(MotionEvent event, int pointerIndex); public int getPointerCount(MotionEvent event); } /** * Interface implementation that doesn't use anything about v4 APIs. */ static class BaseMotionEventVersionImpl implements MotionEventVersionImpl { @Override public int findPointerIndex(MotionEvent event, int pointerId) { if (pointerId == 0) { // id 0 == index 0 and vice versa. return 0; } return -1; } @Override public int getPointerId(MotionEvent event, int pointerIndex) { if (pointerIndex == 0) { // index 0 == id 0 and vice versa. return 0; } throw new IndexOutOfBoundsException("Pre-Eclair does not support multiple pointers"); } @Override public float getX(MotionEvent event, int pointerIndex) { if (pointerIndex == 0) { return event.getX(); } throw new IndexOutOfBoundsException("Pre-Eclair does not support multiple pointers"); } @Override public float getY(MotionEvent event, int pointerIndex) { if (pointerIndex == 0) { return event.getY(); } throw new IndexOutOfBoundsException("Pre-Eclair does not support multiple pointers"); } @Override public int getPointerCount(MotionEvent event) { return 1; } } /** * Interface implementation for devices with at least v11 APIs. */ static class EclairMotionEventVersionImpl implements MotionEventVersionImpl { @Override public int findPointerIndex(MotionEvent event, int pointerId) { return MotionEventCompatEclair.findPointerIndex(event, pointerId); } @Override public int getPointerId(MotionEvent event, int pointerIndex) { return MotionEventCompatEclair.getPointerId(event, pointerIndex); } @Override public float getX(MotionEvent event, int pointerIndex) { return MotionEventCompatEclair.getX(event, pointerIndex); } @Override public float getY(MotionEvent event, int pointerIndex) { return MotionEventCompatEclair.getY(event, pointerIndex); } @Override public int getPointerCount(MotionEvent event) { return MotionEventCompatEclair.getPointerCount(event); } } /** * Select the correct implementation to use for the current platform. */ static final MotionEventVersionImpl IMPL; static { if (android.os.Build.VERSION.SDK_INT >= 5) { IMPL = new EclairMotionEventVersionImpl(); } else { IMPL = new BaseMotionEventVersionImpl(); } } // ------------------------------------------------------------------- /** * Synonym for {@link MotionEvent#ACTION_MASK}. */ public static final int ACTION_MASK = 0xff; /** * Synonym for {@link MotionEvent#ACTION_POINTER_DOWN}. */ public static final int ACTION_POINTER_DOWN = 5; /** * Synonym for {@link MotionEvent#ACTION_POINTER_UP}. */ public static final int ACTION_POINTER_UP = 6; /** * Synonym for {@link MotionEvent#ACTION_HOVER_MOVE}. */ public static final int ACTION_HOVER_MOVE = 7; /** * Synonym for {@link MotionEvent#ACTION_SCROLL}. */ public static final int ACTION_SCROLL = 8; /** * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_MASK}. */ public static final int ACTION_POINTER_INDEX_MASK = 0xff00; /** * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_SHIFT}. */ public static final int ACTION_POINTER_INDEX_SHIFT = 8; /** * Constant for {@link #getActionMasked}: The pointer is not down but has entered the * boundaries of a window or view. *

* This action is always delivered to the window or view under the pointer. *

* This action is not a touch event so it is delivered to * {@link android.view.View#onGenericMotionEvent(MotionEvent)} rather than * {@link android.view.View#onTouchEvent(MotionEvent)}. *

*/ public static final int ACTION_HOVER_ENTER = 9; /** * Constant for {@link #getActionMasked}: The pointer is not down but has exited the * boundaries of a window or view. *

* This action is always delivered to the window or view that was previously under the pointer. *

* This action is not a touch event so it is delivered to * {@link android.view.View#onGenericMotionEvent(MotionEvent)} rather than * {@link android.view.View#onTouchEvent(MotionEvent)}. *

*/ public static final int ACTION_HOVER_EXIT = 10; /** * Call {@link MotionEvent#getAction}, returning only the {@link #ACTION_MASK} * portion. */ public static int getActionMasked(MotionEvent event) { return event.getAction() & ACTION_MASK; } /** * Call {@link MotionEvent#getAction}, returning only the pointer index * portion */ public static int getActionIndex(MotionEvent event) { return (event.getAction() & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT; } /** * Call {@link MotionEvent#findPointerIndex(int)}. * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device, * does nothing and returns -1. */ public static int findPointerIndex(MotionEvent event, int pointerId) { return IMPL.findPointerIndex(event, pointerId); } /** * Call {@link MotionEvent#getPointerId(int)}. * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device, * {@link IndexOutOfBoundsException} is thrown. */ public static int getPointerId(MotionEvent event, int pointerIndex) { return IMPL.getPointerId(event, pointerIndex); } /** * Call {@link MotionEvent#getX(int)}. * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device, * {@link IndexOutOfBoundsException} is thrown. */ public static float getX(MotionEvent event, int pointerIndex) { return IMPL.getX(event, pointerIndex); } /** * Call {@link MotionEvent#getY(int)}. * If running on a pre-{@link android.os.Build.VERSION_CODES#ECLAIR} device, * {@link IndexOutOfBoundsException} is thrown. */ public static float getY(MotionEvent event, int pointerIndex) { return IMPL.getY(event, pointerIndex); } /** * The number of pointers of data contained in this event. Always * >= 1. */ public static int getPointerCount(MotionEvent event) { return IMPL.getPointerCount(event); } }