MotionEvent.java revision dffbb4dbceb7e90e91b65d02dfdbd1abd6147b94
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 * Scales down the cood of this event by the given scale. 216 * 217 * @hide 218 */ 219 public void scale(float scale) { 220 if (scale != 1.0f) { 221 mX *= scale; 222 mY *= scale; 223 mRawX *= scale; 224 mRawY *= scale; 225 mSize *= scale; 226 mXPrecision *= scale; 227 mYPrecision *= scale; 228 if (mHistory != null) { 229 float[] history = mHistory; 230 int length = history.length; 231 for (int i = 0; i < length; i++) { 232 history[i] *= scale; 233 } 234 } 235 } 236 } 237 238 /** 239 * Create a new MotionEvent, copying from an existing one. 240 */ 241 static public MotionEvent obtain(MotionEvent o) { 242 MotionEvent ev = obtain(); 243 ev.mDeviceId = o.mDeviceId; 244 ev.mEdgeFlags = o.mEdgeFlags; 245 ev.mDownTime = o.mDownTime; 246 ev.mEventTime = o.mEventTime; 247 ev.mAction = o.mAction; 248 ev.mX = o.mX; 249 ev.mRawX = o.mRawX; 250 ev.mY = o.mY; 251 ev.mRawY = o.mRawY; 252 ev.mPressure = o.mPressure; 253 ev.mSize = o.mSize; 254 ev.mMetaState = o.mMetaState; 255 ev.mXPrecision = o.mXPrecision; 256 ev.mYPrecision = o.mYPrecision; 257 final int N = o.mNumHistory; 258 ev.mNumHistory = N; 259 if (N > 0) { 260 // could be more efficient about this... 261 ev.mHistory = (float[])o.mHistory.clone(); 262 ev.mHistoryTimes = (long[])o.mHistoryTimes.clone(); 263 } 264 return ev; 265 } 266 267 /** 268 * Recycle the MotionEvent, to be re-used by a later caller. After calling 269 * this function you must not ever touch the event again. 270 */ 271 public void recycle() { 272 // Ensure recycle is only called once! 273 if (TRACK_RECYCLED_LOCATION) { 274 if (mRecycledLocation != null) { 275 throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation); 276 } 277 mRecycledLocation = new RuntimeException("Last recycled here"); 278 } else if (mRecycled) { 279 throw new RuntimeException(toString() + " recycled twice!"); 280 } 281 282 //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation); 283 synchronized (gRecyclerLock) { 284 if (gRecyclerUsed < MAX_RECYCLED) { 285 gRecyclerUsed++; 286 mNumHistory = 0; 287 mNext = gRecyclerTop; 288 gRecyclerTop = this; 289 } 290 } 291 } 292 293 /** 294 * Return the kind of action being performed -- one of either 295 * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or 296 * {@link #ACTION_CANCEL}. 297 */ 298 public final int getAction() { 299 return mAction; 300 } 301 302 /** 303 * Returns the time (in ms) when the user originally pressed down to start 304 * a stream of position events. 305 */ 306 public final long getDownTime() { 307 return mDownTime; 308 } 309 310 /** 311 * Returns the time (in ms) when this specific event was generated. 312 */ 313 public final long getEventTime() { 314 return mEventTime; 315 } 316 317 /** 318 * Returns the X coordinate of this event. Whole numbers are pixels; the 319 * value may have a fraction for input devices that are sub-pixel precise. 320 */ 321 public final float getX() { 322 return mX; 323 } 324 325 /** 326 * Returns the Y coordinate of this event. Whole numbers are pixels; the 327 * value may have a fraction for input devices that are sub-pixel precise. 328 */ 329 public final float getY() { 330 return mY; 331 } 332 333 /** 334 * Returns the current pressure of this event. The pressure generally 335 * ranges from 0 (no pressure at all) to 1 (normal pressure), however 336 * values higher than 1 may be generated depending on the calibration of 337 * the input device. 338 */ 339 public final float getPressure() { 340 return mPressure; 341 } 342 343 /** 344 * Returns a scaled value of the approximate size, of the area being pressed when 345 * touched with the finger. The actual value in pixels corresponding to the finger 346 * touch is normalized with the device specific range of values 347 * and scaled to a value between 0 and 1. The value of size can be used to 348 * determine fat touch events. 349 */ 350 public final float getSize() { 351 return mSize; 352 } 353 354 /** 355 * Returns the state of any meta / modifier keys that were in effect when 356 * the event was generated. This is the same values as those 357 * returned by {@link KeyEvent#getMetaState() KeyEvent.getMetaState}. 358 * 359 * @return an integer in which each bit set to 1 represents a pressed 360 * meta key 361 * 362 * @see KeyEvent#getMetaState() 363 */ 364 public final int getMetaState() { 365 return mMetaState; 366 } 367 368 /** 369 * Returns the original raw X coordinate of this event. For touch 370 * events on the screen, this is the original location of the event 371 * on the screen, before it had been adjusted for the containing window 372 * and views. 373 */ 374 public final float getRawX() { 375 return mRawX; 376 } 377 378 /** 379 * Returns the original raw Y coordinate of this event. For touch 380 * events on the screen, this is the original location of the event 381 * on the screen, before it had been adjusted for the containing window 382 * and views. 383 */ 384 public final float getRawY() { 385 return mRawY; 386 } 387 388 /** 389 * Return the precision of the X coordinates being reported. You can 390 * multiple this number with {@link #getX} to find the actual hardware 391 * value of the X coordinate. 392 * @return Returns the precision of X coordinates being reported. 393 */ 394 public final float getXPrecision() { 395 return mXPrecision; 396 } 397 398 /** 399 * Return the precision of the Y coordinates being reported. You can 400 * multiple this number with {@link #getY} to find the actual hardware 401 * value of the Y coordinate. 402 * @return Returns the precision of Y coordinates being reported. 403 */ 404 public final float getYPrecision() { 405 return mYPrecision; 406 } 407 408 /** 409 * Returns the number of historical points in this event. These are 410 * movements that have occurred between this event and the previous event. 411 * This only applies to ACTION_MOVE events -- all other actions will have 412 * a size of 0. 413 * 414 * @return Returns the number of historical points in the event. 415 */ 416 public final int getHistorySize() { 417 return mNumHistory; 418 } 419 420 /** 421 * Returns the time that a historical movement occurred between this event 422 * and the previous event. Only applies to ACTION_MOVE events. 423 * 424 * @param pos Which historical value to return; must be less than 425 * {@link #getHistorySize} 426 * 427 * @see #getHistorySize 428 * @see #getEventTime 429 */ 430 public final long getHistoricalEventTime(int pos) { 431 return mHistoryTimes[pos]; 432 } 433 434 /** 435 * Returns a historical X coordinate that occurred between this event 436 * and the previous event. Only applies to ACTION_MOVE events. 437 * 438 * @param pos Which historical value to return; must be less than 439 * {@link #getHistorySize} 440 * 441 * @see #getHistorySize 442 * @see #getX 443 */ 444 public final float getHistoricalX(int pos) { 445 return mHistory[pos*4]; 446 } 447 448 /** 449 * Returns a historical Y coordinate that occurred between this event 450 * and the previous event. Only applies to ACTION_MOVE events. 451 * 452 * @param pos Which historical value to return; must be less than 453 * {@link #getHistorySize} 454 * 455 * @see #getHistorySize 456 * @see #getY 457 */ 458 public final float getHistoricalY(int pos) { 459 return mHistory[pos*4 + 1]; 460 } 461 462 /** 463 * Returns a historical pressure coordinate that occurred between this event 464 * and the previous event. Only applies to ACTION_MOVE events. 465 * 466 * @param pos Which historical value to return; must be less than 467 * {@link #getHistorySize} 468 * 469 * @see #getHistorySize 470 * @see #getPressure 471 */ 472 public final float getHistoricalPressure(int pos) { 473 return mHistory[pos*4 + 2]; 474 } 475 476 /** 477 * Returns a historical size coordinate that occurred between this event 478 * and the previous event. Only applies to ACTION_MOVE events. 479 * 480 * @param pos Which historical value to return; must be less than 481 * {@link #getHistorySize} 482 * 483 * @see #getHistorySize 484 * @see #getSize 485 */ 486 public final float getHistoricalSize(int pos) { 487 return mHistory[pos*4 + 3]; 488 } 489 490 /** 491 * Return the id for the device that this event came from. An id of 492 * zero indicates that the event didn't come from a physical device; other 493 * numbers are arbitrary and you shouldn't depend on the values. 494 */ 495 public final int getDeviceId() { 496 return mDeviceId; 497 } 498 499 /** 500 * Returns a bitfield indicating which edges, if any, where touched by this 501 * MotionEvent. For touch events, clients can use this to determine if the 502 * user's finger was touching the edge of the display. 503 * 504 * @see #EDGE_LEFT 505 * @see #EDGE_TOP 506 * @see #EDGE_RIGHT 507 * @see #EDGE_BOTTOM 508 */ 509 public final int getEdgeFlags() { 510 return mEdgeFlags; 511 } 512 513 514 /** 515 * Sets the bitfield indicating which edges, if any, where touched by this 516 * MotionEvent. 517 * 518 * @see #getEdgeFlags() 519 */ 520 public final void setEdgeFlags(int flags) { 521 mEdgeFlags = flags; 522 } 523 524 /** 525 * Sets this event's action. 526 */ 527 public final void setAction(int action) { 528 mAction = action; 529 } 530 531 /** 532 * Adjust this event's location. 533 * @param deltaX Amount to add to the current X coordinate of the event. 534 * @param deltaY Amount to add to the current Y coordinate of the event. 535 */ 536 public final void offsetLocation(float deltaX, float deltaY) { 537 mX += deltaX; 538 mY += deltaY; 539 final int N = mNumHistory*4; 540 if (N <= 0) { 541 return; 542 } 543 final float[] pos = mHistory; 544 for (int i=0; i<N; i+=4) { 545 pos[i] += deltaX; 546 pos[i+1] += deltaY; 547 } 548 } 549 550 /** 551 * Set this event's location. Applies {@link #offsetLocation} with a 552 * delta from the current location to the given new location. 553 * 554 * @param x New absolute X location. 555 * @param y New absolute Y location. 556 */ 557 public final void setLocation(float x, float y) { 558 float deltaX = x-mX; 559 float deltaY = y-mY; 560 if (deltaX != 0 || deltaY != 0) { 561 offsetLocation(deltaX, deltaY); 562 } 563 } 564 565 /** 566 * Add a new movement to the batch of movements in this event. The event's 567 * current location, position and size is updated to the new values. In 568 * the future, the current values in the event will be added to a list of 569 * historic values. 570 * 571 * @param x The new X position. 572 * @param y The new Y position. 573 * @param pressure The new pressure. 574 * @param size The new size. 575 */ 576 public final void addBatch(long eventTime, float x, float y, 577 float pressure, float size, int metaState) { 578 float[] history = mHistory; 579 long[] historyTimes = mHistoryTimes; 580 int N; 581 int avail; 582 if (history == null) { 583 mHistory = history = new float[8*4]; 584 mHistoryTimes = historyTimes = new long[8]; 585 mNumHistory = N = 0; 586 avail = 8; 587 } else { 588 N = mNumHistory; 589 avail = history.length/4; 590 if (N == avail) { 591 avail += 8; 592 float[] newHistory = new float[avail*4]; 593 System.arraycopy(history, 0, newHistory, 0, N*4); 594 mHistory = history = newHistory; 595 long[] newHistoryTimes = new long[avail]; 596 System.arraycopy(historyTimes, 0, newHistoryTimes, 0, N); 597 mHistoryTimes = historyTimes = newHistoryTimes; 598 } 599 } 600 601 historyTimes[N] = mEventTime; 602 603 final int pos = N*4; 604 history[pos] = mX; 605 history[pos+1] = mY; 606 history[pos+2] = mPressure; 607 history[pos+3] = mSize; 608 mNumHistory = N+1; 609 610 mEventTime = eventTime; 611 mX = mRawX = x; 612 mY = mRawY = y; 613 mPressure = pressure; 614 mSize = size; 615 mMetaState |= metaState; 616 } 617 618 @Override 619 public String toString() { 620 return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this)) 621 + " action=" + mAction + " x=" + mX 622 + " y=" + mY + " pressure=" + mPressure + " size=" + mSize + "}"; 623 } 624 625 public static final Parcelable.Creator<MotionEvent> CREATOR 626 = new Parcelable.Creator<MotionEvent>() { 627 public MotionEvent createFromParcel(Parcel in) { 628 MotionEvent ev = obtain(); 629 ev.readFromParcel(in); 630 return ev; 631 } 632 633 public MotionEvent[] newArray(int size) { 634 return new MotionEvent[size]; 635 } 636 }; 637 638 public int describeContents() { 639 return 0; 640 } 641 642 public void writeToParcel(Parcel out, int flags) { 643 out.writeLong(mDownTime); 644 out.writeLong(mEventTime); 645 out.writeInt(mAction); 646 out.writeFloat(mX); 647 out.writeFloat(mY); 648 out.writeFloat(mPressure); 649 out.writeFloat(mSize); 650 out.writeInt(mMetaState); 651 out.writeFloat(mRawX); 652 out.writeFloat(mRawY); 653 final int N = mNumHistory; 654 out.writeInt(N); 655 if (N > 0) { 656 final int N4 = N*4; 657 int i; 658 float[] history = mHistory; 659 for (i=0; i<N4; i++) { 660 out.writeFloat(history[i]); 661 } 662 long[] times = mHistoryTimes; 663 for (i=0; i<N; i++) { 664 out.writeLong(times[i]); 665 } 666 } 667 out.writeFloat(mXPrecision); 668 out.writeFloat(mYPrecision); 669 out.writeInt(mDeviceId); 670 out.writeInt(mEdgeFlags); 671 } 672 673 private void readFromParcel(Parcel in) { 674 mDownTime = in.readLong(); 675 mEventTime = in.readLong(); 676 mAction = in.readInt(); 677 mX = in.readFloat(); 678 mY = in.readFloat(); 679 mPressure = in.readFloat(); 680 mSize = in.readFloat(); 681 mMetaState = in.readInt(); 682 mRawX = in.readFloat(); 683 mRawY = in.readFloat(); 684 final int N = in.readInt(); 685 if ((mNumHistory=N) > 0) { 686 final int N4 = N*4; 687 float[] history = mHistory; 688 if (history == null || history.length < N4) { 689 mHistory = history = new float[N4 + (4*4)]; 690 } 691 for (int i=0; i<N4; i++) { 692 history[i] = in.readFloat(); 693 } 694 long[] times = mHistoryTimes; 695 if (times == null || times.length < N) { 696 mHistoryTimes = times = new long[N + 4]; 697 } 698 for (int i=0; i<N; i++) { 699 times[i] = in.readLong(); 700 } 701 } 702 mXPrecision = in.readFloat(); 703 mYPrecision = in.readFloat(); 704 mDeviceId = in.readInt(); 705 mEdgeFlags = in.readInt(); 706 } 707 708} 709