blob: 6147a7187de7b1a57fd3d61240f9384c2f6279b1 [file] [log] [blame]
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +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
17package com.android.documentsui;
18
19import android.content.Context;
20import android.content.pm.ProviderInfo;
21import android.database.Cursor;
22import android.database.MatrixCursor.RowBuilder;
23import android.database.MatrixCursor;
24import android.os.CancellationSignal;
25import android.os.FileUtils;
26import android.os.ParcelFileDescriptor;
27import android.provider.DocumentsContract.Document;
28import android.provider.DocumentsContract.Root;
29import android.provider.DocumentsContract;
30import android.provider.DocumentsProvider;
31
32import java.io.File;
33import java.io.FileNotFoundException;
34import java.util.ArrayList;
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +090035import java.util.HashMap;
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +090036import java.util.List;
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +090037import java.util.Map;
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +090038import java.util.Random;
39
40/**
41 * Provider with thousands of files for testing loading time of directories in DocumentsUI.
42 * It doesn't support any file operations.
43 */
44public class StressProvider extends DocumentsProvider {
45
46 public static final String DEFAULT_AUTHORITY = "com.android.documentsui.stressprovider";
47
48 // Empty root.
49 public static final String STRESS_ROOT_0_ID = "STRESS_ROOT_0";
50
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +090051 // Root with thousands of directories.
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +090052 public static final String STRESS_ROOT_1_ID = "STRESS_ROOT_1";
53
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +090054 // Root with hundreds of files.
55 public static final String STRESS_ROOT_2_ID = "STRESS_ROOT_2";
56
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +090057 private static final String STRESS_ROOT_0_DOC_ID = "STRESS_ROOT_0_DOC";
58 private static final String STRESS_ROOT_1_DOC_ID = "STRESS_ROOT_1_DOC";
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +090059 private static final String STRESS_ROOT_2_DOC_ID = "STRESS_ROOT_2_DOC";
60
61 private static final int STRESS_ROOT_1_ITEMS = 10000;
62 private static final int STRESS_ROOT_2_ITEMS = 300;
63
64 private static final String MIME_TYPE_IMAGE = "image/jpeg";
65 private static final long REFERENCE_TIMESTAMP = 1459159369359L;
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +090066
67 private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
68 Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
69 Root.COLUMN_AVAILABLE_BYTES
70 };
71 private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
72 Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
73 Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
74 };
75
76 private String mAuthority = DEFAULT_AUTHORITY;
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +090077
78 // Map from a root document id to children document ids.
79 private Map<String, ArrayList<StubDocument>> mChildDocuments = new HashMap<>();
80
81 private Map<String, StubDocument> mDocuments = new HashMap<>();
82 private Map<String, StubRoot> mRoots = new HashMap<>();
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +090083
84 @Override
85 public void attachInfo(Context context, ProviderInfo info) {
86 mAuthority = info.authority;
87 super.attachInfo(context, info);
88 }
89
90 @Override
91 public boolean onCreate() {
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +090092 StubDocument document;
93
94 ArrayList<StubDocument> children = new ArrayList<StubDocument>();
95 mChildDocuments.put(STRESS_ROOT_1_DOC_ID, children);
96 for (int i = 0; i < STRESS_ROOT_1_ITEMS; i++) {
97 document = StubDocument.createDirectory(i);
98 mDocuments.put(document.id, document);
99 children.add(document);
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900100 }
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900101
102 children = new ArrayList<StubDocument>();
103 mChildDocuments.put(STRESS_ROOT_2_DOC_ID, children);
104 for (int i = 0; i < STRESS_ROOT_2_ITEMS; i++) {
105 document = StubDocument.createFile(STRESS_ROOT_1_ITEMS + i);
106 mDocuments.put(document.id, document);
107 children.add(document);
108 }
109
110 mRoots.put(STRESS_ROOT_0_ID, new StubRoot(STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID));
111 mRoots.put(STRESS_ROOT_1_ID, new StubRoot(STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID));
112 mRoots.put(STRESS_ROOT_2_ID, new StubRoot(STRESS_ROOT_2_ID, STRESS_ROOT_2_DOC_ID));
113
114 mDocuments.put(STRESS_ROOT_0_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_0_DOC_ID));
115 mDocuments.put(STRESS_ROOT_1_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_1_DOC_ID));
116 mDocuments.put(STRESS_ROOT_2_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_2_DOC_ID));
117
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900118 return true;
119 }
120
121 @Override
122 public Cursor queryRoots(String[] projection) throws FileNotFoundException {
123 final MatrixCursor result = new MatrixCursor(DEFAULT_ROOT_PROJECTION);
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900124 for (StubRoot root : mRoots.values()) {
125 includeRoot(result, root);
126 }
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900127 return result;
128 }
129
130 @Override
131 public Cursor queryDocument(String documentId, String[] projection)
132 throws FileNotFoundException {
133 final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900134 final StubDocument document = mDocuments.get(documentId);
135 includeDocument(result, document);
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900136 return result;
137 }
138
139 @Override
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900140 public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
141 String sortOrder)
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900142 throws FileNotFoundException {
143 final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900144 final ArrayList<StubDocument> childDocuments = mChildDocuments.get(parentDocumentId);
145 if (childDocuments != null) {
146 for (StubDocument document : childDocuments) {
147 includeDocument(result, document);
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900148 }
149 }
150 return result;
151 }
152
153 @Override
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900154 public ParcelFileDescriptor openDocument(String docId, String mode,
155 CancellationSignal signal)
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900156 throws FileNotFoundException {
157 throw new UnsupportedOperationException();
158 }
159
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900160 private void includeRoot(MatrixCursor result, StubRoot root) {
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900161 final RowBuilder row = result.newRow();
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900162 row.add(Root.COLUMN_ROOT_ID, root.id);
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900163 row.add(Root.COLUMN_FLAGS, 0);
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900164 row.add(Root.COLUMN_TITLE, root.id);
165 row.add(Root.COLUMN_DOCUMENT_ID, root.documentId);
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900166 }
167
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900168 private void includeDocument(MatrixCursor result, StubDocument document) {
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900169 final RowBuilder row = result.newRow();
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900170 row.add(Document.COLUMN_DOCUMENT_ID, document.id);
171 row.add(Document.COLUMN_DISPLAY_NAME, document.id);
172 row.add(Document.COLUMN_SIZE, document.size);
173 row.add(Document.COLUMN_MIME_TYPE, document.mimeType);
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900174 row.add(Document.COLUMN_FLAGS, 0);
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900175 row.add(Document.COLUMN_LAST_MODIFIED, document.lastModified);
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900176 }
177
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900178 private static String getStubDocumentIdForFile(File file) {
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900179 return file.getAbsolutePath();
180 }
181
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900182 private static class StubDocument {
183 final String mimeType;
184 final String id;
185 final int size;
186 final long lastModified;
187
188 private StubDocument(String mimeType, String id, int size, long lastModified) {
189 this.mimeType = mimeType;
190 this.id = id;
191 this.size = size;
192 this.lastModified = lastModified;
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900193 }
Tomasz Mikolajewski8ee8ebf2016-03-28 12:13:43 +0900194
195 public static StubDocument createDirectory(int index) {
196 return new StubDocument(
197 DocumentsContract.Document.MIME_TYPE_DIR, createRandomId(index), 0,
198 createRandomTime(index));
199 }
200
201 public static StubDocument createDirectory(String id) {
202 return new StubDocument(DocumentsContract.Document.MIME_TYPE_DIR, id, 0, 0);
203 }
204
205 public static StubDocument createFile(int index) {
206 return new StubDocument(
207 MIME_TYPE_IMAGE, createRandomId(index), createRandomSize(index),
208 createRandomTime(index));
209 }
210
211 private static String createRandomId(int index) {
212 final Random random = new Random(index);
213 final StringBuilder builder = new StringBuilder();
214 for (int i = 0; i < 20; i++) {
215 builder.append((char) (random.nextInt(96) + 32));
216 }
217 builder.append(index); // Append a number to guarantee uniqueness.
218 return builder.toString();
219 }
220
221 private static int createRandomSize(int index) {
222 final Random random = new Random(index);
223 return random.nextInt(1024 * 1024 * 100); // Up to 100 MB.
224 }
225
226 private static long createRandomTime(int index) {
227 final Random random = new Random(index);
228 // Up to 30 days backwards from REFERENCE_TIMESTAMP.
229 return REFERENCE_TIMESTAMP - random.nextLong() % 1000L * 60 * 60 * 24 * 30;
230 }
231 }
232
233 private static class StubRoot {
234 final String id;
235 final String documentId;
236
237 public StubRoot(String id, String documentId) {
238 this.id = id;
239 this.documentId = documentId;
240 }
Tomasz Mikolajewskiae6d6b42016-02-24 12:53:44 +0900241 }
242}