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.files;
18 
19 import static com.android.documentsui.testing.IntentAsserts.assertHasAction;
20 import static com.android.documentsui.testing.IntentAsserts.assertHasData;
21 import static com.android.documentsui.testing.IntentAsserts.assertHasExtra;
22 import static com.android.documentsui.testing.IntentAsserts.assertHasExtraIntent;
23 import static com.android.documentsui.testing.IntentAsserts.assertHasExtraList;
24 import static com.android.documentsui.testing.IntentAsserts.assertHasExtraUri;
25 import static com.android.documentsui.testing.IntentAsserts.assertTargetsComponent;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertFalse;
29 import static org.junit.Assert.assertNotNull;
30 import static org.junit.Assert.assertNull;
31 import static org.junit.Assert.assertSame;
32 import static org.junit.Assert.assertTrue;
33 
34 import android.app.Activity;
35 import android.app.DownloadManager;
36 import android.app.PendingIntent;
37 import android.content.ClipData;
38 import android.content.Intent;
39 import android.net.Uri;
40 import android.os.Parcelable;
41 import android.provider.DocumentsContract;
42 import android.provider.DocumentsContract.Path;
43 import android.util.Pair;
44 import android.view.DragEvent;
45 
46 import androidx.core.util.Preconditions;
47 import androidx.test.InstrumentationRegistry;
48 import androidx.test.filters.MediumTest;
49 import androidx.test.runner.AndroidJUnit4;
50 
51 import com.android.documentsui.AbstractActionHandler;
52 import com.android.documentsui.ModelId;
53 import com.android.documentsui.R;
54 import com.android.documentsui.TestActionModeAddons;
55 import com.android.documentsui.archives.ArchivesProvider;
56 import com.android.documentsui.base.DebugFlags;
57 import com.android.documentsui.base.DocumentInfo;
58 import com.android.documentsui.base.DocumentStack;
59 import com.android.documentsui.base.RootInfo;
60 import com.android.documentsui.base.Shared;
61 import com.android.documentsui.inspector.InspectorActivity;
62 import com.android.documentsui.testing.ClipDatas;
63 import com.android.documentsui.testing.DocumentStackAsserts;
64 import com.android.documentsui.testing.Roots;
65 import com.android.documentsui.testing.TestActivityConfig;
66 import com.android.documentsui.testing.TestDocumentClipper;
67 import com.android.documentsui.testing.TestDragAndDropManager;
68 import com.android.documentsui.testing.TestEnv;
69 import com.android.documentsui.testing.TestFeatures;
70 import com.android.documentsui.testing.TestProvidersAccess;
71 import com.android.documentsui.testing.UserManagers;
72 import com.android.documentsui.ui.TestDialogController;
73 
74 import org.junit.Before;
75 import org.junit.Test;
76 import org.junit.runner.RunWith;
77 
78 import java.util.ArrayList;
79 import java.util.Arrays;
80 import java.util.List;
81 
82 @RunWith(AndroidJUnit4.class)
83 @MediumTest
84 public class ActionHandlerTest {
85 
86     private TestEnv mEnv;
87     private TestActivity mActivity;
88     private TestActionModeAddons mActionModeAddons;
89     private TestDialogController mDialogs;
90     private ActionHandler<TestActivity> mHandler;
91     private TestDocumentClipper mClipper;
92     private TestDragAndDropManager mDragAndDropManager;
93     private TestFeatures mFeatures;
94     private boolean refreshAnswer = false;
95 
96     @Before
setUp()97     public void setUp() {
98         mFeatures = new TestFeatures();
99         mEnv = TestEnv.create(mFeatures);
100         mActivity = TestActivity.create(mEnv);
101         mActivity.userManager = UserManagers.create();
102         mActionModeAddons = new TestActionModeAddons();
103         mDialogs = new TestDialogController();
104         mClipper = new TestDocumentClipper();
105         mDragAndDropManager = new TestDragAndDropManager();
106 
107         mEnv.providers.configurePm(mActivity.packageMgr);
108         ((TestActivityConfig) mEnv.injector.config).nextDocumentEnabled = true;
109         mEnv.injector.dialogs = mDialogs;
110 
111         mHandler = createHandler();
112 
113         mEnv.selectDocument(TestEnv.FILE_GIF);
114     }
115 
116     @Test
testOpenSelectedInNewWindow()117     public void testOpenSelectedInNewWindow() {
118         mHandler.openSelectedInNewWindow();
119 
120         DocumentStack path = new DocumentStack(Roots.create("123"), mEnv.model.getDocument("1"));
121 
122         Intent expected = LauncherActivity.createLaunchIntent(mActivity);
123         expected.putExtra(Shared.EXTRA_STACK, (Parcelable) path);
124 
125         Intent actual = mActivity.startActivity.getLastValue();
126         assertEquals(expected.toString(), actual.toString());
127     }
128 
129     @Test
testSpringOpenDirectory()130     public void testSpringOpenDirectory() {
131         mHandler.springOpenDirectory(TestEnv.FOLDER_0);
132         assertTrue(mActionModeAddons.finishActionModeCalled);
133         assertEquals(TestEnv.FOLDER_0, mEnv.state.stack.peek());
134     }
135 
136     @Test
testCutSelectedDocuments_NoGivenSelection()137     public void testCutSelectedDocuments_NoGivenSelection() {
138         mEnv.populateStack();
139 
140         mEnv.selectionMgr.clearSelection();
141         mHandler.cutToClipboard();
142         mDialogs.assertDocumentsClippedNotShown();
143     }
144 
145     @Test
testCutSelectedDocuments_ContainsNonMovableItem()146     public void testCutSelectedDocuments_ContainsNonMovableItem() {
147         mEnv.populateStack();
148         mEnv.selectDocument(TestEnv.FILE_READ_ONLY);
149 
150         mHandler.cutToClipboard();
151         mDialogs.assertDocumentsClippedNotShown();
152         mDialogs.assertShowOperationUnsupported();
153         mClipper.clipForCut.assertNotCalled();
154     }
155 
156     @Test
testCopySelectedDocuments_NoGivenSelection()157     public void testCopySelectedDocuments_NoGivenSelection() {
158         mEnv.populateStack();
159 
160         mEnv.selectionMgr.clearSelection();
161         mHandler.copyToClipboard();
162         mDialogs.assertDocumentsClippedNotShown();
163     }
164 
165     @Test
testShowDeleteDialog_NoSelection()166     public void testShowDeleteDialog_NoSelection() {
167         mEnv.populateStack();
168 
169         mEnv.selectionMgr.clearSelection();
170         mHandler.showDeleteDialog();
171         mActivity.startService.assertNotCalled();
172         assertFalse(mActionModeAddons.finishActionModeCalled);
173     }
174 
175     @Test
testDeleteSelectedDocuments()176     public void testDeleteSelectedDocuments() {
177         mEnv.populateStack();
178 
179         mEnv.selectionMgr.clearSelection();
180         mEnv.selectDocument(TestEnv.FILE_PNG);
181 
182         List<DocumentInfo> docs = new ArrayList<>();
183         docs.add(TestEnv.FILE_PNG);
184         mHandler.deleteSelectedDocuments(docs, mEnv.state.stack.peek());
185 
186         mActivity.startService.assertCalled();
187         assertTrue(mActionModeAddons.finishActionModeCalled);
188     }
189 
190     @Test
testShareSelectedDocuments_ShowsChooser()191     public void testShareSelectedDocuments_ShowsChooser() {
192         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
193         mHandler.shareSelectedDocuments();
194 
195         mActivity.assertActivityStarted(Intent.ACTION_CHOOSER);
196     }
197 
198     @Test
testShareSelectedDocuments_Single()199     public void testShareSelectedDocuments_Single() {
200         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
201         mHandler.shareSelectedDocuments();
202 
203         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
204         assertHasAction(intent, Intent.ACTION_SEND);
205         assertFalse(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
206         assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
207         assertHasExtraUri(intent, Intent.EXTRA_STREAM);
208     }
209 
210     @Test
testShareSelectedDocuments_ArchivedFile()211     public void testShareSelectedDocuments_ArchivedFile() {
212         mEnv = TestEnv.create(ArchivesProvider.AUTHORITY);
213         mHandler = createHandler();
214 
215         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
216         mEnv.selectionMgr.clearSelection();
217         mEnv.selectDocument(TestEnv.FILE_PDF);
218         mHandler.shareSelectedDocuments();
219 
220         Intent intent = mActivity.startActivity.getLastValue();
221         assertNull(intent);
222     }
223 
224     @Test
testShareSelectedDocuments_Multiple()225     public void testShareSelectedDocuments_Multiple() {
226         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
227         mEnv.selectDocument(TestEnv.FILE_PDF);
228         mHandler.shareSelectedDocuments();
229 
230         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
231         assertHasAction(intent, Intent.ACTION_SEND_MULTIPLE);
232         assertFalse(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
233         assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
234         assertHasExtraList(intent, Intent.EXTRA_STREAM, 2);
235     }
236 
237     @Test
testShareSelectedDocuments_overShareLimit()238     public void testShareSelectedDocuments_overShareLimit() {
239         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
240         mEnv.selectMultipleFiles(500);
241         mHandler.shareSelectedDocuments();
242 
243         Intent intent = mActivity.startActivity.getLastValue();
244         assertNull(intent);
245         mDialogs.assertShareOverLimitShown();
246     }
247 
248     @Test
testShareSelectedDocuments_VirtualFiles()249     public void testShareSelectedDocuments_VirtualFiles() {
250         if (!mEnv.features.isVirtualFilesSharingEnabled()) {
251             return;
252         }
253 
254         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
255         mEnv.selectionMgr.clearSelection();
256         mEnv.selectDocument(TestEnv.FILE_VIRTUAL);
257         mHandler.shareSelectedDocuments();
258 
259         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
260         assertHasAction(intent, Intent.ACTION_SEND);
261         assertTrue(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
262         assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
263         assertHasExtraUri(intent, Intent.EXTRA_STREAM);
264     }
265 
266     @Test
testShareSelectedDocuments_RegularAndVirtualFiles()267     public void testShareSelectedDocuments_RegularAndVirtualFiles() {
268         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
269         mEnv.selectDocument(TestEnv.FILE_PNG);
270         mEnv.selectDocument(TestEnv.FILE_VIRTUAL);
271         mHandler.shareSelectedDocuments();
272 
273         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
274         assertHasAction(intent, Intent.ACTION_SEND_MULTIPLE);
275 
276         assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
277         if (mEnv.features.isVirtualFilesSharingEnabled()) {
278             assertTrue(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
279             assertHasExtraList(intent, Intent.EXTRA_STREAM, 3);
280         }else {
281             assertHasExtraList(intent, Intent.EXTRA_STREAM, 2);
282         }
283     }
284 
285     @Test
testShareSelectedDocuments_OmitsPartialFiles()286     public void testShareSelectedDocuments_OmitsPartialFiles() {
287         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
288         mEnv.selectDocument(TestEnv.FILE_PARTIAL);
289         mEnv.selectDocument(TestEnv.FILE_PNG);
290         mHandler.shareSelectedDocuments();
291 
292         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
293         assertHasAction(intent, Intent.ACTION_SEND_MULTIPLE);
294         assertFalse(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
295         assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
296         assertHasExtraList(intent, Intent.EXTRA_STREAM, 2);
297     }
298 
299     @Test
testDocumentPicked_DefaultsToView()300     public void testDocumentPicked_DefaultsToView() throws Exception {
301         mActivity.currentRoot = TestProvidersAccess.HOME;
302 
303         mHandler.openDocument(TestEnv.FILE_GIF, ActionHandler.VIEW_TYPE_PREVIEW,
304                 ActionHandler.VIEW_TYPE_REGULAR);
305         mActivity.assertActivityStarted(Intent.ACTION_VIEW);
306     }
307 
308     @Test
testDocumentPicked_InArchive_QuickViewable()309     public void testDocumentPicked_InArchive_QuickViewable() throws Exception {
310         mActivity.resources.setQuickViewerPackage("corptropolis.viewer");
311         mActivity.currentRoot = TestProvidersAccess.HOME;
312 
313         mHandler.openDocument(TestEnv.FILE_IN_ARCHIVE, ActionHandler.VIEW_TYPE_PREVIEW,
314                 ActionHandler.VIEW_TYPE_REGULAR);
315         mActivity.assertActivityStarted(Intent.ACTION_QUICK_VIEW);
316     }
317 
318     @Test
testDocumentPicked_InArchive_Unopenable()319     public void testDocumentPicked_InArchive_Unopenable() throws Exception {
320         mActivity.currentRoot = TestProvidersAccess.HOME;
321 
322         mHandler.openDocument(TestEnv.FILE_IN_ARCHIVE, ActionHandler.VIEW_TYPE_PREVIEW,
323                 ActionHandler.VIEW_TYPE_REGULAR);
324         mDialogs.assertViewInArchivesShownUnsupported();
325     }
326 
327     @Test
testDocumentPicked_PreviewsWhenResourceSet()328     public void testDocumentPicked_PreviewsWhenResourceSet() throws Exception {
329         mActivity.resources.setQuickViewerPackage("corptropolis.viewer");
330         mActivity.currentRoot = TestProvidersAccess.HOME;
331 
332         mHandler.openDocument(TestEnv.FILE_GIF, ActionHandler.VIEW_TYPE_PREVIEW,
333                 ActionHandler.VIEW_TYPE_REGULAR);
334         mActivity.assertActivityStarted(Intent.ACTION_QUICK_VIEW);
335     }
336 
337     @Test
testDocumentPicked_Downloads_ManagesApks()338     public void testDocumentPicked_Downloads_ManagesApks() throws Exception {
339         mActivity.currentRoot = TestProvidersAccess.DOWNLOADS;
340         TestEnv.FILE_APK.authority = TestProvidersAccess.DOWNLOADS.authority;
341 
342         mHandler.openDocument(TestEnv.FILE_APK, ActionHandler.VIEW_TYPE_PREVIEW,
343                 ActionHandler.VIEW_TYPE_REGULAR);
344         mActivity.assertActivityStarted(DocumentsContract.ACTION_MANAGE_DOCUMENT);
345     }
346 
347     @Test
testDocumentPicked_Downloads_ManagesPartialFiles()348     public void testDocumentPicked_Downloads_ManagesPartialFiles() throws Exception {
349         mActivity.currentRoot = TestProvidersAccess.DOWNLOADS;
350         TestEnv.FILE_PARTIAL.authority = TestProvidersAccess.DOWNLOADS.authority;
351 
352         mHandler.openDocument(TestEnv.FILE_PARTIAL, ActionHandler.VIEW_TYPE_PREVIEW,
353                 ActionHandler.VIEW_TYPE_REGULAR);
354         mActivity.assertActivityStarted(DocumentsContract.ACTION_MANAGE_DOCUMENT);
355     }
356 
357     @Test
testDocumentPicked_Recent_ManagesApks()358     public void testDocumentPicked_Recent_ManagesApks() throws Exception {
359         mActivity.currentRoot = TestProvidersAccess.RECENTS;
360         TestEnv.FILE_APK.authority = TestProvidersAccess.DOWNLOADS.authority;
361 
362         mHandler.openDocument(TestEnv.FILE_APK, ActionHandler.VIEW_TYPE_PREVIEW,
363                 ActionHandler.VIEW_TYPE_REGULAR);
364         mActivity.assertActivityStarted(DocumentsContract.ACTION_MANAGE_DOCUMENT);
365     }
366 
367     @Test
testDocumentPicked_Home_SendsActionViewForApks()368     public void testDocumentPicked_Home_SendsActionViewForApks() throws Exception {
369         mActivity.currentRoot = TestProvidersAccess.HOME;
370 
371         mHandler.openDocument(TestEnv.FILE_APK, ActionHandler.VIEW_TYPE_PREVIEW,
372                 ActionHandler.VIEW_TYPE_REGULAR);
373         mActivity.assertActivityStarted(Intent.ACTION_VIEW);
374     }
375 
376     @Test
testDocumentPicked_OpensArchives()377     public void testDocumentPicked_OpensArchives() throws Exception {
378         mActivity.currentRoot = TestProvidersAccess.HOME;
379         mEnv.docs.nextDocument = TestEnv.FILE_ARCHIVE;
380 
381         final boolean result = mHandler.openDocument(TestEnv.FILE_ARCHIVE,
382                 ActionHandler.VIEW_TYPE_PREVIEW, ActionHandler.VIEW_TYPE_REGULAR);
383         assertEquals(TestEnv.FILE_ARCHIVE, mEnv.state.stack.peek());
384         assertEquals(false, result);
385     }
386 
387     @Test
testDocumentPicked_OpensDirectories()388     public void testDocumentPicked_OpensDirectories() throws Exception {
389         mActivity.currentRoot = TestProvidersAccess.HOME;
390 
391         final boolean result = mHandler.openDocument(TestEnv.FOLDER_1,
392                 ActionHandler.VIEW_TYPE_PREVIEW, ActionHandler.VIEW_TYPE_REGULAR);
393         assertEquals(TestEnv.FOLDER_1, mEnv.state.stack.peek());
394         assertEquals(false, result);
395     }
396 
397     @Test
testShowChooser()398     public void testShowChooser() throws Exception {
399         mActivity.currentRoot = TestProvidersAccess.DOWNLOADS;
400 
401         mHandler.showChooserForDoc(TestEnv.FILE_PDF);
402         mActivity.assertActivityStarted(Intent.ACTION_CHOOSER);
403     }
404 
405     @Test
testInitLocation_LaunchToStackLocation()406     public void testInitLocation_LaunchToStackLocation() {
407         DocumentStack path = new DocumentStack(Roots.create("123"), mEnv.model.getDocument("1"));
408 
409         Intent intent = LauncherActivity.createLaunchIntent(mActivity);
410         intent.putExtra(Shared.EXTRA_STACK, (Parcelable) path);
411 
412         mHandler.initLocation(intent);
413         mActivity.refreshCurrentRootAndDirectory.assertCalled();
414     }
415 
416     @Test
testInitLocation_RestoresIfStackIsLoaded()417     public void testInitLocation_RestoresIfStackIsLoaded() throws Exception {
418         mEnv.state.stack.changeRoot(TestProvidersAccess.DOWNLOADS);
419         mEnv.state.stack.push(TestEnv.FOLDER_0);
420 
421         mHandler.initLocation(mActivity.getIntent());
422         mActivity.restoreRootAndDirectory.assertCalled();
423     }
424 
425     @Test
testInitLocation_LoadsRootDocIfStackOnlyHasRoot()426     public void testInitLocation_LoadsRootDocIfStackOnlyHasRoot() throws Exception {
427         mEnv.state.stack.changeRoot(TestProvidersAccess.HAMMY);
428 
429         mHandler.initLocation(mActivity.getIntent());
430         assertRootPicked(TestProvidersAccess.HAMMY.getUri());
431     }
432 
433     @Test
testInitLocation_forceDefaultsToRoot()434     public void testInitLocation_forceDefaultsToRoot() throws Exception {
435         mActivity.resources.strings.put(R.string.default_root_uri,
436                 TestProvidersAccess.DOWNLOADS.getUri().toString());
437 
438         mHandler.initLocation(mActivity.getIntent());
439         assertRootPicked(TestProvidersAccess.DOWNLOADS.getUri());
440     }
441 
442     @Test
testInitLocation_BrowseRootWithoutRootId()443     public void testInitLocation_BrowseRootWithoutRootId() throws Exception {
444         Intent intent = mActivity.getIntent();
445         intent.setAction(Intent.ACTION_VIEW);
446         intent.setData(DocumentsContract.buildRootsUri(TestProvidersAccess.HAMMY.authority));
447 
448         mHandler.initLocation(intent);
449         assertRootPicked(TestProvidersAccess.HAMMY.getUri());
450     }
451 
452     @Test
testInitLocation_BrowseRootWrongAuthority_ShowDefault()453     public void testInitLocation_BrowseRootWrongAuthority_ShowDefault() throws Exception {
454         Intent intent = mActivity.getIntent();
455         intent.setAction(Intent.ACTION_VIEW);
456         intent.setData(DocumentsContract.buildRootsUri("com.test.wrongauthority"));
457         mActivity.resources.strings.put(R.string.default_root_uri,
458                 TestProvidersAccess.HOME.getUri().toString());
459 
460         mHandler.initLocation(intent);
461         assertRootPicked(TestProvidersAccess.HOME.getUri());
462     }
463 
464     @Test
testInitLocation_BrowseRoot()465     public void testInitLocation_BrowseRoot() throws Exception {
466         Intent intent = mActivity.getIntent();
467         intent.setAction(Intent.ACTION_VIEW);
468         intent.setData(TestProvidersAccess.PICKLES.getUri());
469 
470         mHandler.initLocation(intent);
471         assertRootPicked(TestProvidersAccess.PICKLES.getUri());
472     }
473 
474     @Test
testInitLocation_LaunchToDocuments()475     public void testInitLocation_LaunchToDocuments() throws Exception {
476         if (!mEnv.features.isLaunchToDocumentEnabled()) {
477             return;
478         }
479 
480         mEnv.docs.nextIsDocumentsUri = true;
481         mEnv.docs.nextPath = new Path(
482                 TestProvidersAccess.HOME.rootId,
483                 Arrays.asList(
484                         TestEnv.FOLDER_0.documentId,
485                         TestEnv.FOLDER_1.documentId));
486         mEnv.docs.nextDocuments =
487                 Arrays.asList(TestEnv.FOLDER_0, TestEnv.FOLDER_1);
488 
489         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
490         Intent intent = mActivity.getIntent();
491         intent.setAction(Intent.ACTION_VIEW);
492         intent.setData(TestEnv.FOLDER_1.derivedUri);
493         mHandler.initLocation(intent);
494 
495         mEnv.beforeAsserts();
496 
497         DocumentStackAsserts.assertEqualsTo(mEnv.state.stack, TestProvidersAccess.HOME,
498                 Arrays.asList(TestEnv.FOLDER_0, TestEnv.FOLDER_1));
499         mActivity.refreshCurrentRootAndDirectory.assertCalled();
500     }
501 
502     @Test
testInitLocation_LaunchToDownloads()503     public void testInitLocation_LaunchToDownloads() throws Exception {
504         Intent intent = mActivity.getIntent();
505         intent.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
506 
507         mHandler.initLocation(intent);
508         assertRootPicked(TestProvidersAccess.DOWNLOADS.getUri());
509     }
510 
511     @Test
testDragAndDrop_OnReadOnlyRoot()512     public void testDragAndDrop_OnReadOnlyRoot() throws Exception {
513         RootInfo root = new RootInfo(); // root by default has no SUPPORT_CREATE flag
514         DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, null, null, null,
515                 null, true);
516         assertFalse(mHandler.dropOn(event, root));
517     }
518 
519     @Test
testDragAndDrop_OnLibraryRoot()520     public void testDragAndDrop_OnLibraryRoot() throws Exception {
521         DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, null, null, null,
522                 null, true);
523         assertFalse(mHandler.dropOn(event, TestProvidersAccess.RECENTS));
524     }
525 
526     @Test
testDragAndDrop_DropsOnWritableRoot()527     public void testDragAndDrop_DropsOnWritableRoot() throws Exception {
528         // DragEvent gets recycled in Android, so it is possible that by the time the callback is
529         // called, event.getLocalState() and event.getClipData() returns null. This tests to ensure
530         // our Clipper is getting the original CipData passed in.
531         Object localState = new Object();
532         ClipData clipData = ClipDatas.createTestClipData();
533         DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, localState, null, clipData,
534                 null, true);
535 
536         mHandler.dropOn(event, TestProvidersAccess.DOWNLOADS);
537         event.recycle();
538 
539         Pair<ClipData, RootInfo> actual = mDragAndDropManager.dropOnRootHandler.getLastValue();
540         assertSame(clipData, actual.first);
541         assertSame(TestProvidersAccess.DOWNLOADS, actual.second);
542     }
543 
544     @Test
testRefresh_nullUri()545     public void testRefresh_nullUri() throws Exception {
546         refreshAnswer = true;
547         mHandler.refreshDocument(null, (boolean answer) -> {
548             refreshAnswer = answer;
549         });
550 
551         mEnv.beforeAsserts();
552         assertFalse(refreshAnswer);
553     }
554 
555     @Test
testRefresh_emptyStack()556     public void testRefresh_emptyStack() throws Exception {
557         refreshAnswer = true;
558         assertTrue(mEnv.state.stack.isEmpty());
559         mHandler.refreshDocument(new DocumentInfo(), (boolean answer) -> {
560             refreshAnswer = answer;
561         });
562 
563         mEnv.beforeAsserts();
564         assertFalse(refreshAnswer);
565     }
566 
567     @Test
testRefresh()568     public void testRefresh() throws Exception {
569         refreshAnswer = false;
570         mEnv.populateStack();
571         mHandler.refreshDocument(mEnv.model.getDocument(
572                 ModelId.build(mEnv.model.mUserId, TestProvidersAccess.HOME.authority, "1")),
573                 (boolean answer) -> {
574                     refreshAnswer = answer;
575                 });
576 
577         mEnv.beforeAsserts();
578         if (mEnv.features.isContentRefreshEnabled()) {
579             assertTrue(refreshAnswer);
580         } else {
581             assertFalse(refreshAnswer);
582         }
583     }
584 
585     @Test
testAuthentication()586     public void testAuthentication() throws Exception {
587         PendingIntent intent = PendingIntent.getActivity(
588                 InstrumentationRegistry.getInstrumentation().getTargetContext(), 0, new Intent(),
589                 0);
590 
591         mHandler.startAuthentication(intent);
592         assertEquals(intent.getIntentSender(), mActivity.startIntentSender.getLastValue().first);
593         assertEquals(AbstractActionHandler.CODE_AUTHENTICATION,
594                 mActivity.startIntentSender.getLastValue().second.intValue());
595     }
596 
597     @Test
testOnActivityResult_onOK()598     public void testOnActivityResult_onOK() throws Exception {
599         mHandler.onActivityResult(AbstractActionHandler.CODE_AUTHENTICATION, Activity.RESULT_OK,
600                 null);
601         mActivity.refreshCurrentRootAndDirectory.assertCalled();
602     }
603 
604     @Test
testOnActivityResult_onNotOK()605     public void testOnActivityResult_onNotOK() throws Exception {
606         mHandler.onActivityResult(0, Activity.RESULT_OK, null);
607         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
608 
609         mHandler.onActivityResult(AbstractActionHandler.CODE_AUTHENTICATION,
610                 Activity.RESULT_CANCELED, null);
611         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
612     }
613 
614     @Test
testShowInspector()615     public void testShowInspector() throws Exception {
616         mHandler.showInspector(TestEnv.FILE_GIF);
617 
618         mActivity.startActivity.assertCalled();
619         Intent intent = mActivity.startActivity.getLastValue();
620         assertTargetsComponent(intent, InspectorActivity.class);
621         assertHasData(intent, TestEnv.FILE_GIF.derivedUri);
622 
623         // should only send this under especial circumstances. See test below.
624         assertFalse(intent.getExtras().containsKey(Intent.EXTRA_TITLE));
625     }
626 
627     @Test
testShowInspector_DebugDisabled()628     public void testShowInspector_DebugDisabled() throws Exception {
629         mFeatures.debugSupport = false;
630 
631         mHandler.showInspector(TestEnv.FILE_GIF);
632         Intent intent = mActivity.startActivity.getLastValue();
633 
634         assertHasExtra(intent, Shared.EXTRA_SHOW_DEBUG);
635         assertFalse(intent.getExtras().getBoolean(Shared.EXTRA_SHOW_DEBUG));
636     }
637 
638     @Test
testShowInspector_DebugEnabled()639     public void testShowInspector_DebugEnabled() throws Exception {
640         mFeatures.debugSupport = true;
641         DebugFlags.setDocumentDetailsEnabled(true);
642 
643         mHandler.showInspector(TestEnv.FILE_GIF);
644         Intent intent = mActivity.startActivity.getLastValue();
645 
646         assertHasExtra(intent, Shared.EXTRA_SHOW_DEBUG);
647         assertTrue(intent.getExtras().getBoolean(Shared.EXTRA_SHOW_DEBUG));
648         DebugFlags.setDocumentDetailsEnabled(false);
649     }
650 
651     @Test
testShowInspector_OverridesRootDocumentName()652     public void testShowInspector_OverridesRootDocumentName() throws Exception {
653         mActivity.currentRoot = TestProvidersAccess.PICKLES;
654         mEnv.populateStack();
655 
656         // Verify test setup is correct, but not an assert related to the logic of our test.
657         Preconditions.checkState(mEnv.state.stack.size() == 1);
658         Preconditions.checkNotNull(mEnv.state.stack.peek());
659 
660         DocumentInfo rootDoc = mEnv.state.stack.peek();
661         rootDoc.displayName = "poodles";
662 
663         mHandler.showInspector(rootDoc);
664         Intent intent = mActivity.startActivity.getLastValue();
665         assertEquals(
666                 TestProvidersAccess.PICKLES.title,
667                 intent.getExtras().getString(Intent.EXTRA_TITLE));
668     }
669 
670     @Test
testShowInspector_OverridesRootDocumentNameX()671     public void testShowInspector_OverridesRootDocumentNameX() throws Exception {
672         mActivity.currentRoot = TestProvidersAccess.PICKLES;
673         mEnv.populateStack();
674         mEnv.state.stack.push(TestEnv.FOLDER_2);
675 
676         // Verify test setup is correct, but not an assert related to the logic of our test.
677         Preconditions.checkState(mEnv.state.stack.size() == 2);
678         Preconditions.checkNotNull(mEnv.state.stack.peek());
679 
680         DocumentInfo rootDoc = mEnv.state.stack.peek();
681         rootDoc.displayName = "poodles";
682 
683         mHandler.showInspector(rootDoc);
684         Intent intent = mActivity.startActivity.getLastValue();
685         assertFalse(intent.getExtras().containsKey(Intent.EXTRA_TITLE));
686     }
687 
assertRootPicked(Uri expectedUri)688     private void assertRootPicked(Uri expectedUri) throws Exception {
689         mEnv.beforeAsserts();
690 
691         mActivity.rootPicked.assertCalled();
692         RootInfo root = mActivity.rootPicked.getLastValue();
693         assertNotNull(root);
694         assertEquals(expectedUri, root.getUri());
695     }
696 
createHandler()697     private ActionHandler<TestActivity> createHandler() {
698         return new ActionHandler<>(
699                 mActivity,
700                 mEnv.state,
701                 mEnv.providers,
702                 mEnv.docs,
703                 mEnv.searchViewManager,
704                 mEnv::lookupExecutor,
705                 mActionModeAddons,
706                 mClipper,
707                 null,  // clip storage, not utilized unless we venture into *jumbo* clip territory.
708                 mDragAndDropManager,
709                 mEnv.injector
710         );
711     }
712 }
713