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