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 junit.framework.Assert.assertTrue;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 
24 import android.app.Activity;
25 import android.content.ClipData;
26 import android.content.Intent;
27 import android.net.Uri;
28 import android.os.AsyncTask;
29 import android.provider.DocumentsContract;
30 import android.provider.DocumentsContract.Path;
31 import android.support.test.filters.MediumTest;
32 import android.support.test.runner.AndroidJUnit4;
33 
34 import com.android.documentsui.AbstractActionHandler;
35 import com.android.documentsui.R;
36 import com.android.documentsui.base.DocumentStack;
37 import com.android.documentsui.base.RootInfo;
38 import com.android.documentsui.base.Shared;
39 import com.android.documentsui.base.State;
40 import com.android.documentsui.base.State.ActionType;
41 import com.android.documentsui.testing.DocumentStackAsserts;
42 import com.android.documentsui.testing.TestEnv;
43 import com.android.documentsui.testing.TestProvidersAccess;
44 import com.android.documentsui.testing.TestLastAccessedStorage;
45 import com.android.documentsui.testing.TestResolveInfo;
46 
47 import org.junit.AfterClass;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 
52 import java.util.Arrays;
53 
54 @RunWith(AndroidJUnit4.class)
55 @MediumTest
56 public class ActionHandlerTest {
57 
58     private TestEnv mEnv;
59     private TestActivity mActivity;
60     private ActionHandler<TestActivity> mHandler;
61     private TestLastAccessedStorage mLastAccessed;
62 
63     @Before
setUp()64     public void setUp() {
65         mEnv = TestEnv.create();
66         mActivity = TestActivity.create(mEnv);
67         mEnv.roots.configurePm(mActivity.packageMgr);
68         mLastAccessed = new TestLastAccessedStorage();
69 
70         mHandler = new ActionHandler<>(
71                 mActivity,
72                 mEnv.state,
73                 mEnv.roots,
74                 mEnv.docs,
75                 mEnv.searchViewManager,
76                 mEnv::lookupExecutor,
77                 mEnv.injector,
78                 mLastAccessed
79         );
80 
81         mEnv.dialogs.confirmNext();
82 
83         mEnv.selectionMgr.toggleSelection("1");
84 
85         AsyncTask.setDefaultExecutor(mEnv.mExecutor);
86     }
87 
88     @AfterClass
tearDownOnce()89     public static void tearDownOnce() {
90         AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
91     }
92 
93     @Test
testInitLocation_CopyDestination_DefaultsToDownloads()94     public void testInitLocation_CopyDestination_DefaultsToDownloads() throws Exception {
95         mActivity.resources.bools.put(R.bool.show_documents_root, false);
96 
97         Intent intent = mActivity.getIntent();
98         intent.setAction(Shared.ACTION_PICK_COPY_DESTINATION);
99         mHandler.initLocation(mActivity.getIntent());
100         assertRootPicked(TestProvidersAccess.DOWNLOADS.getUri());
101     }
102 
103     @Test
testInitLocation_CopyDestination_DocumentsRootEnabled()104     public void testInitLocation_CopyDestination_DocumentsRootEnabled() throws Exception {
105         mActivity.resources.bools.put(R.bool.show_documents_root, true);
106 
107         Intent intent = mActivity.getIntent();
108         intent.setAction(Shared.ACTION_PICK_COPY_DESTINATION);
109         mHandler.initLocation(intent);
110         assertRootPicked(TestProvidersAccess.HOME.getUri());
111     }
112 
113     @Test
testInitLocation_LaunchToDocuments()114     public void testInitLocation_LaunchToDocuments() throws Exception {
115         mEnv.docs.nextIsDocumentsUri = true;
116         mEnv.docs.nextPath = new Path(
117                 TestProvidersAccess.HOME.rootId,
118                 Arrays.asList(
119                         TestEnv.FOLDER_0.documentId,
120                         TestEnv.FOLDER_1.documentId,
121                         TestEnv.FILE_GIF.documentId));
122         mEnv.docs.nextDocuments =
123                 Arrays.asList(TestEnv.FOLDER_0, TestEnv.FOLDER_1, TestEnv.FILE_GIF);
124 
125         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
126         Intent intent = mActivity.getIntent();
127         intent.setAction(Intent.ACTION_GET_CONTENT);
128         intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, TestEnv.FILE_GIF.derivedUri);
129         mHandler.initLocation(intent);
130 
131         mEnv.beforeAsserts();
132 
133         DocumentStackAsserts.assertEqualsTo(mEnv.state.stack, TestProvidersAccess.HOME,
134                 Arrays.asList(TestEnv.FOLDER_0, TestEnv.FOLDER_1));
135         mActivity.refreshCurrentRootAndDirectory.assertCalled();
136     }
137 
138     @Test
testInitLocation_RestoresLastAccessedStack()139     public void testInitLocation_RestoresLastAccessedStack() throws Exception {
140         final DocumentStack stack =
141                 new DocumentStack(TestProvidersAccess.HAMMY, TestEnv.FOLDER_0, TestEnv.FOLDER_1);
142         mLastAccessed.setLastAccessed(mActivity, stack);
143 
144         mHandler.initLocation(mActivity.getIntent());
145 
146         mEnv.beforeAsserts();
147         assertEquals(stack, mEnv.state.stack);
148         mActivity.refreshCurrentRootAndDirectory.assertCalled();
149     }
150 
151     @Test
testInitLocation_DefaultToRecents_ActionGetContent()152     public void testInitLocation_DefaultToRecents_ActionGetContent() throws Exception {
153         testInitLocationDefaultToRecentsOnAction(State.ACTION_GET_CONTENT);
154     }
155 
156     @Test
testInitLocation_DefaultToRecents_ActionOpen()157     public void testInitLocation_DefaultToRecents_ActionOpen() throws Exception {
158         testInitLocationDefaultToRecentsOnAction(State.ACTION_OPEN);
159     }
160 
161     @Test
testInitLocation_DefaultToRecents_ActionOpenTree()162     public void testInitLocation_DefaultToRecents_ActionOpenTree() throws Exception {
163         testInitLocationDefaultToRecentsOnAction(State.ACTION_OPEN_TREE);
164     }
165 
166     @Test
testInitLocation_DefaultsToDownloads_ActionCreate()167     public void testInitLocation_DefaultsToDownloads_ActionCreate() throws Exception {
168         mEnv.state.action = State.ACTION_CREATE;
169         mActivity.resources.bools.put(R.bool.show_documents_root, false);
170 
171         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
172 
173         mHandler.initLocation(mActivity.getIntent());
174 
175         assertRootPicked(TestProvidersAccess.DOWNLOADS.getUri());
176     }
177 
178     @Test
testOpenContainerDocument()179     public void testOpenContainerDocument() {
180         mHandler.openContainerDocument(TestEnv.FOLDER_0);
181 
182         assertEquals(TestEnv.FOLDER_0, mEnv.state.stack.peek());
183 
184         mActivity.refreshCurrentRootAndDirectory.assertCalled();
185     }
186 
187     @Test
testPickDocument_SetsCorrectResultAndFinishes_ActionPickCopyDestination()188     public void testPickDocument_SetsCorrectResultAndFinishes_ActionPickCopyDestination()
189             throws Exception {
190 
191         mEnv.state.action = State.ACTION_PICK_COPY_DESTINATION;
192         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
193         mEnv.state.stack.push(TestEnv.FOLDER_1);
194         mEnv.state.stack.push(TestEnv.FOLDER_2);
195 
196         mActivity.finishedHandler.assertNotCalled();
197 
198         mHandler.pickDocument(TestEnv.FOLDER_2);
199 
200         mEnv.beforeAsserts();
201 
202         assertLastAccessedStackUpdated();
203 
204         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
205         final Intent result = mActivity.setResult.getLastValue().second;
206         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, false);
207         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
208         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
209         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
210         assertContent(result, TestEnv.FOLDER_2.derivedUri);
211 
212         mActivity.finishedHandler.assertCalled();
213     }
214 
215     @Test
testPickDocument_SetsCorrectResultAndFinishes_ActionOpenTree()216     public void testPickDocument_SetsCorrectResultAndFinishes_ActionOpenTree() throws Exception {
217         mEnv.state.action = State.ACTION_OPEN_TREE;
218         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
219         mEnv.state.stack.push(TestEnv.FOLDER_1);
220         mEnv.state.stack.push(TestEnv.FOLDER_2);
221 
222         mActivity.finishedHandler.assertNotCalled();
223 
224         mHandler.pickDocument(TestEnv.FOLDER_2);
225 
226         mEnv.beforeAsserts();
227 
228         assertLastAccessedStackUpdated();
229 
230         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
231         final Intent result = mActivity.setResult.getLastValue().second;
232         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
233         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
234         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
235         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, true);
236         assertContent(result, DocumentsContract.buildTreeDocumentUri(
237                 TestProvidersAccess.HOME.authority, TestEnv.FOLDER_2.documentId));
238 
239         mActivity.finishedHandler.assertCalled();
240     }
241 
242     @Test
testSaveDocument_SetsCorrectResultAndFinishes()243     public void testSaveDocument_SetsCorrectResultAndFinishes() throws Exception {
244         mEnv.state.action = State.ACTION_CREATE;
245         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
246         mEnv.state.stack.push(TestEnv.FOLDER_1);
247 
248         final String mimeType = "audio/aac";
249         final String displayName = "foobar.m4a";
250 
251         mHandler.saveDocument(mimeType, displayName, (boolean inProgress) -> {});
252 
253         mEnv.beforeAsserts();
254 
255         mEnv.docs.assertCreatedDocument(TestEnv.FOLDER_1, mimeType, displayName);
256         final Uri docUri = mEnv.docs.getLastCreatedDocumentUri();
257 
258         assertLastAccessedStackUpdated();
259 
260         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
261         final Intent result = mActivity.setResult.getLastValue().second;
262         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
263         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
264         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
265         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
266         assertContent(result, docUri);
267 
268         mActivity.finishedHandler.assertCalled();
269     }
270 
271     @Test
testSaveDocument_ConfirmsOverwrite()272     public void testSaveDocument_ConfirmsOverwrite() {
273         mEnv.state.action = State.ACTION_CREATE;
274         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
275         mEnv.state.stack.push(TestEnv.FOLDER_1);
276 
277         mHandler.saveDocument(null, TestEnv.FILE_JPG);
278 
279         mEnv.dialogs.assertOverwriteConfirmed(TestEnv.FILE_JPG);
280     }
281 
282     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent()283     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent() throws Exception {
284         mEnv.state.action = State.ACTION_GET_CONTENT;
285         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
286         mEnv.state.stack.push(TestEnv.FOLDER_1);
287 
288         mActivity.finishedHandler.assertNotCalled();
289 
290         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri);
291 
292         mEnv.beforeAsserts();
293 
294         assertLastAccessedStackUpdated();
295 
296         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
297         final Intent result = mActivity.setResult.getLastValue().second;
298         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
299         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
300         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
301         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
302         assertContent(result, TestEnv.FILE_JPG.derivedUri);
303 
304         mActivity.finishedHandler.assertCalled();
305     }
306 
307     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent_MultipleSelection()308     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionGetContent_MultipleSelection()
309             throws Exception {
310         mEnv.state.action = State.ACTION_GET_CONTENT;
311         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
312         mEnv.state.stack.push(TestEnv.FOLDER_1);
313         mEnv.state.acceptMimes = new String[] { "image/*" };
314 
315         mActivity.finishedHandler.assertNotCalled();
316 
317         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
318 
319         mEnv.beforeAsserts();
320 
321         assertLastAccessedStackUpdated();
322 
323         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
324         final Intent result = mActivity.setResult.getLastValue().second;
325         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
326         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
327         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
328         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
329         assertContent(result, TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
330 
331         mActivity.finishedHandler.assertCalled();
332     }
333 
334     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen()335     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen() throws Exception {
336         mEnv.state.action = State.ACTION_OPEN;
337         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
338         mEnv.state.stack.push(TestEnv.FOLDER_1);
339 
340         mActivity.finishedHandler.assertNotCalled();
341 
342         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri);
343 
344         mEnv.beforeAsserts();
345 
346         assertLastAccessedStackUpdated();
347 
348         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
349         final Intent result = mActivity.setResult.getLastValue().second;
350         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
351         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
352         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
353         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
354         assertContent(result, TestEnv.FILE_JPG.derivedUri);
355 
356         mActivity.finishedHandler.assertCalled();
357     }
358 
359     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen_MultipleSelection()360     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionOpen_MultipleSelection()
361             throws Exception {
362         mEnv.state.action = State.ACTION_OPEN;
363         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
364         mEnv.state.stack.push(TestEnv.FOLDER_1);
365         mEnv.state.acceptMimes = new String[] { "image/*" };
366 
367         mActivity.finishedHandler.assertNotCalled();
368 
369         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
370 
371         mEnv.beforeAsserts();
372 
373         assertLastAccessedStackUpdated();
374 
375         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
376         final Intent result = mActivity.setResult.getLastValue().second;
377         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
378         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
379         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
380         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
381         assertContent(result, TestEnv.FILE_JPG.derivedUri, TestEnv.FILE_GIF.derivedUri);
382 
383         mActivity.finishedHandler.assertCalled();
384     }
385 
386     @Test
testFinishPicking_SetsCorrectResultAndFinishes_ActionCreate()387     public void testFinishPicking_SetsCorrectResultAndFinishes_ActionCreate() throws Exception {
388         mEnv.state.action = State.ACTION_CREATE;
389         mEnv.state.stack.changeRoot(TestProvidersAccess.HOME);
390         mEnv.state.stack.push(TestEnv.FOLDER_1);
391 
392         mActivity.finishedHandler.assertNotCalled();
393 
394         mHandler.finishPicking(TestEnv.FILE_JPG.derivedUri);
395 
396         mEnv.beforeAsserts();
397 
398         assertLastAccessedStackUpdated();
399 
400         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
401         final Intent result = mActivity.setResult.getLastValue().second;
402         assertPermission(result, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
403         assertPermission(result, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
404         assertPermission(result, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
405         assertPermission(result, Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
406         assertContent(result, TestEnv.FILE_JPG.derivedUri);
407 
408         mActivity.finishedHandler.assertCalled();
409     }
410 
411     @Test
testOnAppPickedResult_OnOK()412     public void testOnAppPickedResult_OnOK() throws Exception {
413         Intent intent = new Intent();
414         mHandler.onActivityResult(AbstractActionHandler.CODE_FORWARD, Activity.RESULT_OK, intent);
415         mActivity.finishedHandler.assertCalled();
416         mActivity.setResult.assertCalled();
417 
418         assertEquals(Activity.RESULT_OK, (long) mActivity.setResult.getLastValue().first);
419         assertEquals(intent, mActivity.setResult.getLastValue().second);
420     }
421 
422     @Test
testOnAppPickedResult_OnNotOK()423     public void testOnAppPickedResult_OnNotOK() throws Exception {
424         Intent intent = new Intent();
425         mHandler.onActivityResult(0, Activity.RESULT_OK, intent);
426         mActivity.finishedHandler.assertNotCalled();
427         mActivity.setResult.assertNotCalled();
428 
429         mHandler.onActivityResult(AbstractActionHandler.CODE_FORWARD, Activity.RESULT_CANCELED,
430                 intent);
431         mActivity.finishedHandler.assertNotCalled();
432         mActivity.setResult.assertNotCalled();
433     }
434 
435     @Test
testOpenAppRoot()436     public void testOpenAppRoot() throws Exception {
437         mHandler.openRoot(TestResolveInfo.create());
438         assertEquals((long) mActivity.startActivityForResult.getLastValue().second,
439                 AbstractActionHandler.CODE_FORWARD);
440         assertNotNull(mActivity.startActivityForResult.getLastValue().first);
441     }
442 
testInitLocationDefaultToRecentsOnAction(@ctionType int action)443     private void testInitLocationDefaultToRecentsOnAction(@ActionType int action)
444             throws Exception {
445         mEnv.state.action = action;
446 
447         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
448 
449         mHandler.initLocation(mActivity.getIntent());
450 
451         mEnv.beforeAsserts();
452         assertEquals(TestProvidersAccess.RECENTS, mEnv.state.stack.getRoot());
453         mActivity.refreshCurrentRootAndDirectory.assertCalled();
454     }
455 
assertRootPicked(Uri expectedUri)456     private void assertRootPicked(Uri expectedUri) throws Exception {
457         mEnv.beforeAsserts();
458 
459         mActivity.rootPicked.assertCalled();
460         RootInfo root = mActivity.rootPicked.getLastValue();
461         assertNotNull(root);
462         assertEquals(expectedUri, root.getUri());
463     }
464 
assertLastAccessedStackUpdated()465     private void assertLastAccessedStackUpdated() {
466         assertEquals(
467                 mEnv.state.stack, mLastAccessed.getLastAccessed(mActivity, mEnv.roots, mEnv.state));
468     }
469 
assertPermission(Intent intent, int permission, boolean granted)470     private void assertPermission(Intent intent, int permission, boolean granted) {
471         int flags = intent.getFlags();
472 
473         if (granted) {
474             assertEquals(permission, flags & permission);
475         } else {
476             assertEquals(0, flags & permission);
477         }
478     }
479 
assertContent(Intent intent, Uri... contents)480     private void assertContent(Intent intent, Uri... contents) {
481         if (contents.length == 1) {
482             assertEquals(contents[0], intent.getData());
483         } else {
484             ClipData clipData = intent.getClipData();
485 
486             assertNotNull(clipData);
487             for (int i = 0; i < mEnv.state.acceptMimes.length; ++i) {
488                 assertEquals(mEnv.state.acceptMimes[i], clipData.getDescription().getMimeType(i));
489             }
490             for (int i = 0; i < contents.length; ++i) {
491                 assertEquals(contents[i], clipData.getItemAt(i).getUri());
492             }
493         }
494     }
495 }
496