1 /*
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 package com.android.documentsui.testing;
17 
18 import android.content.Context;
19 import android.os.UserHandle;
20 import android.provider.DocumentsContract.Document;
21 import android.test.mock.MockContentResolver;
22 
23 import androidx.test.InstrumentationRegistry;
24 
25 import com.android.documentsui.DocsSelectionHelper;
26 import com.android.documentsui.FocusManager;
27 import com.android.documentsui.Injector;
28 import com.android.documentsui.ModelId;
29 import com.android.documentsui.SelectionHelpers;
30 import com.android.documentsui.archives.ArchivesProvider;
31 import com.android.documentsui.base.DocumentInfo;
32 import com.android.documentsui.base.Features;
33 import com.android.documentsui.base.RootInfo;
34 import com.android.documentsui.base.State;
35 import com.android.documentsui.base.UserId;
36 import com.android.documentsui.dirlist.TestFocusHandler;
37 import com.android.documentsui.sorting.SortModel;
38 import com.android.documentsui.ui.TestDialogController;
39 
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.concurrent.Executor;
45 
46 public class TestEnv {
47 
48     public static DocumentInfo FOLDER_0;
49     public static DocumentInfo FOLDER_1;
50     public static DocumentInfo FOLDER_2;
51     public static DocumentInfo FILE_TXT;
52     public static DocumentInfo FILE_PNG;
53     public static DocumentInfo FILE_JPG;
54     public static DocumentInfo FILE_GIF;
55     public static DocumentInfo FILE_PDF;
56     public static DocumentInfo FILE_MP4;
57     public static DocumentInfo FILE_APK;
58     public static DocumentInfo FILE_PARTIAL;
59     public static DocumentInfo FILE_ARCHIVE;
60     public static DocumentInfo FILE_IN_ARCHIVE;
61     public static DocumentInfo FILE_VIRTUAL;
62     public static DocumentInfo FILE_READ_ONLY;
63 
64     public static class OtherUser {
65         public static DocumentInfo FOLDER_0;
66         public static DocumentInfo FILE_PNG;
67     }
68 
69     public final TestScheduledExecutorService mExecutor;
70     public final State state = new State();
71     public final TestProvidersAccess providers = new TestProvidersAccess();
72     public final TestDocumentsAccess docs = new TestDocumentsAccess();
73     public final TestFocusHandler focusHandler = new TestFocusHandler();
74     public final TestDialogController dialogs = new TestDialogController();
75     public final TestModel model;
76     public final TestModel modelOtherUser;
77     public final TestModel archiveModel;
78     public final DocsSelectionHelper selectionMgr;
79     public final TestSearchViewManager searchViewManager;
80     public final Injector<?> injector;
81     public final Features features;
82     public final UserId userId;
83     public final UserHandle userHandle;
84 
85     public final MockContentResolver contentResolver;
86     public final Map<String, TestDocumentsProvider> mockProviders;
87 
TestEnv(Context context, Features features, String authority)88     private TestEnv(Context context, Features features, String authority) {
89         this.features = features;
90         this.userId = TestProvidersAccess.USER_ID;
91         userHandle = UserHandle.of(userId.getIdentifier());
92         state.sortModel = SortModel.createModel();
93         mExecutor = new TestScheduledExecutorService();
94         model = new TestModel(userId, authority, features);
95         modelOtherUser = new TestModel(TestProvidersAccess.OtherUser.USER_ID, authority, features);
96         archiveModel = new TestModel(userId, ArchivesProvider.AUTHORITY, features);
97         selectionMgr = SelectionHelpers.createTestInstance();
98         searchViewManager = new TestSearchViewManager();
99         injector = new Injector(
100                 features,
101                 new TestActivityConfig(),
102                 null,       // MessageBuilder is not currently required for tests
103                 dialogs,
104                 new TestFileTypeLookup(),
105                 (roots) -> {},  // not sure why, but java gets angry when I declare roots type.
106                 model);
107 
108         injector.selectionMgr = selectionMgr;
109         injector.focusManager = new FocusManager(features, selectionMgr, null, null, 0);
110         injector.searchManager = searchViewManager;
111 
112         contentResolver = new MockContentResolver();
113         mockProviders = new HashMap<>(providers.getRootsBlocking().size());
114         registerProviders();
115     }
116 
registerProviders()117     private void registerProviders() {
118         for (RootInfo root : providers.getRootsBlocking()) {
119             if (!mockProviders.containsKey(root.authority)) {
120                 TestDocumentsProvider provider = new TestDocumentsProvider(root.authority);
121                 contentResolver.addProvider(root.authority, provider);
122                 mockProviders.put(root.authority, provider);
123             }
124         }
125     }
126 
127     // Many terrible creational permutations == easy to user for test authors!
create(Features features)128     public static TestEnv create(Features features) {
129         return create(features, TestProvidersAccess.HOME.authority);
130     }
131 
create()132     public static TestEnv create() {
133         return create(TestProvidersAccess.HOME.authority);
134     }
135 
create(Features features, String authority)136     public static TestEnv create(Features features, String authority) {
137         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
138         return create(context, features, authority);
139     }
140 
create(String authority)141     public static TestEnv create(String authority) {
142         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
143         Features features = new Features.RuntimeFeatures(context.getResources(), null);
144         return create(context, features, authority);
145     }
146 
create(Context context, Features features, String authority)147     private static TestEnv create(Context context, Features features, String authority) {
148         TestEnv env = new TestEnv(context, features, authority);
149         env.reset();
150         return env;
151     }
152 
clear()153     public void clear() {
154         model.reset();
155         model.update();
156     }
157 
reset()158     public void reset() {
159         model.reset();
160         FOLDER_0 = model.createFolder("folder 0");
161         FOLDER_1 = model.createFolder("folder 1");
162         FOLDER_2 = model.createFolder("folder 2");
163         FILE_TXT = model.createFile("woowoo.txt");
164         FILE_PNG = model.createFile("peppey.png");
165         FILE_JPG = model.createFile("jiffy.jpg");
166         FILE_GIF = model.createFile("glibby.gif");
167         FILE_PDF = model.createFile("busy.pdf");
168         FILE_MP4 = model.createFile("cameravideo.mp4");
169         FILE_APK = model.createFile("becareful.apk");
170         FILE_PARTIAL = model.createFile(
171                 "UbuntuFlappyBird.iso",
172                 Document.FLAG_SUPPORTS_DELETE
173                         | Document.FLAG_PARTIAL);
174         FILE_READ_ONLY = model.createFile("topsecretsystemfile.bin", 0);
175         FILE_ARCHIVE = model.createFile("whatsinthere.zip");
176         FILE_IN_ARCHIVE = archiveModel.createFile("whatsinthere.png", 0);
177         FILE_VIRTUAL = model.createDocument(
178                 "virtualdoc.vnd",
179                 "application/vnd.google-apps.document",
180                 Document.FLAG_VIRTUAL_DOCUMENT
181                         | Document.FLAG_SUPPORTS_DELETE
182                         | Document.FLAG_SUPPORTS_RENAME);
183 
184         OtherUser.FOLDER_0 = modelOtherUser.createFolder("folder 0");
185         OtherUser.FILE_PNG = modelOtherUser.createFile("work.png");
186 
187         archiveModel.update();
188         model.update();
189     }
190 
populateStack()191     public void populateStack() {
192         DocumentInfo rootDoc = model.getDocument(
193                 ModelId.build(model.mUserId, TestProvidersAccess.HOME.authority, "1"));
194 
195         // These are test setup sanity checks, not test assertions.
196         assert rootDoc != null;
197         assert rootDoc.isDirectory();
198         assert FOLDER_0.equals(rootDoc);
199 
200         state.stack.changeRoot(TestProvidersAccess.HOME);
201         state.stack.push(rootDoc);
202     }
203 
beforeAsserts()204     public void beforeAsserts() throws Exception {
205         mExecutor.waitForTasks(30000); // 30 secs
206     }
207 
lookupExecutor(String authority)208     public Executor lookupExecutor(String authority) {
209         return mExecutor;
210     }
211 
selectDocument(DocumentInfo info)212     public void selectDocument(DocumentInfo info) {
213         List<String> ids = new ArrayList<>(1);
214         ids.add(ModelId.build(info.userId, info.authority, info.documentId));
215         selectionMgr.setItemsSelected(ids, true);
216     }
217 
selectMultipleFiles(int count)218     public void selectMultipleFiles(int count) {
219         List<String> ids = new ArrayList<>(count);
220         for (int i = 0; i < count; i++) {
221             DocumentInfo info = model.createFile(String.valueOf(i));
222             ids.add(ModelId.build(info.userId, info.authority, info.documentId));
223         }
224         selectionMgr.setItemsSelected(ids, true);
225     }
226 
227     // Easily copy docs, so we don't pollute static data across tests.
clone(DocumentInfo a)228     public static DocumentInfo clone(DocumentInfo a) {
229         DocumentInfo b = new DocumentInfo();
230         b.authority = a.authority;
231         b.documentId = a.documentId;
232         b.mimeType = a.mimeType;
233         b.displayName = a.displayName;
234         b.lastModified = a.lastModified;
235         b.flags = a.flags;
236         b.summary = a.summary;
237         b.size = a.size;
238         b.icon = a.icon;
239         b.derivedUri = a.derivedUri;
240 
241         return b;
242     }
243 }
244