1 /*
2  * Copyright (C) 2017 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;
18 
19 import static junit.framework.Assert.assertEquals;
20 import static junit.framework.Assert.assertFalse;
21 import static junit.framework.Assert.assertNotNull;
22 import static junit.framework.Assert.assertSame;
23 import static junit.framework.Assert.assertTrue;
24 
25 import android.content.ClipData;
26 import android.content.ClipDescription;
27 import android.graphics.drawable.Drawable;
28 import android.os.PersistableBundle;
29 import android.util.Pair;
30 import android.view.KeyEvent;
31 import android.view.View;
32 
33 import androidx.test.filters.SmallTest;
34 import androidx.test.runner.AndroidJUnit4;
35 
36 import com.android.documentsui.DragAndDropManager.RuntimeDragAndDropManager;
37 import com.android.documentsui.DragAndDropManager.State;
38 import com.android.documentsui.base.DocumentStack;
39 import com.android.documentsui.base.RootInfo;
40 import com.android.documentsui.services.FileOperationService;
41 import com.android.documentsui.services.FileOperations;
42 import com.android.documentsui.testing.ClipDatas;
43 import com.android.documentsui.testing.KeyEvents;
44 import com.android.documentsui.testing.TestActionHandler;
45 import com.android.documentsui.testing.TestDocumentClipper;
46 import com.android.documentsui.testing.TestDrawable;
47 import com.android.documentsui.testing.TestEnv;
48 import com.android.documentsui.testing.TestEventListener;
49 import com.android.documentsui.testing.TestIconHelper;
50 import com.android.documentsui.testing.TestProvidersAccess;
51 import com.android.documentsui.testing.TestSelectionDetails;
52 import com.android.documentsui.testing.Views;
53 
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.mockito.Mockito;
58 
59 import java.util.Arrays;
60 
61 @RunWith(AndroidJUnit4.class)
62 @SmallTest
63 public class DragAndDropManagerTests {
64 
65     private static final String PLURAL_FORMAT = "%1$d items";
66 
67     private TestEnv mEnv;
68     private TestActivity mActivity;
69     private TestDragShadowBuilder mShadowBuilder;
70     private View mStartDragView;
71     private View mUpdateShadowView;
72     private TestActionHandler mActions;
73 
74     private TestDocumentClipper mClipper;
75     private TestSelectionDetails mDetails;
76     private ClipData mClipData;
77 
78     private TestIconHelper mIconHelper;
79     private Drawable mDefaultIcon;
80 
81     private TestEventListener<ClipData> mStartDragListener;
82     private TestEventListener<Void> mShadowUpdateListener;
83     private TestEventListener<Integer> mFlagListener;
84 
85     private TestEventListener<Integer> mCallbackListener;
86     private FileOperations.Callback mCallback = new FileOperations.Callback() {
87         @Override
88         public void onOperationResult(@Status int status,
89                 @FileOperationService.OpType int opType, int docCount) {
90             mCallbackListener.accept(status);
91         }
92     };
93 
94     private DragAndDropManager mManager;
95 
96     @Before
setUp()97     public void setUp() {
98         mEnv = TestEnv.create();
99         mActivity = TestActivity.create(mEnv);
100         mActivity.resources.plurals.put(R.plurals.elements_dragged, PLURAL_FORMAT);
101 
102         mShadowBuilder = TestDragShadowBuilder.create();
103 
104         mStartDragView = Views.createTestView();
105         mUpdateShadowView = Views.createTestView();
106 
107         mActions = new TestActionHandler(mEnv);
108 
109         mClipper = new TestDocumentClipper();
110         mDetails = new TestSelectionDetails();
111         mDetails.canDelete = true;
112         ClipDescription description = new ClipDescription("", new String[]{});
113         description.setExtras(new PersistableBundle());
114         mClipData = ClipDatas.createTestClipData(description);
115         mClipper.nextClip = mClipData;
116 
117         mDefaultIcon = new TestDrawable();
118         mIconHelper = TestIconHelper.create();
119         mIconHelper.nextDocumentIcon = new TestDrawable();
120 
121         mStartDragListener = new TestEventListener<>();
122         mShadowUpdateListener = new TestEventListener<>();
123         mCallbackListener = new TestEventListener<>();
124         mFlagListener = new TestEventListener<>();
125 
126         mManager = new RuntimeDragAndDropManager(mActivity, mClipper, mShadowBuilder,
127                 mDefaultIcon) {
128             @Override
129             void startDragAndDrop(View v, ClipData clipData, DragShadowBuilder builder,
130                     Object localState, int flag) {
131                 assertSame(mStartDragView, v);
132                 assertSame(mShadowBuilder, builder);
133                 assertNotNull(localState);
134 
135                 mFlagListener.accept(flag);
136                 mStartDragListener.accept(clipData);
137             }
138 
139             @Override
140             void updateDragShadow(View v) {
141                 assertSame(mUpdateShadowView, v);
142 
143                 mShadowUpdateListener.accept(null);
144             }
145         };
146     }
147 
148     @Test
testStartDrag_SetsCorrectClipData()149     public void testStartDrag_SetsCorrectClipData() {
150         mManager.startDrag(
151                 mStartDragView,
152                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
153                 TestProvidersAccess.HOME,
154                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
155                         TestEnv.FILE_JPG.derivedUri),
156                 mDetails,
157                 mIconHelper,
158                 TestEnv.FOLDER_0);
159 
160         mStartDragListener.assertLastArgument(mClipper.nextClip);
161     }
162 
163     @Test
testStartDrag_SetsCorrectClipData_NullParent()164     public void testStartDrag_SetsCorrectClipData_NullParent() {
165         mManager.startDrag(
166                 mStartDragView,
167                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
168                 TestProvidersAccess.HOME,
169                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
170                         TestEnv.FILE_JPG.derivedUri),
171                 mDetails,
172                 mIconHelper,
173                 null);
174 
175         mStartDragListener.assertLastArgument(mClipper.nextClip);
176     }
177 
178     @Test
testStartDrag_BuildsCorrectShadow_SingleDoc()179     public void testStartDrag_BuildsCorrectShadow_SingleDoc() {
180         mManager.startDrag(
181                 mStartDragView,
182                 Arrays.asList(TestEnv.FILE_APK),
183                 TestProvidersAccess.HOME,
184                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri),
185                 mDetails,
186                 mIconHelper,
187                 TestEnv.FOLDER_0);
188 
189         mShadowBuilder.title.assertLastArgument(TestEnv.FILE_APK.displayName);
190         mShadowBuilder.icon.assertLastArgument(mIconHelper.nextDocumentIcon);
191     }
192 
193     @Test
testStartDrag_BuildsCorrectShadow_MultipleDocs()194     public void testStartDrag_BuildsCorrectShadow_MultipleDocs() {
195         mManager.startDrag(
196                 mStartDragView,
197                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
198                 TestProvidersAccess.HOME,
199                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
200                         TestEnv.FILE_JPG.derivedUri),
201                 mDetails,
202                 mIconHelper,
203                 TestEnv.FOLDER_0);
204 
205         mShadowBuilder.title.assertLastArgument(mActivity.getResources().getQuantityString(
206                 R.plurals.elements_dragged, 2, 2));
207         mShadowBuilder.icon.assertLastArgument(mDefaultIcon);
208     }
209 
210     @Test
testCanSpringOpen_ReturnsFalse_RootNotSupportCreate()211     public void testCanSpringOpen_ReturnsFalse_RootNotSupportCreate() {
212         mManager.startDrag(
213                 mStartDragView,
214                 Arrays.asList(TestEnv.FOLDER_1, TestEnv.FILE_JPG),
215                 TestProvidersAccess.HOME,
216                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FOLDER_1.derivedUri,
217                         TestEnv.FILE_JPG.derivedUri),
218                 mDetails,
219                 mIconHelper,
220                 TestEnv.FOLDER_0);
221 
222         assertFalse(mManager.canSpringOpen(TestProvidersAccess.HAMMY, TestEnv.FOLDER_2));
223     }
224 
225     @Test
testInArchiveUris_HasCorrectFlagPermission()226     public void testInArchiveUris_HasCorrectFlagPermission() {
227         mDetails.containsFilesInArchive = true;
228         mManager.startDrag(
229                 mStartDragView,
230                 Arrays.asList(TestEnv.FILE_IN_ARCHIVE),
231                 TestProvidersAccess.HOME,
232                 Arrays.asList(TestEnv.FILE_ARCHIVE.derivedUri, TestEnv.FILE_IN_ARCHIVE.derivedUri),
233                 mDetails,
234                 mIconHelper,
235                 TestEnv.FILE_ARCHIVE);
236 
237         mFlagListener.assertLastArgument(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE);
238     }
239 
240     @Test
testCanSpringOpen_ReturnsFalse_DocIsInvalidDestination()241     public void testCanSpringOpen_ReturnsFalse_DocIsInvalidDestination() {
242         mManager.startDrag(
243                 mStartDragView,
244                 Arrays.asList(TestEnv.FOLDER_1, TestEnv.FILE_JPG),
245                 TestProvidersAccess.HOME,
246                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FOLDER_1.derivedUri,
247                         TestEnv.FILE_JPG.derivedUri),
248                 mDetails,
249                 mIconHelper,
250                 TestEnv.FOLDER_0);
251 
252         assertFalse(mManager.canSpringOpen(TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1));
253     }
254 
255     @Test
testCanSpringOpen()256     public void testCanSpringOpen() {
257         mManager.startDrag(
258                 mStartDragView,
259                 Arrays.asList(TestEnv.FOLDER_1, TestEnv.FILE_JPG),
260                 TestProvidersAccess.HOME,
261                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FOLDER_1.derivedUri,
262                         TestEnv.FILE_JPG.derivedUri),
263                 mDetails,
264                 mIconHelper,
265                 TestEnv.FOLDER_0);
266 
267         assertTrue(mManager.canSpringOpen(TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_2));
268     }
269 
270     @Test
testDefaultToUnknownState()271     public void testDefaultToUnknownState() {
272         mManager.startDrag(
273                 mStartDragView,
274                 Arrays.asList(TestEnv.FOLDER_1, TestEnv.FILE_JPG),
275                 TestProvidersAccess.HOME,
276                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FOLDER_1.derivedUri,
277                         TestEnv.FILE_JPG.derivedUri),
278                 mDetails,
279                 mIconHelper,
280                 TestEnv.FOLDER_0);
281 
282         mShadowBuilder.state.assertLastArgument(DragAndDropManager.STATE_UNKNOWN);
283     }
284 
285     @Test
testUpdateStateToNotAllowed()286     public void testUpdateStateToNotAllowed() {
287         mManager.startDrag(
288                 mStartDragView,
289                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
290                 TestProvidersAccess.HOME,
291                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
292                         TestEnv.FILE_JPG.derivedUri),
293                 mDetails,
294                 mIconHelper,
295                 TestEnv.FOLDER_0);
296 
297         mManager.updateStateToNotAllowed(mUpdateShadowView);
298 
299         assertStateUpdated(DragAndDropManager.STATE_NOT_ALLOWED);
300     }
301 
302     @Test
testUpdateState_UpdatesToNotAllowed_RootNotSupportCreate()303     public void testUpdateState_UpdatesToNotAllowed_RootNotSupportCreate() {
304         mManager.startDrag(
305                 mStartDragView,
306                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
307                 TestProvidersAccess.HOME,
308                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
309                         TestEnv.FILE_JPG.derivedUri),
310                 mDetails,
311                 mIconHelper,
312                 TestEnv.FOLDER_0);
313 
314         final @State int state = mManager.updateState(
315                 mUpdateShadowView, TestProvidersAccess.HAMMY, TestEnv.FOLDER_2);
316 
317         assertEquals(DragAndDropManager.STATE_NOT_ALLOWED, state);
318         assertStateUpdated(DragAndDropManager.STATE_NOT_ALLOWED);
319     }
320 
321     @Test
testUpdateState_UpdatesToUnknown_RootDocIsNull()322     public void testUpdateState_UpdatesToUnknown_RootDocIsNull() {
323         mManager.startDrag(
324                 mStartDragView,
325                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
326                 TestProvidersAccess.HOME,
327                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
328                         TestEnv.FILE_JPG.derivedUri),
329                 mDetails,
330                 mIconHelper,
331                 TestEnv.FOLDER_0);
332 
333         final @State int state = mManager.updateState(
334                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, null);
335 
336         assertEquals(DragAndDropManager.STATE_UNKNOWN, state);
337         assertStateUpdated(DragAndDropManager.STATE_UNKNOWN);
338     }
339 
340     @Test
testUpdateState_UpdatesToMove_SameRoot()341     public void testUpdateState_UpdatesToMove_SameRoot() {
342         mManager.startDrag(
343                 mStartDragView,
344                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
345                 TestProvidersAccess.DOWNLOADS,
346                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
347                         TestEnv.FILE_JPG.derivedUri),
348                 mDetails,
349                 mIconHelper,
350                 TestEnv.FOLDER_0);
351 
352         final @State int state = mManager.updateState(
353                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
354 
355         assertEquals(DragAndDropManager.STATE_MOVE, state);
356         assertStateUpdated(DragAndDropManager.STATE_MOVE);
357     }
358 
359     @Test
testUpdateState_UpdatesToCopy_DifferentRoot()360     public void testUpdateState_UpdatesToCopy_DifferentRoot() {
361         mManager.startDrag(
362                 mStartDragView,
363                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
364                 TestProvidersAccess.HOME,
365                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
366                         TestEnv.FILE_JPG.derivedUri),
367                 mDetails,
368                 mIconHelper,
369                 TestEnv.FOLDER_0);
370 
371         final @State int state = mManager.updateState(
372                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
373 
374         assertEquals(DragAndDropManager.STATE_COPY, state);
375         assertStateUpdated(DragAndDropManager.STATE_COPY);
376     }
377 
378     @Test
testUpdateState_UpdatesToCopy_SameRoot_LeftCtrlPressed()379     public void testUpdateState_UpdatesToCopy_SameRoot_LeftCtrlPressed() {
380         mManager.startDrag(
381                 mStartDragView,
382                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
383                 TestProvidersAccess.DOWNLOADS,
384                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
385                         TestEnv.FILE_JPG.derivedUri),
386                 mDetails,
387                 mIconHelper,
388                 TestEnv.FOLDER_0);
389 
390         KeyEvent event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_DOWN);
391         mManager.onKeyEvent(event);
392 
393         final @State int state = mManager.updateState(
394                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
395 
396         assertEquals(DragAndDropManager.STATE_COPY, state);
397         assertStateUpdated(DragAndDropManager.STATE_COPY);
398     }
399 
400     @Test
testIsDragFromSameApp_afterStartDrag()401     public void testIsDragFromSameApp_afterStartDrag() {
402         mManager.startDrag(
403                 mStartDragView,
404                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
405                 TestProvidersAccess.DOWNLOADS,
406                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
407                         TestEnv.FILE_JPG.derivedUri),
408                 mDetails,
409                 mIconHelper,
410                 TestEnv.FOLDER_0);
411 
412         assertTrue(mManager.isDragFromSameApp());
413     }
414 
415     @Test
testIsDragFromSameApp_beforeStartDrag()416     public void testIsDragFromSameApp_beforeStartDrag() {
417         assertFalse(mManager.isDragFromSameApp());
418     }
419 
420     @Test
testIsDragFromSameApp_afterStartDrag_afterDragEnded()421     public void testIsDragFromSameApp_afterStartDrag_afterDragEnded() {
422         mManager.startDrag(
423                 mStartDragView,
424                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
425                 TestProvidersAccess.DOWNLOADS,
426                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
427                         TestEnv.FILE_JPG.derivedUri),
428                 mDetails,
429                 mIconHelper,
430                 TestEnv.FOLDER_0);
431         assertTrue(mManager.isDragFromSameApp());
432 
433         mManager.dragEnded();
434         assertFalse(mManager.isDragFromSameApp());
435     }
436 
437 
438     @Test
testUpdateState_UpdatesToCopy_SameRoot_RightCtrlPressed()439     public void testUpdateState_UpdatesToCopy_SameRoot_RightCtrlPressed() {
440         mManager.startDrag(
441                 mStartDragView,
442                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
443                 TestProvidersAccess.DOWNLOADS,
444                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
445                         TestEnv.FILE_JPG.derivedUri),
446                 mDetails,
447                 mIconHelper,
448                 TestEnv.FOLDER_0);
449 
450         KeyEvent event = KeyEvents.createRightCtrlKey(KeyEvent.ACTION_DOWN);
451         mManager.onKeyEvent(event);
452 
453         final @State int state = mManager.updateState(
454                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
455 
456         assertEquals(DragAndDropManager.STATE_COPY, state);
457         assertStateUpdated(DragAndDropManager.STATE_COPY);
458     }
459 
460     @Test
testUpdateState_UpdatesToMove_DifferentRoot_LeftCtrlPressed()461     public void testUpdateState_UpdatesToMove_DifferentRoot_LeftCtrlPressed() {
462         mManager.startDrag(
463                 mStartDragView,
464                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
465                 TestProvidersAccess.HOME,
466                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
467                         TestEnv.FILE_JPG.derivedUri),
468                 mDetails,
469                 mIconHelper,
470                 TestEnv.FOLDER_0);
471 
472         KeyEvent event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_DOWN);
473         mManager.onKeyEvent(event);
474 
475         final @State int state = mManager.updateState(
476                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
477 
478         assertEquals(DragAndDropManager.STATE_MOVE, state);
479         assertStateUpdated(DragAndDropManager.STATE_MOVE);
480     }
481 
482     @Test
testUpdateState_UpdatesToMove_DifferentRoot_RightCtrlPressed()483     public void testUpdateState_UpdatesToMove_DifferentRoot_RightCtrlPressed() {
484         mManager.startDrag(
485                 mStartDragView,
486                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
487                 TestProvidersAccess.HOME,
488                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
489                         TestEnv.FILE_JPG.derivedUri),
490                 mDetails,
491                 mIconHelper,
492                 TestEnv.FOLDER_0);
493 
494         KeyEvent event = KeyEvents.createRightCtrlKey(KeyEvent.ACTION_DOWN);
495         mManager.onKeyEvent(event);
496 
497         final @State int state = mManager.updateState(
498                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
499 
500         assertEquals(DragAndDropManager.STATE_MOVE, state);
501         assertStateUpdated(DragAndDropManager.STATE_MOVE);
502     }
503 
504     @Test
testUpdateState_UpdatesToMove_SameRoot_LeftCtrlReleased()505     public void testUpdateState_UpdatesToMove_SameRoot_LeftCtrlReleased() {
506         mManager.startDrag(
507                 mStartDragView,
508                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
509                 TestProvidersAccess.DOWNLOADS,
510                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
511                         TestEnv.FILE_JPG.derivedUri),
512                 mDetails,
513                 mIconHelper,
514                 TestEnv.FOLDER_0);
515 
516         KeyEvent event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_DOWN);
517         mManager.onKeyEvent(event);
518 
519         event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_UP);
520         mManager.onKeyEvent(event);
521 
522         final @State int state = mManager.updateState(
523                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
524 
525         assertEquals(DragAndDropManager.STATE_MOVE, state);
526         assertStateUpdated(DragAndDropManager.STATE_MOVE);
527     }
528 
529     @Test
testUpdateState_UpdatesToMove_SameRoot_RightCtrlReleased()530     public void testUpdateState_UpdatesToMove_SameRoot_RightCtrlReleased() {
531         mManager.startDrag(
532                 mStartDragView,
533                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
534                 TestProvidersAccess.DOWNLOADS,
535                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
536                         TestEnv.FILE_JPG.derivedUri),
537                 mDetails,
538                 mIconHelper,
539                 TestEnv.FOLDER_0);
540 
541         KeyEvent event = KeyEvents.createRightCtrlKey(KeyEvent.ACTION_DOWN);
542         mManager.onKeyEvent(event);
543 
544         event = KeyEvents.createRightCtrlKey(KeyEvent.ACTION_UP);
545         mManager.onKeyEvent(event);
546 
547         final @State int state = mManager.updateState(
548                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
549 
550         assertEquals(DragAndDropManager.STATE_MOVE, state);
551         assertStateUpdated(DragAndDropManager.STATE_MOVE);
552     }
553 
554     @Test
testUpdateState_UpdatesToCopy_DifferentRoot_LeftCtrlReleased()555     public void testUpdateState_UpdatesToCopy_DifferentRoot_LeftCtrlReleased() {
556         mManager.startDrag(
557                 mStartDragView,
558                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
559                 TestProvidersAccess.HOME,
560                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
561                         TestEnv.FILE_JPG.derivedUri),
562                 mDetails,
563                 mIconHelper,
564                 TestEnv.FOLDER_0);
565 
566         KeyEvent event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_DOWN);
567         mManager.onKeyEvent(event);
568 
569         event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_UP);
570         mManager.onKeyEvent(event);
571 
572         final @State int state = mManager.updateState(
573                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
574 
575         assertEquals(DragAndDropManager.STATE_COPY, state);
576         assertStateUpdated(DragAndDropManager.STATE_COPY);
577     }
578 
579     @Test
testUpdateState_UpdatesToCopy_DifferentRoot_RightCtrlReleased()580     public void testUpdateState_UpdatesToCopy_DifferentRoot_RightCtrlReleased() {
581         mManager.startDrag(
582                 mStartDragView,
583                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
584                 TestProvidersAccess.HOME,
585                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
586                         TestEnv.FILE_JPG.derivedUri),
587                 mDetails,
588                 mIconHelper,
589                 TestEnv.FOLDER_0);
590 
591         KeyEvent event = KeyEvents.createRightCtrlKey(KeyEvent.ACTION_DOWN);
592         mManager.onKeyEvent(event);
593 
594         event = KeyEvents.createRightCtrlKey(KeyEvent.ACTION_UP);
595         mManager.onKeyEvent(event);
596 
597         final @State int state = mManager.updateState(
598                 mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
599 
600         assertEquals(DragAndDropManager.STATE_COPY, state);
601         assertStateUpdated(DragAndDropManager.STATE_COPY);
602     }
603 
604     @Test
testResetState_UpdatesToUnknown()605     public void testResetState_UpdatesToUnknown() {
606         mManager.startDrag(
607                 mStartDragView,
608                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
609                 TestProvidersAccess.HOME,
610                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
611                         TestEnv.FILE_JPG.derivedUri),
612                 mDetails,
613                 mIconHelper,
614                 TestEnv.FOLDER_0);
615 
616         mManager.updateStateToNotAllowed(mUpdateShadowView);
617 
618         mManager.resetState(mUpdateShadowView);
619 
620         assertStateUpdated(DragAndDropManager.STATE_UNKNOWN);
621     }
622 
623     @Test
testDrop_Rejects_RootNotSupportCreate_DropOnRoot()624     public void testDrop_Rejects_RootNotSupportCreate_DropOnRoot() {
625         mManager.startDrag(
626                 mStartDragView,
627                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
628                 TestProvidersAccess.HOME,
629                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
630                         TestEnv.FILE_JPG.derivedUri),
631                 mDetails,
632                 mIconHelper,
633                 TestEnv.FOLDER_0);
634 
635         mManager.updateState(mUpdateShadowView, TestProvidersAccess.HAMMY, TestEnv.FOLDER_1);
636 
637         assertFalse(mManager.drop(
638                 mClipData, mManager, TestProvidersAccess.HAMMY, mActions, mCallback));
639     }
640 
641     @Test
testDrop_Rejects_InvalidRoot()642     public void testDrop_Rejects_InvalidRoot() {
643         RootInfo root = new RootInfo();
644         root.authority = TestProvidersAccess.HOME.authority;
645         root.documentId = TestEnv.FOLDER_0.documentId;
646 
647         mManager.startDrag(
648                 mStartDragView,
649                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
650                 root,
651                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
652                         TestEnv.FILE_JPG.derivedUri),
653                 mDetails,
654                 mIconHelper,
655                 TestEnv.FOLDER_0);
656 
657         mManager.updateState(mUpdateShadowView, TestProvidersAccess.HOME, TestEnv.FOLDER_0);
658 
659         assertFalse(mManager.drop(mClipData, mManager, root, mActions, mCallback));
660     }
661 
662     @Test
testDrop_Fails_NotGetRootDoc()663     public void testDrop_Fails_NotGetRootDoc() throws Exception {
664         mManager.startDrag(
665                 mStartDragView,
666                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
667                 TestProvidersAccess.HOME,
668                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
669                         TestEnv.FILE_JPG.derivedUri),
670                 mDetails,
671                 mIconHelper,
672                 TestEnv.FOLDER_0);
673 
674         mManager.updateState(mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
675 
676         mManager.drop(
677                 mClipData, mManager, TestProvidersAccess.DOWNLOADS, mActions, mCallback);
678 
679         mEnv.beforeAsserts();
680         mCallbackListener.assertLastArgument(FileOperations.Callback.STATUS_FAILED);
681     }
682 
683     @Test
testDrop_Copies_DifferentRoot_DropOnRoot()684     public void testDrop_Copies_DifferentRoot_DropOnRoot() throws Exception {
685         mActions.nextRootDocument = TestEnv.FOLDER_1;
686 
687         mManager.startDrag(
688                 mStartDragView,
689                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
690                 TestProvidersAccess.HOME,
691                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
692                         TestEnv.FILE_JPG.derivedUri),
693                 mDetails,
694                 mIconHelper,
695                 TestEnv.FOLDER_0);
696 
697         mManager.updateState(mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
698 
699         mManager.drop(
700                 mClipData, mManager, TestProvidersAccess.DOWNLOADS, mActions, mCallback);
701 
702         mEnv.beforeAsserts();
703         final DocumentStack expect =
704                 new DocumentStack(TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
705         mClipper.copyFromClip.assertLastArgument(Pair.create(expect, mClipData));
706         mClipper.opType.assertLastArgument(FileOperationService.OPERATION_COPY);
707     }
708 
709     @Test
testDrop_Moves_SameRoot_DropOnRoot()710     public void testDrop_Moves_SameRoot_DropOnRoot() throws Exception {
711         mActions.nextRootDocument = TestEnv.FOLDER_1;
712 
713         mManager.startDrag(
714                 mStartDragView,
715                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
716                 TestProvidersAccess.DOWNLOADS,
717                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
718                         TestEnv.FILE_JPG.derivedUri),
719                 mDetails,
720                 mIconHelper,
721                 TestEnv.FOLDER_0);
722 
723         mManager.updateState(mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
724 
725         mManager.drop(
726                 mClipData, mManager, TestProvidersAccess.DOWNLOADS, mActions, mCallback);
727 
728         mEnv.beforeAsserts();
729         final DocumentStack expect =
730                 new DocumentStack(TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
731         mClipper.copyFromClip.assertLastArgument(Pair.create(expect, mClipData));
732         mClipper.opType.assertLastArgument(FileOperationService.OPERATION_MOVE);
733     }
734 
735     @Test
testDrop_Copies_SameRoot_DropOnRoot_ReleasesCtrlBeforeGettingRootDocument()736     public void testDrop_Copies_SameRoot_DropOnRoot_ReleasesCtrlBeforeGettingRootDocument()
737             throws Exception{
738         mActions.nextRootDocument = TestEnv.FOLDER_1;
739 
740         mManager.startDrag(
741                 mStartDragView,
742                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
743                 TestProvidersAccess.DOWNLOADS,
744                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
745                         TestEnv.FILE_JPG.derivedUri),
746                 mDetails,
747                 mIconHelper,
748                 TestEnv.FOLDER_0);
749 
750         KeyEvent event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_DOWN);
751         mManager.onKeyEvent(event);
752 
753         mManager.updateState(mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
754 
755         mManager.drop(
756                 mClipData, mManager, TestProvidersAccess.DOWNLOADS, mActions, mCallback);
757 
758         event = KeyEvents.createLeftCtrlKey(KeyEvent.ACTION_UP);
759         mManager.onKeyEvent(event);
760 
761         mEnv.beforeAsserts();
762         final DocumentStack expect =
763                 new DocumentStack(TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1);
764         mClipper.copyFromClip.assertLastArgument(Pair.create(expect, mClipData));
765         mClipper.opType.assertLastArgument(FileOperationService.OPERATION_COPY);
766     }
767 
768     @Test
testDrop_Rejects_RootNotSupportCreate_DropOnDocument()769     public void testDrop_Rejects_RootNotSupportCreate_DropOnDocument() {
770         mManager.startDrag(
771                 mStartDragView,
772                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
773                 TestProvidersAccess.HOME,
774                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
775                         TestEnv.FILE_JPG.derivedUri),
776                 mDetails,
777                 mIconHelper,
778                 TestEnv.FOLDER_0);
779 
780         mManager.updateState(mUpdateShadowView, TestProvidersAccess.HAMMY, TestEnv.FOLDER_2);
781 
782         final DocumentStack stack = new DocumentStack(
783                 TestProvidersAccess.HAMMY, TestEnv.FOLDER_1, TestEnv.FOLDER_2);
784         assertFalse(mManager.drop(mClipData, mManager, stack, mCallback));
785     }
786 
787     @Test
testDrop_Copies_DifferentRoot_DropOnDocument()788     public void testDrop_Copies_DifferentRoot_DropOnDocument() {
789         mManager.startDrag(
790                 mStartDragView,
791                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
792                 TestProvidersAccess.HOME,
793                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
794                         TestEnv.FILE_JPG.derivedUri),
795                 mDetails,
796                 mIconHelper,
797                 TestEnv.FOLDER_0);
798 
799         mManager.updateState(mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_2);
800 
801         final DocumentStack stack = new DocumentStack(
802                 TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1, TestEnv.FOLDER_2);
803         assertTrue(mManager.drop(mClipData, mManager, stack, mCallback));
804 
805         mClipper.copyFromClip.assertLastArgument(Pair.create(stack, mClipData));
806         mClipper.opType.assertLastArgument(FileOperationService.OPERATION_COPY);
807     }
808 
809     @Test
testDrop_Moves_SameRoot_DropOnDocument()810     public void testDrop_Moves_SameRoot_DropOnDocument() {
811         mManager.startDrag(
812                 mStartDragView,
813                 Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG),
814                 TestProvidersAccess.DOWNLOADS,
815                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri,
816                         TestEnv.FILE_JPG.derivedUri),
817                 mDetails,
818                 mIconHelper,
819                 TestEnv.FOLDER_0);
820 
821         mManager.updateState(mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_2);
822 
823         final DocumentStack stack = new DocumentStack(
824                 TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1, TestEnv.FOLDER_2);
825         assertTrue(mManager.drop(mClipData, mManager, stack, mCallback));
826 
827         mClipper.copyFromClip.assertLastArgument(Pair.create(stack, mClipData));
828         mClipper.opType.assertLastArgument(FileOperationService.OPERATION_MOVE);
829     }
830 
831     @Test
testDrop_Copies_SameRoot_ReadOnlyFile_DropOnDocument()832     public void testDrop_Copies_SameRoot_ReadOnlyFile_DropOnDocument() {
833         mDetails.canDelete = false;
834         mManager.startDrag(
835                 mStartDragView,
836                 Arrays.asList(TestEnv.FILE_READ_ONLY),
837                 TestProvidersAccess.DOWNLOADS,
838                 Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_READ_ONLY.derivedUri),
839                 mDetails,
840                 mIconHelper,
841                 TestEnv.FOLDER_0);
842 
843         mManager.updateState(mUpdateShadowView, TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_2);
844 
845         final DocumentStack stack = new DocumentStack(
846                 TestProvidersAccess.DOWNLOADS, TestEnv.FOLDER_1, TestEnv.FOLDER_2);
847         assertTrue(mManager.drop(mClipData, mManager, stack, mCallback));
848 
849         mClipper.copyFromClip.assertLastArgument(Pair.create(stack, mClipData));
850         mClipper.opType.assertLastArgument(FileOperationService.OPERATION_COPY);
851     }
852 
assertStateUpdated(@tate int expected)853     private void assertStateUpdated(@State int expected) {
854         mShadowBuilder.state.assertLastArgument(expected);
855         mShadowUpdateListener.assertCalled();
856     }
857 
858     public static class TestDragShadowBuilder extends DragShadowBuilder {
859 
860         public TestEventListener<String> title;
861         public TestEventListener<Drawable> icon;
862         public TestEventListener<Integer> state;
863 
TestDragShadowBuilder()864         private TestDragShadowBuilder() {
865             super(null);
866         }
867 
868         @Override
updateTitle(String title)869         void updateTitle(String title) {
870             this.title.accept(title);
871         }
872 
873         @Override
updateIcon(Drawable icon)874         void updateIcon(Drawable icon) {
875             this.icon.accept(icon);
876         }
877 
878         @Override
onStateUpdated(@tate int state)879         void onStateUpdated(@State int state) {
880             this.state.accept(state);
881         }
882 
create()883         public static TestDragShadowBuilder create() {
884             TestDragShadowBuilder builder =
885                     Mockito.mock(TestDragShadowBuilder.class, Mockito.CALLS_REAL_METHODS);
886 
887             builder.title = new TestEventListener<>();
888             builder.icon = new TestEventListener<>();
889             builder.state = new TestEventListener<>();
890 
891             return builder;
892         }
893     }
894 }
895