Refactoring PinItemDragListener into a base class to allow diffenret implementations
of multi-window drag and drop

Bug: 62702235
Change-Id: Ie87e0f7d131575bac1cb1099b0a70b230560be9a
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index b136e7d..0370777 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -217,6 +217,10 @@
         return info == null ? null : (ShortcutInfo) info.getItemInfo().first;
     }
 
+    public static ShortcutInfo fromActivityInfo(LauncherActivityInfo info, Context context) {
+        return (ShortcutInfo) (new PendingInstallShortcutInfo(info, context).getItemInfo().first);
+    }
+
     public static void queueShortcut(ShortcutInfoCompat info, Context context) {
         queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
     }
diff --git a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
index 6bdc627..31c0087 100644
--- a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
@@ -125,7 +125,7 @@
     }
 
     @TargetApi(26)
-    static class ShortcutConfigActivityInfoVO extends ShortcutConfigActivityInfo {
+    public static class ShortcutConfigActivityInfoVO extends ShortcutConfigActivityInfo {
 
         private final LauncherActivityInfo mInfo;
 
diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
new file mode 100644
index 0000000..d0f2629
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dragndrop;
+
+import android.content.ClipDescription;
+import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.DragEvent;
+import android.view.View;
+
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.widget.PendingItemDragHelper;
+
+import java.util.UUID;
+
+/**
+ * {@link DragSource} for handling drop from a different window.
+ */
+public abstract class BaseItemDragListener implements
+        View.OnDragListener, DragSource, DragOptions.PreDragCondition {
+
+    private static final String TAG = "BaseItemDragListener";
+
+    private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/";
+    public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener";
+
+    // Position of preview relative to the touch location
+    private final Rect mPreviewRect;
+
+    private final int mPreviewBitmapWidth;
+    private final int mPreviewViewWidth;
+
+    // Randomly generated id used to verify the drag event.
+    private final String mId;
+
+    protected Launcher mLauncher;
+    private DragController mDragController;
+    private long mDragStartTime;
+
+    public BaseItemDragListener(Rect previewRect, int previewBitmapWidth, int previewViewWidth) {
+        mPreviewRect = previewRect;
+        mPreviewBitmapWidth = previewBitmapWidth;
+        mPreviewViewWidth = previewViewWidth;
+        mId = UUID.randomUUID().toString();
+    }
+
+    protected BaseItemDragListener(Parcel parcel) {
+        mPreviewRect = Rect.CREATOR.createFromParcel(parcel);
+        mPreviewBitmapWidth = parcel.readInt();
+        mPreviewViewWidth = parcel.readInt();
+        mId = parcel.readString();
+    }
+
+    protected void writeToParcel(Parcel parcel, int i) {
+        mPreviewRect.writeToParcel(parcel, i);
+        parcel.writeInt(mPreviewBitmapWidth);
+        parcel.writeInt(mPreviewViewWidth);
+        parcel.writeString(mId);
+    }
+
+    public String getMimeType() {
+        return MIME_TYPE_PREFIX + mId;
+    }
+
+    public void setLauncher(Launcher launcher) {
+        mLauncher = launcher;
+        mDragController = launcher.getDragController();
+    }
+
+    @Override
+    public boolean onDrag(View view, DragEvent event) {
+        if (mLauncher == null || mDragController == null) {
+            postCleanup();
+            return false;
+        }
+        if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
+            if (onDragStart(event)) {
+                return true;
+            } else {
+                postCleanup();
+                return false;
+            }
+        }
+        return mDragController.onDragEvent(mDragStartTime, event);
+    }
+
+    protected boolean onDragStart(DragEvent event) {
+        ClipDescription desc =  event.getClipDescription();
+        if (desc == null || !desc.hasMimeType(getMimeType())) {
+            Log.e(TAG, "Someone started a dragAndDrop before us.");
+            return false;
+        }
+
+        Point downPos = new Point((int) event.getX(), (int) event.getY());
+        DragOptions options = new DragOptions();
+        options.systemDndStartPoint = downPos;
+        options.preDragCondition = this;
+
+        // We use drag event position as the screenPos for the preview image. Since mPreviewRect
+        // already includes the view position relative to the drag event on the source window,
+        // and the absolute position (position relative to the screen) of drag event is same
+        // across windows, using drag position here give a good estimate for relative position
+        // to source window.
+        createDragHelper().startDrag(new Rect(mPreviewRect),
+                mPreviewBitmapWidth, mPreviewViewWidth, downPos,  this, options);
+        mDragStartTime = SystemClock.uptimeMillis();
+        return true;
+    }
+
+    protected abstract PendingItemDragHelper createDragHelper();
+
+    @Override
+    public boolean shouldStartDrag(double distanceDragged) {
+        // Stay in pre-drag mode, if workspace is locked.
+        return !mLauncher.isWorkspaceLocked();
+    }
+
+    @Override
+    public void onPreDragStart(DropTarget.DragObject dragObject) {
+        // The predrag starts when the workspace is not yet loaded. In some cases we set
+        // the dragLayer alpha to 0 to have a nice fade-in animation. But that will prevent the
+        // dragView from being visible. Instead just skip the fade-in animation here.
+        mLauncher.getDragLayer().setAlpha(1);
+
+        dragObject.dragView.setColor(
+                mLauncher.getResources().getColor(R.color.delete_target_hover_tint));
+    }
+
+    @Override
+    public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
+        if (dragStarted) {
+            dragObject.dragView.setColor(0);
+        }
+    }
+
+    @Override
+    public boolean supportsAppInfoDropTarget() {
+        return false;
+    }
+
+    @Override
+    public boolean supportsDeleteDropTarget() {
+        return false;
+    }
+
+    @Override
+    public float getIntrinsicIconScaleFactor() {
+        return 1f;
+    }
+
+    @Override
+    public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete,
+            boolean success) {
+        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
+                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
+            // Exit spring loaded mode if we have not successfully dropped or have not handled the
+            // drop in Workspace
+            mLauncher.exitSpringLoadedDragModeDelayed(true,
+                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+        }
+
+        if (!success) {
+            d.deferDragViewCleanupPostAnimation = false;
+        }
+        postCleanup();
+    }
+
+    private void postCleanup() {
+        if (mLauncher != null) {
+            // Remove any drag params from the launcher intent since the drag operation is complete.
+            Intent newIntent = new Intent(mLauncher.getIntent());
+            newIntent.removeExtra(EXTRA_PIN_ITEM_DRAG_LISTENER);
+            mLauncher.setIntent(newIntent);
+        }
+
+        new Handler(Looper.getMainLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                removeListener();
+            }
+        });
+    }
+
+    public void removeListener() {
+        if (mLauncher != null) {
+            mLauncher.getDragLayer().setOnDragListener(null);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index f9f4e50..c8d3890 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -18,89 +18,49 @@
 
 import android.annotation.TargetApi;
 import android.appwidget.AppWidgetManager;
-import android.content.ClipDescription;
 import android.content.Intent;
 import android.content.pm.LauncherApps.PinItemRequest;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.Log;
 import android.view.DragEvent;
 import android.view.View;
 import android.widget.RemoteViews;
 
-import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DragSource;
-import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.PendingAddItemInfo;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.folder.Folder;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.PendingItemDragHelper;
 import com.android.launcher3.widget.WidgetAddFlowHandler;
 
-import java.util.UUID;
-
 /**
  * {@link DragSource} for handling drop from a different window. This object is initialized
  * in the source window and is passed on to the Launcher activity as an Intent extra.
  */
 @TargetApi(Build.VERSION_CODES.O)
-public class PinItemDragListener
-        implements Parcelable, View.OnDragListener, DragSource, DragOptions.PreDragCondition {
+public class PinItemDragListener extends BaseItemDragListener implements Parcelable {
 
-    private static final String TAG = "PinItemDragListener";
-
-    private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/";
     public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener";
 
     private final PinItemRequest mRequest;
 
-    // Position of preview relative to the touch location
-    private final Rect mPreviewRect;
-
-    private final int mPreviewBitmapWidth;
-    private final int mPreviewViewWidth;
-
-    // Randomly generated id used to verify the drag event.
-    private final String mId;
-
-    private Launcher mLauncher;
-    private DragController mDragController;
-    private long mDragStartTime;
-
     public PinItemDragListener(PinItemRequest request, Rect previewRect,
             int previewBitmapWidth, int previewViewWidth) {
+        super(previewRect, previewBitmapWidth, previewViewWidth);
         mRequest = request;
-        mPreviewRect = previewRect;
-        mPreviewBitmapWidth = previewBitmapWidth;
-        mPreviewViewWidth = previewViewWidth;
-        mId = UUID.randomUUID().toString();
     }
 
     private PinItemDragListener(Parcel parcel) {
+        super(parcel);
         mRequest = PinItemRequest.CREATOR.createFromParcel(parcel);
-        mPreviewRect = Rect.CREATOR.createFromParcel(parcel);
-        mPreviewBitmapWidth = parcel.readInt();
-        mPreviewViewWidth = parcel.readInt();
-        mId = parcel.readString();
-    }
-
-    public String getMimeType() {
-        return MIME_TYPE_PREFIX + mId;
     }
 
     @Override
@@ -110,45 +70,20 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int i) {
+        super.writeToParcel(parcel, i);
         mRequest.writeToParcel(parcel, i);
-        mPreviewRect.writeToParcel(parcel, i);
-        parcel.writeInt(mPreviewBitmapWidth);
-        parcel.writeInt(mPreviewViewWidth);
-        parcel.writeString(mId);
-    }
-
-    public void setLauncher(Launcher launcher) {
-        mLauncher = launcher;
-        mDragController = launcher.getDragController();
     }
 
     @Override
-    public boolean onDrag(View view, DragEvent event) {
-        if (mLauncher == null || mDragController == null) {
-            postCleanup();
-            return false;
-        }
-        if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
-            if (onDragStart(event)) {
-                return true;
-            } else {
-                postCleanup();
-                return false;
-            }
-        }
-        return mDragController.onDragEvent(mDragStartTime, event);
-    }
-
-    private boolean onDragStart(DragEvent event) {
+    protected boolean onDragStart(DragEvent event) {
         if (!mRequest.isValid()) {
             return false;
         }
-        ClipDescription desc =  event.getClipDescription();
-        if (desc == null || !desc.hasMimeType(getMimeType())) {
-            Log.e(TAG, "Someone started a dragAndDrop before us.");
-            return false;
-        }
+        return super.onDragStart(event);
+    }
 
+    @Override
+    protected PendingItemDragHelper createDragHelper() {
         final PendingAddItemInfo item;
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
             item = new PendingAddShortcutInfo(
@@ -170,109 +105,17 @@
         View view = new View(mLauncher);
         view.setTag(item);
 
-        Point downPos = new Point((int) event.getX(), (int) event.getY());
-        DragOptions options = new DragOptions();
-        options.systemDndStartPoint = downPos;
-        options.preDragCondition = this;
-
-        // We use drag event position as the screenPos for the preview image. Since mPreviewRect
-        // already includes the view position relative to the drag event on the source window,
-        // and the absolute position (position relative to the screen) of drag event is same
-        // across windows, using drag position here give a good estimate for relative position
-        // to source window.
         PendingItemDragHelper dragHelper = new PendingItemDragHelper(view);
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_APPWIDGET) {
             dragHelper.setPreview(getPreview(mRequest));
         }
-
-        dragHelper.startDrag(new Rect(mPreviewRect),
-                mPreviewBitmapWidth, mPreviewViewWidth, downPos,  this, options);
-        mDragStartTime = SystemClock.uptimeMillis();
-        return true;
-    }
-
-    @Override
-    public boolean shouldStartDrag(double distanceDragged) {
-        // Stay in pre-drag mode, if workspace is locked.
-        return !mLauncher.isWorkspaceLocked();
-    }
-
-    @Override
-    public void onPreDragStart(DropTarget.DragObject dragObject) {
-        // The predrag starts when the workspace is not yet loaded. In some cases we set
-        // the dragLayer alpha to 0 to have a nice fade-in animation. But that will prevent the
-        // dragView from being visible. Instead just skip the fade-in animation here.
-        mLauncher.getDragLayer().setAlpha(1);
-
-        dragObject.dragView.setColor(
-                mLauncher.getResources().getColor(R.color.delete_target_hover_tint));
-    }
-
-    @Override
-    public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
-        if (dragStarted) {
-            dragObject.dragView.setColor(0);
-        }
-    }
-
-    @Override
-    public boolean supportsAppInfoDropTarget() {
-        return false;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return false;
-    }
-
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        return 1f;
-    }
-
-    @Override
-    public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete,
-            boolean success) {
-        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
-                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
-            // Exit spring loaded mode if we have not successfully dropped or have not handled the
-            // drop in Workspace
-            mLauncher.exitSpringLoadedDragModeDelayed(true,
-                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
-        }
-
-        if (!success) {
-            d.deferDragViewCleanupPostAnimation = false;
-        }
-        postCleanup();
+        return dragHelper;
     }
 
     @Override
     public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
             LauncherLogProto.Target targetParent) {
-        targetParent.containerType = ContainerType.PINITEM;
-    }
-
-    private void postCleanup() {
-        if (mLauncher != null) {
-            // Remove any drag params from the launcher intent since the drag operation is complete.
-            Intent newIntent = new Intent(mLauncher.getIntent());
-            newIntent.removeExtra(EXTRA_PIN_ITEM_DRAG_LISTENER);
-            mLauncher.setIntent(newIntent);
-        }
-
-        new Handler(Looper.getMainLooper()).post(new Runnable() {
-            @Override
-            public void run() {
-                removeListener();
-            }
-        });
-    }
-
-    public void removeListener() {
-        if (mLauncher != null) {
-            mLauncher.getDragLayer().setOnDragListener(null);
-        }
+        targetParent.containerType = LauncherLogProto.ContainerType.PINITEM;
     }
 
     public static RemoteViews getPreview(PinItemRequest request) {
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 9ea11a7..fcd91b6 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -28,7 +28,6 @@
 import android.support.v4.graphics.ColorUtils;
 
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.util.Preconditions;
 
 /**
  * Utility class to add shadows to bitmaps.
@@ -126,7 +125,9 @@
     }
 
     public static ShadowGenerator getInstance(Context context) {
-        Preconditions.assertNonUiThread();
+        // TODO: This currently fails as the system default icon also needs a shadow as it
+        // uses adaptive icon.
+        // Preconditions.assertNonUiThread();
         synchronized (LOCK) {
             if (sShadowGenerator == null) {
                 sShadowGenerator = new ShadowGenerator(context);