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.documentsui.bots;
18 
19 import static junit.framework.Assert.assertEquals;
20 import static junit.framework.Assert.assertFalse;
21 import static junit.framework.Assert.assertNotNull;
22 import static junit.framework.Assert.assertTrue;
23 
24 import android.content.Context;
25 import android.support.test.uiautomator.By;
26 import android.support.test.uiautomator.UiDevice;
27 import android.support.test.uiautomator.UiObject;
28 import android.support.test.uiautomator.UiObject2;
29 import android.support.test.uiautomator.UiObjectNotFoundException;
30 import android.support.test.uiautomator.UiSelector;
31 import android.support.test.uiautomator.Until;
32 
33 import com.android.documentsui.R;
34 
35 import java.util.Iterator;
36 import java.util.List;
37 
38 /**
39  * A test helper class that provides support for controlling DocumentsUI activities
40  * programmatically, and making assertions against the state of the UI.
41  *
42  * <p>Support for working directly with Roots and Directory view can be found
43  * in the respective bots.
44  */
45 public class UiBot extends BaseBot {
46     public static final String TARGET_PKG = "com.android.documentsui";
47     private static final String LAUNCHER_PKG = "com.android.launcher";
48 
UiBot(UiDevice device, Context context, int timeout)49     public UiBot(UiDevice device, Context context, int timeout) {
50         super(device, context, timeout);
51     }
52 
assertWindowTitle(String expected)53     public void assertWindowTitle(String expected) {
54         // Turns out the title field on a window does not have
55         // an id associated with it at runtime (which confuses the hell out of me)
56         // In code we address this via "android.R.id.title".
57         UiObject2 o = find(By.text(expected));
58         // It's a bit of a conceit that we then *assert* that the title
59         // is the value that we used to identify the UiObject2.
60         // If the preceeding lookup fails, this'll choke with an NPE.
61         // But given the issue described in the comment above, we're
62         // going to do it anyway. Because we shouldn't be looking up
63         // the uiobject by it's expected content :|
64         assertEquals(expected, o.getText());
65     }
66 
assertMenuEnabled(int id, boolean enabled)67     public void assertMenuEnabled(int id, boolean enabled) {
68         UiObject2 menu= findMenuWithName(mContext.getString(id));
69         assertNotNull(menu);
70         assertEquals(enabled, menu.isEnabled());
71     }
72 
assertSearchTextField(boolean isFocused, String query)73     public void assertSearchTextField(boolean isFocused, String query)
74             throws UiObjectNotFoundException {
75         UiObject textField = findSearchViewTextField();
76         UiObject searchIcon = findSearchViewIcon();
77 
78         assertFalse(searchIcon.exists());
79         assertTrue(textField.exists());
80         assertEquals(isFocused, textField.isFocused());
81         if(query != null) {
82             assertEquals(query, textField.getText());
83         }
84     }
85 
assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists)86     public void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) {
87         assertEquals(searchTextFieldExists, findSearchViewTextField().exists());
88         assertEquals(searchIconExists, findSearchViewIcon().exists());
89     }
90 
assertInActionMode(boolean inActionMode)91     public void assertInActionMode(boolean inActionMode) {
92         UiObject actionModeBar = findActionModeBar();
93         assertEquals(inActionMode, actionModeBar.exists());
94     }
95 
openSearchView()96     public void openSearchView() throws UiObjectNotFoundException {
97         UiObject searchView = findSearchView();
98         searchView.click();
99         assertTrue(searchView.exists());
100     }
101 
setSearchQuery(String query)102     public void setSearchQuery(String query) throws UiObjectNotFoundException {
103         UiObject searchView = findSearchView();
104         assertTrue(searchView.exists());
105         UiObject searchTextField = findSearchViewTextField();
106         searchTextField.setText(query);
107         assertSearchTextField(true, query);
108     }
109 
openOverflowMenu()110     public UiObject openOverflowMenu() throws UiObjectNotFoundException {
111         UiObject obj = findMenuMoreOptions();
112         obj.click();
113         mDevice.waitForIdle(mTimeout);
114         return obj;
115     }
116 
setDialogText(String text)117     public void setDialogText(String text) throws UiObjectNotFoundException {
118         findDialogEditText().setText(text);
119     }
120 
switchViewMode()121     void switchViewMode() {
122         UiObject2 mode = menuGridMode();
123         if (mode != null) {
124             mode.click();
125         } else {
126             menuListMode().click();
127         }
128     }
129 
menuGridMode()130     UiObject2 menuGridMode() {
131         // Note that we're using By.desc rather than By.res, because of b/25285770
132         return find(By.desc("Grid view"));
133     }
134 
menuListMode()135         UiObject2 menuListMode() {
136         // Note that we're using By.desc rather than By.res, because of b/25285770
137         return find(By.desc("List view"));
138     }
139 
menuDelete()140     public UiObject2 menuDelete() {
141         return find(By.res("com.android.documentsui:id/menu_delete"));
142     }
143 
menuShare()144     public UiObject2 menuShare() {
145         return find(By.res("com.android.documentsui:id/menu_share"));
146     }
147 
menuRename()148     public UiObject2 menuRename() {
149         return findMenuWithName(mContext.getString(R.string.menu_rename));
150     }
151 
menuNewFolder()152     public UiObject2 menuNewFolder() {
153         return findMenuWithName(mContext.getString(R.string.menu_create_dir));
154     }
155 
findSearchView()156     UiObject findSearchView() {
157         return findObject("com.android.documentsui:id/menu_search");
158     }
159 
findSearchViewTextField()160     UiObject findSearchViewTextField() {
161         return findObject("com.android.documentsui:id/menu_search", "android:id/search_src_text");
162     }
163 
findSearchViewIcon()164     UiObject findSearchViewIcon() {
165         return mContext.getResources().getBoolean(R.bool.full_bar_search_view)
166                 ? findObject("com.android.documentsui:id/menu_search")
167                 : findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
168     }
169 
findActionModeBar()170     UiObject findActionModeBar() {
171         return findObject("android:id/action_mode_bar");
172     }
173 
findDialogEditText()174     public UiObject findDialogEditText() {
175         return findObject("android:id/content", "android:id/text1");
176     }
177 
findDownloadRetryDialog()178     public UiObject findDownloadRetryDialog() {
179         UiSelector selector = new UiSelector().text("Couldn't download");
180         UiObject title = mDevice.findObject(selector);
181         title.waitForExists(mTimeout);
182         return title;
183     }
184 
findDialogOkButton()185     public UiObject findDialogOkButton() {
186         UiObject object = findObject("android:id/content", "android:id/button1");
187         object.waitForExists(mTimeout);
188         return object;
189     }
190 
findDialogCancelButton()191     public UiObject findDialogCancelButton() {
192         UiObject object = findObject("android:id/content", "android:id/button2");
193         object.waitForExists(mTimeout);
194         return object;
195     }
196 
findMenuLabelWithName(String label)197     UiObject findMenuLabelWithName(String label) {
198         UiSelector selector = new UiSelector().text(label);
199         return mDevice.findObject(selector);
200     }
201 
findMenuWithName(String label)202     UiObject2 findMenuWithName(String label) {
203         List<UiObject2> menuItems = mDevice.findObjects(By.clazz("android.widget.LinearLayout"));
204         Iterator<UiObject2> it = menuItems.iterator();
205 
206         UiObject2 menuItem = null;
207         while(it.hasNext()) {
208             menuItem = it.next();
209             UiObject2 text = menuItem.findObject(By.text(label));
210             if(text != null) {
211                 break;
212             }
213         }
214         return menuItem;
215     }
216 
findMenuMoreOptions()217     UiObject findMenuMoreOptions() {
218         UiSelector selector = new UiSelector().className("android.widget.ImageButton")
219                 .descriptionContains("More options");
220         //TODO: use the system string ? android.R.string.action_menu_overflow_description
221         return mDevice.findObject(selector);
222     }
223 
pressKey(int keyCode)224     public void pressKey(int keyCode) {
225         mDevice.pressKeyCode(keyCode);
226     }
227 }
228