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