• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import static junit.framework.Assert.fail;
24 
25 import android.app.UiAutomation;
26 import android.content.Context;
27 import android.graphics.Point;
28 import android.graphics.Rect;
29 import android.os.SystemClock;
30 import android.support.test.uiautomator.By;
31 import android.support.test.uiautomator.BySelector;
32 import android.support.test.uiautomator.Configurator;
33 import android.support.test.uiautomator.UiDevice;
34 import android.support.test.uiautomator.UiObject;
35 import android.support.test.uiautomator.UiObject2;
36 import android.support.test.uiautomator.UiObjectNotFoundException;
37 import android.support.test.uiautomator.UiSelector;
38 import android.support.test.uiautomator.Until;
39 import android.view.InputDevice;
40 import android.view.KeyEvent;
41 import android.view.MotionEvent;
42 import android.view.View;
43 import android.widget.ImageView;
44 
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.List;
48 import java.util.regex.Pattern;
49 
50 /**
51  * A test helper class that provides support for controlling directory list
52  * and making assertions against the state of it.
53  */
54 public class DirectoryListBot extends Bots.BaseBot {
55     private static final String DIR_CONTAINER_ID = "com.android.documentsui:id/container_directory";
56     private static final String DIR_LIST_ID = "com.android.documentsui:id/dir_list";
57 
58     private static final BySelector SNACK_DELETE =
59             By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
60     private UiAutomation mAutomation;
61 
DirectoryListBot( UiDevice device, UiAutomation automation, Context context, int timeout)62     public DirectoryListBot(
63             UiDevice device, UiAutomation automation, Context context, int timeout) {
64         super(device, context, timeout);
65         mAutomation = automation;
66     }
67 
assertDocumentsCount(int count)68     public void assertDocumentsCount(int count) throws UiObjectNotFoundException {
69         UiObject docsList = findDocumentsList();
70         assertEquals(count, docsList.getChildCount());
71     }
72 
assertDocumentsPresent(String... labels)73     public void assertDocumentsPresent(String... labels) throws UiObjectNotFoundException {
74         List<String> absent = new ArrayList<>();
75         for (String label : labels) {
76             if (!findDocument(label).exists()) {
77                 absent.add(label);
78             }
79         }
80         if (!absent.isEmpty()) {
81             fail("Expected documents " + Arrays.asList(labels)
82                     + ", but missing " + absent);
83         }
84     }
85 
assertDocumentsAbsent(String... labels)86     public void assertDocumentsAbsent(String... labels) throws UiObjectNotFoundException {
87         List<String> found = new ArrayList<>();
88         for (String label : labels) {
89             if (findDocument(label).exists()) {
90                 found.add(label);
91             }
92         }
93         if (!found.isEmpty()) {
94             fail("Expected documents not present" + Arrays.asList(labels)
95                     + ", but present " + found);
96         }
97     }
98 
assertDocumentsCountOnList(boolean exists, int count)99     public void assertDocumentsCountOnList(boolean exists, int count) throws UiObjectNotFoundException {
100         UiObject docsList = findDocumentsList();
101         assertEquals(exists, docsList.exists());
102         if(docsList.exists()) {
103             assertEquals(count, docsList.getChildCount());
104         }
105     }
106 
assertHasMessage(String expected)107     public void assertHasMessage(String expected) throws UiObjectNotFoundException {
108         UiObject messageTextView = findHeaderMessageTextView();
109         String msg = String.valueOf(expected);
110         assertEquals(msg, messageTextView.getText());
111     }
112 
assertHasMessage(boolean expected)113     public void assertHasMessage(boolean expected) throws UiObjectNotFoundException {
114         UiObject messageTextView = findHeaderMessageTextView();
115         if (expected) {
116             assertTrue(messageTextView.exists());
117         } else {
118             assertFalse(messageTextView.exists());
119         }
120     }
121 
assertHasMessageButtonText(String expected)122     public void assertHasMessageButtonText(String expected) throws UiObjectNotFoundException {
123         UiObject button = findHeaderMessageButton();
124         String msg = String.valueOf(expected);
125         assertEquals(msg, button.getText());
126     }
127 
clickMessageButton()128     public void clickMessageButton() throws UiObjectNotFoundException {
129         UiObject button = findHeaderMessageButton();
130         button.click();
131     }
132 
133     /**
134      * Checks against placeholder text. Placeholder can be Empty page, No results page, or the
135      * "Hourglass" page (ie. something-went-wrong page).
136      */
assertPlaceholderMessageText(String message)137     public void assertPlaceholderMessageText(String message) throws UiObjectNotFoundException {
138         UiObject messageTextView = findPlaceholderMessageTextView();
139         assertTrue(messageTextView.exists());
140 
141         String msg = String.valueOf(message);
142         assertEquals(msg, messageTextView.getText());
143 
144     }
145 
findHeaderMessageTextView()146     private UiObject findHeaderMessageTextView() {
147         return findObject(
148                 DIR_CONTAINER_ID,
149                 "com.android.documentsui:id/message_textview");
150     }
151 
findHeaderMessageButton()152     private UiObject findHeaderMessageButton() {
153         return findObject(
154                 DIR_CONTAINER_ID,
155                 "com.android.documentsui:id/button_dismiss");
156     }
157 
findPlaceholderMessageTextView()158     private UiObject findPlaceholderMessageTextView() {
159         return findObject(
160                 DIR_CONTAINER_ID,
161                 "com.android.documentsui:id/message");
162     }
163 
assertSnackbar(int id)164     public void assertSnackbar(int id) {
165         assertNotNull(getSnackbar(mContext.getString(id)));
166     }
167 
openDocument(String label)168     public void openDocument(String label) throws UiObjectNotFoundException {
169         int toolType = Configurator.getInstance().getToolType();
170         Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
171         UiObject doc = findDocument(label);
172         doc.click();
173         Configurator.getInstance().setToolType(toolType);
174     }
175 
selectDocument(String label)176     public void selectDocument(String label) throws UiObjectNotFoundException {
177         waitForDocument(label);
178         UiObject2 selectionHotspot = findSelectionHotspot(label);
179         selectionHotspot.click();
180     }
181 
182     /**
183      * @param label The filename of the document
184      * @param number Which nth document it is. The number corresponding to "n selected"
185      */
selectDocument(String label, int number)186     public void selectDocument(String label, int number) throws UiObjectNotFoundException {
187         selectDocument(label);
188 
189         // wait until selection is fully done to avoid future click being registered as double
190         // clicking
191         assertSelection(number);
192     }
193 
findSelectionHotspot(String label)194     public UiObject2 findSelectionHotspot(String label) {
195         final BySelector list = By.res(DIR_LIST_ID);
196 
197         BySelector selector = By.hasChild(By.text(label));
198         UiObject2 parent = mDevice.findObject(list).findObject(selector);
199         if (parent.getClassName().equals("android.widget.LinearLayout")) {
200             // For list mode, the parent of the textView does not contain the selector icon, but the
201             // grandparent of the textView does
202             // Gotta go one more level up
203             selector = By.hasDescendant(By.text(label).depth(2));
204             parent = mDevice.findObject(list).findObject(selector);
205         }
206         return parent.findObject(By.clazz(ImageView.class));
207     }
208 
copyFilesToClipboard(String...labels)209     public void copyFilesToClipboard(String...labels) throws UiObjectNotFoundException {
210         for (String label: labels) {
211             selectDocument(label);
212         }
213         mDevice.pressKeyCode(KeyEvent.KEYCODE_C, KeyEvent.META_CTRL_ON);
214     }
215 
pasteFilesFromClipboard()216     public void pasteFilesFromClipboard() {
217         mDevice.pressKeyCode(KeyEvent.KEYCODE_V, KeyEvent.META_CTRL_ON);
218     }
219 
getSnackbar(String message)220     public UiObject2 getSnackbar(String message) {
221         return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
222     }
223 
waitForDeleteSnackbar()224     public void waitForDeleteSnackbar() {
225         mDevice.wait(Until.findObject(SNACK_DELETE), mTimeout);
226     }
227 
waitForDeleteSnackbarGone()228     public void waitForDeleteSnackbarGone() {
229         // wait a little longer for snackbar to go away, as it disappears after a timeout.
230         mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
231     }
232 
waitForDocument(String label)233     public void waitForDocument(String label) throws UiObjectNotFoundException {
234         findDocument(label).waitForExists(mTimeout);
235     }
236 
findDocument(String label)237     public UiObject findDocument(String label) throws UiObjectNotFoundException {
238         final UiSelector docList = new UiSelector().resourceId(
239                 DIR_CONTAINER_ID).childSelector(
240                         new UiSelector().resourceId(DIR_LIST_ID));
241 
242         // Wait for the first list item to appear
243         new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
244 
245         // new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
246         return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
247     }
248 
hasDocuments(String... labels)249     public boolean hasDocuments(String... labels) throws UiObjectNotFoundException {
250         for (String label : labels) {
251             if (!findDocument(label).exists()) {
252                 return false;
253             }
254         }
255         return true;
256     }
257 
assertFirstDocumentHasFocus()258     public void assertFirstDocumentHasFocus() throws UiObjectNotFoundException {
259         final UiSelector docList = new UiSelector().resourceId(
260                 DIR_CONTAINER_ID).childSelector(
261                         new UiSelector().resourceId(DIR_LIST_ID));
262 
263         // Wait for the first list item to appear
264         UiObject doc = new UiObject(docList.childSelector(new UiSelector()));
265         doc.waitForExists(mTimeout);
266 
267         assertTrue(doc.isFocused());
268     }
269 
findDocumentsList()270     public UiObject findDocumentsList() {
271         return findObject(
272                 DIR_CONTAINER_ID,
273                 DIR_LIST_ID);
274     }
275 
assertHasFocus()276     public void assertHasFocus() {
277         assertHasFocus(DIR_LIST_ID);
278     }
279 
assertSelection(int numSelected)280     public void assertSelection(int numSelected) {
281         String assertSelectionText = numSelected + " selected";
282         UiObject2 selectionText = mDevice.wait(
283                 Until.findObject(By.text(assertSelectionText)), mTimeout);
284         assertTrue(selectionText != null);
285     }
286 
assertOrder(String[] dirs, String[] files)287     public void assertOrder(String[] dirs, String[] files) throws UiObjectNotFoundException {
288         for (int i = 0; i < dirs.length - 1; ++i) {
289             assertOrder(dirs[i], dirs[i + 1]);
290         }
291 
292         if (dirs.length > 0 && files.length > 0) {
293             assertOrder(dirs[dirs.length - 1], files[0]);
294         }
295 
296         for (int i = 0; i < files.length - 1; ++i) {
297             assertOrder(files[i], files[i + 1]);
298         }
299     }
300 
rightClickDocument(String label)301     public void rightClickDocument(String label) throws UiObjectNotFoundException {
302         Rect startCoord = findDocument(label).getBounds();
303         rightClickDocument(new Point(startCoord.centerX(), startCoord.centerY()));
304     }
305 
rightClickDocument(Point point)306     public void rightClickDocument(Point point) throws UiObjectNotFoundException {
307         //TODO: Use Espresso instead of doing the events mock ourselves
308         MotionEvent motionDown = getTestMotionEvent(
309                 MotionEvent.ACTION_DOWN,
310                 MotionEvent.BUTTON_SECONDARY,
311                 MotionEvent.TOOL_TYPE_MOUSE,
312                 InputDevice.SOURCE_MOUSE,
313                 point.x,
314                 point.y);
315         mAutomation.injectInputEvent(motionDown, true);
316         SystemClock.sleep(100);
317 
318         MotionEvent motionUp = getTestMotionEvent(
319                 MotionEvent.ACTION_UP,
320                 MotionEvent.BUTTON_SECONDARY,
321                 MotionEvent.TOOL_TYPE_MOUSE,
322                 InputDevice.SOURCE_MOUSE,
323                 point.x,
324                 point.y);
325 
326         mAutomation.injectInputEvent(motionUp, true);
327     }
328 
getTestMotionEvent( int action, int buttonState, int toolType, int source, int x, int y)329     private MotionEvent getTestMotionEvent(
330             int action, int buttonState, int toolType, int source, int x, int y) {
331         long eventTime = SystemClock.uptimeMillis();
332 
333         MotionEvent.PointerProperties[] pp = {new MotionEvent.PointerProperties()};
334         pp[0].clear();
335         pp[0].id = 0;
336         pp[0].toolType = toolType;
337 
338         MotionEvent.PointerCoords[] pointerCoords = {new MotionEvent.PointerCoords()};
339         pointerCoords[0].clear();
340         pointerCoords[0].x = x;
341         pointerCoords[0].y = y;
342         pointerCoords[0].pressure = 0;
343         pointerCoords[0].size = 1;
344 
345         return MotionEvent.obtain(
346                 eventTime,
347                 eventTime,
348                 action,
349                 1,
350                 pp,
351                 pointerCoords,
352                 0,
353                 buttonState,
354                 1f,
355                 1f,
356                 0,
357                 0,
358                 source,
359                 0);
360     }
361 
assertOrder(String first, String second)362     private void assertOrder(String first, String second) throws UiObjectNotFoundException {
363 
364         final UiObject firstObj = findDocument(first);
365         final UiObject secondObj = findDocument(second);
366 
367         final int layoutDirection = mContext.getResources().getConfiguration().getLayoutDirection();
368         final Rect firstBound = firstObj.getVisibleBounds();
369         final Rect secondBound = secondObj.getVisibleBounds();
370         if (layoutDirection == View.LAYOUT_DIRECTION_LTR) {
371             assertTrue(
372                     "\"" + first + "\" is not located above or to the left of \"" + second
373                             + "\" in LTR",
374                     firstBound.bottom < secondBound.top || firstBound.right < secondBound.left);
375         } else {
376             assertTrue(
377                     "\"" + first + "\" is not located above or to the right of \"" + second +
378                             "\" in RTL",
379                     firstBound.bottom < secondBound.top || firstBound.left > secondBound.right);
380         }
381     }
382 }
383