Merge "Check for droppability when dropping onto Roots." into arc-apps
diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java
index cde116b..76f6812 100644
--- a/src/com/android/documentsui/AbstractActionHandler.java
+++ b/src/com/android/documentsui/AbstractActionHandler.java
@@ -20,7 +20,6 @@
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
 
 import android.app.Activity;
-import android.content.ClipData;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.database.Cursor;
@@ -29,6 +28,7 @@
 import android.provider.DocumentsContract;
 import android.support.annotation.VisibleForTesting;
 import android.util.Log;
+import android.view.DragEvent;
 
 import com.android.documentsui.AbstractActionHandler.CommonAddons;
 import com.android.documentsui.LoadDocStackTask.LoadDocStackCallback;
@@ -40,10 +40,9 @@
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.AnimationView.AnimationType;
 import com.android.documentsui.dirlist.AnimationView;
+import com.android.documentsui.dirlist.AnimationView.AnimationType;
 import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.dirlist.DocumentsAdapter;
 import com.android.documentsui.dirlist.FocusHandler;
 import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.files.LauncherActivity;
@@ -58,7 +57,6 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
-import java.util.function.Consumer;
 
 import javax.annotation.Nullable;
 
@@ -181,7 +179,7 @@
     }
 
     @Override
-    public boolean dropOn(ClipData data, RootInfo root) {
+    public boolean dropOn(DragEvent event, RootInfo root) {
         throw new UnsupportedOperationException("Can't open an app.");
     }
 
diff --git a/src/com/android/documentsui/ActionHandler.java b/src/com/android/documentsui/ActionHandler.java
index 0df824f..7b0eef4 100644
--- a/src/com/android/documentsui/ActionHandler.java
+++ b/src/com/android/documentsui/ActionHandler.java
@@ -16,10 +16,11 @@
 
 package com.android.documentsui;
 
-import android.content.ClipData;
+import android.content.ContentProvider;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
+import android.view.DragEvent;
 
 import com.android.documentsui.base.BooleanConsumer;
 import com.android.documentsui.base.DocumentInfo;
@@ -37,7 +38,7 @@
     /**
      * Drops documents on a root.
      */
-    boolean dropOn(ClipData data, RootInfo root);
+    boolean dropOn(DragEvent event, RootInfo root);
 
     /**
      * Attempts to eject the identified root. Returns a boolean answer to listener.
diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java
index 602446a..921a3ed 100644
--- a/src/com/android/documentsui/files/ActionHandler.java
+++ b/src/com/android/documentsui/files/ActionHandler.java
@@ -21,21 +21,20 @@
 
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
-import android.content.ClipData;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.net.Uri;
 import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Root;
-import android.provider.DocumentsContract.Document;
 import android.util.Log;
+import android.view.DragEvent;
 
 import com.android.documentsui.AbstractActionHandler;
 import com.android.documentsui.ActionModeAddons;
 import com.android.documentsui.ActivityConfig;
 import com.android.documentsui.DocumentsAccess;
 import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.DragAndDropHelper;
 import com.android.documentsui.Injector;
 import com.android.documentsui.Metrics;
 import com.android.documentsui.R;
@@ -53,14 +52,12 @@
 import com.android.documentsui.clipping.UrisSupplier;
 import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.dirlist.FocusHandler;
 import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.files.ActionHandler.Addons;
 import com.android.documentsui.queries.SearchViewManager;
 import com.android.documentsui.roots.GetRootDocumentTask;
 import com.android.documentsui.roots.RootsAccess;
 import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionManager;
 import com.android.documentsui.services.FileOperation;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperations;
@@ -109,17 +106,25 @@
     }
 
     @Override
-    public boolean dropOn(ClipData data, RootInfo root) {
+    public boolean dropOn(DragEvent event, RootInfo root) {
         new GetRootDocumentTask(
                 root,
                 mActivity,
                 mActivity::isDestroyed,
-                (DocumentInfo doc) -> mClipper.copyFromClipData(
-                        root, doc, data, mDialogs::showFileOperationStatus)
+                (DocumentInfo rootDoc) -> dropOnCallback(event, rootDoc, root)
         ).executeOnExecutor(mExecutors.lookup(root.authority));
         return true;
     }
 
+    private void dropOnCallback(DragEvent event, DocumentInfo rootDoc, RootInfo root) {
+        if (!DragAndDropHelper.canCopyTo(event.getLocalState(), rootDoc)) {
+            return;
+        }
+
+        mClipper.copyFromClipData(
+                root, rootDoc, event.getClipData(), mDialogs::showFileOperationStatus);
+    }
+
     @Override
     public void openSelectedInNewWindow() {
         Selection selection = getStableSelection();
diff --git a/src/com/android/documentsui/sidebar/Item.java b/src/com/android/documentsui/sidebar/Item.java
index 077385f..3b550e6 100644
--- a/src/com/android/documentsui/sidebar/Item.java
+++ b/src/com/android/documentsui/sidebar/Item.java
@@ -17,8 +17,7 @@
 package com.android.documentsui.sidebar;
 
 import android.annotation.LayoutRes;
-import android.content.ClipData;
-import android.content.Context;
+import android.view.DragEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -27,7 +26,6 @@
 
 import com.android.documentsui.MenuManager;
 import com.android.documentsui.R;
-import com.android.documentsui.base.CheckedTask.Check;
 
 /**
  * Describes a root navigation point of documents. Each one of them is presented as an item in the
@@ -60,7 +58,7 @@
 
     abstract void open();
 
-    boolean dropOn(ClipData data) {
+    boolean dropOn(DragEvent event) {
         return false;
     }
 
diff --git a/src/com/android/documentsui/sidebar/RootItem.java b/src/com/android/documentsui/sidebar/RootItem.java
index 97ec89f..a4501a0 100644
--- a/src/com/android/documentsui/sidebar/RootItem.java
+++ b/src/com/android/documentsui/sidebar/RootItem.java
@@ -17,11 +17,11 @@
 package com.android.documentsui.sidebar;
 
 import android.annotation.Nullable;
-import android.content.ClipData;
 import android.content.Context;
 import android.provider.DocumentsProvider;
 import android.text.TextUtils;
 import android.text.format.Formatter;
+import android.view.DragEvent;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.View;
@@ -106,8 +106,8 @@
     }
 
     @Override
-    boolean dropOn(ClipData data) {
-        return mActionHandler.dropOn(data, root);
+    boolean dropOn(DragEvent event) {
+        return mActionHandler.dropOn(event, root);
     }
 
     @Override
diff --git a/src/com/android/documentsui/sidebar/RootsFragment.java b/src/com/android/documentsui/sidebar/RootsFragment.java
index 0debf72..7fbe8e9 100644
--- a/src/com/android/documentsui/sidebar/RootsFragment.java
+++ b/src/com/android/documentsui/sidebar/RootsFragment.java
@@ -201,7 +201,7 @@
 
                     assert (item.isDropTarget());
 
-                    return item.dropOn(event.getClipData());
+                    return item.dropOn(event);
                 }
             };
         }