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