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