MotionEvent.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
1/* 2 * Copyright (C) 2007 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.view; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.os.SystemClock; 22import android.util.Config; 23 24/** 25 * Object used to report movement (mouse, pen, finger, trackball) events. This 26 * class may hold either absolute or relative movements, depending on what 27 * it is being used for. 28 */ 29public final class MotionEvent implements Parcelable { 30 /** 31 * Constant for {@link #getAction}: A pressed gesture has started, the 32 * motion contains the initial starting location. 33 */ 34 public static final int ACTION_DOWN = 0; 35 /** 36 * Constant for {@link #getAction}: A pressed gesture has finished, the 37 * motion contains the final release location as well as any intermediate 38 * points since the last down or move event. 39 */ 40 public static final int ACTION_UP = 1; 41 /** 42 * Constant for {@link #getAction}: A change has happened during a 43 * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}). 44 * The motion contains the most recent point, as well as any intermediate 45 * points since the last down or move event. 46 */ 47 public static final int ACTION_MOVE = 2; 48 /** 49 * Constant for {@link #getAction}: The current gesture has been aborted. 50 * You will not receive any more points in it. You should treat this as 51 * an up event, but not perform any action that you normally would. 52 */ 53 public static final int ACTION_CANCEL = 3; 54 /** 55 * Constant for {@link #getAction}: A movement has happened outside of the 56 * normal bounds of the UI element. This does not provide a full gesture, 57 * but only the initial location of the movement/touch. 58 */ 59 public static final int ACTION_OUTSIDE = 4; 60 61 private static final boolean TRACK_RECYCLED_LOCATION = false; 62 63 /** 64 * Flag indicating the motion event intersected the top edge of the screen. 65 */ 66 public static final int EDGE_TOP = 0x00000001; 67 68 /** 69 * Flag indicating the motion event intersected the bottom edge of the screen. 70 */ 71 public static final int EDGE_BOTTOM = 0x00000002; 72 73 /** 74 * Flag indicating the motion event intersected the left edge of the screen. 75 */ 76 public static final int EDGE_LEFT = 0x00000004; 77 78 /** 79 * Flag indicating the motion event intersected the right edge of the screen. 80 */ 81 public static final int EDGE_RIGHT = 0x00000008; 82 83 static private final int MAX_RECYCLED = 10; 84 static private Object gRecyclerLock = new Object(); 85 static private int gRecyclerUsed = 0; 86 static private MotionEvent gRecyclerTop = null; 87 88 private long mDownTime; 89 private long mEventTime; 90 private int mAction; 91 private float mX; 92 private float mY; 93 private float mRawX; 94 private float mRawY; 95 private float mPressure; 96 private float mSize; 97 private int mMetaState; 98 private int mNumHistory; 99 private float[] mHistory; 100 private long[] mHistoryTimes; 101 private float mXPrecision; 102 private float mYPrecision; 103 private int mDeviceId; 104 private int mEdgeFlags; 105 106 private MotionEvent mNext; 107 private RuntimeException mRecycledLocation; 108 private boolean mRecycled; 109 110 private MotionEvent() { 111 } 112 113 static private MotionEvent obtain() { 114 synchronized (gRecyclerLock) { 115 if (gRecyclerTop == null) { 116 return new MotionEvent(); 117 } 118 MotionEvent ev = gRecyclerTop; 119 gRecyclerTop = ev.mNext; 120 gRecyclerUsed--; 121 ev.mRecycledLocation = null; 122 ev.mRecycled = false; 123 return ev; 124 } 125 } 126 127 /** 128 * Create a new MotionEvent, filling in all of the basic values that 129 * define the motion. 130 * 131 * @param downTime The time (in ms) when the user originally pressed down to start 132 * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. 133 * @param eventTime The the time (in ms) when this specific event was generated. This 134 * must be obtained from {@link SystemClock#uptimeMillis()}. 135 * @param action The kind of action being performed -- one of either 136 * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or 137 * {@link #ACTION_CANCEL}. 138 * @param x The X coordinate of this event. 139 * @param y The Y coordinate of this event. 140 * @param pressure The current pressure of this event. The pressure generally 141 * ranges from 0 (no pressure at all) to 1 (normal pressure), however 142 * values higher than 1 may be generated depending on the calibration of 143 * the input device. 144 * @param size A scaled value of the approximate size of the area being pressed when 145 * touched with the finger. The actual value in pixels corresponding to the finger 146 * touch is normalized with a device specific range of values 147 * and scaled to a value between 0 and 1. 148 * @param metaState The state of any meta / modifier keys that were in effect when 149 * the event was generated. 150 * @param xPrecision The precision of the X coordinate being reported. 151 * @param yPrecision The precision of the Y coordinate being reported. 152 * @param deviceId The id for the device that this event came from. An id of 153 * zero indicates that the event didn't come from a physical device; other 154 * numbers are arbitrary and you shouldn't depend on the values. 155 * @param edgeFlags A bitfield indicating which edges, if any, where touched by this 156 * MotionEvent. 157 */ 158 static public MotionEvent obtain(long downTime, long eventTime, int action, 159 float x, float y, float pressure, float size, int metaState, 160 float xPrecision, float yPrecision, int deviceId, int edgeFlags) { 161 MotionEvent ev = obtain(); 162 ev.mDeviceId = deviceId; 163 ev.mEdgeFlags = edgeFlags; 164 ev.mDownTime = downTime; 165 ev.mEventTime = eventTime; 166 ev.mAction = action; 167 ev.mX = ev.mRawX = x; 168 ev.mY = ev.mRawY = y; 169 ev.mPressure = pressure; 170 ev.mSize = size; 171 ev.mMetaState = metaState; 172 ev.mXPrecision = xPrecision; 173 ev.mYPrecision = yPrecision; 174 175 return ev; 176 } 177 178 /** 179 * Create a new MotionEvent, filling in a subset of the basic motion 180 * values. Those not specified here are: device id (always 0), pressure 181 * and size (always 1), x and y precision (always 1), and edgeFlags (always 0). 182 * 183 * @param downTime The time (in ms) when the user originally pressed down to start 184 * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. 185 * @param eventTime The the time (in ms) when this specific event was generated. This 186 * must be obtained from {@link SystemClock#uptimeMillis()}. 187 * @param action The kind of action being performed -- one of either 188 * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or 189 * {@link #ACTION_CANCEL}. 190 * @param x The X coordinate of this event. 191 * @param y The Y coordinate of this event. 192 * @param metaState The state of any meta / modifier keys that were in effect when 193 * the event was generated. 194 */ 195 static public MotionEvent obtain(long downTime, long eventTime, int action, 196 float x, float y, int metaState) { 197 MotionEvent ev = obtain(); 198 ev.mDeviceId = 0; 199 ev.mEdgeFlags = 0; 200 ev.mDownTime = downTime; 201 ev.mEventTime = eventTime; 202 ev.mAction = action; 203 ev.mX = ev.mRawX = x; 204 ev.mY = ev.mRawY = y; 205 ev.mPressure = 1.0f; 206 ev.mSize = 1.0f; 207 ev.mMetaState = metaState; 208 ev.mXPrecision = 1.0f; 209 ev.mYPrecision = 1.0f; 210 211 return ev; 212 } 213 214 /** 215 * Create a new MotionEvent, copying from an existing one. 216 */ 217 static public MotionEvent obtain(MotionEvent o) { 218 MotionEvent ev = obtain(); 219 ev.mDeviceId = o.mDeviceId; 220 ev.mEdgeFlags = o.mEdgeFlags; 221 ev.mDownTime = o.mDownTime; 222 ev.mEventTime = o.mEventTime; 223 ev.mAction = o.mAction; 224 ev.mX = o.mX; 225 ev.mRawX = o.mRawX; 226 ev.mY = o.mY; 227 ev.mRawY = o.mRawY; 228 ev.mPressure = o.mPressure; 229 ev.mSize = o.mSize; 230 ev.mMetaState = o.mMetaState; 231 ev.mXPrecision = o.mXPrecision; 232 ev.mYPrecision = o.mYPrecision; 233 final int N = o.mNumHistory; 234 ev.mNumHistory = N; 235 if (N > 0) { 236 // could be more efficient about this... 237 ev.mHistory = (float[])o.mHistory.clone(); 238 ev.mHistoryTimes = (long[])o.mHistoryTimes.clone(); 239 } 240 return ev; 241 } 242 243 /** 244 * Recycle the MotionEvent, to be re-used by a later caller. After calling 245 * this function you must not ever touch the event again. 246 */ 247 public void recycle() { 248 // Ensure recycle is only called once! 249 if (TRACK_RECYCLED_LOCATION) { 250 if (mRecycledLocation != null) { 251 throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation); 252 } 253 mRecycledLocation = new RuntimeException("Last recycled here"); 254 } else if (mRecycled) { 255 throw new RuntimeException(toString() + " recycled twice!"); 256 } 257 258 //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation); 259 synchronized (gRecyclerLock) { 260 if (gRecyclerUsed < MAX_RECYCLED) { 261 gRecyclerUsed++; 262 mNumHistory = 0; 263 mNext = gRecyclerTop; 264 gRecyclerTop = this; 265 } 266 } 267 } 268 269 /** 270 * Return the kind of action being performed -- one of either 271 * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or 272 * {@link #ACTION_CANCEL}. 273 */ 274 public final int getAction() { 275 return mAction; 276 } 277 278 /** 279 * Returns the time (in ms) when the user originally pressed down to start 280 * a stream of position events. 281 */ 282 public final long getDownTime() { 283 return mDownTime; 284 } 285 286 /** 287 * Returns the time (in ms) when this specific event was generated. 288 */ 289 public final long getEventTime() { 290 return mEventTime; 291 } 292 293 /** 294 * Returns the X coordinate of this event. Whole numbers are pixels; the 295 * value may have a fraction for input devices that are sub-pixel precise. 296 */ 297 public final float getX() { 298 return mX; 299 } 300 301 /** 302 * Returns the Y coordinate of this event. Whole numbers are pixels; the 303 * value may have a fraction for input devices that are sub-pixel precise. 304 */ 305 public final float getY() { 306 return mY; 307 } 308 309 /** 310 * Returns the current pressure of this event. The pressure generally 311 * ranges from 0 (no pressure at all) to 1 (normal pressure), however 312 * values higher than 1 may be generated depending on the calibration of 313 * the input device. 314 */ 315 public final float getPressure() { 316 return mPressure; 317 } 318 319 /** 320 * Returns a scaled value of the approximate size, of the area being pressed when 321 * touched with the finger. The actual value in pixels corresponding to the finger 322 * touch is normalized with the device specific range of values 323 * and scaled to a value between 0 and 1. The value of size can be used to 324 * determine fat touch events. 325 */ 326 public final float getSize() { 327 return mSize; 328 } 329 330 /** 331 * Returns the state of any meta / modifier keys that were in effect when 332 * the event was generated. This is the same values as those 333 * returned by {@link KeyEvent#getMetaState() KeyEvent.getMetaState}. 334 * 335 * @return an integer in which each bit set to 1 represents a pressed 336 * meta key 337 * 338 * @see KeyEvent#getMetaState() 339 */ 340 public final int getMetaState() { 341 return mMetaState; 342 } 343 344 /** 345 * Returns the original raw X coordinate of this event. For touch 346 * events on the screen, this is the original location of the event 347 * on the screen, before it had been adjusted for the containing window 348 * and views. 349 */ 350 public final float getRawX() { 351 return mRawX; 352 } 353 354 /** 355 * Returns the original raw Y coordinate of this event. For touch 356 * events on the screen, this is the original location of the event 357 * on the screen, before it had been adjusted for the containing window 358 * and views. 359 */ 360 public final float getRawY() { 361 return mRawY; 362 } 363 364 /** 365 * Return the precision of the X coordinates being reported. You can 366 * multiple this number with {@link #getX} to find the actual hardware 367 * value of the X coordinate. 368 * @return Returns the precision of X coordinates being reported. 369 */ 370 public final float getXPrecision() { 371 return mXPrecision; 372 } 373 374 /** 375 * Return the precision of the Y coordinates being reported. You can 376 * multiple this number with {@link #getY} to find the actual hardware 377 * value of the Y coordinate. 378 * @return Returns the precision of Y coordinates being reported. 379 */ 380 public final float getYPrecision() { 381 return mYPrecision; 382 } 383 384 /** 385 * Returns the number of historical points in this event. These are 386 * movements that have occurred between this event and the previous event. 387 * This only applies to ACTION_MOVE events -- all other actions will have 388 * a size of 0. 389 * 390 * @return Returns the number of historical points in the event. 391 */ 392 public final int getHistorySize() { 393 return mNumHistory; 394 } 395 396 /** 397 * Returns the time that a historical movement occurred between this event 398 * and the previous event. Only applies to ACTION_MOVE events. 399 * 400 * @param pos Which historical value to return; must be less than 401 * {@link #getHistorySize} 402 * 403 * @see #getHistorySize 404 * @see #getEventTime 405 */ 406 public final long getHistoricalEventTime(int pos) { 407 return mHistoryTimes[pos]; 408 } 409 410 /** 411 * Returns a historical X coordinate that occurred between this event 412 * and the previous event. Only applies to ACTION_MOVE events. 413 * 414 * @param pos Which historical value to return; must be less than 415 * {@link #getHistorySize} 416 * 417 * @see #getHistorySize 418 * @see #getX 419 */ 420 public final float getHistoricalX(int pos) { 421 return mHistory[pos*4]; 422 } 423 424 /** 425 * Returns a historical Y coordinate that occurred between this event 426 * and the previous event. Only applies to ACTION_MOVE events. 427 * 428 * @param pos Which historical value to return; must be less than 429 * {@link #getHistorySize} 430 * 431 * @see #getHistorySize 432 * @see #getY 433 */ 434 public final float getHistoricalY(int pos) { 435 return mHistory[pos*4 + 1]; 436 } 437 438 /** 439 * Returns a historical pressure coordinate that occurred between this event 440 * and the previous event. Only applies to ACTION_MOVE events. 441 * 442 * @param pos Which historical value to return; must be less than 443 * {@link #getHistorySize} 444 * 445 * @see #getHistorySize 446 * @see #getPressure 447 */ 448 public final float getHistoricalPressure(int pos) { 449 return mHistory[pos*4 + 2]; 450 } 451 452 /** 453 * Returns a historical size coordinate that occurred between this event 454 * and the previous event. Only applies to ACTION_MOVE events. 455 * 456 * @param pos Which historical value to return; must be less than 457 * {@link #getHistorySize} 458 * 459 * @see #getHistorySize 460 * @see #getSize 461 */ 462 public final float getHistoricalSize(int pos) { 463 return mHistory[pos*4 + 3]; 464 } 465 466 /** 467 * Return the id for the device that this event came from. An id of 468 * zero indicates that the event didn't come from a physical device; other 469 * numbers are arbitrary and you shouldn't depend on the values. 470 */ 471 public final int getDeviceId() { 472 return mDeviceId; 473 } 474 475 /** 476 * Returns a bitfield indicating which edges, if any, where touched by this 477 * MotionEvent. For touch events, clients can use this to determine if the 478 * user's finger was touching the edge of the display. 479 * 480 * @see #EDGE_LEFT 481 * @see #EDGE_TOP 482 * @see #EDGE_RIGHT 483 * @see #EDGE_BOTTOM 484 */ 485 public final int getEdgeFlags() { 486 return mEdgeFlags; 487 } 488 489 490 /** 491 * Sets the bitfield indicating which edges, if any, where touched by this 492 * MotionEvent. 493 * 494 * @see #getEdgeFlags() 495 */ 496 public final void setEdgeFlags(int flags) { 497 mEdgeFlags = flags; 498 } 499 500 /** 501 * Sets this event's action. 502 */ 503 public final void setAction(int action) { 504 mAction = action; 505 } 506 507 /** 508 * Adjust this event's location. 509 * @param deltaX Amount to add to the current X coordinate of the event. 510 * @param deltaY Amount to add to the current Y coordinate of the event. 511 */ 512 public final void offsetLocation(float deltaX, float deltaY) { 513 mX += deltaX; 514 mY += deltaY; 515 final int N = mNumHistory*4; 516 if (N <= 0) { 517 return; 518 } 519 final float[] pos = mHistory; 520 for (int i=0; i<N; i+=4) { 521 pos[i] += deltaX; 522 pos[i+1] += deltaY; 523 } 524 } 525 526 /** 527 * Set this event's location. Applies {@link #offsetLocation} with a 528 * delta from the current location to the given new location. 529 * 530 * @param x New absolute X location. 531 * @param y New absolute Y location. 532 */ 533 public final void setLocation(float x, float y) { 534 float deltaX = x-mX; 535 float deltaY = y-mY; 536 if (deltaX != 0 || deltaY != 0) { 537 offsetLocation(deltaX, deltaY); 538 } 539 } 540 541 /** 542 * Add a new movement to the batch of movements in this event. The event's 543 * current location, position and size is updated to the new values. In 544 * the future, the current values in the event will be added to a list of 545 * historic values. 546 * 547 * @param x The new X position. 548 * @param y The new Y position. 549 * @param pressure The new pressure. 550 * @param size The new size. 551 */ 552 public final void addBatch(long eventTime, float x, float y, 553 float pressure, float size, int metaState) { 554 float[] history = mHistory; 555 long[] historyTimes = mHistoryTimes; 556 int N; 557 int avail; 558 if (history == null) { 559 mHistory = history = new float[8*4]; 560 mHistoryTimes = historyTimes = new long[8]; 561 mNumHistory = N = 0; 562 avail = 8; 563 } else { 564 N = mNumHistory; 565 avail = history.length/4; 566 if (N == avail) { 567 avail += 8; 568 float[] newHistory = new float[avail*4]; 569 System.arraycopy(history, 0, newHistory, 0, N*4); 570 mHistory = history = newHistory; 571 long[] newHistoryTimes = new long[avail]; 572 System.arraycopy(historyTimes, 0, newHistoryTimes, 0, N); 573 mHistoryTimes = historyTimes = newHistoryTimes; 574 } 575 } 576 577 historyTimes[N] = mEventTime; 578 579 final int pos = N*4; 580 history[pos] = mX; 581 history[pos+1] = mY; 582 history[pos+2] = mPressure; 583 history[pos+3] = mSize; 584 mNumHistory = N+1; 585 586 mEventTime = eventTime; 587 mX = mRawX = x; 588 mY = mRawY = y; 589 mPressure = pressure; 590 mSize = size; 591 mMetaState |= metaState; 592 } 593 594 @Override 595 public String toString() { 596 return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this)) 597 + " action=" + mAction + " x=" + mX 598 + " y=" + mY + " pressure=" + mPressure + " size=" + mSize + "}"; 599 } 600 601 public static final Parcelable.Creator<MotionEvent> CREATOR 602 = new Parcelable.Creator<MotionEvent>() { 603 public MotionEvent createFromParcel(Parcel in) { 604 MotionEvent ev = obtain(); 605 ev.readFromParcel(in); 606 return ev; 607 } 608 609 public MotionEvent[] newArray(int size) { 610 return new MotionEvent[size]; 611 } 612 }; 613 614 public int describeContents() { 615 return 0; 616 } 617 618 public void writeToParcel(Parcel out, int flags) { 619 out.writeLong(mDownTime); 620 out.writeLong(mEventTime); 621 out.writeInt(mAction); 622 out.writeFloat(mX); 623 out.writeFloat(mY); 624 out.writeFloat(mPressure); 625 out.writeFloat(mSize); 626 out.writeInt(mMetaState); 627 out.writeFloat(mRawX); 628 out.writeFloat(mRawY); 629 final int N = mNumHistory; 630 out.writeInt(N); 631 if (N > 0) { 632 final int N4 = N*4; 633 int i; 634 float[] history = mHistory; 635 for (i=0; i<N4; i++) { 636 out.writeFloat(history[i]); 637 } 638 long[] times = mHistoryTimes; 639 for (i=0; i<N; i++) { 640 out.writeLong(times[i]); 641 } 642 } 643 out.writeFloat(mXPrecision); 644 out.writeFloat(mYPrecision); 645 out.writeInt(mDeviceId); 646 out.writeInt(mEdgeFlags); 647 } 648 649 private void readFromParcel(Parcel in) { 650 mDownTime = in.readLong(); 651 mEventTime = in.readLong(); 652 mAction = in.readInt(); 653 mX = in.readFloat(); 654 mY = in.readFloat(); 655 mPressure = in.readFloat(); 656 mSize = in.readFloat(); 657 mMetaState = in.readInt(); 658 mRawX = in.readFloat(); 659 mRawY = in.readFloat(); 660 final int N = in.readInt(); 661 if ((mNumHistory=N) > 0) { 662 final int N4 = N*4; 663 float[] history = mHistory; 664 if (history == null || history.length < N4) { 665 mHistory = history = new float[N4 + (4*4)]; 666 } 667 for (int i=0; i<N4; i++) { 668 history[i] = in.readFloat(); 669 } 670 long[] times = mHistoryTimes; 671 if (times == null || times.length < N) { 672 mHistoryTimes = times = new long[N + 4]; 673 } 674 for (int i=0; i<N; i++) { 675 times[i] = in.readLong(); 676 } 677 } 678 mXPrecision = in.readFloat(); 679 mYPrecision = in.readFloat(); 680 mDeviceId = in.readInt(); 681 mEdgeFlags = in.readInt(); 682 } 683 684} 685 686