blob: 568e9e4039604e30a6a38be48b682585d13101ca [file] [log] [blame]
Ben Kwaaac9e2e2015-04-16 18:14:35 -07001/*
2 * Copyright (C) 2015 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
Ben Kwaaac9e2e2015-04-16 18:14:35 -070019import android.content.ContentProviderClient;
20import android.content.ContentResolver;
21import android.content.Context;
22import android.content.ContextWrapper;
23import android.content.Intent;
Ben Kwac06f3fd2015-04-24 15:35:25 -070024import android.content.pm.ProviderInfo;
25import android.database.ContentObserver;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070026import android.database.Cursor;
27import android.net.Uri;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070028import android.os.Parcelable;
29import android.os.RemoteException;
30import android.provider.DocumentsContract;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070031import android.test.MoreAsserts;
32import android.test.ServiceTestCase;
Ben Kwac06f3fd2015-04-24 15:35:25 -070033import android.test.mock.MockContentResolver;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070034import android.util.Log;
35
36import com.android.documentsui.model.DocumentInfo;
37import com.android.documentsui.model.DocumentStack;
38import com.android.documentsui.model.RootInfo;
39import com.google.common.collect.Lists;
40
41import libcore.io.IoUtils;
42import libcore.io.Streams;
43
Ben Kwac06f3fd2015-04-24 15:35:25 -070044import java.io.File;
45import java.io.FileInputStream;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070046import java.io.FileNotFoundException;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070047import java.util.ArrayList;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070048import java.util.List;
Ben Kwac06f3fd2015-04-24 15:35:25 -070049import java.util.concurrent.CountDownLatch;
50import java.util.concurrent.TimeUnit;
51import java.util.concurrent.TimeoutException;
Ben Kwaaac9e2e2015-04-16 18:14:35 -070052
53public class CopyTest extends ServiceTestCase<CopyService> {
54
Ben Kwac06f3fd2015-04-24 15:35:25 -070055 /**
56 * A test resolver that enables this test suite to listen for notifications that mark when copy
57 * operations are done.
58 */
59 class TestContentResolver extends MockContentResolver {
60 private CountDownLatch mReadySignal;
61 private CountDownLatch mNotificationSignal;
62
63 public TestContentResolver() {
64 mReadySignal = new CountDownLatch(1);
65 }
66
67 /**
68 * Wait for the given number of files to be copied to destination. Times out after 1 sec.
69 */
70 public void waitForChanges(int count) throws Exception {
71 // Wait for no more than 1 second by default.
72 waitForChanges(count, 1000);
73 }
74
75 /**
76 * Wait for files to be copied to destination.
77 *
78 * @param count Number of files to wait for.
79 * @param timeOut Timeout in ms. TimeoutException will be thrown if this function times out.
80 */
81 public void waitForChanges(int count, int timeOut) throws Exception {
82 mNotificationSignal = new CountDownLatch(count);
83 // Signal that the test is now waiting for files.
84 mReadySignal.countDown();
85 if (!mNotificationSignal.await(timeOut, TimeUnit.MILLISECONDS)) {
Ben Kwacb4461f2015-05-05 11:50:11 -070086 throw new TimeoutException("Timed out waiting for file operations to complete.");
Ben Kwac06f3fd2015-04-24 15:35:25 -070087 }
88 }
89
90 @Override
91 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
92 // Wait until the test is ready to receive file notifications.
93 try {
94 mReadySignal.await();
95 } catch (InterruptedException e) {
96 Log.d(TAG, "Interrupted while waiting for file copy readiness");
97 Thread.currentThread().interrupt();
98 }
99 if (DocumentsContract.isDocumentUri(mContext, uri)) {
100 Log.d(TAG, "Notification: " + uri);
101 // Watch for document URI change notifications - this signifies the end of a copy.
102 mNotificationSignal.countDown();
103 }
104 }
105 };
106
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700107 public CopyTest() {
108 super(CopyService.class);
109 }
110
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700111 private static String AUTHORITY = "com.android.documentsui.stubprovider";
Ben Kwac06f3fd2015-04-24 15:35:25 -0700112 private static String DST = "sd1";
113 private static String SRC = "sd0";
114 private static String TAG = "CopyTest";
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700115 private List<RootInfo> mRoots;
116 private Context mContext;
Ben Kwac06f3fd2015-04-24 15:35:25 -0700117 private TestContentResolver mResolver;
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700118 private ContentProviderClient mClient;
Ben Kwac06f3fd2015-04-24 15:35:25 -0700119 private StubProvider mStorage;
120 private Context mSystemContext;
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700121
122 @Override
123 protected void setUp() throws Exception {
124 super.setUp();
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700125
Ben Kwac06f3fd2015-04-24 15:35:25 -0700126 setupTestContext();
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700127 mClient = mResolver.acquireContentProviderClient(AUTHORITY);
128
129 // Reset the stub provider's storage.
Ben Kwac06f3fd2015-04-24 15:35:25 -0700130 mStorage.clearCacheAndBuildRoots();
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700131
132 mRoots = Lists.newArrayList();
133 Uri queryUri = DocumentsContract.buildRootsUri(AUTHORITY);
134 Cursor cursor = null;
135 try {
136 cursor = mClient.query(queryUri, null, null, null, null);
137 while (cursor.moveToNext()) {
Ben Kwac06f3fd2015-04-24 15:35:25 -0700138 mRoots.add(RootInfo.fromRootsCursor(AUTHORITY, cursor));
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700139 }
140 } finally {
141 IoUtils.closeQuietly(cursor);
142 }
143
144 }
145
146 @Override
147 protected void tearDown() throws Exception {
148 mClient.release();
149 super.tearDown();
150 }
151
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700152 /**
153 * Test copying a single file.
154 */
155 public void testCopyFile() throws Exception {
Ben Kwac06f3fd2015-04-24 15:35:25 -0700156 String srcPath = "/test0.txt";
157 Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain",
158 "The five boxing wizards jump quickly".getBytes());
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700159
Ben Kwac06f3fd2015-04-24 15:35:25 -0700160 assertDstFileCountEquals(0);
161
Ben Kwacb4461f2015-05-05 11:50:11 -0700162 startService(createCopyIntent(Lists.newArrayList(testFile)));
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700163
Ben Kwac06f3fd2015-04-24 15:35:25 -0700164 // 2 operations: file creation, then writing data.
165 mResolver.waitForChanges(2);
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700166
167 // Verify that one file was copied; check file contents.
168 assertDstFileCountEquals(1);
Ben Kwac06f3fd2015-04-24 15:35:25 -0700169 assertCopied(srcPath);
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700170 }
171
Ben Kwacb4461f2015-05-05 11:50:11 -0700172 public void testMoveFile() throws Exception {
173 String srcPath = "/test0.txt";
174 String testContent = "The five boxing wizards jump quickly";
175 Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain", testContent.getBytes());
176
177 assertDstFileCountEquals(0);
178
179 Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile));
180 moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
181 startService(moveIntent);
182
183 // 3 operations: file creation, writing data, deleting original.
184 mResolver.waitForChanges(3);
185
186 // Verify that one file was moved; check file contents.
187 assertDstFileCountEquals(1);
188 assertDoesNotExist(SRC, srcPath);
189
190 byte[] dstContent = readFile(DST, srcPath);
191 MoreAsserts.assertEquals("Moved file contents differ", testContent.getBytes(), dstContent);
192 }
193
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700194 /**
195 * Test copying multiple files.
196 */
197 public void testCopyMultipleFiles() throws Exception {
Ben Kwac06f3fd2015-04-24 15:35:25 -0700198 String testContent[] = {
199 "The five boxing wizards jump quickly",
200 "The quick brown fox jumps over the lazy dog",
201 "Jackdaws love my big sphinx of quartz"
202 };
203 String srcPaths[] = {
204 "/test0.txt",
205 "/test1.txt",
206 "/test2.txt"
207 };
208 List<Uri> testFiles = Lists.newArrayList(
209 mStorage.createFile(SRC, srcPaths[0], "text/plain", testContent[0].getBytes()),
210 mStorage.createFile(SRC, srcPaths[1], "text/plain", testContent[1].getBytes()),
211 mStorage.createFile(SRC, srcPaths[2], "text/plain", testContent[2].getBytes()));
212
213 assertDstFileCountEquals(0);
214
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700215 // Copy all the test files.
Ben Kwacb4461f2015-05-05 11:50:11 -0700216 startService(createCopyIntent(testFiles));
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700217
Ben Kwac06f3fd2015-04-24 15:35:25 -0700218 // 3 file creations, 3 file writes.
219 mResolver.waitForChanges(6);
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700220
221 assertDstFileCountEquals(3);
Ben Kwac06f3fd2015-04-24 15:35:25 -0700222 for (String path : srcPaths) {
223 assertCopied(path);
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700224 }
225 }
226
Ben Kwac06f3fd2015-04-24 15:35:25 -0700227 public void testCopyEmptyDir() throws Exception {
228 String srcPath = "/emptyDir";
229 Uri testDir = mStorage.createFile(SRC, srcPath, DocumentsContract.Document.MIME_TYPE_DIR,
230 null);
231
232 assertDstFileCountEquals(0);
233
Ben Kwacb4461f2015-05-05 11:50:11 -0700234 startService(createCopyIntent(Lists.newArrayList(testDir)));
Ben Kwac06f3fd2015-04-24 15:35:25 -0700235
236 // Just 1 operation: Directory creation.
237 mResolver.waitForChanges(1);
238
239 assertDstFileCountEquals(1);
240
Ben Kwacb4461f2015-05-05 11:50:11 -0700241 // Verify that the dst exists and is a directory.
Ben Kwac06f3fd2015-04-24 15:35:25 -0700242 File dst = mStorage.getFile(DST, srcPath);
243 assertTrue(dst.isDirectory());
244 }
245
Ben Kwacb4461f2015-05-05 11:50:11 -0700246 public void testMoveEmptyDir() throws Exception {
247 String srcPath = "/emptyDir";
248 Uri testDir = mStorage.createFile(SRC, srcPath, DocumentsContract.Document.MIME_TYPE_DIR,
249 null);
250
251 assertDstFileCountEquals(0);
252
253 Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
254 moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
255 startService(moveIntent);
256
257 // 2 operations: Directory creation, and removal of the original.
258 mResolver.waitForChanges(2);
259
260 assertDstFileCountEquals(1);
261
262 // Verify that the dst exists and is a directory.
263 File dst = mStorage.getFile(DST, srcPath);
264 assertTrue(dst.isDirectory());
265
266 // Verify that the src was cleaned up.
267 assertDoesNotExist(SRC, srcPath);
268 }
269
270 public void testMovePopulatedDir() throws Exception {
271 String testContent[] = {
272 "The five boxing wizards jump quickly",
273 "The quick brown fox jumps over the lazy dog",
274 "Jackdaws love my big sphinx of quartz"
275 };
276 String srcDir = "/testdir";
277 String srcFiles[] = {
278 srcDir + "/test0.txt",
279 srcDir + "/test1.txt",
280 srcDir + "/test2.txt"
281 };
282 // Create test dir; put some files in it.
283 Uri testDir = mStorage.createFile(SRC, srcDir, DocumentsContract.Document.MIME_TYPE_DIR,
284 null);
285 mStorage.createFile(SRC, srcFiles[0], "text/plain", testContent[0].getBytes());
286 mStorage.createFile(SRC, srcFiles[1], "text/plain", testContent[1].getBytes());
287 mStorage.createFile(SRC, srcFiles[2], "text/plain", testContent[2].getBytes());
288
289 Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
290 moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
291 startService(moveIntent);
292
293 // dir creation, then creation and writing of 3 files, then removal of src dir and 3 src
294 // files.
295 mResolver.waitForChanges(11);
296
297 // Check the content of the moved files.
298 File dst = mStorage.getFile(DST, srcDir);
299 assertTrue(dst.isDirectory());
300 for (int i = 0; i < testContent.length; ++i) {
301 byte[] dstContent = readFile(DST, srcFiles[i]);
302 MoreAsserts.assertEquals("Copied file contents differ", testContent[i].getBytes(),
303 dstContent);
304 }
305
306 // Check that the src files were removed.
307 assertDoesNotExist(SRC, srcDir);
308 for (String srcFile : srcFiles) {
309 assertDoesNotExist(SRC, srcFile);
310 }
311 }
312
313 public void testCopyFileWithReadErrors() throws Exception {
Ben Kwac06f3fd2015-04-24 15:35:25 -0700314 String srcPath = "/test0.txt";
315 Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain",
316 "The five boxing wizards jump quickly".getBytes());
317
318 assertDstFileCountEquals(0);
319
Ben Kwacb4461f2015-05-05 11:50:11 -0700320 mStorage.simulateReadErrorsForFile(testFile);
Ben Kwac06f3fd2015-04-24 15:35:25 -0700321
Ben Kwacb4461f2015-05-05 11:50:11 -0700322 startService(createCopyIntent(Lists.newArrayList(testFile)));
Ben Kwac06f3fd2015-04-24 15:35:25 -0700323
324 // 3 operations: file creation, writing, then deletion (due to failed copy).
325 mResolver.waitForChanges(3);
326
Ben Kwacb4461f2015-05-05 11:50:11 -0700327 // Verify that the failed copy was cleaned up.
Ben Kwac06f3fd2015-04-24 15:35:25 -0700328 assertDstFileCountEquals(0);
329 }
330
Ben Kwacb4461f2015-05-05 11:50:11 -0700331 public void testMoveFileWithReadErrors() throws Exception {
332 String srcPath = "/test0.txt";
333 Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain",
334 "The five boxing wizards jump quickly".getBytes());
335
336 assertDstFileCountEquals(0);
337
338 mStorage.simulateReadErrorsForFile(testFile);
339
340 Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile));
341 moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
342 startService(moveIntent);
343
344 try {
345 // There should be 3 operations: file creation, writing, then deletion (due to failed
346 // copy). Wait for 4, in case the CopyService also attempts to do extra stuff (like
347 // delete the src file). This should time out.
348 mResolver.waitForChanges(4);
349 } catch (TimeoutException e) {
350 // Success path
351 return;
352 } finally {
353 // Verify that the failed copy was cleaned up, and the src file wasn't removed.
354 assertDstFileCountEquals(0);
355 assertExists(SRC, srcPath);
356 }
357 // The asserts above didn't fail, but the CopyService did something unexpected.
358 fail("Extra file operations were detected");
359 }
360
361 public void testMoveDirectoryWithReadErrors() throws Exception {
362 String testContent[] = {
363 "The five boxing wizards jump quickly",
364 "The quick brown fox jumps over the lazy dog",
365 "Jackdaws love my big sphinx of quartz"
366 };
367 String srcDir = "/testdir";
368 String srcFiles[] = {
369 srcDir + "/test0.txt",
370 srcDir + "/test1.txt",
371 srcDir + "/test2.txt"
372 };
373 // Create test dir; put some files in it.
374 Uri testDir = mStorage.createFile(SRC, srcDir, DocumentsContract.Document.MIME_TYPE_DIR,
375 null);
376 mStorage.createFile(SRC, srcFiles[0], "text/plain", testContent[0].getBytes());
377 Uri errFile = mStorage
378 .createFile(SRC, srcFiles[1], "text/plain", testContent[1].getBytes());
379 mStorage.createFile(SRC, srcFiles[2], "text/plain", testContent[2].getBytes());
380
381 mStorage.simulateReadErrorsForFile(errFile);
382
383 Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
384 moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
385 startService(moveIntent);
386
387 // - dst dir creation,
388 // - creation and writing of 2 files, removal of 2 src files
389 // - creation and writing of 1 file, then removal of that file (due to error)
390 mResolver.waitForChanges(10);
391
392 // Check that both the src and dst dirs exist. The src dir shouldn't have been removed,
393 // because it should contain the one errFile.
394 assertTrue(mStorage.getFile(SRC, srcDir).isDirectory());
395 assertTrue(mStorage.getFile(DST, srcDir).isDirectory());
396
397 // Check the content of the moved files.
398 MoreAsserts.assertEquals("Copied file contents differ", testContent[0].getBytes(),
399 readFile(DST, srcFiles[0]));
400 MoreAsserts.assertEquals("Copied file contents differ", testContent[2].getBytes(),
401 readFile(DST, srcFiles[2]));
402
403 // Check that the src files were removed.
404 assertDoesNotExist(SRC, srcFiles[0]);
405 assertDoesNotExist(SRC, srcFiles[2]);
406
407 // Check that the error file was not copied over.
408 assertDoesNotExist(DST, srcFiles[1]);
409 assertExists(SRC, srcFiles[1]);
410 }
411
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700412 /**
413 * Copies the given files to a pre-determined destination.
414 *
415 * @throws FileNotFoundException
416 */
Ben Kwacb4461f2015-05-05 11:50:11 -0700417 private Intent createCopyIntent(List<Uri> srcs) throws FileNotFoundException {
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700418 final ArrayList<DocumentInfo> srcDocs = Lists.newArrayList();
419 for (Uri src : srcs) {
420 srcDocs.add(DocumentInfo.fromUri(mResolver, src));
421 }
422
423 final Uri dst = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(1).documentId);
424 DocumentStack stack = new DocumentStack();
425 stack.push(DocumentInfo.fromUri(mResolver, dst));
426 final Intent copyIntent = new Intent(mContext, CopyService.class);
427 copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs);
428 copyIntent.putExtra(CopyService.EXTRA_STACK, (Parcelable) stack);
429
Ben Kwacb4461f2015-05-05 11:50:11 -0700430 // startService(copyIntent);
431 return copyIntent;
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700432 }
433
434 /**
435 * Returns a count of the files in the given directory.
436 */
437 private void assertDstFileCountEquals(int expected) throws RemoteException {
438 final Uri queryUri = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
439 mRoots.get(1).documentId);
440 Cursor c = null;
441 int count = 0;
442 try {
443 c = mClient.query(queryUri, null, null, null, null);
444 count = c.getCount();
445 } finally {
446 IoUtils.closeQuietly(c);
447 }
448 assertEquals("Incorrect file count after copy", expected, count);
449 }
450
Ben Kwacb4461f2015-05-05 11:50:11 -0700451 private void assertExists(String rootId, String path) throws Exception {
452 assertNotNull("An expected file was not found: " + path + " on root " + rootId,
453 mStorage.getFile(rootId, path));
454 }
Ben Kwac06f3fd2015-04-24 15:35:25 -0700455
Ben Kwacb4461f2015-05-05 11:50:11 -0700456 private void assertDoesNotExist(String rootId, String path) throws Exception {
457 assertNull("Unexpected file found: " + path + " on root " + rootId,
458 mStorage.getFile(rootId, path));
459 }
460
461 private byte[] readFile(String rootId, String path) throws Exception {
462 File file = mStorage.getFile(rootId, path);
463 byte[] buf = null;
464 assertNotNull(file);
465
466 FileInputStream in = null;
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700467 try {
Ben Kwacb4461f2015-05-05 11:50:11 -0700468 in = new FileInputStream(file);
469 buf = Streams.readFully(in);
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700470 } finally {
Ben Kwacb4461f2015-05-05 11:50:11 -0700471 IoUtils.closeQuietly(in);
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700472 }
Ben Kwacb4461f2015-05-05 11:50:11 -0700473 return buf;
474 }
475
476 private void assertCopied(String path) throws Exception {
477 MoreAsserts.assertEquals("Copied file contents differ", readFile(SRC, path),
478 readFile(DST, path));
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700479 }
480
481 /**
482 * Sets up a ContextWrapper that substitutes a stub NotificationManager. This allows the test to
483 * listen for notification events, to gauge copy progress.
Ben Kwac06f3fd2015-04-24 15:35:25 -0700484 *
485 * @throws FileNotFoundException
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700486 */
Ben Kwac06f3fd2015-04-24 15:35:25 -0700487 private void setupTestContext() throws FileNotFoundException {
488 mSystemContext = getSystemContext();
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700489
Ben Kwac06f3fd2015-04-24 15:35:25 -0700490 // Set up the context with the test content resolver.
491 mResolver = new TestContentResolver();
492 mContext = new ContextWrapper(mSystemContext) {
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700493 @Override
Ben Kwac06f3fd2015-04-24 15:35:25 -0700494 public ContentResolver getContentResolver() {
495 return mResolver;
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700496 }
Ben Kwac06f3fd2015-04-24 15:35:25 -0700497 };
498 setContext(mContext);
499
500 // Create a local stub provider and add it to the content resolver.
501 ProviderInfo info = new ProviderInfo();
502 info.authority = AUTHORITY;
503 info.exported = true;
504 info.grantUriPermissions = true;
505 info.readPermission = android.Manifest.permission.MANAGE_DOCUMENTS;
506 info.writePermission = android.Manifest.permission.MANAGE_DOCUMENTS;
507
508 mStorage = new StubProvider();
509 mStorage.attachInfo(mContext, info);
510 mResolver.addProvider(AUTHORITY, mStorage);
Ben Kwaaac9e2e2015-04-16 18:14:35 -0700511 }
512}