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.dirlist; 18 19 import static com.android.documentsui.base.SharedMinimal.DEBUG; 20 21 import android.app.Activity; 22 import android.content.ClipData; 23 import android.util.Log; 24 import android.view.DragEvent; 25 import android.view.View; 26 27 import androidx.recyclerview.selection.SelectionTracker; 28 29 import com.android.documentsui.AbstractActionHandler; 30 import com.android.documentsui.AbstractDragHost; 31 import com.android.documentsui.ActionHandler; 32 import com.android.documentsui.DragAndDropManager; 33 import com.android.documentsui.Metrics; 34 import com.android.documentsui.R; 35 import com.android.documentsui.base.DocumentInfo; 36 import com.android.documentsui.base.DocumentStack; 37 import com.android.documentsui.base.Lookup; 38 import com.android.documentsui.base.State; 39 import com.android.documentsui.ui.DialogController; 40 41 import com.google.android.material.snackbar.Snackbar; 42 43 import java.util.function.Predicate; 44 45 /** 46 * Drag host for items in {@link DirectoryFragment}. 47 */ 48 class DragHost<T extends Activity & AbstractActionHandler.CommonAddons> extends AbstractDragHost { 49 50 private static final String TAG = "dirlist.DragHost"; 51 52 private final T mActivity; 53 private final SelectionTracker<String> mSelectionMgr; 54 private final ActionHandler mActions; 55 private final State mState; 56 private final DialogController mDialogs; 57 private final Predicate<View> mIsDocumentView; 58 private final Lookup<View, DocumentHolder> mHolderLookup; 59 private final Lookup<View, DocumentInfo> mDestinationLookup; 60 DragHost( T activity, DragAndDropManager dragAndDropManager, SelectionTracker<String> selectionMgr, ActionHandler actions, State state, DialogController dialogs, Predicate<View> isDocumentView, Lookup<View, DocumentHolder> holderLookup, Lookup<View, DocumentInfo> destinationLookup)61 DragHost( 62 T activity, 63 DragAndDropManager dragAndDropManager, 64 SelectionTracker<String> selectionMgr, 65 ActionHandler actions, 66 State state, 67 DialogController dialogs, 68 Predicate<View> isDocumentView, 69 Lookup<View, DocumentHolder> holderLookup, 70 Lookup<View, DocumentInfo> destinationLookup) { 71 super(dragAndDropManager); 72 73 mActivity = activity; 74 mSelectionMgr = selectionMgr; 75 mActions = actions; 76 mState = state; 77 mDialogs = dialogs; 78 mIsDocumentView = isDocumentView; 79 mHolderLookup = holderLookup; 80 mDestinationLookup = destinationLookup; 81 } 82 dragStopped(boolean result)83 void dragStopped(boolean result) { 84 if (result) { 85 mSelectionMgr.clearSelection(); 86 } 87 } 88 89 @Override runOnUiThread(Runnable runnable)90 public void runOnUiThread(Runnable runnable) { 91 mActivity.runOnUiThread(runnable); 92 } 93 94 @Override setDropTargetHighlight(View v, boolean highlight)95 public void setDropTargetHighlight(View v, boolean highlight) { 96 } 97 98 @Override onViewHovered(View v)99 public void onViewHovered(View v) { 100 if (mIsDocumentView.test(v)) { 101 mActions.springOpenDirectory(mDestinationLookup.lookup(v)); 102 } 103 mActivity.setRootsDrawerOpen(false); 104 } 105 106 @Override onDragEntered(View v)107 public void onDragEntered(View v) { 108 mActivity.setRootsDrawerOpen(false); 109 mDragAndDropManager.updateState(v, mState.stack.getRoot(), mDestinationLookup.lookup(v)); 110 } 111 112 @Override canHandleDragEvent(View v)113 public boolean canHandleDragEvent(View v) { 114 boolean dragInitiatedFromDocsUI = mDragAndDropManager.isDragFromSameApp(); 115 Metrics.logDragInitiated(dragInitiatedFromDocsUI); 116 if (!dragInitiatedFromDocsUI) { 117 Snackbar.make( 118 v, R.string.drag_from_another_app, Snackbar.LENGTH_LONG).show(); 119 return false; 120 } 121 return true; 122 } 123 canSpringOpen(View v)124 boolean canSpringOpen(View v) { 125 DocumentInfo doc = mDestinationLookup.lookup(v); 126 return (doc != null) && mDragAndDropManager.canSpringOpen(mState.stack.getRoot(), doc); 127 } 128 handleDropEvent(View v, DragEvent event)129 boolean handleDropEvent(View v, DragEvent event) { 130 mActivity.setRootsDrawerOpen(false); 131 132 ClipData clipData = event.getClipData(); 133 assert (clipData != null); 134 135 DocumentInfo dst = mDestinationLookup.lookup(v); 136 if (dst == null) { 137 if (DEBUG) { 138 Log.d(TAG, "Invalid destination. Ignoring."); 139 } 140 return false; 141 } 142 143 // If destination is already at top of stack, no need to pass it in 144 DocumentStack dstStack = dst.equals(mState.stack.peek()) 145 ? mState.stack 146 : new DocumentStack(mState.stack, dst); 147 return mDragAndDropManager.drop(event.getClipData(), event.getLocalState(), dstStack, 148 mDialogs::showFileOperationStatus); 149 } 150 } 151