1/* 2 * Copyright (C) 2013 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 */ 16package com.android.uiautomator.tests.cts; 17 18import android.content.Intent; 19import android.content.ComponentName; 20import android.graphics.Point; 21import android.graphics.Rect; 22import android.os.RemoteException; 23import android.os.SystemClock; 24import android.util.Log; 25 26import com.android.uiautomator.core.UiCollection; 27import com.android.uiautomator.core.UiDevice; 28import com.android.uiautomator.core.UiObject; 29import com.android.uiautomator.core.UiObjectNotFoundException; 30import com.android.uiautomator.core.UiScrollable; 31import com.android.uiautomator.core.UiSelector; 32import com.android.uiautomator.core.UiWatcher; 33import com.android.uiautomator.testrunner.UiAutomatorTestCase; 34 35import java.io.File; 36import java.io.IOException; 37 38/** 39 * Sanity test uiautomator functionality on target device. 40 */ 41public class CtsUiAutomatorTest extends UiAutomatorTestCase { 42 private static final String LOG_TAG = CtsUiAutomatorTest.class.getSimpleName(); 43 private static final String[] LIST_SCROLL_TESTS = new String[] { 44 "Test 17", "Test 11", "Test 20", "Test 35" 45 }; 46 private static final String PKG_NAME = "com.android.uiautomator.tests.cts.testapp"; 47 48 // Maximum wait for key object to become visible 49 private static final int WAIT_EXIST_TIMEOUT = 5 * 1000; 50 51 private static final String SCREEN_SHOT_FILE_PATH_NAME = "ctsScreenShot"; 52 53 @Override 54 protected void setUp() throws Exception { 55 super.setUp(); 56 // Make sure the test app is always running 57 UiDevice.getInstance().waitForIdle(); 58 if (!new UiObject(new UiSelector().packageName(PKG_NAME)).exists()) { 59 Intent intent = new Intent(Intent.ACTION_MAIN) 60 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 61 .setComponent(new ComponentName(PKG_NAME, PKG_NAME + ".MainActivity")); 62 getInstrumentation().getContext().startActivity(intent); 63 } 64 } 65 66 /* 67 * Items in the listScrollTests array should be spread out such that a 68 * scroll is required to reach each item at each of the far ends. 69 */ 70 public void testListScrollAndSelect() throws UiObjectNotFoundException { 71 UiScrollable listView = new UiScrollable( 72 new UiSelector().className(android.widget.ListView.class.getName())); 73 74 // on single fragment display 75 if (!listView.exists()) 76 UiDevice.getInstance().pressBack(); 77 78 for (String test : LIST_SCROLL_TESTS) { 79 openTest(test); 80 verifyTestDetailsExists(test); 81 } 82 } 83 84 /** 85 * Test erasing of multi word text in edit field and input of new text. Test 86 * verifying input text using a complex UiSelector 87 * 88 * @throws UiObjectNotFoundException 89 */ 90 public void testTextEraseAndInput() throws UiObjectNotFoundException { 91 String testText = "Android Ui Automator Input Text"; 92 openTest("Test 1"); 93 94 UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class 95 .getName())); 96 editText.setText(testText); 97 98 UiObject submitButton = new UiObject(new UiSelector() 99 .className(android.widget.Button.class.getName()).clickable(true) 100 .textStartsWith("Submit")); 101 submitButton.click(); 102 103 UiObject result = new UiObject(new UiSelector().className( 104 android.widget.LinearLayout.class.getName()).childSelector( 105 (new UiSelector().className(android.widget.ScrollView.class.getName()) 106 .childSelector(new UiSelector().className(android.widget.TextView.class 107 .getName()))))); 108 109 if (!testText.equals(result.getText())) { 110 throw new UiObjectNotFoundException("Test text: " + testText); 111 } 112 113 getObjectByText("OK").click(); 114 } 115 116 /** 117 * Select each of the buttons by using only the content description property 118 * 119 * @throws UiObjectNotFoundException 120 */ 121 public void testSelectByContentDescription() throws UiObjectNotFoundException { 122 openTest("Test 2"); 123 getObjectByDescription("Button 1").click(); 124 verifyDialogActionResults("Button 1"); 125 getObjectByDescription("Button 2").click(); 126 verifyDialogActionResults("Button 2"); 127 getObjectByDescription("Button 3").click(); 128 verifyDialogActionResults("Button 3"); 129 } 130 131 /** 132 * Select each of the buttons by using only the text property 133 * 134 * @throws UiObjectNotFoundException 135 */ 136 public void testSelectByText() throws UiObjectNotFoundException { 137 openTest("Test 2"); 138 getObjectByText("Button 1").click(); 139 verifyDialogActionResults("Button 1"); 140 getObjectByText("Button 2").click(); 141 verifyDialogActionResults("Button 2"); 142 getObjectByText("Button 3").click(); 143 verifyDialogActionResults("Button 3"); 144 } 145 146 /** 147 * Select each of the buttons by using only the index property 148 * 149 * @throws UiObjectNotFoundException 150 */ 151 public void testSelectByIndex() throws UiObjectNotFoundException { 152 openTest("Test 2"); 153 getObjectByIndex(android.widget.Button.class.getName(), 0).click(); 154 verifyDialogActionResults("Button 1"); 155 getObjectByIndex(android.widget.Button.class.getName(), 1).click(); 156 verifyDialogActionResults("Button 2"); 157 getObjectByIndex(android.widget.Button.class.getName(), 2).click(); 158 verifyDialogActionResults("Button 3"); 159 } 160 161 /** 162 * Select each of the buttons by using only the instance number 163 * 164 * @throws UiObjectNotFoundException 165 */ 166 public void testSelectByInstance() throws UiObjectNotFoundException { 167 openTest("Test 2"); 168 getObjectByInstance(android.widget.Button.class.getName(), 0).click(); 169 verifyDialogActionResults("Button 1"); 170 getObjectByInstance(android.widget.Button.class.getName(), 1).click(); 171 verifyDialogActionResults("Button 2"); 172 getObjectByInstance(android.widget.Button.class.getName(), 2).click(); 173 verifyDialogActionResults("Button 3"); 174 } 175 176 /** 177 * Test when a node's state is changed due to an action, it is updated in the accessibility 178 * hierarchy. 179 * 180 * @throws UiObjectNotFoundException 181 */ 182 public void testSelectAfterContentChanged() throws UiObjectNotFoundException { 183 openTest("Test 2"); 184 UiObject dynaButton = getObjectByText("Before"); 185 dynaButton.click(); 186 assertTrue("Button state change is not refreshed in accessibility hierarchy", 187 getObjectByText("After").exists()); 188 } 189 190 /** 191 * Test opening the options menu using the soft buttons 192 * 193 * @throws UiObjectNotFoundException 194 * @throws InterruptedException 195 * @throws IOException 196 */ 197 public void testDeviceSoftKeys() throws UiObjectNotFoundException, IOException, 198 InterruptedException { 199 openTest("Test 2"); 200 UiDevice device = UiDevice.getInstance(); 201 device.pressMenu(); 202 getObjectByText("Finish").click(); 203 verifyDialogActionResults("Finish"); 204 205 // Back button 206 openTest("Test 1"); 207 UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class 208 .getName())); 209 editText.setText("Android Geppetto Test Application"); 210 211 UiObject submitButton = new UiObject(new UiSelector() 212 .className(android.widget.Button.class.getName()).clickable(true) 213 .textStartsWith("Submit")); 214 submitButton.click(); 215 216 // Text from the popup dialog 217 UiObject result = new UiObject(new UiSelector().textContains("geppetto")); 218 219 // Back button test to dismiss the dialog 220 assertTrue("Wait for exist must return true", result.waitForExists(2000)); 221 device.pressBack(); 222 result.waitUntilGone(1000); 223 assertFalse("Wait for exist must return false after press back", result.exists()); 224 225 // Home button test 226 openTest("Test 5"); 227 String pkgName = device.getCurrentPackageName(); 228 assertTrue("CTS test app must be running", pkgName.equals(PKG_NAME)); 229 device.pressHome(); 230 boolean gone = new UiObject(new UiSelector().packageName(PKG_NAME)).waitUntilGone(5000); 231 assertTrue("CTS test app still visble after pressing home", gone); 232 } 233 234 /** 235 * This view is in constant update generating window content changed events. 236 * The test will read the time displayed and exhaust each wait for idle 237 * timeout until it read and sets the text back into the edit field and 238 * presses submit. A dialog box should pop up with the time it took since 239 * reading the value until pressing submit. 240 * 241 * @throws UiObjectNotFoundException 242 */ 243 public void testWaitForIdleTimeout() throws UiObjectNotFoundException { 244 openTest("Test 3"); 245 UiObject clk = new UiObject(new UiSelector().descriptionStartsWith("Performance ")); 246 247 // First default wait for idle timeout assumed to be 10 seconds 248 String txtTime = clk.getText(); 249 UiObject edit = new UiObject(new UiSelector().className(android.widget.EditText.class 250 .getName())); 251 252 // Second default wait for idle timeout assumed to be 10 seconds. 253 // Total ~20. 254 edit.setText(txtTime); 255 256 // Third default wait for idle timeout assumed to be 10 seconds. 257 // Total ~30. 258 getObjectByText("Submit").click(); 259 260 // The value read should have value between 30 and 60 seconds indicating 261 // that the internal default timeouts for wait-for-idle is in acceptable 262 // range. 263 UiObject readTime = new UiObject(new UiSelector().className( 264 android.widget.TextView.class.getName()).instance(1)); 265 String timeDiff = readTime.getText(); 266 Log.i(LOG_TAG, "Sync time: " + timeDiff); 267 268 getObjectByText("OK").click(); 269 270 int totalDelay = Integer.parseInt(timeDiff); 271 272 // Cumulative waits in this test should add up to at minimum 30 seconds 273 assertFalse("Timeout for wait-for-idle is too short. Expecting minimum 30 seconds", 274 totalDelay < 30 * 1000); 275 276 // allow for tolerance in time measurements due to differences between 277 // device speeds 278 assertFalse("Timeout for wait-for-idle is too long. Expecting maximum 60 seconds", 279 totalDelay > 60 * 1000); 280 } 281 282 /** 283 * This view is in constant update generating window content changed events. 284 * This test uses the soft key presses and clicks while the background 285 * screen is constantly updating causing a constant busy state. 286 * 287 * @throws UiObjectNotFoundException 288 */ 289 public void testVerifyMenuClicks() throws UiObjectNotFoundException { 290 openTest("Test 3"); 291 UiDevice.getInstance().pressMenu(); 292 new UiObject(new UiSelector().text("Submit")).click(); 293 verifyDialogActionResults("Submit"); 294 UiDevice.getInstance().pressMenu(); 295 new UiObject(new UiSelector().text("Exit")).click(); 296 verifyDialogActionResults("Exit"); 297 } 298 299 /** 300 * Verifies swipeRight, swipeLeft and raw swipe APIs perform as expected. 301 * 302 * @throws UiObjectNotFoundException 303 */ 304 public void testSwipes() throws UiObjectNotFoundException { 305 openTest("Test 4"); 306 UiObject textView = new UiObject(new UiSelector().textContains("[")); 307 308 textView.swipeLeft(10); 309 assertTrue("UiObject swipe left 1->2", "[ 2 ]".equals(textView.getText())); 310 311 textView.swipeLeft(10); 312 assertTrue("UiObject swipe left 2->3", "[ 3 ]".equals(textView.getText())); 313 314 textView.swipeLeft(10); 315 assertTrue("UiObject swipe left 3->4", "[ 4 ]".equals(textView.getText())); 316 317 textView.swipeRight(10); 318 assertTrue("UiObject swipe right 3<-4", "[ 3 ]".equals(textView.getText())); 319 320 textView.swipeRight(10); 321 assertTrue("UiObject swipe right 2<-3", "[ 2 ]".equals(textView.getText())); 322 323 textView.swipeRight(10); 324 assertTrue("UiObject swipe right 1<-2", "[ 1 ]".equals(textView.getText())); 325 326 Rect tb = textView.getBounds(); 327 UiDevice.getInstance().swipe(tb.right - 20, tb.centerY(), tb.left + 20, tb.centerY(), 50); 328 329 SystemClock.sleep(100); 330 assertTrue("UiDevice raw swipe 1->2", "[ 2 ]".equals(textView.getText())); 331 } 332 333 /** 334 * Creates a complex selector 335 * 336 * @throws UiObjectNotFoundException 337 */ 338 public void testComplexSelectors() throws UiObjectNotFoundException { 339 openTest("Test 5"); 340 UiSelector frameLayout = new UiSelector().className(android.widget.FrameLayout.class 341 .getName()); 342 UiSelector gridLayout = new UiSelector().className(android.widget.GridLayout.class 343 .getName()); 344 UiSelector toggleButton = new UiSelector().className(android.widget.ToggleButton.class 345 .getName()); 346 UiObject button = new UiObject(frameLayout.childSelector(gridLayout).childSelector( 347 toggleButton)); 348 349 assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText())); 350 button.click(); 351 assertTrue("Toggle button value should be ON", "ON".equals(button.getText())); 352 button.click(); 353 assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText())); 354 } 355 356 /** 357 * Test when an object does not exist, an exception is thrown 358 * @throws UiObjectNotFoundException 359 */ 360 public void testExceptionObjectNotFound() throws UiObjectNotFoundException { 361 UiSelector selector = new UiSelector().text("Nothing should be found"); 362 UiSelector child = new UiSelector().className("Nothing"); 363 UiObject obj = new UiObject(selector.childSelector(child)); 364 365 assertFalse("Object is reported as existing", obj.exists()); 366 367 try { 368 obj.click(); 369 } catch (UiObjectNotFoundException e) { 370 return; 371 } 372 assertTrue("Exception not thrown for Object not found", false); 373 } 374 375 /** 376 * Verifies the UiWatcher registration and trigger function 377 * 378 * @throws UiObjectNotFoundException 379 */ 380 public void testUiWatcher() throws UiObjectNotFoundException { 381 openTest("Test 5"); 382 UiDevice device = UiDevice.getInstance(); 383 device.registerWatcher("Artificial crash", new UiWatcher() { 384 385 @Override 386 public boolean checkForCondition() { 387 if (new UiObject(new UiSelector().packageName("android")).exists()) { 388 try { 389 // Expecting a localized OK button 390 new UiObject(new UiSelector().className( 391 android.widget.Button.class.getName()).enabled(true)).click(); 392 } catch (UiObjectNotFoundException e) { 393 } 394 return true; 395 } 396 return false; 397 } 398 }); 399 400 // Causes a runtime exception to be thrown 401 getObjectByText("Button").click(); 402 403 // Fake doing something while the exception is being displayed 404 SystemClock.sleep(2000); 405 device.runWatchers(); 406 assertTrue("UiWatcher not triggered", device.hasAnyWatcherTriggered()); 407 } 408 409 /** 410 * Verifies the 'checked' property of both UiSelector and UiObject 411 * 412 * @throws UiObjectNotFoundException 413 */ 414 public void testSelectorChecked() throws UiObjectNotFoundException { 415 openTest("Test 5"); 416 UiObject checkboxChecked = new UiObject(new UiSelector().className( 417 android.widget.CheckBox.class.getName()).checked(true)); 418 UiObject checkboxNotChecked = new UiObject(new UiSelector().className( 419 android.widget.CheckBox.class.getName()).checked(false)); 420 421 checkboxNotChecked.click(); 422 assertTrue("Checkbox should be checked", checkboxChecked.isChecked()); 423 checkboxChecked.click(); 424 assertFalse("Checkbox should be unchecked", checkboxNotChecked.isChecked()); 425 } 426 427 /** 428 * Verifies the 'Clickable' property of both the UiSelector and UiObject 429 * 430 * @throws UiObjectNotFoundException 431 */ 432 public void testSelectorClickable() throws UiObjectNotFoundException { 433 openTest("Test 5"); 434 UiSelector clickableCheckbox = new UiSelector().clickable(true).className( 435 android.widget.CheckBox.class.getName()); 436 UiSelector notClickableProgress = new UiSelector().clickable(false).className( 437 android.widget.ProgressBar.class.getName()); 438 439 assertTrue("Selector clickable", new UiObject(clickableCheckbox).isClickable()); 440 assertFalse("Selector not clickable", new UiObject(notClickableProgress).isClickable()); 441 } 442 443 /** 444 * Verifies the 'focusable' property of both UiSelector and UiObject 445 * 446 * @throws UiObjectNotFoundException 447 */ 448 public void testSelectorFocusable() throws UiObjectNotFoundException { 449 openTest("Test 5"); 450 UiSelector mainLayout = new UiSelector().description("Widgets Collection"); 451 UiSelector focusableCheckbox = mainLayout.childSelector(new UiSelector().className( 452 android.widget.CheckBox.class.getName()).focusable(true)); 453 UiSelector notFocusableSpinner = mainLayout.childSelector(new UiSelector().className( 454 android.widget.Spinner.class.getName()).focusable(false)); 455 456 assertTrue("Selector focusable", new UiObject(focusableCheckbox).isFocusable()); 457 assertFalse("Selector not focusable", new UiObject(notFocusableSpinner).isFocusable()); 458 } 459 460 /** 461 * Verifies the 'DescriptionContains' property of UiSelector 462 * 463 * @throws UiObjectNotFoundException 464 */ 465 public void testSelectorDescriptionContains() throws UiObjectNotFoundException { 466 openTest("Test 5"); 467 UiSelector progressDescriptionContains = new UiSelector().descriptionContains("%"); 468 assertTrue("Selector descriptionContains", "Progress is 50 %".equals(new UiObject( 469 progressDescriptionContains).getContentDescription())); 470 } 471 472 /** 473 * Verifies the 'DescriptionStarts' property of UiSelector 474 * 475 * @throws UiObjectNotFoundException 476 */ 477 public void testSelectorDescriptionStarts() throws UiObjectNotFoundException { 478 openTest("Test 5"); 479 UiSelector progressDescriptionStart = new UiSelector().descriptionStartsWith("progress"); 480 assertTrue("Selector descriptionStart", "Progress is 50 %".equals(new UiObject( 481 progressDescriptionStart).getContentDescription())); 482 } 483 484 /** 485 * Verifies the 'Enabled' property of both UiSelector and UiObject 486 * 487 * @throws UiObjectNotFoundException 488 */ 489 public void testSelectorEnabled() throws UiObjectNotFoundException { 490 openTest("Test 5"); 491 UiSelector mainLayout = new UiSelector().description("Widgets Collection"); 492 UiSelector buttonDisabled = mainLayout.childSelector(new UiSelector().className( 493 android.widget.Button.class.getName()).enabled(false)); 494 UiSelector buttonEnabled = mainLayout.childSelector(new UiSelector().className( 495 android.widget.Button.class.getName()).enabled(true)); 496 497 assertFalse("Selector enabled false", new UiObject(buttonDisabled).isEnabled()); 498 assertTrue("Selector enabled true", new UiObject(buttonEnabled).isEnabled()); 499 } 500 501 /** 502 * Verifies the UiCollection object child counting by object pattern 503 * 504 * @throws UiObjectNotFoundException 505 */ 506 public void testCollectionCount() throws UiObjectNotFoundException { 507 openTest("Test 5"); 508 UiCollection collection = new UiCollection( 509 new UiSelector().description("Widgets Collection")); 510 assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT)); 511 512 assertTrue("Collection count", 513 collection.getChildCount(new UiSelector().clickable(true)) == 6); 514 } 515 516 /** 517 * Verifies the UiCollection can find an object by text and returning by 518 * pattern 519 * 520 * @throws UiObjectNotFoundException 521 */ 522 public void testCollectionGetChildByText() throws UiObjectNotFoundException { 523 openTest("Test 5"); 524 UiCollection collection = new UiCollection( 525 new UiSelector().description("Widgets Collection")); 526 assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT)); 527 528 UiObject item = collection.getChildByText( 529 new UiSelector().className(android.widget.Button.class.getName()), "Button"); 530 531 assertTrue("Collection get child by text", "Button".equals(item.getText())); 532 } 533 534 /** 535 * Verifies the UiCollection can find an object by instance and returning by 536 * pattern 537 * 538 * @throws UiObjectNotFoundException 539 */ 540 public void testCollectionGetChildByInstance() throws UiObjectNotFoundException { 541 openTest("Test 5"); 542 UiCollection collection = new UiCollection( 543 new UiSelector().description("Widgets Collection")); 544 assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT)); 545 546 // find the second button 547 UiObject item = collection.getChildByInstance( 548 new UiSelector().className(android.widget.Button.class.getName()), 1); 549 550 assertTrue("Collection get child by instance", "Button".equals(item.getText())); 551 } 552 553 /** 554 * Verifies the UiCollection can find an object by description and returning 555 * by pattern 556 * 557 * @throws UiObjectNotFoundException 558 */ 559 public void testCollectionGetChildByDescription() throws UiObjectNotFoundException { 560 openTest("Test 5"); 561 UiCollection collection = new UiCollection( 562 new UiSelector().description("Widgets Collection")); 563 assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT)); 564 565 UiObject item = collection.getChildByDescription( 566 new UiSelector().className(android.widget.Button.class.getName()), 567 "Description for Button"); 568 569 assertTrue("Collection get child by description", "Button".equals(item.getText())); 570 } 571 572 /** 573 * Test Orientation APIs by causing rotations and verifying current state 574 * 575 * @throws RemoteException 576 * @throws UiObjectNotFoundException 577 * @since API Level 17 578 */ 579 public void testRotation() throws RemoteException, UiObjectNotFoundException { 580 openTest("Test 5"); 581 UiDevice device = UiDevice.getInstance(); 582 583 device.setOrientationLeft(); 584 device.waitForIdle(); // isNaturalOrientation is not waiting for idle 585 SystemClock.sleep(1000); 586 assertFalse("Device orientation should not be natural", device.isNaturalOrientation()); 587 588 device.setOrientationNatural(); 589 device.waitForIdle(); // isNaturalOrientation is not waiting for idle 590 SystemClock.sleep(1000); 591 assertTrue("Device orientation should be natural", device.isNaturalOrientation()); 592 593 device.setOrientationRight(); 594 device.waitForIdle(); // isNaturalOrientation is not waiting for idle 595 SystemClock.sleep(1000); 596 assertFalse("Device orientation should not be natural", device.isNaturalOrientation()); 597 598 device.setOrientationNatural(); 599 } 600 601 /** 602 * Reads the current device's product name. Since it is not possible to predetermine the 603 * would be value, the check verifies that the value is not null and not empty. 604 * 605 * @since API Level 17 606 */ 607 public void testGetProductName() { 608 String name = UiDevice.getInstance().getProductName(); 609 assertFalse("Product name check returned empty string", name.isEmpty()); 610 } 611 612 /** 613 * Select each of the buttons by using only regex text 614 * 615 * @throws UiObjectNotFoundException 616 * @since API Level 17 617 */ 618 public void testSelectByTextMatch() throws UiObjectNotFoundException { 619 openTest("Test 2"); 620 getObjectByTextMatch(".*n\\s1$").click(); 621 verifyDialogActionResults("Button 1"); 622 getObjectByTextMatch(".*n\\s2$").click(); 623 verifyDialogActionResults("Button 2"); 624 getObjectByTextMatch(".*n\\s3$").click(); 625 verifyDialogActionResults("Button 3"); 626 } 627 628 /** 629 * Select each of the buttons by using only regex content-description 630 * 631 * @throws UiObjectNotFoundException 632 * @since API Level 17 633 */ 634 public void testSelectByDescriptionMatch() throws UiObjectNotFoundException { 635 openTest("Test 2"); 636 getObjectByDescriptionMatch(".*n\\s1$").click(); 637 verifyDialogActionResults("Button 1"); 638 getObjectByDescriptionMatch(".*n\\s2$").click(); 639 verifyDialogActionResults("Button 2"); 640 getObjectByDescriptionMatch(".*n\\s3$").click(); 641 verifyDialogActionResults("Button 3"); 642 } 643 644 /** 645 * Select each of the buttons by using only regex class name 646 * 647 * @throws UiObjectNotFoundException 648 * @since API Level 17 649 */ 650 public void testSelectByClassMatch() throws UiObjectNotFoundException { 651 openTest("Test 5"); 652 UiObject tgl = getObjectByClassMatch(".*ToggleButton$", 0); 653 String tglValue = tgl.getText(); 654 tgl.click(); 655 656 assertFalse("Matching class by Regex failed", tglValue.equals(tgl.getText())); 657 } 658 659 /** 660 * Select each of the buttons by using only class type 661 * 662 * @throws UiObjectNotFoundException 663 * @since API Level 17 664 */ 665 public void testSelectByClassType() throws UiObjectNotFoundException { 666 openTest("Test 5"); 667 UiObject tgl = getObjectByClass(android.widget.ToggleButton.class, 0); 668 String tglValue = tgl.getText(); 669 tgl.click(); 670 671 assertFalse("Matching class by class type failed", tglValue.equals(tgl.getText())); 672 } 673 674 /** 675 * Test the coordinates of 3 buttons side by side verifying vertical and 676 * horizontal coordinates. 677 * 678 * @throws UiObjectNotFoundException 679 * @since API Level 17 680 */ 681 public void testGetVisibleBounds() throws UiObjectNotFoundException { 682 openTest("Test 2"); 683 Rect rect1 = getObjectByText("Button 1").getVisibleBounds(); 684 Rect rect2 = getObjectByText("Button 2").getVisibleBounds(); 685 Rect rect3 = getObjectByText("Button 3").getVisibleBounds(); 686 687 assertTrue("X coordinate check failed", 688 rect1.left < rect2.left && rect2.right < rect3.right); 689 assertTrue("Y coordinate check failed", 690 rect1.top == rect2.top && rect2.bottom == rect3.bottom); 691 } 692 693 /** 694 * Tests the LongClick functionality in the API 695 * 696 * @throws UiObjectNotFoundException 697 * @since API Level 17 698 */ 699 public void testSelectorLongClickable() throws UiObjectNotFoundException { 700 openTest("Test 2"); 701 getObjectByText("Button 1").longClick(); 702 verifyDialogActionResults("Longclick Button 1"); 703 } 704 705 /** 706 * Test the UiSelector's long-clickable property 707 * 708 * @throws UiObjectNotFoundException 709 * @since API Level 17 710 */ 711 public void testSelectorLongClickableProperty() throws UiObjectNotFoundException { 712 openTest("Test 2"); 713 UiObject button3 = new UiObject(new UiSelector().className( 714 android.widget.Button.class).longClickable(true).instance(2)); 715 button3.longClick(); 716 verifyDialogActionResults("Longclick Button 3"); 717 } 718 719 /** 720 * Takes a screen shot of the current display and checks if the file is 721 * created and is not zero size. 722 * 723 * @since API Level 17 724 */ 725 public void testTakeScreenShots() { 726 File storePath = getInstrumentation().getContext().getFileStreamPath(SCREEN_SHOT_FILE_PATH_NAME); 727 getUiDevice().takeScreenshot(storePath); 728 729 assertTrue("Screenshot file not detected in store", storePath.exists()); 730 assertTrue("Zero size for screenshot file", storePath.length() > 0); 731 } 732 733 /** 734 * Verifies the 'Resource-Id' property of UiSelector 735 * 736 * @throws UiObjectNotFoundException 737 * @since API Level 18 738 */ 739 public void testSelectorResourceId() throws UiObjectNotFoundException { 740 openTest("Test 5"); 741 UiSelector toggleSelector = 742 new UiSelector().resourceId("com.android.uiautomator.tests.cts.testapp:id/test_5_toggleButton"); 743 UiObject toggleButton = new UiObject(toggleSelector); 744 assertTrue("Object with selector resource-id not found", toggleButton.exists()); 745 assertTrue("Incorrect object for selector resource-id returned", 746 "OFF".equals(toggleButton.getText()) || "ON".equals(toggleButton.getText())); 747 } 748 749 /** 750 * Verify the UiSelector property resourceIdMatches 751 * 752 * @throws UiObjectNotFoundException 753 * @since API Level 18 754 */ 755 public void testSelectorResourceIdMatches() throws UiObjectNotFoundException { 756 openTest("Test 2"); 757 new UiObject(new UiSelector().resourceIdMatches("(?i).*button.*").instance(2)).click(); 758 verifyDialogActionResults("Button 3"); 759 new UiObject(new UiSelector().resourceIdMatches("(?i).*button1.*")).click(); 760 verifyDialogActionResults("Button 1"); 761 } 762 763 /** 764 * Performs a pinch out from the center of a view to its edges and listens to 765 * the motion events to make sure the starting and ending points of both pointers 766 * are correct. 767 * 768 * @throws UiObjectNotFoundException 769 * @since API Level 18 770 */ 771 public void testPinchOut() throws UiObjectNotFoundException { 772 openTest("Test 12"); 773 774 UiObject screen = new UiObject( 775 new UiSelector().description("Details View")); 776 777 // get the current view dimensions 778 Rect screenRect = screen.getBounds(); 779 780 // perform the pinch for 100% of the view dimensions starting form 781 // the center out to the edges. 782 screen.pinchOut(100, 30); 783 784 // dialog with the detected pointers motion coordinates is displayed. 785 UiObject results = new UiObject(new UiSelector().className( 786 android.widget.ScrollView.class).childSelector(new UiSelector().className( 787 android.widget.TextView.class))); 788 String allPointers = results.getText(); 789 new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog 790 791 // parse pointer 1 792 Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start 793 Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end 794 // parse pointer 2 795 Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start 796 Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end 797 798 assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y); 799 assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y); 800 assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y); 801 assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY()); 802 803 assertTrue("Touch-down X coordinate for pointer 1 is invalid", 804 withinMarginOfError(0.1f, screenRect.centerX(), p1s.x)); 805 806 assertTrue("Touch-down X coordinate for pointer 2 is invalid", 807 withinMarginOfError(0.1f, screenRect.centerX(), p2s.x)); 808 809 assertTrue("Touch-up X coordinate for pointer 1 is invalid", 810 withinMarginOfError(0.1f, screenRect.centerX() - screenRect.left, 811 screenRect.centerX() - p1e.x)); 812 813 assertTrue("Touch-up X coordinate for pointer 2 is invalid", 814 withinMarginOfError(0.1f, screenRect.right, p2e.x)); 815 } 816 817 /** 818 * Performs a pinch in from the edges of a view to its center and listens to 819 * the motion events to make sure the starting and ending points of both pointers 820 * are correct. 821 * 822 * @throws UiObjectNotFoundException 823 * @since API Level 18 824 */ 825 public void testPinchIn() throws UiObjectNotFoundException { 826 openTest("Test 12"); 827 828 UiObject screen = new UiObject( 829 new UiSelector().description("Details View")); 830 831 // get the current view dimensions 832 Rect screenRect = screen.getBounds(); 833 834 // perform the pinch for 100% of the view dimensions starting form 835 // the edges in towards the center. 836 screen.pinchIn(100, 30); 837 838 // dialog with the detected pointers motion coordinates is displayed. 839 UiObject results = new UiObject(new UiSelector().className( 840 android.widget.ScrollView.class).childSelector(new UiSelector().className( 841 android.widget.TextView.class))); 842 String allPointers = results.getText(); 843 new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog 844 845 // parse pointer 1 846 Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start 847 Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end 848 // parse pointer 2 849 Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start 850 Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end 851 852 assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y); 853 assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y); 854 assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y); 855 assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY()); 856 857 assertTrue("Touch-down X coordinate for pointer 1 is invalid", 858 withinMarginOfError(0.1f, screenRect.centerX() - screenRect.left, 859 screenRect.centerX() - p1s.x)); 860 861 assertTrue("Touch-down X coordinate for pointer 2 is invalid", 862 withinMarginOfError(0.1f, screenRect.right, p2s.x)); 863 864 assertTrue("Touch-up X coordinate for pointer 1 is invalid", 865 withinMarginOfError(0.1f, screenRect.centerX(), p1e.x)); 866 867 assertTrue("Touch-up X coordinate for pointer 2 is invalid", 868 withinMarginOfError(0.1f, screenRect.centerX(), p2e.x)); 869 } 870 871 /** 872 * Performs a drag and drop operation from one UiObject to another UiObject 873 * 874 * @throws UiObjectNotFoundException 875 * @since API Level 18 876 */ 877 public void testDragToObject() throws UiObjectNotFoundException { 878 openTest("Test 5"); 879 880 UiObject imageButton = new UiObject(new UiSelector().description("Image button")); 881 UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class)); 882 883 Rect starsBarRect = starsBar.getBounds(); 884 Rect imageButtonRect = imageButton.getBounds(); 885 imageButton.dragTo(starsBar, 30); 886 887 // dialog with the detected pointers motion coordinates is displayed. 888 UiObject results = new UiObject(new UiSelector().className( 889 android.widget.ScrollView.class).childSelector(new UiSelector().className( 890 android.widget.TextView.class))); 891 String allPointers = results.getText(); 892 new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog 893 894 // parse pointer 1 895 Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start 896 Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end 897 898 assertTrue("Invalid touch starting.X reported", 899 withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x)); 900 assertTrue("Invalid touch starting.Y reported", 901 withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y)); 902 assertTrue("Invalid touch ending.X reported", 903 withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x)); 904 assertTrue("Invalid touch ending.Y reported", 905 withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y)); 906 } 907 908 /** 909 * Performs a drag and drop operation from one UiObject to a specified coordinates 910 * 911 * @throws UiObjectNotFoundException 912 * @since API Level 18 913 */ 914 public void testDragToCoordinates() throws UiObjectNotFoundException { 915 openTest("Test 5"); 916 917 UiObject imageButton = new UiObject(new UiSelector().description("Image button")); 918 UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class)); 919 920 Rect starsBarRect = starsBar.getBounds(); 921 Rect imageButtonRect = imageButton.getBounds(); 922 imageButton.dragTo(starsBarRect.centerX(), starsBarRect.centerY(), 30); 923 924 // dialog with the detected pointers motion coordinates is displayed. 925 UiObject results = new UiObject(new UiSelector().className( 926 android.widget.ScrollView.class).childSelector(new UiSelector().className( 927 android.widget.TextView.class))); 928 String allPointers = results.getText(); 929 new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog 930 931 // parse pointer 1 932 Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start 933 Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end 934 935 assertTrue("Invalid touch starting.X reported", 936 withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x)); 937 assertTrue("Invalid touch starting.Y reported", 938 withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y)); 939 assertTrue("Invalid touch ending.X reported", 940 withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x)); 941 assertTrue("Invalid touch ending.Y reported", 942 withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y)); 943 } 944 945 /** 946 * Detect if actual value is within the allowable margin of error of the expected value. 947 * 948 * Used essentially with actual values that may vary from the expected values such in the 949 * cases of touch and pinch and touch and swipe where the starting or ending points may 950 * not exactly match the expected value. 951 * 952 * @param marginPrecent is values between 0 and 1 953 * @param expected 954 * @param actual 955 * @return true if actual is within the allowed range from expected 956 */ 957 private boolean withinMarginOfError(float marginPrecent, int expected, int actual) { 958 int m = (int) (marginPrecent * expected); 959 return actual >= expected - m && actual <= expected + m; 960 } 961 962 /** 963 * Parses a string containing starting to ending coordinates of one or more pointers. 964 * 965 * @param allPointers is a raw string with coordinates from all detected pointers 966 * @param pointerNumber is the desired pointer to be parsed 967 * @param edge is the 0 for the start or 1 for the end of the swipe 968 * @return Point containing the start or end coordinates of the specified pointer number 969 */ 970 private Point parsePointerCoordinates(String allPointers, int pointerNumber, int edge) { 971 String pointers[] = allPointers.split("\n"); 972 String coordinates = pointers[pointerNumber].split(":")[edge]; 973 String xy[] = coordinates.split(","); 974 return new Point(Integer.parseInt(xy[0]), Integer.parseInt(xy[1])); 975 } 976 977 /** 978 * Private helper to open test views. Also covers UiScrollable tests 979 * 980 * @param name 981 * @throws UiObjectNotFoundException 982 */ 983 private void openTest(String name) throws UiObjectNotFoundException { 984 try { 985 UiDevice.getInstance().setOrientationNatural(); 986 } catch (RemoteException e) { 987 // will catch it in its own test. For now try to put the device 988 // in its natural orientation prior to each test 989 } 990 UiScrollable listView = new UiScrollable( 991 new UiSelector().className(android.widget.ListView.class.getName())); 992 993 // on single fragment display 994 if (!listView.exists()) 995 UiDevice.getInstance().pressBack(); 996 997 UiObject testItem = listView.getChildByText( 998 new UiSelector().className(android.widget.TextView.class.getName()), name); 999 1000 testItem.click(); 1001 } 1002 1003 private void verifyTestDetailsExists(String name) throws UiObjectNotFoundException { 1004 // verify that we're at the right test 1005 new UiObject(new UiSelector().description("Details").text(name)).getText(); 1006 } 1007 1008 private UiObject getObjectByText(String txt) { 1009 return new UiObject(new UiSelector().text(txt)); 1010 } 1011 1012 private UiObject getObjectByTextMatch(String regex) { 1013 return new UiObject(new UiSelector().textMatches(regex)); 1014 } 1015 1016 private UiObject getObjectByDescriptionMatch(String regex) { 1017 return new UiObject(new UiSelector().descriptionMatches(regex)); 1018 } 1019 1020 private UiObject getObjectByDescription(String txt) { 1021 return new UiObject(new UiSelector().description(txt)); 1022 } 1023 1024 private UiObject getObjectByClassMatch(String regex, int instance) { 1025 return new UiObject(new UiSelector().classNameMatches(regex).instance(instance)); 1026 } 1027 1028 private <T> UiObject getObjectByClass(Class<T> type, int instance) { 1029 return new UiObject(new UiSelector().className(type).instance(instance)); 1030 } 1031 1032 private UiObject getObjectByIndex(String className, int index) { 1033 return new UiObject(new UiSelector().className(className).index(index)); 1034 } 1035 1036 private UiObject getObjectByInstance(String className, int instance) { 1037 return new UiObject(new UiSelector().className(className).instance(instance)); 1038 } 1039 1040 private void verifyDialogActionResults(String txt) throws UiObjectNotFoundException { 1041 if (!getObjectByText("Action results").exists() || !getObjectByText(txt).exists()) { 1042 throw new UiObjectNotFoundException(txt); 1043 } 1044 getObjectByText("OK").click(); 1045 } 1046} 1047