1c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski/*
2c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * Copyright (C) 2016 The Android Open Source Project
3c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski *
4c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * Licensed under the Apache License, Version 2.0 (the "License");
5c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * you may not use this file except in compliance with the License.
6c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * You may obtain a copy of the License at
7c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski *
8c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski *      http://www.apache.org/licenses/LICENSE-2.0
9c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski *
10c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * Unless required by applicable law or agreed to in writing, software
11c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * distributed under the License is distributed on an "AS IS" BASIS,
12c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * See the License for the specific language governing permissions and
14c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * limitations under the License.
15c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski */
16c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
17c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskipackage com.android.documentsui;
18c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
19c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY;
20c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport static com.android.documentsui.StubProvider.ROOT_0_ID;
21c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport static com.android.documentsui.StubProvider.ROOT_1_ID;
22c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
23b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronskaimport android.annotation.Nullable;
24c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.app.Activity;
25c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.content.ContentProviderClient;
26c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.content.ContentResolver;
27c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.content.Context;
28c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.content.Intent;
29c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.os.RemoteException;
30c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.provider.DocumentsContract.Document;
31c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.support.test.uiautomator.Configurator;
32c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.support.test.uiautomator.UiDevice;
33c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.support.test.uiautomator.UiObjectNotFoundException;
34c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.test.ActivityInstrumentationTestCase2;
35ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewskiimport android.util.Log;
36c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport android.view.MotionEvent;
37c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
38ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewskiimport com.android.documentsui.BaseActivity;
39ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewskiimport com.android.documentsui.EventListener;
40b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKayimport com.android.documentsui.bots.DirectoryListBot;
41b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKayimport com.android.documentsui.bots.KeyboardBot;
42b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKayimport com.android.documentsui.bots.RootsListBot;
43b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKayimport com.android.documentsui.bots.UiBot;
44c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskiimport com.android.documentsui.model.RootInfo;
45c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
46c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski/**
47c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * Provides basic test environment for UI tests:
48c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * - Launches activity
49c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * - Creates and gives access to test root directories and test files
50c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski * - Cleans up the test environment
51c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski */
52c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewskipublic abstract class ActivityTest<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
53c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
54c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    static final int TIMEOUT = 5000;
55c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
56c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    // Testing files. For custom ones, override initTestFiles().
57c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public static final String dirName1 = "Dir1";
58c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public static final String fileName1 = "file1.log";
59c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public static final String fileName2 = "file12.png";
60c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public static final String fileName3 = "anotherFile0.log";
61c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public static final String fileName4 = "poodles.text";
62c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public static final String fileNameNoRename = "NO_RENAMEfile.txt";
63c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
64b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay    public Bots bots;
65c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public UiDevice device;
66c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public Context context;
67c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
68c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public RootInfo rootDir0;
69c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public RootInfo rootDir1;
70c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    ContentResolver mResolver;
71c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    DocumentsProviderHelper mDocsHelper;
72c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    ContentProviderClient mClient;
73c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
74c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public ActivityTest(Class<T> activityClass) {
75c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        super(activityClass);
76c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
77c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
78b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska    /*
79b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska     * Returns the root that will be opened within the activity.
80b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska     * By default tests are started with one of the test roots.
81b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska     * Override the method if you want to open different root on start.
82b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska     * @return Root that will be opened. Return null if you want to open activity's default root.
83b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska     */
84b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska    @Nullable
85b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska    protected RootInfo getInitialRoot() {
86b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska        return rootDir0;
87b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska    }
88b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska
89ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski    /**
90ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski     * Returns the authority of the testing provider begin used.
91ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski     * By default it's StubProvider's authority.
92ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski     * @return Authority of the provider.
93ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski     */
94ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski    protected String getTestingProviderAuthority() {
95ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski        return DEFAULT_AUTHORITY;
96ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski    }
97ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski
98ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski    /**
99ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski     * Resolves testing roots.
100ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski     */
101ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski    protected void setupTestingRoots() throws RemoteException {
102ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski        rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
103ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski        rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
104ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski    }
105ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski
106c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    @Override
107c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public void setUp() throws Exception {
108c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        device = UiDevice.getInstance(getInstrumentation());
109c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        // NOTE: Must be the "target" context, else security checks in content provider will fail.
110c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        context = getInstrumentation().getTargetContext();
111b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay
112b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        bots = new Bots(device, context, TIMEOUT);
113c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
114c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
115c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
116c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mResolver = context.getContentResolver();
117ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski        mClient = mResolver.acquireUnstableContentProviderClient(getTestingProviderAuthority());
118ae6d6b494c2f5837889ebe8cbd50d6782697884fTomasz Mikolajewski        mDocsHelper = new DocumentsProviderHelper(getTestingProviderAuthority(), mClient);
119c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
120cf057efaff07fb22e2d4424e87f8ac1800c23afcTomasz Mikolajewski        setupTestingRoots();
121cf057efaff07fb22e2d4424e87f8ac1800c23afcTomasz Mikolajewski
122c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        launchActivity();
123c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        resetStorage();
124c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
125c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
126c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    @Override
127c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    public void tearDown() throws Exception {
128c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mClient.release();
129c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        super.tearDown();
130c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
131c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
132c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    void launchActivity() {
133c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        final Intent intent = context.getPackageManager().getLaunchIntentForPackage(
134c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski                UiBot.TARGET_PKG);
135c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
136b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska        if (getInitialRoot() != null) {
137b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska            intent.setData(getInitialRoot().getUri());
138b9eeee154339ba3a69bb9f822bd49b8094f51960Aga Wronska        }
139c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        setActivityIntent(intent);
140c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        getActivity();  // Launch the activity.
141c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
142c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
143c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    void resetStorage() throws RemoteException {
144c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mClient.call("clear", null, null);
145c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        device.waitForIdle();
146c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
147c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
148c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    void initTestFiles() throws RemoteException {
149c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mDocsHelper.createFolder(rootDir0, dirName1);
150c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mDocsHelper.createDocument(rootDir0, "text/plain", fileName1);
151c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mDocsHelper.createDocument(rootDir0, "image/png", fileName2);
152c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mDocsHelper.createDocumentWithFlags(rootDir0.documentId, "text/plain", fileNameNoRename,
153c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski                Document.FLAG_SUPPORTS_WRITE);
154c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
155c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mDocsHelper.createDocument(rootDir1, "text/plain", fileName3);
156c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski        mDocsHelper.createDocument(rootDir1, "text/plain", fileName4);
157c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
158c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
159c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    void assertDefaultContentOfTestDir0() throws UiObjectNotFoundException {
160b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        bots.directory.assertDocumentsCount(4);
161b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        bots.directory.assertDocumentsPresent(fileName1, fileName2, dirName1, fileNameNoRename);
162c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
163c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski
164c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    void assertDefaultContentOfTestDir1() throws UiObjectNotFoundException {
165b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        bots.directory.assertDocumentsCount(2);
166b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        bots.directory.assertDocumentsPresent(fileName3, fileName4);
167b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay    }
168b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay
169b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay    /**
170b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay     * Handy collection of bots for working with Files app.
171b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay     */
172b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay    public static final class Bots {
173b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        public final UiBot main;
174b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        public final RootsListBot roots;
175b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        public final DirectoryListBot directory;
176b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        public final KeyboardBot keyboard;
177b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay
178b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        private Bots(UiDevice device, Context context, int timeout) {
179b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay            this.main = new UiBot(device, context, TIMEOUT);
180b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay            this.roots = new RootsListBot(device, context, TIMEOUT);
181b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay            this.directory = new DirectoryListBot(device, context, TIMEOUT);
182b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay            this.keyboard = new KeyboardBot(device, context, TIMEOUT);
183b9a20d10c948cf111b70981e08233ea97323fe6cSteve McKay        }
184c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski    }
185c7b832202a8f1f91e378e255e61c4aa703f53394Tomasz Mikolajewski}
186