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 
17 package com.android.documentsui.picker;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.verify;
25 
26 import android.app.Activity;
27 import android.content.ClipData;
28 import android.content.ComponentName;
29 import android.content.Intent;
30 import android.content.pm.ResolveInfo;
31 import android.net.Uri;
32 import android.os.AsyncTask;
33 import android.provider.DocumentsContract;
34 import android.provider.DocumentsContract.Path;
35 
36 import androidx.fragment.app.FragmentActivity;
37 import androidx.test.filters.MediumTest;
38 import androidx.test.filters.SdkSuppress;
39 
40 import com.android.documentsui.DocumentsAccess;
41 import com.android.documentsui.Injector;
42 import com.android.documentsui.R;
43 import com.android.documentsui.TestConfigStore;
44 import com.android.documentsui.base.DocumentInfo;
45 import com.android.documentsui.base.DocumentStack;
46 import com.android.documentsui.base.Lookup;
47 import com.android.documentsui.base.RootInfo;
48 import com.android.documentsui.base.Shared;
49 import com.android.documentsui.base.State;
50 import com.android.documentsui.base.State.ActionType;
51 import com.android.documentsui.picker.ActionHandler.Addons;
52 import com.android.documentsui.queries.SearchViewManager;
53 import com.android.documentsui.roots.ProvidersAccess;
54 import com.android.documentsui.testing.DocumentStackAsserts;
55 import com.android.documentsui.testing.TestEnv;
56 import com.android.documentsui.testing.TestLastAccessedStorage;
57 import com.android.documentsui.testing.TestProvidersAccess;
58 import com.android.documentsui.testing.TestResolveInfo;
59 import com.android.documentsui.util.VersionUtils;
60 import com.android.modules.utils.build.SdkLevel;
61 
62 import com.google.common.collect.Lists;
63 
64 import org.junit.AfterClass;
65 import org.junit.Before;
66 import org.junit.Test;
67 import org.junit.runner.RunWith;
68 import org.junit.runners.Parameterized;
69 import org.junit.runners.Parameterized.Parameter;
70 import org.junit.runners.Parameterized.Parameters;
71 
72 import java.util.Arrays;
73 import java.util.concurrent.Executor;
74 
75 @RunWith(Parameterized.class)
76 @MediumTest
77 public class ActionHandlerTest {
78 
79     private static final String EXTRA_INTENT = "EXTRA_INTENT";
80     private static final String EXTRA_USER = "EXTRA_USER";
81 
82     private final TestConfigStore mTestConfigStore = new TestConfigStore();
83 
84     private TestEnv mEnv;
85     private TestActivity mActivity;
86     private TestableActionHandler<TestActivity> mHandler;
87     private TestLastAccessedStorage mLastAccessed;
88     private PickCountRecordStorage mPickCountRecord;
89 
90     @Parameter(0)
91     public boolean isPrivateSpaceEnabled;
92 
93     /**
94      * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with
95      * private space flag enabled and once with it disabled.
96      */
97     @Parameters(name = "privateSpaceEnabled={0}")
data()98     public static Iterable<?> data() {
99         return Lists.newArrayList(true, false);
100     }
101 
102     @Before
setUp()103     public void setUp() {
104         mEnv = TestEnv.create();
105         mActivity = TestActivity.create(mEnv);
106         mEnv.providers.configurePm(mActivity.packageMgr);
107         mEnv.injector.pickResult = new PickResult();
108         mLastAccessed = new TestLastAccessedStorage();
109         mPickCountRecord = mock(PickCountRecordStorage.class);
110         mEnv.state.configStore = mTestConfigStore;
111 
112         isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled;
113         if (isPrivateSpaceEnabled) {
114             mTestConfigStore.enablePrivateSpaceInPhotoPicker();
115             mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true);
116         }
117 
118         mHandler = new TestableActionHandler<>(
119                 mActivity,
120                 mEnv.state,
121                 mEnv.providers,
122                 mEnv.docs,
123                 mEnv.searchViewManager,
124                 mEnv::lookupExecutor,
125                 mEnv.injector,
126                 mLastAccessed,
127                 mPickCountRecord
128         );
129 
130 
131         mEnv.selectionMgr.select("1");
132 
133         AsyncTask.setDefaultExecutor(mEnv.mExecutor);
134     }
135 
136     private static class TestableActionHandler<T extends FragmentActivity & Addons>
137             extends ActionHandler {
138 
139         private UpdatePickResultTask mTask;
140 
TestableActionHandler( T activity, State state, ProvidersAccess providers, DocumentsAccess docs, SearchViewManager searchMgr, Lookup<String, Executor> executors, Injector injector, LastAccessedStorage lastAccessed, PickCountRecordStorage pickCountRecordStorage)141         TestableActionHandler(
142                 T activity,
143                 State state,
144                 ProvidersAccess providers,
145                 DocumentsAccess docs,
146                 SearchViewManager searchMgr,
147                 Lookup<String, Executor> executors,
148                 Injector injector,
149                 LastAccessedStorage lastAccessed,
150                 PickCountRecordStorage pickCountRecordStorage) {
151             super(activity, state, providers, docs, searchMgr, executors, injector, lastAccessed);
152             mTask = new UpdatePickResultTask(
153                     mActivity, mInjector.pickResult, pickCountRecordStorage);
154         }
155 
156         @Override
getUpdatePickResultTask()157         public UpdatePickResultTask getUpdatePickResultTask() {
158             return mTask;
159         }
160     }
161 
162     @AfterClass
tearDownOnce()163     public static void tearDownOnce() {
164         AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
165     }
166 
167     @Test
testInitLocation_RestoresIfStackIsLoaded()168     public void testInitLocation_RestoresIfStackIsLoaded() throws Exception {
169         mEnv.state.stack.changeRoot(TestProvidersAccess.DOWNLOADS);
170         mEnv.state.stack.push(TestEnv.FOLDER_0);
171 
172         mHandler.initLocation(mActivity.getIntent());
173         mActivity.restoreRootAndDirectory.assertCalled();
174     }
175 
176     @Test
testInitLocation_LoadsRootDocIfStackOnlyHasRoot()177     public void testInitLocation_LoadsRootDocIfStackOnlyHasRoot() throws Exception {
178         mEnv.state.stack.changeRoot(TestProvidersAccess.HAMMY);
179 
180         mHandler.initLocation(mActivity.getIntent());
181         assertRootPicked(TestProvidersAccess.HAMMY.getUri());
182     }
183 
184     @Test
testInitLocation_CopyDestination_DefaultsToDownloads()185     public void testInitLocation_CopyDestination_DefaultsToDownloads() throws Exception {
186         Intent intent = mActivity.getIntent();
187         intent.setAction(Shared.ACTION_PICK_COPY_DESTINATION);
188         mHandler.initLocation(mActivity.getIntent());
189         assertRootPicked(TestProvidersAccess.DOWNLOADS.getUri());
190     }
191 
192     @Test
193     // TODO(b/236963677) Test is broken pre-S by ag/16425947. The change introduces usage
194     // of PackageManager, which is mocked by the test and results in NPE.
195     @SdkSuppress(minSdkVersion = 31, codeName = "S")
testInitLocation_LaunchToDocuments()196     public void testInitLocation_LaunchToDocuments() throws Exception {
197         if (!mEnv.features.isLaunchToDocumentEnabled()) {
198             return;
199         }
200 
201         mEnv.docs.nextIsDocumentsUri = true;
202         mEnv.docs.nextPath = new Path(
203                 TestProvidersAccess.HOME.rootId,
204                 Arrays.asList(
205                         TestEnv.FOLDER_0.documentId,
206                         TestEnv.FOLDER_1.documentId,
207                         TestEnv.FILE_GIF.documentId));
208         mEnv.docs.nextDocuments =
209                 Arrays.asList(TestEnv.FOLDER_0, TestEnv.FOLDER_1, TestEnv.FILE_GIF);
210 
211         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
212         Intent intent = mActivity.getIntent();
213         intent.setAction(Intent.ACTION_GET_CONTENT);
214         intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, TestEnv.FILE_GIF.derivedUri);
215         mHandler.initLocation(intent);
216 
217         mEnv.beforeAsserts();
218 
219         DocumentStackAsserts.assertEqualsTo(mEnv.state.stack, TestProvidersAccess.HOME,
220                 Arrays.asList(TestEnv.FOLDER_0, TestEnv.FOLDER_1));
221         mActivity.refreshCurrentRootAndDirectory.assertCalled();
222     }
223 
224     @Test
testInitLocation_RestoresLastAccessedStack()225     public void testInitLocation_RestoresLastAccessedStack() throws Exception {
226         final DocumentStack stack =
227                 new DocumentStack(TestProvidersAccess.HAMMY, TestEnv.FOLDER_0, TestEnv.FOLDER_1);
228         mLastAccessed.setLastAccessed(mActivity, stack);
229 
230         mHandler.initLocation(mActivity.getIntent());
231 
232         mEnv.beforeAsserts();
233         assertEquals(stack, mEnv.state.stack);
234         mActivity.refreshCurrentRootAndDirectory.assertCalled();
235     }
236 
237     @Test
testInitLocation_DefaultToRecents_ActionGetContent()238     public void testInitLocation_DefaultToRecents_ActionGetContent() throws Exception {
239         testInitLocationDefaultToRecentsOnAction(State.ACTION_GET_CONTENT);
240     }
241 
242     @Test
testInitLocation_DefaultToRecents_ActionOpen()243     public void testInitLocation_DefaultToRecents_ActionOpen() throws Exception {
244         testInitLocationDefaultToRecentsOnAction(State.ACTION_OPEN);
245     }
246 
247     @Test
testInitLocation_DefaultsToDownloads_ActionCreate()248     public void testInitLocation_DefaultsToDownloads_ActionCreate() throws Exception {
249         testInitLocationDefaultToDownloadsOnAction(State.ACTION_CREATE);
250     }
251 
252     @Test
testInitLocation_DefaultToDeviceRoot_ActionOpenTree()253     public void testInitLocation_DefaultToDeviceRoot_ActionOpenTree() throws Exception {
254         mEnv.state.action = State.ACTION_OPEN_TREE;
255 
256         mHandler.initLocation(mActivity.getIntent());
257 
258         assertRootPicked(TestProvidersAccess.EXTERNALSTORAGE.getUri());
259     }
260 
261     @Test
262     // TODO(b/236963677) Test is broken pre-S by ag/16425947. The change introduces usage
263     // of PackageManager, which is mocked by the test and results in NPE.
264     @SdkSuppress(minSdkVersion = 31, codeName = "S")
testInitLocation_DefaultToDeviceRoot_ActionOpenTree_RootDoesNotSupportChildren()265     public void testInitLocation_DefaultToDeviceRoot_ActionOpenTree_RootDoesNotSupportChildren()
266             throws Exception {
267         mEnv.state.action = State.ACTION_OPEN_TREE;
268 
269         String authority = TestProvidersAccess.NO_TREE_ROOT.authority;
270         String rootId = TestProvidersAccess.NO_TREE_ROOT.rootId;
271         Uri hintUri = DocumentsContract.buildRootUri(authority, rootId);
272 
273         mActivity.getIntent().putExtra(DocumentsContract.EXTRA_INITIAL_URI, hintUri);
274         mHandler.initLocation(mActivity.getIntent());
275 
276         assertRootPicked(TestProvidersAccess.EXTERNALSTORAGE.getUri());
277     }
278 
279     @Test
testOpenContainerDocument()280     public void testOpenContainerDocument() {
281         mHandler.openContainerDocument(TestEnv.FOLDER_0);
282 
283         assertEquals(TestEnv.FOLDER_0, mEnv.state.stack.peek());
284 
285         mActivity.refreshCurrentRootAndDirectory.assertCalled();
286     }
287 
288     @Test
testOpenContainerDocument_sameDocumentInfo()289     public void testOpenContainerDocument_sameDocumentInfo() {
290         mHandler.openContainerDocument(TestEnv.FOLDER_0);
291         mHandler.openContainerDocument(TestEnv.FOLDER_0);
292 
293         assertEquals(1, mEnv.state.stack.size());
294     }
295 
296     @Test
testIncreasePickCountRecordCalled()297     public void testIncreasePickCountRecordCalled() throws Exception {
298         mEnv.state.action = State.ACTION_GET_CONTENT;
299         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
300         mEnv.state.stack.push(TestEnv.FOLDER_1);
301 
302         mActivity.finishedHandler.assertNotCalled();
303         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri);
304 
305         mEnv.beforeAsserts();
306 
307         verify(mPickCountRecord).increasePickCountRecord(
308                 mActivity.getApplicationContext(), TestEnv.FILE_JPG.derivedUri);
309 
310         mActivity.finishedHandler.assertCalled();
311     }
312 
313     @Test
testPickDocument_SetsCorrectResultAndFinishes_ActionPickCopyDestination()314     public void testPickDocument_SetsCorrectResultAndFinishes_ActionPickCopyDestination()
315             throws Exception {
316 
317         mEnv.state.action = State.ACTION_PICK_COPY_DESTINATION;
318         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
319         mEnv.state.stack.push(TestEnv.FOLDER_1);
320         mEnv.state.stack.push(TestEnv.FOLDER_2);
321 
322         mActivity.finishedHandler.assertNotCalled();
323 
324         mHandler.pickDocument(null, TestEnv.FOLDER_2);
325 
326         mEnv.beforeAsserts();
327 
328         assertLastAccessedStackUpdated();
329 
330         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
331         final Intent result = mActivity.setResult.getLastValue().second;
332         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, false);
333         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
334         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
335         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
336         assertContent(result, TestEnv.FOLDER_2.derivedUri);
337 
338         mActivity.finishedHandler.assertCalled();
339     }
340 
341     @Test
testPickDocument_SetsCorrectResultAndFinishes_ActionOpenTree()342     public void testPickDocument_SetsCorrectResultAndFinishes_ActionOpenTree() throws Exception {
343         mEnv.state.action = State.ACTION_OPEN_TREE;
344         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
345         mEnv.state.stack.push(TestEnv.FOLDER_1);
346         mEnv.state.stack.push(TestEnv.FOLDER_2);
347 
348         mActivity.finishedHandler.assertNotCalled();
349 
350         Uri uri = DocumentsContract.buildTreeDocumentUri(
351                 TestEnv.FOLDER_2.authority, TestEnv.FOLDER_2.documentId);
352         mHandler.finishPicking(uri);
353 
354         mEnv.beforeAsserts();
355 
356         assertLastAccessedStackUpdated();
357 
358         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
359         final Intent result = mActivity.setResult.getLastValue().second;
360         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
361         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
362         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
363         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, true);
364         assertContent(result, DocumentsContract.buildTreeDocumentUri(
365                 TestProvidersAccess.HOME.authority, TestEnv.FOLDER_2.documentId));
366 
367         mActivity.finishedHandler.assertCalled();
368     }
369 
370     @Test
testSaveDocument_SetsCorrectResultAndFinishes()371     public void testSaveDocument_SetsCorrectResultAndFinishes() throws Exception {
372         mEnv.state.action = State.ACTION_CREATE;
373         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
374         mEnv.state.stack.push(TestEnv.FOLDER_1);
375 
376         final String mimeType = "audio/aac";
377         final String displayName = "foobar.m4a";
378 
379         mHandler.saveDocument(mimeType, displayName, (boolean inProgress) -> {
380         });
381 
382         mEnv.beforeAsserts();
383 
384         mEnv.docs.assertCreatedDocument(TestEnv.FOLDER_1, mimeType, displayName);
385         final Uri docUri = mEnv.docs.getLastCreatedDocumentUri();
386 
387         assertLastAccessedStackUpdated();
388 
389         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
390         final Intent result = mActivity.setResult.getLastValue().second;
391         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
392         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
393         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
394         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
395         assertContent(result, docUri);
396 
397         mActivity.finishedHandler.assertCalled();
398     }
399 
400     @Test
testSaveDocument_ConfirmsOverwrite()401     public void testSaveDocument_ConfirmsOverwrite() {
402         if (!mEnv.features.isOverwriteConfirmationEnabled()) {
403             return;
404         }
405 
406         mEnv.state.action = State.ACTION_CREATE;
407         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
408         mEnv.state.stack.push(TestEnv.FOLDER_1);
409 
410         mHandler.saveDocument(null, TestEnv.FILE_JPG);
411 
412         mEnv.dialogs.assertOverwriteConfirmed(TestEnv.FILE_JPG);
413     }
414 
415     @Test
testPickDocument_ConfirmsOpenTree()416     public void testPickDocument_ConfirmsOpenTree() {
417         mEnv.state.action = State.ACTION_OPEN_TREE;
418         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
419 
420         mHandler.pickDocument(null, TestEnv.FOLDER_1);
421 
422         mEnv.dialogs.assertDocumentTreeConfirmed(TestEnv.FOLDER_1);
423     }
424 
425     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent()426     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent() throws Exception {
427         mEnv.state.action = State.ACTION_GET_CONTENT;
428         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
429         mEnv.state.stack.push(TestEnv.FOLDER_1);
430 
431         mActivity.finishedHandler.assertNotCalled();
432 
433         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri);
434 
435         mEnv.beforeAsserts();
436 
437         assertLastAccessedStackUpdated();
438 
439         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
440         final Intent result = mActivity.setResult.getLastValue().second;
441         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
442         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
443         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
444         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
445         assertContent(result, TestEnv.FILE_JPG.derivedUri);
446 
447         mActivity.finishedHandler.assertCalled();
448     }
449 
450     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent_MultipleSelection()451     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent_MultipleSelection()
452             throws Exception {
453         mEnv.state.action = State.ACTION_GET_CONTENT;
454         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
455         mEnv.state.stack.push(TestEnv.FOLDER_1);
456         mEnv.state.acceptMimes = new String[]{"image/*"};
457 
458         mActivity.finishedHandler.assertNotCalled();
459 
460         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
461 
462         mEnv.beforeAsserts();
463 
464         assertLastAccessedStackUpdated();
465 
466         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
467         final Intent result = mActivity.setResult.getLastValue().second;
468         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
469         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
470         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
471         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
472         assertContent(result, TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
473 
474         mActivity.finishedHandler.assertCalled();
475     }
476 
477     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen()478     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen() throws Exception {
479         mEnv.state.action = State.ACTION_OPEN;
480         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
481         mEnv.state.stack.push(TestEnv.FOLDER_1);
482 
483         mActivity.finishedHandler.assertNotCalled();
484 
485         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri);
486 
487         mEnv.beforeAsserts();
488 
489         assertLastAccessedStackUpdated();
490 
491         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
492         final Intent result = mActivity.setResult.getLastValue().second;
493         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
494         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
495         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
496         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
497         assertContent(result, TestEnv.FILE_JPG.derivedUri);
498 
499         mActivity.finishedHandler.assertCalled();
500     }
501 
502     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen_MultipleSelection()503     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen_MultipleSelection()
504             throws Exception {
505         mEnv.state.action = State.ACTION_OPEN;
506         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
507         mEnv.state.stack.push(TestEnv.FOLDER_1);
508         mEnv.state.acceptMimes = new String[]{"image/*"};
509 
510         mActivity.finishedHandler.assertNotCalled();
511 
512         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
513 
514         mEnv.beforeAsserts();
515 
516         assertLastAccessedStackUpdated();
517 
518         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
519         final Intent result = mActivity.setResult.getLastValue().second;
520         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
521         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
522         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
523         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
524         assertContent(result, TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
525 
526         mActivity.finishedHandler.assertCalled();
527     }
528 
529     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionCreate()530     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionCreate() throws Exception {
531         mEnv.state.action = State.ACTION_CREATE;
532         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
533         mEnv.state.stack.push(TestEnv.FOLDER_1);
534 
535         mActivity.finishedHandler.assertNotCalled();
536 
537         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri);
538 
539         mEnv.beforeAsserts();
540 
541         assertLastAccessedStackUpdated();
542 
543         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
544         final Intent result = mActivity.setResult.getLastValue().second;
545         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
546         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
547         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
548         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
549         assertContent(result, TestEnv.FILE_JPG.derivedUri);
550 
551         mActivity.finishedHandler.assertCalled();
552     }
553 
554 
555     @Test
testOpenAppRoot()556     public void testOpenAppRoot() throws Exception {
557         mHandler.openRoot(TestResolveInfo.create(), TestProvidersAccess.USER_ID);
558         assertNotNull(mActivity.startActivity.getLastValue());
559     }
560 
561     @Test
testOpenAppRoot_otherUser()562     public void testOpenAppRoot_otherUser() throws Exception {
563         ResolveInfo info = TestResolveInfo.create();
564         if (isPrivateSpaceEnabled) {
565             mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true);
566         } else {
567             mEnv.state.canShareAcrossProfile = true;
568         }
569         mHandler.openRoot(info, TestProvidersAccess.OtherUser.USER_ID);
570         assertThat(mActivity.startActivityAsUser.getLastValue().first.getComponent()).isEqualTo(
571                 new ComponentName(info.activityInfo.applicationInfo.packageName,
572                         info.activityInfo.name));
573         assertThat(mActivity.startActivityAsUser.getLastValue().second)
574                 .isEqualTo(TestProvidersAccess.OtherUser.USER_HANDLE);
575 
576         int flags = mActivity.startActivityAsUser.getLastValue().first.getFlags();
577         assertEquals(0, flags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
578         assertEquals(0, flags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
579         assertEquals(0, flags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
580         assertEquals(0, flags & Intent.FLAG_GRANT_READ_URI_PERMISSION);
581         assertEquals(Intent.FLAG_ACTIVITY_FORWARD_RESULT,
582                 flags & Intent.FLAG_ACTIVITY_FORWARD_RESULT);
583         assertEquals(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP,
584                 flags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
585     }
586 
587     @Test
testOpenAppRoot_removeFlagsAddForwardResult()588     public void testOpenAppRoot_removeFlagsAddForwardResult() throws Exception {
589         ResolveInfo info = TestResolveInfo.create();
590         mActivity.intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
591                 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
592                 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
593                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
594                 | Intent.FLAG_GRANT_READ_URI_PERMISSION);
595         mHandler.openRoot(info, TestProvidersAccess.USER_ID);
596         assertThat(mActivity.startActivity.getLastValue().getComponent()).isEqualTo(
597                 new ComponentName(info.activityInfo.applicationInfo.packageName,
598                         info.activityInfo.name));
599 
600         int flags = mActivity.startActivity.getLastValue().getFlags();
601         assertEquals(0, flags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
602         assertEquals(0, flags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
603         assertEquals(0, flags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
604         assertEquals(0, flags & Intent.FLAG_GRANT_READ_URI_PERMISSION);
605         assertEquals(Intent.FLAG_ACTIVITY_FORWARD_RESULT,
606                 flags & Intent.FLAG_ACTIVITY_FORWARD_RESULT);
607         assertEquals(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP,
608                 flags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
609     }
610 
611     @Test
testOpenAppRootWithQueryContent_matchedContent()612     public void testOpenAppRootWithQueryContent_matchedContent() throws Exception {
613         final String queryContent = "query";
614         mActivity.intent.putExtra(Intent.EXTRA_CONTENT_QUERY, queryContent);
615         mHandler.openRoot(TestResolveInfo.create(), TestProvidersAccess.USER_ID);
616         assertEquals(queryContent,
617                 mActivity.startActivity.getLastValue().getStringExtra(
618                         Intent.EXTRA_CONTENT_QUERY));
619     }
620 
621     @Test
testOpenAppRoot_doesNotHappen_differentUser()622     public void testOpenAppRoot_doesNotHappen_differentUser() throws Exception {
623         final String queryContent = "query";
624         mActivity.intent.putExtra(Intent.EXTRA_CONTENT_QUERY, queryContent);
625         mHandler.openRoot(TestResolveInfo.create(), TestProvidersAccess.OtherUser.USER_ID);
626         assertThat(mActivity.startActivityForResult.getLastValue()).isNull();
627         mEnv.dialogs.assertActionNotAllowedShown();
628     }
629 
630     @Test
testPreviewItem()631     public void testPreviewItem() throws Exception {
632         mActivity.resources.setQuickViewerPackage("corptropolis.viewer");
633         mActivity.currentRoot = TestProvidersAccess.HOME;
634 
635         mHandler.onDocumentOpened(TestEnv.FILE_GIF, ActionHandler.VIEW_TYPE_PREVIEW,
636                 ActionHandler.VIEW_TYPE_REGULAR, true);
637         mActivity.assertActivityStarted(Intent.ACTION_QUICK_VIEW);
638     }
639 
640     @Test
testPreviewItem_onOtherUser()641     public void testPreviewItem_onOtherUser() throws Exception {
642         if (VersionUtils.isAtLeastR()) {
643             mActivity.resources.setQuickViewerPackage("corptropolis.viewer");
644             mActivity.currentRoot = TestProvidersAccess.OtherUser.DOWNLOADS;
645             mEnv.model.reset();
646             DocumentInfo otherUserDoc = mEnv.model.createDocumentForUser("a.png",
647                     "image/png", /* flags= */ 0, TestProvidersAccess.OtherUser.USER_ID);
648             mEnv.model.update();
649 
650             mHandler.onDocumentOpened(otherUserDoc, ActionHandler.VIEW_TYPE_PREVIEW,
651                     ActionHandler.VIEW_TYPE_REGULAR, true);
652             mActivity.assertActivityAsUserStarted(Intent.ACTION_QUICK_VIEW,
653                     TestProvidersAccess.OtherUser.USER_HANDLE);
654         }
655     }
656 
657     @Test
testPreviewItem_archives()658     public void testPreviewItem_archives() throws Exception {
659         mActivity.resources.setQuickViewerPackage("corptropolis.viewer");
660         mActivity.currentRoot = TestProvidersAccess.HOME;
661 
662         mHandler.onDocumentOpened(TestEnv.FILE_ARCHIVE, ActionHandler.VIEW_TYPE_PREVIEW,
663                 ActionHandler.VIEW_TYPE_REGULAR, true);
664         mActivity.assertActivityStarted(Intent.ACTION_QUICK_VIEW);
665     }
666 
667     @Test
testPreviewItem_noQuickViewer()668     public void testPreviewItem_noQuickViewer() throws Exception {
669         mActivity.currentRoot = TestProvidersAccess.HOME;
670 
671         mHandler.onDocumentOpened(TestEnv.FILE_GIF, ActionHandler.VIEW_TYPE_PREVIEW,
672                 ActionHandler.VIEW_TYPE_REGULAR, true);
673         mActivity.assertActivityStarted(Intent.ACTION_VIEW);
674     }
675 
testInitLocationDefaultToRecentsOnAction(@ctionType int action)676     private void testInitLocationDefaultToRecentsOnAction(@ActionType int action)
677             throws Exception {
678         mEnv.state.action = action;
679 
680         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
681 
682         mHandler.initLocation(mActivity.getIntent());
683 
684         mEnv.beforeAsserts();
685         assertEquals(TestProvidersAccess.RECENTS, mEnv.state.stack.getRoot());
686         mActivity.refreshCurrentRootAndDirectory.assertCalled();
687     }
688 
testInitLocationDefaultToDownloadsOnAction(@ctionType int action)689     private void testInitLocationDefaultToDownloadsOnAction(@ActionType int action)
690             throws Exception {
691         mEnv.state.action = action;
692         mActivity.resources.strings.put(R.string.default_root_uri,
693                 TestProvidersAccess.DOWNLOADS.getUri().toString());
694 
695         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
696 
697         mHandler.initLocation(mActivity.getIntent());
698 
699         assertRootPicked(TestProvidersAccess.DOWNLOADS.getUri());
700     }
701 
assertRootPicked(Uri expectedUri)702     private void assertRootPicked(Uri expectedUri) throws Exception {
703         mEnv.beforeAsserts();
704 
705         mActivity.rootPicked.assertCalled();
706         RootInfo root = mActivity.rootPicked.getLastValue();
707         assertNotNull(root);
708         assertEquals(expectedUri, root.getUri());
709     }
710 
assertLastAccessedStackUpdated()711     private void assertLastAccessedStackUpdated() {
712         assertEquals(mEnv.state.stack, mLastAccessed.getLastAccessed(
713                 mActivity, mEnv.providers, mEnv.state));
714     }
715 
assertPermission(Intent intent, int permission, boolean granted)716     private void assertPermission(Intent intent, int permission, boolean granted) {
717         int flags = intent.getFlags();
718 
719         if (granted) {
720             assertEquals(permission, flags & permission);
721         } else {
722             assertEquals(0, flags & permission);
723         }
724     }
725 
assertContent(Intent intent, Uri... contents)726     private void assertContent(Intent intent, Uri... contents) {
727         if (contents.length == 1) {
728             assertEquals(contents[0], intent.getData());
729         } else {
730             ClipData clipData = intent.getClipData();
731 
732             assertNotNull(clipData);
733             for (int i = 0; i < mEnv.state.acceptMimes.length; ++i) {
734                 assertEquals(mEnv.state.acceptMimes[i], clipData.getDescription().getMimeType(i));
735             }
736             for (int i = 0; i < contents.length; ++i) {
737                 assertEquals(contents[i], clipData.getItemAt(i).getUri());
738             }
739         }
740     }
741 }