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 17 package android.test; 18 19 import android.app.Activity; 20 import android.app.Instrumentation; 21 import android.graphics.Point; 22 import android.os.SystemClock; 23 import android.view.Display; 24 import android.view.Gravity; 25 import android.view.MotionEvent; 26 import android.view.View; 27 import android.view.ViewConfiguration; 28 import android.view.ViewGroup; 29 30 /** 31 * Reusable methods for generating touch events. These methods can be used with 32 * InstrumentationTestCase or ActivityInstrumentationTestCase2 to simulate user interaction with 33 * the application through a touch screen. 34 */ 35 public class TouchUtils { 36 37 /** 38 * Simulate touching in the center of the screen and dragging one quarter of the way down 39 * @param test The test case that is being run 40 * 41 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 42 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 43 * configuring the Activity under test 44 */ 45 @Deprecated dragQuarterScreenDown(ActivityInstrumentationTestCase test)46 public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) { 47 dragQuarterScreenDown(test, test.getActivity()); 48 } 49 50 /** 51 * Simulate touching in the center of the screen and dragging one quarter of the way down 52 * @param test The test case that is being run 53 * @param activity The activity that is in the foreground of the test case 54 */ dragQuarterScreenDown(InstrumentationTestCase test, Activity activity)55 public static void dragQuarterScreenDown(InstrumentationTestCase test, Activity activity) { 56 Display display = activity.getWindowManager().getDefaultDisplay(); 57 final Point size = new Point(); 58 display.getSize(size); 59 60 final float x = size.x / 2.0f; 61 final float fromY = size.y * 0.5f; 62 final float toY = size.y * 0.75f; 63 64 drag(test, x, x, fromY, toY, 4); 65 } 66 67 /** 68 * Simulate touching in the center of the screen and dragging one quarter of the way up 69 * @param test The test case that is being run 70 * 71 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 72 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 73 * configuring the Activity under test 74 */ 75 @Deprecated dragQuarterScreenUp(ActivityInstrumentationTestCase test)76 public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) { 77 dragQuarterScreenUp(test, test.getActivity()); 78 } 79 80 /** 81 * Simulate touching in the center of the screen and dragging one quarter of the way up 82 * @param test The test case that is being run 83 * @param activity The activity that is in the foreground of the test case 84 */ dragQuarterScreenUp(InstrumentationTestCase test, Activity activity)85 public static void dragQuarterScreenUp(InstrumentationTestCase test, Activity activity) { 86 Display display = activity.getWindowManager().getDefaultDisplay(); 87 final Point size = new Point(); 88 display.getSize(size); 89 90 final float x = size.x / 2.0f; 91 final float fromY = size.y * 0.5f; 92 final float toY = size.y * 0.25f; 93 94 drag(test, x, x, fromY, toY, 4); 95 } 96 97 /** 98 * Scroll a ViewGroup to the bottom by repeatedly calling 99 * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)} 100 * 101 * @param test The test case that is being run 102 * @param v The ViewGroup that should be dragged 103 * 104 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 105 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 106 * configuring the Activity under test 107 */ 108 @Deprecated scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v)109 public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) { 110 scrollToBottom(test, test.getActivity(), v); 111 } 112 113 /** 114 * Scroll a ViewGroup to the bottom by repeatedly calling 115 * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)} 116 * 117 * @param test The test case that is being run 118 * @param activity The activity that is in the foreground of the test case 119 * @param v The ViewGroup that should be dragged 120 */ scrollToBottom(InstrumentationTestCase test, Activity activity, ViewGroup v)121 public static void scrollToBottom(InstrumentationTestCase test, Activity activity, 122 ViewGroup v) { 123 ViewStateSnapshot prev; 124 ViewStateSnapshot next = new ViewStateSnapshot(v); 125 do { 126 prev = next; 127 TouchUtils.dragQuarterScreenUp(test, activity); 128 next = new ViewStateSnapshot(v); 129 } while (!prev.equals(next)); 130 } 131 132 /** 133 * Scroll a ViewGroup to the top by repeatedly calling 134 * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)} 135 * 136 * @param test The test case that is being run 137 * @param v The ViewGroup that should be dragged 138 * 139 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 140 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 141 * configuring the Activity under test 142 */ 143 @Deprecated scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v)144 public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) { 145 scrollToTop(test, test.getActivity(), v); 146 } 147 148 /** 149 * Scroll a ViewGroup to the top by repeatedly calling 150 * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)} 151 * 152 * @param test The test case that is being run 153 * @param activity The activity that is in the foreground of the test case 154 * @param v The ViewGroup that should be dragged 155 */ scrollToTop(InstrumentationTestCase test, Activity activity, ViewGroup v)156 public static void scrollToTop(InstrumentationTestCase test, Activity activity, ViewGroup v) { 157 ViewStateSnapshot prev; 158 ViewStateSnapshot next = new ViewStateSnapshot(v); 159 do { 160 prev = next; 161 TouchUtils.dragQuarterScreenDown(test, activity); 162 next = new ViewStateSnapshot(v); 163 } while (!prev.equals(next)); 164 } 165 166 /** 167 * Simulate touching the center of a view and dragging to the bottom of the screen. 168 * 169 * @param test The test case that is being run 170 * @param v The view that should be dragged 171 * 172 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 173 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 174 * configuring the Activity under test 175 */ 176 @Deprecated dragViewToBottom(ActivityInstrumentationTestCase test, View v)177 public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) { 178 dragViewToBottom(test, test.getActivity(), v, 4); 179 } 180 181 /** 182 * Simulate touching the center of a view and dragging to the bottom of the screen. 183 * 184 * @param test The test case that is being run 185 * @param activity The activity that is in the foreground of the test case 186 * @param v The view that should be dragged 187 */ dragViewToBottom(InstrumentationTestCase test, Activity activity, View v)188 public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v) { 189 dragViewToBottom(test, activity, v, 4); 190 } 191 192 /** 193 * Simulate touching the center of a view and dragging to the bottom of the screen. 194 * 195 * @param test The test case that is being run 196 * @param v The view that should be dragged 197 * @param stepCount How many move steps to include in the drag 198 * 199 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 200 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 201 * configuring the Activity under test 202 */ 203 @Deprecated dragViewToBottom(ActivityInstrumentationTestCase test, View v, int stepCount)204 public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v, 205 int stepCount) { 206 dragViewToBottom(test, test.getActivity(), v, stepCount); 207 } 208 209 /** 210 * Simulate touching the center of a view and dragging to the bottom of the screen. 211 * 212 * @param test The test case that is being run 213 * @param activity The activity that is in the foreground of the test case 214 * @param v The view that should be dragged 215 * @param stepCount How many move steps to include in the drag 216 */ dragViewToBottom(InstrumentationTestCase test, Activity activity, View v, int stepCount)217 public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v, 218 int stepCount) { 219 int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight(); 220 221 int[] xy = new int[2]; 222 v.getLocationOnScreen(xy); 223 224 final int viewWidth = v.getWidth(); 225 final int viewHeight = v.getHeight(); 226 227 final float x = xy[0] + (viewWidth / 2.0f); 228 float fromY = xy[1] + (viewHeight / 2.0f); 229 float toY = screenHeight - 1; 230 231 drag(test, x, x, fromY, toY, stepCount); 232 } 233 234 /** 235 * Simulate touching the center of a view and releasing quickly (before the tap timeout). 236 * 237 * @param test The test case that is being run 238 * @param v The view that should be clicked 239 */ tapView(InstrumentationTestCase test, View v)240 public static void tapView(InstrumentationTestCase test, View v) { 241 int[] xy = new int[2]; 242 v.getLocationOnScreen(xy); 243 244 final int viewWidth = v.getWidth(); 245 final int viewHeight = v.getHeight(); 246 247 final float x = xy[0] + (viewWidth / 2.0f); 248 float y = xy[1] + (viewHeight / 2.0f); 249 250 Instrumentation inst = test.getInstrumentation(); 251 252 long downTime = SystemClock.uptimeMillis(); 253 long eventTime = SystemClock.uptimeMillis(); 254 255 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 256 MotionEvent.ACTION_DOWN, x, y, 0); 257 inst.sendPointerSync(event); 258 inst.waitForIdleSync(); 259 260 eventTime = SystemClock.uptimeMillis(); 261 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 262 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 263 x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0); 264 inst.sendPointerSync(event); 265 inst.waitForIdleSync(); 266 267 eventTime = SystemClock.uptimeMillis(); 268 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 269 inst.sendPointerSync(event); 270 inst.waitForIdleSync(); 271 } 272 273 /** 274 * Simulate touching the center of a view and cancelling (so no onClick should 275 * fire, etc). 276 * 277 * @param test The test case that is being run 278 * @param v The view that should be clicked 279 */ touchAndCancelView(InstrumentationTestCase test, View v)280 public static void touchAndCancelView(InstrumentationTestCase test, View v) { 281 int[] xy = new int[2]; 282 v.getLocationOnScreen(xy); 283 284 final int viewWidth = v.getWidth(); 285 final int viewHeight = v.getHeight(); 286 287 final float x = xy[0] + (viewWidth / 2.0f); 288 float y = xy[1] + (viewHeight / 2.0f); 289 290 Instrumentation inst = test.getInstrumentation(); 291 292 long downTime = SystemClock.uptimeMillis(); 293 long eventTime = SystemClock.uptimeMillis(); 294 295 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 296 MotionEvent.ACTION_DOWN, x, y, 0); 297 inst.sendPointerSync(event); 298 inst.waitForIdleSync(); 299 300 eventTime = SystemClock.uptimeMillis(); 301 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 302 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL, 303 x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0); 304 inst.sendPointerSync(event); 305 inst.waitForIdleSync(); 306 307 } 308 309 /** 310 * Simulate touching the center of a view and releasing. 311 * 312 * @param test The test case that is being run 313 * @param v The view that should be clicked 314 */ clickView(InstrumentationTestCase test, View v)315 public static void clickView(InstrumentationTestCase test, View v) { 316 int[] xy = new int[2]; 317 v.getLocationOnScreen(xy); 318 319 final int viewWidth = v.getWidth(); 320 final int viewHeight = v.getHeight(); 321 322 final float x = xy[0] + (viewWidth / 2.0f); 323 float y = xy[1] + (viewHeight / 2.0f); 324 325 Instrumentation inst = test.getInstrumentation(); 326 327 long downTime = SystemClock.uptimeMillis(); 328 long eventTime = SystemClock.uptimeMillis(); 329 330 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 331 MotionEvent.ACTION_DOWN, x, y, 0); 332 inst.sendPointerSync(event); 333 inst.waitForIdleSync(); 334 335 336 eventTime = SystemClock.uptimeMillis(); 337 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 338 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 339 x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0); 340 inst.sendPointerSync(event); 341 inst.waitForIdleSync(); 342 343 eventTime = SystemClock.uptimeMillis(); 344 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 345 inst.sendPointerSync(event); 346 inst.waitForIdleSync(); 347 348 try { 349 Thread.sleep(1000); 350 } catch (InterruptedException e) { 351 e.printStackTrace(); 352 } 353 } 354 355 /** 356 * Simulate touching the center of a view, holding until it is a long press, and then releasing. 357 * 358 * @param test The test case that is being run 359 * @param v The view that should be clicked 360 * 361 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 362 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 363 * configuring the Activity under test 364 */ 365 @Deprecated longClickView(ActivityInstrumentationTestCase test, View v)366 public static void longClickView(ActivityInstrumentationTestCase test, View v) { 367 longClickView((InstrumentationTestCase) test, v); 368 } 369 370 /** 371 * Simulate touching the center of a view, holding until it is a long press, and then releasing. 372 * 373 * @param test The test case that is being run 374 * @param v The view that should be clicked 375 */ longClickView(InstrumentationTestCase test, View v)376 public static void longClickView(InstrumentationTestCase test, View v) { 377 int[] xy = new int[2]; 378 v.getLocationOnScreen(xy); 379 380 final int viewWidth = v.getWidth(); 381 final int viewHeight = v.getHeight(); 382 383 final float x = xy[0] + (viewWidth / 2.0f); 384 float y = xy[1] + (viewHeight / 2.0f); 385 386 Instrumentation inst = test.getInstrumentation(); 387 388 long downTime = SystemClock.uptimeMillis(); 389 long eventTime = SystemClock.uptimeMillis(); 390 391 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 392 MotionEvent.ACTION_DOWN, x, y, 0); 393 inst.sendPointerSync(event); 394 inst.waitForIdleSync(); 395 396 eventTime = SystemClock.uptimeMillis(); 397 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 398 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 399 x + touchSlop / 2, y + touchSlop / 2, 0); 400 inst.sendPointerSync(event); 401 inst.waitForIdleSync(); 402 403 try { 404 Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f)); 405 } catch (InterruptedException e) { 406 e.printStackTrace(); 407 } 408 409 eventTime = SystemClock.uptimeMillis(); 410 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 411 inst.sendPointerSync(event); 412 inst.waitForIdleSync(); 413 } 414 415 /** 416 * Simulate touching the center of a view and dragging to the top of the screen. 417 * 418 * @param test The test case that is being run 419 * @param v The view that should be dragged 420 * 421 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 422 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 423 * configuring the Activity under test 424 */ 425 @Deprecated dragViewToTop(ActivityInstrumentationTestCase test, View v)426 public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) { 427 dragViewToTop((InstrumentationTestCase) test, v, 4); 428 } 429 430 /** 431 * Simulate touching the center of a view and dragging to the top of the screen. 432 * 433 * @param test The test case that is being run 434 * @param v The view that should be dragged 435 * @param stepCount How many move steps to include in the drag 436 * 437 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 438 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 439 * configuring the Activity under test 440 */ 441 @Deprecated dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount)442 public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) { 443 dragViewToTop((InstrumentationTestCase) test, v, stepCount); 444 } 445 446 /** 447 * Simulate touching the center of a view and dragging to the top of the screen. 448 * 449 * @param test The test case that is being run 450 * @param v The view that should be dragged 451 */ dragViewToTop(InstrumentationTestCase test, View v)452 public static void dragViewToTop(InstrumentationTestCase test, View v) { 453 dragViewToTop(test, v, 4); 454 } 455 456 /** 457 * Simulate touching the center of a view and dragging to the top of the screen. 458 * 459 * @param test The test case that is being run 460 * @param v The view that should be dragged 461 * @param stepCount How many move steps to include in the drag 462 */ dragViewToTop(InstrumentationTestCase test, View v, int stepCount)463 public static void dragViewToTop(InstrumentationTestCase test, View v, int stepCount) { 464 int[] xy = new int[2]; 465 v.getLocationOnScreen(xy); 466 467 final int viewWidth = v.getWidth(); 468 final int viewHeight = v.getHeight(); 469 470 final float x = xy[0] + (viewWidth / 2.0f); 471 float fromY = xy[1] + (viewHeight / 2.0f); 472 float toY = 0; 473 474 drag(test, x, x, fromY, toY, stepCount); 475 } 476 477 /** 478 * Get the location of a view. Use the gravity param to specify which part of the view to 479 * return. 480 * 481 * @param v View to find 482 * @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, 483 * RIGHT) 484 * @param xy Result 485 */ getStartLocation(View v, int gravity, int[] xy)486 private static void getStartLocation(View v, int gravity, int[] xy) { 487 v.getLocationOnScreen(xy); 488 489 final int viewWidth = v.getWidth(); 490 final int viewHeight = v.getHeight(); 491 492 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) { 493 case Gravity.TOP: 494 break; 495 case Gravity.CENTER_VERTICAL: 496 xy[1] += viewHeight / 2; 497 break; 498 case Gravity.BOTTOM: 499 xy[1] += viewHeight - 1; 500 break; 501 default: 502 // Same as top -- do nothing 503 } 504 505 switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 506 case Gravity.LEFT: 507 break; 508 case Gravity.CENTER_HORIZONTAL: 509 xy[0] += viewWidth / 2; 510 break; 511 case Gravity.RIGHT: 512 xy[0] += viewWidth - 1; 513 break; 514 default: 515 // Same as left -- do nothing 516 } 517 } 518 519 /** 520 * Simulate touching a view and dragging it by the specified amount. 521 * 522 * @param test The test case that is being run 523 * @param v The view that should be dragged 524 * @param gravity Which part of the view to use for the initial down event. A combination of 525 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 526 * @param deltaX Amount to drag horizontally in pixels 527 * @param deltaY Amount to drag vertically in pixels 528 * 529 * @return distance in pixels covered by the drag 530 * 531 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 532 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 533 * configuring the Activity under test 534 */ 535 @Deprecated dragViewBy(ActivityInstrumentationTestCase test, View v, int gravity, int deltaX, int deltaY)536 public static int dragViewBy(ActivityInstrumentationTestCase test, View v, int gravity, 537 int deltaX, int deltaY) { 538 return dragViewBy((InstrumentationTestCase) test, v, gravity, deltaX, deltaY); 539 } 540 541 /** 542 * Simulate touching a view and dragging it by the specified amount. 543 * 544 * @param test The test case that is being run 545 * @param v The view that should be dragged 546 * @param gravity Which part of the view to use for the initial down event. A combination of 547 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 548 * @param deltaX Amount to drag horizontally in pixels 549 * @param deltaY Amount to drag vertically in pixels 550 * 551 * @return distance in pixels covered by the drag 552 * 553 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 554 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 555 * configuring the Activity under test 556 */ 557 @Deprecated dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX, int deltaY)558 public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX, 559 int deltaY) { 560 int[] xy = new int[2]; 561 562 getStartLocation(v, gravity, xy); 563 564 final int fromX = xy[0]; 565 final int fromY = xy[1]; 566 567 int distance = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY); 568 569 drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance); 570 571 return distance; 572 } 573 574 /** 575 * Simulate touching a view and dragging it to a specified location. 576 * 577 * @param test The test case that is being run 578 * @param v The view that should be dragged 579 * @param gravity Which part of the view to use for the initial down event. A combination of 580 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 581 * @param toX Final location of the view after dragging 582 * @param toY Final location of the view after dragging 583 * 584 * @return distance in pixels covered by the drag 585 * 586 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 587 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 588 * configuring the Activity under test 589 */ 590 @Deprecated dragViewTo(ActivityInstrumentationTestCase test, View v, int gravity, int toX, int toY)591 public static int dragViewTo(ActivityInstrumentationTestCase test, View v, int gravity, int toX, 592 int toY) { 593 return dragViewTo((InstrumentationTestCase) test, v, gravity, toX, toY); 594 } 595 596 /** 597 * Simulate touching a view and dragging it to a specified location. 598 * 599 * @param test The test case that is being run 600 * @param v The view that should be dragged 601 * @param gravity Which part of the view to use for the initial down event. A combination of 602 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 603 * @param toX Final location of the view after dragging 604 * @param toY Final location of the view after dragging 605 * 606 * @return distance in pixels covered by the drag 607 */ dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX, int toY)608 public static int dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX, 609 int toY) { 610 int[] xy = new int[2]; 611 612 getStartLocation(v, gravity, xy); 613 614 final int fromX = xy[0]; 615 final int fromY = xy[1]; 616 617 int deltaX = fromX - toX; 618 int deltaY = fromY - toY; 619 620 int distance = (int)Math.sqrt(deltaX * deltaX + deltaY * deltaY); 621 drag(test, fromX, toX, fromY, toY, distance); 622 623 return distance; 624 } 625 626 /** 627 * Simulate touching a view and dragging it to a specified location. Only moves horizontally. 628 * 629 * @param test The test case that is being run 630 * @param v The view that should be dragged 631 * @param gravity Which part of the view to use for the initial down event. A combination of 632 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 633 * @param toX Final location of the view after dragging 634 * 635 * @return distance in pixels covered by the drag 636 * 637 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 638 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 639 * configuring the Activity under test 640 */ 641 @Deprecated dragViewToX(ActivityInstrumentationTestCase test, View v, int gravity, int toX)642 public static int dragViewToX(ActivityInstrumentationTestCase test, View v, int gravity, 643 int toX) { 644 return dragViewToX((InstrumentationTestCase) test, v, gravity, toX); 645 } 646 647 /** 648 * Simulate touching a view and dragging it to a specified location. Only moves horizontally. 649 * 650 * @param test The test case that is being run 651 * @param v The view that should be dragged 652 * @param gravity Which part of the view to use for the initial down event. A combination of 653 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 654 * @param toX Final location of the view after dragging 655 * 656 * @return distance in pixels covered by the drag 657 */ dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX)658 public static int dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX) { 659 int[] xy = new int[2]; 660 661 getStartLocation(v, gravity, xy); 662 663 final int fromX = xy[0]; 664 final int fromY = xy[1]; 665 666 int deltaX = fromX - toX; 667 668 drag(test, fromX, toX, fromY, fromY, deltaX); 669 670 return deltaX; 671 } 672 673 /** 674 * Simulate touching a view and dragging it to a specified location. Only moves vertically. 675 * 676 * @param test The test case that is being run 677 * @param v The view that should be dragged 678 * @param gravity Which part of the view to use for the initial down event. A combination of 679 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 680 * @param toY Final location of the view after dragging 681 * 682 * @return distance in pixels covered by the drag 683 * 684 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 685 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 686 * configuring the Activity under test 687 */ 688 @Deprecated dragViewToY(ActivityInstrumentationTestCase test, View v, int gravity, int toY)689 public static int dragViewToY(ActivityInstrumentationTestCase test, View v, int gravity, 690 int toY) { 691 return dragViewToY((InstrumentationTestCase) test, v, gravity, toY); 692 } 693 694 /** 695 * Simulate touching a view and dragging it to a specified location. Only moves vertically. 696 * 697 * @param test The test case that is being run 698 * @param v The view that should be dragged 699 * @param gravity Which part of the view to use for the initial down event. A combination of 700 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) 701 * @param toY Final location of the view after dragging 702 * 703 * @return distance in pixels covered by the drag 704 */ dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY)705 public static int dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY) { 706 int[] xy = new int[2]; 707 708 getStartLocation(v, gravity, xy); 709 710 final int fromX = xy[0]; 711 final int fromY = xy[1]; 712 713 int deltaY = fromY - toY; 714 715 drag(test, fromX, fromX, fromY, toY, deltaY); 716 717 return deltaY; 718 } 719 720 721 /** 722 * Simulate touching a specific location and dragging to a new location. 723 * 724 * @param test The test case that is being run 725 * @param fromX X coordinate of the initial touch, in screen coordinates 726 * @param toX Xcoordinate of the drag destination, in screen coordinates 727 * @param fromY X coordinate of the initial touch, in screen coordinates 728 * @param toY Y coordinate of the drag destination, in screen coordinates 729 * @param stepCount How many move steps to include in the drag 730 * 731 * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of 732 * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for 733 * configuring the Activity under test 734 */ 735 @Deprecated drag(ActivityInstrumentationTestCase test, float fromX, float toX, float fromY, float toY, int stepCount)736 public static void drag(ActivityInstrumentationTestCase test, float fromX, float toX, 737 float fromY, float toY, int stepCount) { 738 drag((InstrumentationTestCase) test, fromX, toX, fromY, toY, stepCount); 739 } 740 741 /** 742 * Simulate touching a specific location and dragging to a new location. 743 * 744 * @param test The test case that is being run 745 * @param fromX X coordinate of the initial touch, in screen coordinates 746 * @param toX Xcoordinate of the drag destination, in screen coordinates 747 * @param fromY X coordinate of the initial touch, in screen coordinates 748 * @param toY Y coordinate of the drag destination, in screen coordinates 749 * @param stepCount How many move steps to include in the drag 750 */ drag(InstrumentationTestCase test, float fromX, float toX, float fromY, float toY, int stepCount)751 public static void drag(InstrumentationTestCase test, float fromX, float toX, float fromY, 752 float toY, int stepCount) { 753 Instrumentation inst = test.getInstrumentation(); 754 755 long downTime = SystemClock.uptimeMillis(); 756 long eventTime = SystemClock.uptimeMillis(); 757 758 float y = fromY; 759 float x = fromX; 760 761 float yStep = (toY - fromY) / stepCount; 762 float xStep = (toX - fromX) / stepCount; 763 764 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 765 MotionEvent.ACTION_DOWN, x, y, 0); 766 inst.sendPointerSync(event); 767 for (int i = 0; i < stepCount; ++i) { 768 y += yStep; 769 x += xStep; 770 eventTime = SystemClock.uptimeMillis(); 771 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0); 772 inst.sendPointerSync(event); 773 } 774 775 eventTime = SystemClock.uptimeMillis(); 776 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 777 inst.sendPointerSync(event); 778 inst.waitForIdleSync(); 779 } 780 781 private static class ViewStateSnapshot { 782 final View mFirst; 783 final View mLast; 784 final int mFirstTop; 785 final int mLastBottom; 786 final int mChildCount; ViewStateSnapshot(ViewGroup viewGroup)787 private ViewStateSnapshot(ViewGroup viewGroup) { 788 mChildCount = viewGroup.getChildCount(); 789 if (mChildCount == 0) { 790 mFirst = mLast = null; 791 mFirstTop = mLastBottom = Integer.MIN_VALUE; 792 } else { 793 mFirst = viewGroup.getChildAt(0); 794 mLast = viewGroup.getChildAt(mChildCount - 1); 795 mFirstTop = mFirst.getTop(); 796 mLastBottom = mLast.getBottom(); 797 } 798 } 799 800 @Override equals(Object o)801 public boolean equals(Object o) { 802 if (this == o) { 803 return true; 804 } 805 if (o == null || getClass() != o.getClass()) { 806 return false; 807 } 808 809 final ViewStateSnapshot that = (ViewStateSnapshot) o; 810 return mFirstTop == that.mFirstTop && 811 mLastBottom == that.mLastBottom && 812 mFirst == that.mFirst && 813 mLast == that.mLast && 814 mChildCount == that.mChildCount; 815 } 816 817 @Override hashCode()818 public int hashCode() { 819 int result = mFirst != null ? mFirst.hashCode() : 0; 820 result = 31 * result + (mLast != null ? mLast.hashCode() : 0); 821 result = 31 * result + mFirstTop; 822 result = 31 * result + mLastBottom; 823 result = 31 * result + mChildCount; 824 return result; 825 } 826 } 827 } 828