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