Home | History | Annotate | Download | only in uiautomatortest
      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
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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     */
    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      */
    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      */
   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 
   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 
   1034     private UiObject getObjectByText(String txt) {
   1035         return new UiObject(new UiSelector().text(txt));
   1036     }
   1037 
   1038     private UiObject getObjectByTextMatch(String regex) {
   1039         return new UiObject(new UiSelector().textMatches(regex));
   1040     }
   1041 
   1042     private UiObject getObjectByDescriptionMatch(String regex) {
   1043         return new UiObject(new UiSelector().descriptionMatches(regex));
   1044     }
   1045 
   1046     private UiObject getObjectByDescription(String txt) {
   1047         return new UiObject(new UiSelector().description(txt));
   1048     }
   1049 
   1050     private UiObject getObjectByClassMatch(String regex, int instance) {
   1051         return new UiObject(new UiSelector().classNameMatches(regex).instance(instance));
   1052     }
   1053 
   1054     private <T> UiObject getObjectByClass(Class<T> type, int instance) {
   1055         return new UiObject(new UiSelector().className(type).instance(instance));
   1056     }
   1057 
   1058     private UiObject getObjectByIndex(String className, int index) {
   1059         return new UiObject(new UiSelector().className(className).index(index));
   1060     }
   1061 
   1062     private UiObject getObjectByInstance(String className, int instance) {
   1063         return new UiObject(new UiSelector().className(className).instance(instance));
   1064     }
   1065 
   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