Home | History | Annotate | Download | only in shell
      1 /*
      2  * Copyright (C) 2015 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 
     17 package com.android.shell;
     18 
     19 import android.support.test.uiautomator.By;
     20 import android.support.test.uiautomator.UiDevice;
     21 import android.support.test.uiautomator.UiObject;
     22 import android.support.test.uiautomator.UiObjectNotFoundException;
     23 import android.support.test.uiautomator.UiScrollable;
     24 import android.support.test.uiautomator.UiSelector;
     25 import android.support.test.uiautomator.Until;
     26 import android.util.Log;
     27 import static junit.framework.Assert.assertTrue;
     28 
     29 /**
     30  * A helper class for UI-related testing tasks.
     31  */
     32 final class UiBot {
     33 
     34     private static final String TAG = "UiBot";
     35     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
     36 
     37     private final UiDevice mDevice;
     38     private final int mTimeout;
     39 
     40     public UiBot(UiDevice device, int timeout) {
     41         mDevice = device;
     42         mTimeout = timeout;
     43     }
     44 
     45     /**
     46      * Opens the system notification and gets a given notification.
     47      *
     48      * @param text Notificaton's text as displayed by the UI.
     49      * @return notification object.
     50      */
     51     public UiObject getNotification(String text) {
     52         boolean opened = mDevice.openNotification();
     53         Log.v(TAG, "openNotification(): " + opened);
     54         boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE)), mTimeout);
     55         assertTrue("could not get system ui (" + SYSTEMUI_PACKAGE + ")", gotIt);
     56 
     57         return getObject(text);
     58     }
     59 
     60     /**
     61      * Opens the system notification and clicks a given notification.
     62      *
     63      * @param text Notificaton's text as displayed by the UI.
     64      */
     65     public void clickOnNotification(String text) {
     66         UiObject notification = getNotification(text);
     67         click(notification, "bug report notification");
     68     }
     69 
     70     /**
     71      * Gets an object that might not yet be available in current UI.
     72      *
     73      * @param text Object's text as displayed by the UI.
     74      */
     75     public UiObject getObject(String text) {
     76         boolean gotIt = mDevice.wait(Until.hasObject(By.text(text)), mTimeout);
     77         assertTrue("object with text '(" + text + "') not visible yet", gotIt);
     78         return getVisibleObject(text);
     79     }
     80 
     81     /**
     82      * Gets an object that might not yet be available in current UI.
     83      *
     84      * @param id Object's fully-qualified resource id (like {@code android:id/button1})
     85      */
     86     public UiObject getObjectById(String id) {
     87         boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), mTimeout);
     88         assertTrue("object with id '(" + id + "') not visible yet", gotIt);
     89         return getVisibleObjectById(id);
     90     }
     91 
     92     /**
     93      * Gets an object which is guaranteed to be present in the current UI.
     94      *
     95      * @param text Object's text as displayed by the UI.
     96      */
     97     public UiObject getVisibleObject(String text) {
     98         UiObject uiObject = mDevice.findObject(new UiSelector().text(text));
     99         assertTrue("could not find object with text '" + text + "'", uiObject.exists());
    100         return uiObject;
    101     }
    102 
    103     /**
    104      * Gets an object which is guaranteed to be present in the current UI.
    105      *
    106      * @param text Object's text as displayed by the UI.
    107      */
    108     public UiObject getVisibleObjectById(String id) {
    109         UiObject uiObject = mDevice.findObject(new UiSelector().resourceId(id));
    110         assertTrue("could not find object with id '" + id+ "'", uiObject.exists());
    111         return uiObject;
    112     }
    113 
    114 
    115     /**
    116      * Clicks on a UI element.
    117      *
    118      * @param uiObject UI element to be clicked.
    119      * @param description Elements's description used on logging statements.
    120      */
    121     public void click(UiObject uiObject, String description) {
    122         try {
    123             boolean clicked = uiObject.click();
    124             // TODO: assertion below fails sometimes, even though the click succeeded,
    125             // (specially when clicking the "Just Once" button), so it's currently just logged.
    126             // assertTrue("could not click on object '" + description + "'", clicked);
    127 
    128             Log.v(TAG, "onClick for " + description + ": " + clicked);
    129         } catch (UiObjectNotFoundException e) {
    130             throw new IllegalStateException("exception when clicking on object '" + description
    131                     + "'", e);
    132         }
    133     }
    134 
    135     /**
    136      * Chooses a given activity to handle an Intent, using the "Just Once" button.
    137      *
    138      * @param name name of the activity as displayed in the UI (typically the value set by
    139      *            {@code android:label} in the manifest).
    140      */
    141     // TODO: UI Automator should provide such logic.
    142     public void chooseActivity(String name) {
    143         // First check if the activity is the default option.
    144         String shareText = "Share with " + name;
    145         Log.v(TAG, "Waiting for ActivityChooser text: '" + shareText + "'");
    146         boolean gotIt = mDevice.wait(Until.hasObject(By.text(shareText)), mTimeout);
    147         boolean justOnceHack = false;
    148 
    149         if (gotIt) {
    150             Log.v(TAG, "Found activity " + name + ", it's the default action");
    151             clickJustOnce();
    152         } else {
    153             // Since it's not, need to find it in the scrollable list...
    154             Log.v(TAG, "Activity " + name + " is not default action");
    155             UiScrollable activitiesList = new UiScrollable(new UiSelector().scrollable(true));
    156             try {
    157                 activitiesList.scrollForward();
    158             } catch (UiObjectNotFoundException e) {
    159                 // TODO: for some paranormal issue, the first time a test is run the scrollable
    160                 // activity list is displayed but calling scrollForwad() (or even isScrollable())
    161                 // throws a "UiObjectNotFoundException: UiSelector[SCROLLABLE=true]" exception
    162                 justOnceHack = true;
    163                 Log.d(TAG, "could not scroll forward", e);
    164             }
    165             UiObject activity = getVisibleObject(name);
    166             // ... then select it.
    167             click(activity, name);
    168             if (justOnceHack) {
    169                 clickJustOnce();
    170             }
    171         }
    172     }
    173 
    174     private void clickJustOnce() {
    175         boolean gotIt = mDevice.wait(Until.hasObject(By.res("android", "button_once")), mTimeout);
    176         assertTrue("'Just Once' button not visible yet", gotIt);
    177 
    178         UiObject justOnce = mDevice
    179                 .findObject(new UiSelector().resourceId("android:id/button_once"));
    180         assertTrue("'Just Once' button not found", justOnce.exists());
    181 
    182         click(justOnce, "Just Once");
    183     }
    184 
    185     public void pressBack() {
    186         mDevice.pressBack();
    187     }
    188 }
    189