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
17package com.android.documentsui.bots;
18
19import static android.support.test.espresso.Espresso.onView;
20import static android.support.test.espresso.action.ViewActions.swipeLeft;
21import static android.support.test.espresso.action.ViewActions.swipeRight;
22import static android.support.test.espresso.matcher.ViewMatchers.withId;
23
24import android.content.Context;
25import android.support.test.uiautomator.UiDevice;
26import android.support.test.uiautomator.UiObject;
27import android.support.test.uiautomator.UiObjectNotFoundException;
28import android.support.test.uiautomator.UiScrollable;
29import android.support.test.uiautomator.UiSelector;
30import android.util.Log;
31import android.view.View;
32
33import com.android.documentsui.R;
34
35import junit.framework.Assert;
36
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.List;
40
41/**
42 * A test helper class that provides support for controlling and asserting against
43 * the roots list drawer.
44 */
45public class SidebarBot extends Bots.BaseBot {
46    private static final String ROOTS_LIST_ID = "com.android.documentsui:id/roots_list";
47    private static final String TAG = "RootsListBot";
48
49    public SidebarBot(UiDevice device, Context context, int timeout) {
50        super(device, context, timeout);
51    }
52
53    private UiObject findRoot(String label) throws UiObjectNotFoundException {
54        // We might need to expand drawer if not visible
55        openDrawer();
56
57        final UiSelector rootsList = new UiSelector().resourceId(
58                "com.android.documentsui:id/container_roots").childSelector(
59                new UiSelector().resourceId(ROOTS_LIST_ID));
60
61        // Wait for the first list item to appear
62        new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
63
64        // Now scroll around to find our item
65        new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
66        return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
67    }
68
69    public void openRoot(String label) throws UiObjectNotFoundException {
70        findRoot(label).click();
71        // Close the drawer in case we select a pre-selected root already
72        closeDrawer();
73    }
74
75    public void openDrawer() throws UiObjectNotFoundException {
76        final UiSelector rootsList = new UiSelector().resourceId(
77                "com.android.documentsui:id/container_roots").childSelector(
78                new UiSelector().resourceId(ROOTS_LIST_ID));
79
80        // We might need to expand drawer if not visible
81        if (!new UiObject(rootsList).waitForExists(mTimeout)) {
82            Log.d(TAG, "Failed to find roots list; trying to expand");
83            final UiSelector hamburger = new UiSelector().resourceId(
84                    "com.android.documentsui:id/toolbar").childSelector(
85                    new UiSelector().className("android.widget.ImageButton").clickable(true));
86            new UiObject(hamburger).click();
87        }
88    }
89
90    public void closeDrawer() {
91      // Espresso will try to close the drawer if it's opened
92      // But if no drawer exists (Tablet devices), we will have to catch the exception
93      // and continue on the test
94      // Why can't we do something like .exist() first?
95      // http://stackoverflow.com/questions/20807131/espresso-return-boolean-if-view-exists
96      try {
97        if (mContext.getResources().getConfiguration()
98            .getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
99            onView(withId(R.id.drawer_layout)).perform(swipeRight());
100        } else {
101          onView(withId(R.id.drawer_layout)).perform(swipeLeft());
102        }
103      } catch (Exception e) {
104      }
105    }
106
107    public void assertRootsPresent(String... labels) throws UiObjectNotFoundException {
108        List<String> missing = new ArrayList<>();
109        for (String label : labels) {
110            if (!findRoot(label).exists()) {
111                missing.add(label);
112            }
113        }
114        if (!missing.isEmpty()) {
115            Assert.fail(
116                    "Expected roots " + Arrays.asList(labels) + ", but missing " + missing);
117        }
118    }
119
120    public void assertRootsAbsent(String... labels) throws UiObjectNotFoundException {
121        List<String> unexpected = new ArrayList<>();
122        for (String label : labels) {
123            if (findRoot(label).exists()) {
124                unexpected.add(label);
125            }
126        }
127        if (!unexpected.isEmpty()) {
128            Assert.fail("Unexpected roots " + unexpected);
129        }
130    }
131
132    public void assertHasFocus() {
133        assertHasFocus(ROOTS_LIST_ID);
134    }
135}
136