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