• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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