/* * Copyright (C) 2007 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.view; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; /** * Object used to report movement (mouse, pen, finger, trackball) events. This * class may hold either absolute or relative movements, depending on what * it is being used for. */ public final class MotionEvent implements Parcelable { /** * Constant for {@link #getAction}: A pressed gesture has started, the * motion contains the initial starting location. */ public static final int ACTION_DOWN = 0; /** * Constant for {@link #getAction}: A pressed gesture has finished, the * motion contains the final release location as well as any intermediate * points since the last down or move event. */ public static final int ACTION_UP = 1; /** * Constant for {@link #getAction}: A change has happened during a * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}). * The motion contains the most recent point, as well as any intermediate * points since the last down or move event. */ public static final int ACTION_MOVE = 2; /** * Constant for {@link #getAction}: The current gesture has been aborted. * You will not receive any more points in it. You should treat this as * an up event, but not perform any action that you normally would. */ public static final int ACTION_CANCEL = 3; /** * Constant for {@link #getAction}: A movement has happened outside of the * normal bounds of the UI element. This does not provide a full gesture, * but only the initial location of the movement/touch. */ public static final int ACTION_OUTSIDE = 4; private static final boolean TRACK_RECYCLED_LOCATION = false; /** * Flag indicating the motion event intersected the top edge of the screen. */ public static final int EDGE_TOP = 0x00000001; /** * Flag indicating the motion event intersected the bottom edge of the screen. */ public static final int EDGE_BOTTOM = 0x00000002; /** * Flag indicating the motion event intersected the left edge of the screen. */ public static final int EDGE_LEFT = 0x00000004; /** * Flag indicating the motion event intersected the right edge of the screen. */ public static final int EDGE_RIGHT = 0x00000008; static private final int MAX_RECYCLED = 10; static private Object gRecyclerLock = new Object(); static private int gRecyclerUsed = 0; static private MotionEvent gRecyclerTop = null; private long mDownTime; private long mEventTime; private long mEventTimeNano; private int mAction; private float mX; private float mY; private float mRawX; private float mRawY; private float mPressure; private float mSize; private int mMetaState; private int mNumHistory; private float[] mHistory; private long[] mHistoryTimes; private float mXPrecision; private float mYPrecision; private int mDeviceId; private int mEdgeFlags; private MotionEvent mNext; private RuntimeException mRecycledLocation; private boolean mRecycled; private MotionEvent() { } static private MotionEvent obtain() { synchronized (gRecyclerLock) { if (gRecyclerTop == null) { return new MotionEvent(); } MotionEvent ev = gRecyclerTop; gRecyclerTop = ev.mNext; gRecyclerUsed--; ev.mRecycledLocation = null; ev.mRecycled = false; return ev; } } /** * Create a new MotionEvent, filling in all of the basic values that * define the motion. * * @param downTime The time (in ms) when the user originally pressed down to start * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. * @param eventTime The the time (in ms) when this specific event was generated. This * must be obtained from {@link SystemClock#uptimeMillis()}. * @param eventTimeNano The the time (in ns) when this specific event was generated. This * must be obtained from {@link System#nanoTime()}. * @param action The kind of action being performed -- one of either * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or * {@link #ACTION_CANCEL}. * @param x The X coordinate of this event. * @param y The Y coordinate of this event. * @param pressure The current pressure of this event. The pressure generally * ranges from 0 (no pressure at all) to 1 (normal pressure), however * values higher than 1 may be generated depending on the calibration of * the input device. * @param size A scaled value of the approximate size of the area being pressed when * touched with the finger. The actual value in pixels corresponding to the finger * touch is normalized with a device specific range of values * and scaled to a value between 0 and 1. * @param metaState The state of any meta / modifier keys that were in effect when * the event was generated. * @param xPrecision The precision of the X coordinate being reported. * @param yPrecision The precision of the Y coordinate being reported. * @param deviceId The id for the device that this event came from. An id of * zero indicates that the event didn't come from a physical device; other * numbers are arbitrary and you shouldn't depend on the values. * @param edgeFlags A bitfield indicating which edges, if any, where touched by this * MotionEvent. * * @hide */ static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano, int action, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { MotionEvent ev = obtain(); ev.mDeviceId = deviceId; ev.mEdgeFlags = edgeFlags; ev.mDownTime = downTime; ev.mEventTime = eventTime; ev.mEventTimeNano = eventTimeNano; ev.mAction = action; ev.mX = ev.mRawX = x; ev.mY = ev.mRawY = y; ev.mPressure = pressure; ev.mSize = size; ev.mMetaState = metaState; ev.mXPrecision = xPrecision; ev.mYPrecision = yPrecision; return ev; } /** * Create a new MotionEvent, filling in all of the basic values that * define the motion. * * @param downTime The time (in ms) when the user originally pressed down to start * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. * @param eventTime The the time (in ms) when this specific event was generated. This * must be obtained from {@link SystemClock#uptimeMillis()}. * @param action The kind of action being performed -- one of either * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or * {@link #ACTION_CANCEL}. * @param x The X coordinate of this event. * @param y The Y coordinate of this event. * @param pressure The current pressure of this event. The pressure generally * ranges from 0 (no pressure at all) to 1 (normal pressure), however * values higher than 1 may be generated depending on the calibration of * the input device. * @param size A scaled value of the approximate size of the area being pressed when * touched with the finger. The actual value in pixels corresponding to the finger * touch is normalized with a device specific range of values * and scaled to a value between 0 and 1. * @param metaState The state of any meta / modifier keys that were in effect when * the event was generated. * @param xPrecision The precision of the X coordinate being reported. * @param yPrecision The precision of the Y coordinate being reported. * @param deviceId The id for the device that this event came from. An id of * zero indicates that the event didn't come from a physical device; other * numbers are arbitrary and you shouldn't depend on the values. * @param edgeFlags A bitfield indicating which edges, if any, where touched by this * MotionEvent. */ static public MotionEvent obtain(long downTime, long eventTime, int action, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { MotionEvent ev = obtain(); ev.mDeviceId = deviceId; ev.mEdgeFlags = edgeFlags; ev.mDownTime = downTime; ev.mEventTime = eventTime; ev.mEventTimeNano = eventTime * 1000000; ev.mAction = action; ev.mX = ev.mRawX = x; ev.mY = ev.mRawY = y; ev.mPressure = pressure; ev.mSize = size; ev.mMetaState = metaState; ev.mXPrecision = xPrecision; ev.mYPrecision = yPrecision; return ev; } /** * Create a new MotionEvent, filling in a subset of the basic motion * values. Those not specified here are: device id (always 0), pressure * and size (always 1), x and y precision (always 1), and edgeFlags (always 0). * * @param downTime The time (in ms) when the user originally pressed down to start * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. * @param eventTime The the time (in ms) when this specific event was generated. This * must be obtained from {@link SystemClock#uptimeMillis()}. * @param action The kind of action being performed -- one of either * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or * {@link #ACTION_CANCEL}. * @param x The X coordinate of this event. * @param y The Y coordinate of this event. * @param metaState The state of any meta / modifier keys that were in effect when * the event was generated. */ static public MotionEvent obtain(long downTime, long eventTime, int action, float x, float y, int metaState) { MotionEvent ev = obtain(); ev.mDeviceId = 0; ev.mEdgeFlags = 0; ev.mDownTime = downTime; ev.mEventTime = eventTime; ev.mEventTimeNano = eventTime * 1000000; ev.mAction = action; ev.mX = ev.mRawX = x; ev.mY = ev.mRawY = y; ev.mPressure = 1.0f; ev.mSize = 1.0f; ev.mMetaState = metaState; ev.mXPrecision = 1.0f; ev.mYPrecision = 1.0f; return ev; } /** * Scales down the coordination of this event by the given scale. * * @hide */ public void scale(float scale) { mX *= scale; mY *= scale; mRawX *= scale; mRawY *= scale; mSize *= scale; mXPrecision *= scale; mYPrecision *= scale; if (mHistory != null) { float[] history = mHistory; int length = history.length; for (int i = 0; i < length; i += 4) { history[i] *= scale; // X history[i + 1] *= scale; // Y // no need to scale pressure ([i+2]) history[i + 3] *= scale; // Size, TODO: square this? } } } /** * Translate the coordination of the event by given x and y. * * @hide */ public void translate(float dx, float dy) { mX += dx; mY += dy; mRawX += dx; mRawY += dx; if (mHistory != null) { float[] history = mHistory; int length = history.length; for (int i = 0; i < length; i += 4) { history[i] += dx; // X history[i + 1] += dy; // Y // no need to translate pressure (i+2) and size (i+3) } } } /** * Create a new MotionEvent, copying from an existing one. */ static public MotionEvent obtain(MotionEvent o) { MotionEvent ev = obtain(); ev.mDeviceId = o.mDeviceId; ev.mEdgeFlags = o.mEdgeFlags; ev.mDownTime = o.mDownTime; ev.mEventTime = o.mEventTime; ev.mEventTimeNano = o.mEventTimeNano; ev.mAction = o.mAction; ev.mX = o.mX; ev.mRawX = o.mRawX; ev.mY = o.mY; ev.mRawY = o.mRawY; ev.mPressure = o.mPressure; ev.mSize = o.mSize; ev.mMetaState = o.mMetaState; ev.mXPrecision = o.mXPrecision; ev.mYPrecision = o.mYPrecision; final int N = o.mNumHistory; ev.mNumHistory = N; if (N > 0) { // could be more efficient about this... ev.mHistory = (float[])o.mHistory.clone(); ev.mHistoryTimes = (long[])o.mHistoryTimes.clone(); } return ev; } /** * Recycle the MotionEvent, to be re-used by a later caller. After calling * this function you must not ever touch the event again. */ public void recycle() { // Ensure recycle is only called once! if (TRACK_RECYCLED_LOCATION) { if (mRecycledLocation != null) { throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation); } mRecycledLocation = new RuntimeException("Last recycled here"); } else if (mRecycled) { throw new RuntimeException(toString() + " recycled twice!"); } //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation); synchronized (gRecyclerLock) { if (gRecyclerUsed < MAX_RECYCLED) { gRecyclerUsed++; mNumHistory = 0; mNext = gRecyclerTop; gRecyclerTop = this; } } } /** * Return the kind of action being performed -- one of either * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or * {@link #ACTION_CANCEL}. */ public final int getAction() { return mAction; } /** * Returns the time (in ms) when the user originally pressed down to start * a stream of position events. */ public final long getDownTime() { return mDownTime; } /** * Returns the time (in ms) when this specific event was generated. */ public final long getEventTime() { return mEventTime; } /** <<<<<<< HEAD:core/java/android/view/MotionEvent.java * Returns the time (in ns) when this specific event was generated. * The value is in nanosecond precision but it may not have nanosecond accuracy. * * @hide */ public final long getEventTimeNano() { return mEventTimeNano; } /** * Returns the X coordinate of this event. Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. ||||||| * Returns the X coordinate of this event. Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. ======= * Returns the X coordinate of this event. Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. >>>>>>> cafdea61a85c8f5d0646cc9413a09346c637f43f:core/java/android/view/MotionEvent.java */ public final float getX() { return mX; } /** * Returns the Y coordinate of this event. Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. */ public final float getY() { return mY; } /** * Returns the current pressure of this event. The pressure generally * ranges from 0 (no pressure at all) to 1 (normal pressure), however * values higher than 1 may be generated depending on the calibration of * the input device. */ public final float getPressure() { return mPressure; } /** * Returns a scaled value of the approximate size, of the area being pressed when * touched with the finger. The actual value in pixels corresponding to the finger * touch is normalized with the device specific range of values * and scaled to a value between 0 and 1. The value of size can be used to * determine fat touch events. */ public final float getSize() { return mSize; } /** * Returns the state of any meta / modifier keys that were in effect when * the event was generated. This is the same values as those * returned by {@link KeyEvent#getMetaState() KeyEvent.getMetaState}. * * @return an integer in which each bit set to 1 represents a pressed * meta key * * @see KeyEvent#getMetaState() */ public final int getMetaState() { return mMetaState; } /** * Returns the original raw X coordinate of this event. For touch * events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window * and views. */ public final float getRawX() { return mRawX; } /** * Returns the original raw Y coordinate of this event. For touch * events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window * and views. */ public final float getRawY() { return mRawY; } /** * Return the precision of the X coordinates being reported. You can * multiple this number with {@link #getX} to find the actual hardware * value of the X coordinate. * @return Returns the precision of X coordinates being reported. */ public final float getXPrecision() { return mXPrecision; } /** * Return the precision of the Y coordinates being reported. You can * multiple this number with {@link #getY} to find the actual hardware * value of the Y coordinate. * @return Returns the precision of Y coordinates being reported. */ public final float getYPrecision() { return mYPrecision; } /** * Returns the number of historical points in this event. These are * movements that have occurred between this event and the previous event. * This only applies to ACTION_MOVE events -- all other actions will have * a size of 0. * * @return Returns the number of historical points in the event. */ public final int getHistorySize() { return mNumHistory; } /** * Returns the time that a historical movement occurred between this event * and the previous event. Only applies to ACTION_MOVE events. * * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getEventTime */ public final long getHistoricalEventTime(int pos) { return mHistoryTimes[pos]; } /** * Returns a historical X coordinate that occurred between this event * and the previous event. Only applies to ACTION_MOVE events. * * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getX */ public final float getHistoricalX(int pos) { return mHistory[pos*4]; } /** * Returns a historical Y coordinate that occurred between this event * and the previous event. Only applies to ACTION_MOVE events. * * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getY */ public final float getHistoricalY(int pos) { return mHistory[pos*4 + 1]; } /** * Returns a historical pressure coordinate that occurred between this event * and the previous event. Only applies to ACTION_MOVE events. * * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getPressure */ public final float getHistoricalPressure(int pos) { return mHistory[pos*4 + 2]; } /** * Returns a historical size coordinate that occurred between this event * and the previous event. Only applies to ACTION_MOVE events. * * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getSize */ public final float getHistoricalSize(int pos) { return mHistory[pos*4 + 3]; } /** * Return the id for the device that this event came from. An id of * zero indicates that the event didn't come from a physical device; other * numbers are arbitrary and you shouldn't depend on the values. */ public final int getDeviceId() { return mDeviceId; } /** * Returns a bitfield indicating which edges, if any, where touched by this * MotionEvent. For touch events, clients can use this to determine if the * user's finger was touching the edge of the display. * * @see #EDGE_LEFT * @see #EDGE_TOP * @see #EDGE_RIGHT * @see #EDGE_BOTTOM */ public final int getEdgeFlags() { return mEdgeFlags; } /** * Sets the bitfield indicating which edges, if any, where touched by this * MotionEvent. * * @see #getEdgeFlags() */ public final void setEdgeFlags(int flags) { mEdgeFlags = flags; } /** * Sets this event's action. */ public final void setAction(int action) { mAction = action; } /** * Adjust this event's location. * @param deltaX Amount to add to the current X coordinate of the event. * @param deltaY Amount to add to the current Y coordinate of the event. */ public final void offsetLocation(float deltaX, float deltaY) { mX += deltaX; mY += deltaY; final int N = mNumHistory*4; if (N <= 0) { return; } final float[] pos = mHistory; for (int i=0; i CREATOR = new Parcelable.Creator() { public MotionEvent createFromParcel(Parcel in) { MotionEvent ev = obtain(); ev.readFromParcel(in); return ev; } public MotionEvent[] newArray(int size) { return new MotionEvent[size]; } }; public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeLong(mDownTime); out.writeLong(mEventTime); out.writeLong(mEventTimeNano); out.writeInt(mAction); out.writeFloat(mX); out.writeFloat(mY); out.writeFloat(mPressure); out.writeFloat(mSize); out.writeInt(mMetaState); out.writeFloat(mRawX); out.writeFloat(mRawY); final int N = mNumHistory; out.writeInt(N); if (N > 0) { final int N4 = N*4; int i; float[] history = mHistory; for (i=0; i 0) { final int N4 = N*4; float[] history = mHistory; if (history == null || history.length < N4) { mHistory = history = new float[N4 + (4*4)]; } for (int i=0; i