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