blob: 18b1e2f9245d53b8b5bd8c160cd90abef83ec27b [file] [log] [blame]
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +09001/*
2 * Copyright (C) 2016 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
Steve McKayae84a182016-09-16 09:36:50 -070017package com.android.documentsui;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090018
19import android.app.Activity;
Ben Linfa1e1362016-09-14 17:57:25 -070020import android.app.UiAutomation;
Bill Lin6b771722018-08-16 19:56:56 +080021import android.app.UiModeManager;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090022import android.content.ContentProviderClient;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
Bill Lin6b771722018-08-16 19:56:56 +080026import android.content.res.Configuration;
Garfield Tanceedd1f2017-05-17 14:10:12 -070027import android.os.Bundle;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090028import android.os.RemoteException;
Steve McKay09404b32016-09-30 13:18:36 -070029import android.provider.DocumentsContract;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090030import android.provider.DocumentsContract.Document;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090031import android.support.test.uiautomator.Configurator;
32import android.support.test.uiautomator.UiDevice;
33import android.support.test.uiautomator.UiObjectNotFoundException;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090034import android.test.ActivityInstrumentationTestCase2;
35import android.view.MotionEvent;
Steve McKay09404b32016-09-30 13:18:36 -070036
Ben Linb18a5262017-05-17 13:56:07 -070037import com.android.documentsui.base.Features;
Steve McKayd0805062016-09-15 14:30:38 -070038import com.android.documentsui.base.RootInfo;
Steve McKay85ec0d62016-06-24 15:05:08 -070039import com.android.documentsui.bots.Bots;
Steve McKay5e1acc92016-02-19 12:57:05 -080040import com.android.documentsui.bots.UiBot;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090041
Steve McKay85ec0d62016-06-24 15:05:08 -070042import javax.annotation.Nullable;
43
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090044/**
45 * Provides basic test environment for UI tests:
46 * - Launches activity
47 * - Creates and gives access to test root directories and test files
48 * - Cleans up the test environment
49 */
50public abstract class ActivityTest<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
51
52 static final int TIMEOUT = 5000;
Bill Lin6b771722018-08-16 19:56:56 +080053 static final int NIGHT_MODE_CHANGE_WAIT_TIME = 1000;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090054
55 // Testing files. For custom ones, override initTestFiles().
56 public static final String dirName1 = "Dir1";
Steve McKay85ec0d62016-06-24 15:05:08 -070057 public static final String childDir1 = "ChildDir1";
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090058 public static final String fileName1 = "file1.log";
59 public static final String fileName2 = "file12.png";
60 public static final String fileName3 = "anotherFile0.log";
61 public static final String fileName4 = "poodles.text";
62 public static final String fileNameNoRename = "NO_RENAMEfile.txt";
63
Steve McKay5e1acc92016-02-19 12:57:05 -080064 public Bots bots;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090065 public UiDevice device;
66 public Context context;
Ben Linfa1e1362016-09-14 17:57:25 -070067 public UiAutomation automation;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090068
Ben Linb18a5262017-05-17 13:56:07 -070069 public Features features;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090070 public RootInfo rootDir0;
71 public RootInfo rootDir1;
Steve McKayd0805062016-09-15 14:30:38 -070072 protected ContentResolver mResolver;
73 protected DocumentsProviderHelper mDocsHelper;
74 protected ContentProviderClient mClient;
Bill Lin6b771722018-08-16 19:56:56 +080075 protected UiModeManager mUiModeManager;
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090076
77 public ActivityTest(Class<T> activityClass) {
78 super(activityClass);
79 }
80
Aga Wronskaec401b72016-02-24 12:57:21 -080081 /*
82 * Returns the root that will be opened within the activity.
83 * By default tests are started with one of the test roots.
84 * Override the method if you want to open different root on start.
85 * @return Root that will be opened. Return null if you want to open activity's default root.
86 */
Steve McKay85ec0d62016-06-24 15:05:08 -070087 protected @Nullable RootInfo getInitialRoot() {
Aga Wronskaec401b72016-02-24 12:57:21 -080088 return rootDir0;
89 }
90
Tomasz Mikolajewskie29e3412016-02-24 12:53:44 +090091 /**
92 * Returns the authority of the testing provider begin used.
93 * By default it's StubProvider's authority.
94 * @return Authority of the provider.
95 */
96 protected String getTestingProviderAuthority() {
Steve McKayae84a182016-09-16 09:36:50 -070097 return StubProvider.DEFAULT_AUTHORITY;
Tomasz Mikolajewskie29e3412016-02-24 12:53:44 +090098 }
99
100 /**
101 * Resolves testing roots.
102 */
103 protected void setupTestingRoots() throws RemoteException {
Steve McKayae84a182016-09-16 09:36:50 -0700104 rootDir0 = mDocsHelper.getRoot(StubProvider.ROOT_0_ID);
105 rootDir1 = mDocsHelper.getRoot(StubProvider.ROOT_1_ID);
Tomasz Mikolajewskie29e3412016-02-24 12:53:44 +0900106 }
107
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900108 @Override
109 public void setUp() throws Exception {
110 device = UiDevice.getInstance(getInstrumentation());
111 // NOTE: Must be the "target" context, else security checks in content provider will fail.
112 context = getInstrumentation().getTargetContext();
Ben Linfa1e1362016-09-14 17:57:25 -0700113 automation = getInstrumentation().getUiAutomation();
Ben Linb18a5262017-05-17 13:56:07 -0700114 features = new Features.RuntimeFeatures(context.getResources(), null);
Steve McKay5e1acc92016-02-19 12:57:05 -0800115
Ben Linfa1e1362016-09-14 17:57:25 -0700116 bots = new Bots(device, automation, context, TIMEOUT);
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900117
118 Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900119
120 mResolver = context.getContentResolver();
Tomasz Mikolajewskie29e3412016-02-24 12:53:44 +0900121 mClient = mResolver.acquireUnstableContentProviderClient(getTestingProviderAuthority());
122 mDocsHelper = new DocumentsProviderHelper(getTestingProviderAuthority(), mClient);
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900123
Ben Linebee3de2016-07-22 18:31:36 -0700124 device.setOrientationNatural();
Tomasz Mikolajewski2fca4cc2016-03-02 14:38:23 +0900125 setupTestingRoots();
126
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900127 launchActivity();
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900128 resetStorage();
Ben Linebee3de2016-07-22 18:31:36 -0700129
130 // Since at the launch of activity, ROOT_0 and ROOT_1 have no files, drawer will
131 // automatically open for phone devices. Espresso register click() as (x, y) MotionEvents,
132 // so if a drawer is on top of a file we want to select, it will actually click the drawer.
133 // Thus to start a clean state, we always try to close first.
134 bots.roots.closeDrawer();
Garfield Tanceedd1f2017-05-17 14:10:12 -0700135
136 // Configure the provider back to default.
137 mDocsHelper.configure(null, Bundle.EMPTY);
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900138 }
139
140 @Override
141 public void tearDown() throws Exception {
Ben Linebee3de2016-07-22 18:31:36 -0700142 device.unfreezeRotation();
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900143 mClient.release();
144 super.tearDown();
145 }
146
Julian Mancinidb28d842017-06-19 10:14:57 -0700147 protected void launchActivity() {
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900148 final Intent intent = context.getPackageManager().getLaunchIntentForPackage(
Bill Lin34329192019-03-05 22:22:20 +0800149 UiBot.targetPackageName);
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900150 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
Aga Wronskaec401b72016-02-24 12:57:21 -0800151 if (getInitialRoot() != null) {
Garfield Tanc5efea02017-02-22 12:58:29 -0800152 intent.setAction(Intent.ACTION_VIEW);
153 intent.setDataAndType(getInitialRoot().getUri(), DocumentsContract.Root.MIME_TYPE_ITEM);
Aga Wronskaec401b72016-02-24 12:57:21 -0800154 }
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900155 setActivityIntent(intent);
156 getActivity(); // Launch the activity.
157 }
158
Steve McKayd0805062016-09-15 14:30:38 -0700159 protected void resetStorage() throws RemoteException {
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900160 mClient.call("clear", null, null);
161 device.waitForIdle();
162 }
163
Steve McKayd0805062016-09-15 14:30:38 -0700164 protected void initTestFiles() throws RemoteException {
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900165 mDocsHelper.createFolder(rootDir0, dirName1);
166 mDocsHelper.createDocument(rootDir0, "text/plain", fileName1);
167 mDocsHelper.createDocument(rootDir0, "image/png", fileName2);
168 mDocsHelper.createDocumentWithFlags(rootDir0.documentId, "text/plain", fileNameNoRename,
169 Document.FLAG_SUPPORTS_WRITE);
170
171 mDocsHelper.createDocument(rootDir1, "text/plain", fileName3);
172 mDocsHelper.createDocument(rootDir1, "text/plain", fileName4);
173 }
174
175 void assertDefaultContentOfTestDir0() throws UiObjectNotFoundException {
Steve McKay85ec0d62016-06-24 15:05:08 -0700176 bots.directory.waitForDocument(fileName1);
177 bots.directory.waitForDocument(fileName2);
178 bots.directory.waitForDocument(dirName1);
179 bots.directory.waitForDocument(fileNameNoRename);
Steve McKay5e1acc92016-02-19 12:57:05 -0800180 bots.directory.assertDocumentsCount(4);
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900181 }
182
183 void assertDefaultContentOfTestDir1() throws UiObjectNotFoundException {
Steve McKay85ec0d62016-06-24 15:05:08 -0700184 bots.directory.waitForDocument(fileName3);
185 bots.directory.waitForDocument(fileName4);
Steve McKay5e1acc92016-02-19 12:57:05 -0800186 bots.directory.assertDocumentsCount(2);
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900187 }
Bill Lin6b771722018-08-16 19:56:56 +0800188
189 /**
190 * Setup test Activity UI Mode YES or not(AUTO/YES/NO) before start to testing
191 * @param uiModeNight Constant for {@link #setNightMode(int)}
192 * 0 - MODE_NIGHT_AUTO
193 * 1 - MODE_NIGHT_NO
194 * 2 - MODE_NIGHT_YES
195 */
196 protected void setSystemUiModeNight(int uiModeNight) {
197 int systemUiMode = getActivity().getResources().getConfiguration().uiMode
198 & Configuration.UI_MODE_NIGHT_MASK;
199 if(uiModeNight != systemUiMode) {
200 /* TODO since ag/4947691 enable config_lockDayNightMode to block app setNightMode()
201 create b/115315612 to handle the UiModeManager permission deny problem */
202 mUiModeManager = (UiModeManager) getActivity()
203 .getSystemService(Context.UI_MODE_SERVICE);
204 mUiModeManager.setNightMode(uiModeNight);
205 device.waitForIdle(NIGHT_MODE_CHANGE_WAIT_TIME);
206 }
207 }
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +0900208}