UiBot.java revision e53e85f6051d20cbd477bc25d446a41996411fab
1e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme/*
2e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * Copyright (C) 2015 The Android Open Source Project
3e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme *
4e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * Licensed under the Apache License, Version 2.0 (the "License");
5e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * you may not use this file except in compliance with the License.
6e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * You may obtain a copy of the License at
7e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme *
8e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme *      http://www.apache.org/licenses/LICENSE-2.0
9e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme *
10e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * Unless required by applicable law or agreed to in writing, software
11e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * distributed under the License is distributed on an "AS IS" BASIS,
12e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * See the License for the specific language governing permissions and
14e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * limitations under the License.
15e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme */
16e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
17e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemepackage com.android.shell;
18e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
19e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport android.support.test.uiautomator.By;
20e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport android.support.test.uiautomator.UiDevice;
21e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport android.support.test.uiautomator.UiObject;
22e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport android.support.test.uiautomator.UiObjectNotFoundException;
23e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport android.support.test.uiautomator.UiSelector;
24e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport android.support.test.uiautomator.Until;
25e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport android.util.Log;
26e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemeimport static junit.framework.Assert.assertTrue;
27e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
28e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme/**
29e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme * A helper class for UI-related testing tasks.
30e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme */
31e53e85f6051d20cbd477bc25d446a41996411fabFelipe Lemefinal class UiBot {
32e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
33e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    private static final String TAG = "UiBot";
34e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    private static final String SYSTEMUI_PACKAGED = "com.android.systemui";
35e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
36e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    private final UiDevice mDevice;
37e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    private final int mTimeout;
38e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
39e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    public UiBot(UiDevice device, int timeout) {
40e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        mDevice = device;
41e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        mTimeout = timeout;
42e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    }
43e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
44e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    /**
45e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * Opens the system notification and clicks a given notification.
46e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     *
47e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * @param text Notificaton's text as displayed by the UI.
48e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     */
49e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    public void clickOnNotification(String text) {
50e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        boolean opened = mDevice.openNotification();
51e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        Log.v(TAG, "openNotification(): " + opened);
52e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGED)), mTimeout);
53e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        assertTrue("could not get system ui (" + SYSTEMUI_PACKAGED + ")", gotIt);
54e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
55e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        gotIt = mDevice.wait(Until.hasObject(By.text(text)), mTimeout);
56e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        assertTrue("object with text '(" + text + "') not visible yet", gotIt);
57e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
58e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        UiObject notification = getVisibleObject(text);
59e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
60e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        click(notification, "bug report notification");
61e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    }
62e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
63e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    /**
64e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * Gets an object which is guaranteed to be present in the current UI.\
65e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     *
66e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * @param text Object's text as displayed by the UI.
67e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     */
68e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    public UiObject getVisibleObject(String text) {
69e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        UiObject uiObject = mDevice.findObject(new UiSelector().text(text));
70e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        assertTrue("could not find object with text '(" + text + "')", uiObject.exists());
71e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        return uiObject;
72e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    }
73e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
74e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    /**
75e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * Clicks on a UI element.
76e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     *
77e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * @param uiObject UI element to be clicked.
78e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * @param description Elements's description used on logging statements.
79e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     */
80e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    public void click(UiObject uiObject, String description) {
81e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        try {
82e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            boolean clicked = uiObject.click();
83e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            // TODO: assertion below fails sometimes, even though the click succeeded,
84e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            // (specially when clicking the "Just Once" button), so it's currently just logged.
85e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            // assertTrue("could not click on object '" + description + "'", clicked);
86e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
87e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            Log.v(TAG, "onClick for " + description + ": " + clicked);
88e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        } catch (UiObjectNotFoundException e) {
89e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            throw new IllegalStateException("exception when clicking on object '" + description
90e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme                    + "'", e);
91e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        }
92e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    }
93e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
94e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    /**
95e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * Chooses a given activity to handle an Intent, using the "Just Once" button.
96e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     *
97e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     * @param name name of the activity as displayed in the UI (typically the value set by
98e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     *            {@code android:label} in the manifest).
99e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme     */
100e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    // TODO: UI Automator should provide such logic.
101e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    public void chooseActivity(String name) {
102e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        // First select activity if it's not the default option.
103e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        boolean gotIt = mDevice.wait(Until.hasObject(By.text(name)), mTimeout);
104e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        // TODO: if the activity is indeed the default option, call above will timeout, which will
105e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        // make the tests run slower. It might be better to change the logic to assume the default
106e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        // first.
107e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        if (gotIt) {
108e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            Log.v(TAG, "Found activity " + name + ", it's not default action");
109e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            UiObject activityChooser = getVisibleObject(name);
110e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            click(activityChooser, "activity chooser");
111e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        } else {
112e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            String text = String.format("Share with %s", name);
113e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            Log.v(TAG, "Didn't find activity " + name
114e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme                    + ", assuming it's the default action and search for '" + text + "'");
115e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            gotIt = mDevice.wait(Until.hasObject(By.text(text)), mTimeout);
116e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme            assertTrue("did not find text '" + text + "'", gotIt);
117e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        }
118e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
119e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        // Then clicks the "Just Once" button.
120e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        gotIt = mDevice
121e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme                .wait(Until.hasObject(By.res("android", "button_once")), mTimeout);
122e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        assertTrue("'Just Once' button not visible yet", gotIt);
123e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
124e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        UiObject justOnce = mDevice
125e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme                .findObject(new UiSelector().resourceId("android:id/button_once"));
126e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        assertTrue("'Just Once' button not found", justOnce.exists());
127e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme
128e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme        click(justOnce, "Just Once");
129e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme    }
130e53e85f6051d20cbd477bc25d446a41996411fabFelipe Leme}
131