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
17package com.android.documentsui.picker;
18
19import static junit.framework.Assert.assertTrue;
20
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertNotNull;
23
24import android.app.Activity;
25import android.content.ClipData;
26import android.content.Intent;
27import android.net.Uri;
28import android.os.AsyncTask;
29import android.provider.DocumentsContract;
30import android.provider.DocumentsContract.Path;
31import android.support.test.filters.MediumTest;
32import android.support.test.runner.AndroidJUnit4;
33
34import com.android.documentsui.AbstractActionHandler;
35import com.android.documentsui.R;
36import com.android.documentsui.base.DocumentStack;
37import com.android.documentsui.base.RootInfo;
38import com.android.documentsui.base.Shared;
39import com.android.documentsui.base.State;
40import com.android.documentsui.base.State.ActionType;
41import com.android.documentsui.testing.DocumentStackAsserts;
42import com.android.documentsui.testing.TestEnv;
43import com.android.documentsui.testing.TestProvidersAccess;
44import com.android.documentsui.testing.TestLastAccessedStorage;
45import com.android.documentsui.testing.TestResolveInfo;
46
47import org.junit.AfterClass;
48import org.junit.Before;
49import org.junit.Test;
50import org.junit.runner.RunWith;
51
52import java.util.Arrays;
53
54@RunWith(AndroidJUnit4.class)
55@MediumTest
56public class ActionHandlerTest {
57
58    private TestEnv mEnv;
59    private TestActivity mActivity;
60    private ActionHandler<TestActivity> mHandler;
61    private TestLastAccessedStorage mLastAccessed;
62
63    @Before
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
89    public static void tearDownOnce() {
90        AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
91    }
92
93    @Test
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
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
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
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
152    public void testInitLocation_DefaultToRecents_ActionGetContent() throws Exception {
153        testInitLocationDefaultToRecentsOnAction(State.ACTION_GET_CONTENT);
154    }
155
156    @Test
157    public void testInitLocation_DefaultToRecents_ActionOpen() throws Exception {
158        testInitLocationDefaultToRecentsOnAction(State.ACTION_OPEN);
159    }
160
161    @Test
162    public void testInitLocation_DefaultToRecents_ActionOpenTree() throws Exception {
163        testInitLocationDefaultToRecentsOnAction(State.ACTION_OPEN_TREE);
164    }
165
166    @Test
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
465    private void assertLastAccessedStackUpdated() {
466        assertEquals(
467                mEnv.state.stack, mLastAccessed.getLastAccessed(mActivity, mEnv.roots, mEnv.state));
468    }
469
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
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