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