Couple fixes for drag and drop

- Add simple fade of the drag surface when dropping and when canceling a
  drag from the shade (since the shade has closed, the default animation
  of animating to the start position is wrong)
- Add case for dragging over home/recents, show the highlighted drop zone
  as fullscreen since there is nothing to split with
- Fix issue with drag listener not being removed after a notification
  drag
- For now, add a toast when attempting to drag a notification that does
  not have a valid intent
- Also don't wait for DRAG_START to start collapsing the shade if the
  call to startDrag() returns true

Bug: 217972792
Bug: 218791595
Bug: 219757067
Test: atest WMShellUnitTests
Test: atest SystemUITests

Change-Id: Ic53de0d8a999d4ae39dc207bfc2927466ad2ba7c
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 101295d..11ecc91 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -35,6 +35,9 @@
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.ClipDescription;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -54,6 +57,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -205,6 +209,7 @@
                 break;
             case ACTION_DRAG_ENTERED:
                 pd.dragLayout.show();
+                pd.dragLayout.update(event);
                 break;
             case ACTION_DRAG_LOCATION:
                 pd.dragLayout.update(event);
@@ -250,10 +255,6 @@
                 // Hide the window if another drag hasn't been started while animating the drop
                 setDropTargetWindowVisibility(pd, View.INVISIBLE);
             }
-
-            // Clean up the drag surface
-            mTransaction.reparent(dragSurface, null);
-            mTransaction.apply();
         });
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index e8bae0f..7568310 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -123,6 +123,13 @@
     }
 
     /**
+     * Returns the number of targets.
+     */
+    int getNumTargets() {
+        return mTargets.size();
+    }
+
+    /**
      * Returns the target's regions based on the current state of the device and display.
      */
     @NonNull
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index d395f95..25fe8b9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -17,6 +17,7 @@
 package com.android.wm.shell.draganddrop;
 
 import static android.app.StatusBarManager.DISABLE_NONE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -24,6 +25,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.StatusBarManager;
@@ -44,6 +46,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -135,6 +138,12 @@
         }
     }
 
+    private void updateContainerMarginsForSingleTask() {
+        mDropZoneView1.setContainerMargin(
+                mDisplayMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin);
+        mDropZoneView2.setContainerMargin(0, 0, 0, 0);
+    }
+
     private void updateContainerMargins(int orientation) {
         final float halfMargin = mDisplayMargin / 2f;
         if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
@@ -165,11 +174,20 @@
         if (!alreadyInSplit) {
             ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
             if (taskInfo1 != null) {
-                Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
-                int bgColor1 = getResizingBackgroundColor(taskInfo1);
-                mDropZoneView1.setAppInfo(bgColor1, icon1);
-                mDropZoneView2.setAppInfo(bgColor1, icon1);
-                updateDropZoneSizes(null, null); // passing null splits the views evenly
+                final int activityType = taskInfo1.getActivityType();
+                if (activityType == ACTIVITY_TYPE_STANDARD) {
+                    Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
+                    int bgColor1 = getResizingBackgroundColor(taskInfo1);
+                    mDropZoneView1.setAppInfo(bgColor1, icon1);
+                    mDropZoneView2.setAppInfo(bgColor1, icon1);
+                    updateDropZoneSizes(null, null); // passing null splits the views evenly
+                } else {
+                    // We use the first drop zone to show the fullscreen highlight, and don't need
+                    // to set additional info
+                    mDropZoneView1.setForceIgnoreBottomMargin(true);
+                    updateDropZoneSizesForSingleTask();
+                    updateContainerMarginsForSingleTask();
+                }
             }
         } else {
             // We're already in split so get taskInfo from the controller to populate icon / color.
@@ -195,6 +213,21 @@
         }
     }
 
+    private void updateDropZoneSizesForSingleTask() {
+        final LinearLayout.LayoutParams dropZoneView1 =
+                (LayoutParams) mDropZoneView1.getLayoutParams();
+        final LinearLayout.LayoutParams dropZoneView2 =
+                (LayoutParams) mDropZoneView2.getLayoutParams();
+        dropZoneView1.width = MATCH_PARENT;
+        dropZoneView1.height = MATCH_PARENT;
+        dropZoneView2.width = 0;
+        dropZoneView2.height = 0;
+        dropZoneView1.weight = 1;
+        dropZoneView2.weight = 0;
+        mDropZoneView1.setLayoutParams(dropZoneView1);
+        mDropZoneView2.setLayoutParams(dropZoneView2);
+    }
+
     /**
      * Sets the size of the two drop zones based on the provided bounds. The divider sits between
      * the views and its size is included in the calculations.
@@ -265,9 +298,12 @@
                 // Animating to no target
                 animateSplitContainers(false, null /* animCompleteCallback */);
             } else if (mCurrentTarget == null) {
-                // Animating to first target
-                animateSplitContainers(true, null /* animCompleteCallback */);
-                animateHighlight(target);
+                if (mPolicy.getNumTargets() == 1) {
+                    animateFullscreenContainer(true);
+                } else {
+                    animateSplitContainers(true, null /* animCompleteCallback */);
+                    animateHighlight(target);
+                }
             } else {
                 // Switching between targets
                 mDropZoneView1.animateSwitch();
@@ -283,6 +319,10 @@
     public void hide(DragEvent event, Runnable hideCompleteCallback) {
         mIsShowing = false;
         animateSplitContainers(false, hideCompleteCallback);
+        // Reset the state if we previously force-ignore the bottom margin
+        mDropZoneView1.setForceIgnoreBottomMargin(false);
+        mDropZoneView2.setForceIgnoreBottomMargin(false);
+        updateContainerMargins(getResources().getConfiguration().orientation);
         mCurrentTarget = null;
     }
 
@@ -297,11 +337,63 @@
         // Process the drop
         mPolicy.handleDrop(mCurrentTarget, event.getClipData());
 
-        // TODO(b/169894807): Coordinate with dragSurface
+        // Start animating the drop UI out with the drag surface
         hide(event, dropCompleteCallback);
+        hideDragSurface(dragSurface);
         return handledDrop;
     }
 
+    private void hideDragSurface(SurfaceControl dragSurface) {
+        final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+        final ValueAnimator dragSurfaceAnimator = ValueAnimator.ofFloat(0f, 1f);
+        // Currently the splash icon animation runs with the default ValueAnimator duration of
+        // 300ms
+        dragSurfaceAnimator.setDuration(300);
+        dragSurfaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        dragSurfaceAnimator.addUpdateListener(animation -> {
+            float t = animation.getAnimatedFraction();
+            float alpha = 1f - t;
+            // TODO: Scale the drag surface as well once we make all the source surfaces
+            //       consistent
+            tx.setAlpha(dragSurface, alpha);
+            tx.apply();
+        });
+        dragSurfaceAnimator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCanceled = false;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cleanUpSurface();
+                mCanceled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mCanceled) {
+                    // Already handled above
+                    return;
+                }
+                cleanUpSurface();
+            }
+
+            private void cleanUpSurface() {
+                // Clean up the drag surface
+                tx.remove(dragSurface);
+                tx.apply();
+            }
+        });
+        dragSurfaceAnimator.start();
+    }
+
+    private void animateFullscreenContainer(boolean visible) {
+        mStatusBarManager.disable(visible
+                ? HIDE_STATUS_BAR_FLAGS
+                : DISABLE_NONE);
+        // We're only using the first drop zone if there is one fullscreen target
+        mDropZoneView1.setShowingMargin(visible);
+        mDropZoneView1.setShowingHighlight(visible);
+    }
+
     private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) {
         mStatusBarManager.disable(visible
                 ? HIDE_STATUS_BAR_FLAGS
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index a3ee8ae..38870bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -65,6 +65,7 @@
     private final float[] mContainerMargin = new float[4];
     private float mCornerRadius;
     private float mBottomInset;
+    private boolean mIgnoreBottomMargin;
     private int mMarginColor; // i.e. color used for negative space like the container insets
 
     private boolean mShowingHighlight;
@@ -141,6 +142,14 @@
         }
     }
 
+    /** Ignores the bottom margin provided by the insets. */
+    public void setForceIgnoreBottomMargin(boolean ignoreBottomMargin) {
+        mIgnoreBottomMargin = ignoreBottomMargin;
+        if (mMarginPercent > 0) {
+            mMarginView.invalidate();
+        }
+    }
+
     /** Sets the bottom inset so the drop zones are above bottom navigation. */
     public void setBottomInset(float bottom) {
         mBottomInset = bottom;
@@ -257,7 +266,8 @@
             mPath.addRoundRect(mContainerMargin[0] * mMarginPercent,
                     mContainerMargin[1] * mMarginPercent,
                     getWidth() - (mContainerMargin[2] * mMarginPercent),
-                    getHeight() - (mContainerMargin[3] * mMarginPercent) - mBottomInset,
+                    getHeight() - (mContainerMargin[3] * mMarginPercent)
+                            - (mIgnoreBottomMargin ? 0 : mBottomInset),
                     mCornerRadius * mMarginPercent,
                     mCornerRadius * mMarginPercent,
                     Path.Direction.CW);
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3f80647..23b2529 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2407,4 +2407,7 @@
     <string name="add_user_supervised" translatable="false">@*android:string/supervised_user_creation_label</string>
     <!-- Manage users - For system user management [CHAR LIMIT=40]  -->
     <string name="manage_users">Manage users</string>
+
+    <!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
+    <string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index 06b739b..c2c40d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -17,6 +17,11 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import static android.widget.Toast.LENGTH_SHORT;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -33,13 +38,15 @@
 import android.util.Log;
 import android.view.DragEvent;
 import android.view.HapticFeedbackConstants;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.widget.ImageView;
+import android.widget.Toast;
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -55,12 +62,15 @@
 
     private final Context mContext;
     private final HeadsUpManager mHeadsUpManager;
+    private final ShadeController mShadeController;
 
     @Inject
     public ExpandableNotificationRowDragController(Context context,
-            HeadsUpManager headsUpManager) {
+            HeadsUpManager headsUpManager,
+            ShadeController shadeController) {
         mContext = context;
         mHeadsUpManager = headsUpManager;
+        mShadeController = shadeController;
 
         init();
     }
@@ -87,6 +97,16 @@
         final PendingIntent contentIntent = notification.contentIntent != null
                 ? notification.contentIntent
                 : notification.fullScreenIntent;
+        if (contentIntent == null) {
+            if (!enr.isPinned()) {
+                // We dismiss the shade for consistency, but also because toasts currently don't
+                // show above the shade
+                dismissShade();
+            }
+            Toast.makeText(mContext, R.string.drag_split_not_supported, LENGTH_SHORT)
+                 .show();
+            return;
+        }
         Bitmap iconBitmap = getBitmapFromDrawable(
                 getPkgIcon(enr.getEntry().getSbn().getPackageName()));
 
@@ -97,15 +117,30 @@
         ClipDescription clipDescription = new ClipDescription("Drag And Drop",
                 new String[]{ClipDescription.MIMETYPE_APPLICATION_ACTIVITY});
         Intent dragIntent = new Intent();
-        dragIntent.putExtra("android.intent.extra.PENDING_INTENT", contentIntent);
+        dragIntent.putExtra(ClipDescription.EXTRA_PENDING_INTENT, contentIntent);
         dragIntent.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
         ClipData.Item item = new ClipData.Item(dragIntent);
         ClipData dragData = new ClipData(clipDescription, item);
         View.DragShadowBuilder myShadow = new View.DragShadowBuilder(snapshot);
         view.setOnDragListener(getDraggedViewDragListener());
-        view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL);
+        boolean result = view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL
+                | View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
+        if (result) {
+            view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            if (enr.isPinned()) {
+                mHeadsUpManager.releaseAllImmediately();
+            } else {
+                dismissShade();
+            }
+        }
     }
 
+    private void dismissShade() {
+        // Speed up dismissing the shade since the drag needs to be handled by
+        // the shell layer underneath
+        mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
+                false /* delayed */, 1.1f /* speedUpFactor */);
+    }
 
     private Drawable getPkgIcon(String pkgName) {
         Drawable pkgicon = null;
@@ -145,16 +180,6 @@
         return (view, dragEvent) -> {
             switch (dragEvent.getAction()) {
                 case DragEvent.ACTION_DRAG_STARTED:
-                    view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    if (view instanceof ExpandableNotificationRow) {
-                        ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
-                        if (enr.isPinned()) {
-                            mHeadsUpManager.releaseAllImmediately();
-                        } else {
-                            Dependency.get(ShadeController.class).animateCollapsePanels(
-                                    CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
-                        }
-                    }
                     return true;
                 case DragEvent.ACTION_DRAG_ENDED:
                     if (dragEvent.getResult()) {
@@ -162,10 +187,55 @@
                             ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
                             enr.dragAndDropSuccess();
                         }
+                    } else {
+                        // Fade out the drag surface in place instead of animating back to the
+                        // start position now that the shade is closed
+                        fadeOutAndRemoveDragSurface(dragEvent);
                     }
+                    // Clear the drag listener set above
+                    view.setOnDragListener(null);
                     return true;
             }
             return false;
         };
     }
+
+    private void fadeOutAndRemoveDragSurface(DragEvent dragEvent) {
+        SurfaceControl dragSurface = dragEvent.getDragSurface();
+        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+        ValueAnimator returnAnimator = ValueAnimator.ofFloat(0f, 1f);
+        returnAnimator.setDuration(200);
+        returnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        returnAnimator.addUpdateListener(animation -> {
+            float t = animation.getAnimatedFraction();
+            float alpha = 1f - t;
+            tx.setAlpha(dragSurface, alpha);
+            tx.apply();
+        });
+        returnAnimator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCanceled = false;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cleanUpSurface();
+                mCanceled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mCanceled) {
+                    // Already handled above
+                    return;
+                }
+                cleanUpSurface();
+            }
+
+            private void cleanUpSurface() {
+                tx.remove(dragSurface);
+                tx.apply();
+                tx.close();
+            }
+        });
+        returnAnimator.start();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index 24a0ad3..bc54bf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -18,6 +18,8 @@
 
 import static android.view.DragEvent.ACTION_DRAG_STARTED;
 
+import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -36,7 +38,12 @@
 import org.junit.runner.RunWith;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -58,6 +65,7 @@
     private NotificationMenuRow mMenuRow = mock(NotificationMenuRow.class);
     private NotificationMenuRowPlugin.MenuItem mMenuItem =
             mock(NotificationMenuRowPlugin.MenuItem.class);
+    private ShadeController mShadeController = mock(ShadeController.class);
 
     @Before
     public void setUp() throws Exception {
@@ -69,11 +77,15 @@
                 mContext,
                 mDependency,
                 TestableLooper.get(this));
-        mRow = mNotificationTestHelper.createRow();
+        mRow = spy(mNotificationTestHelper.createRow());
+        Notification notification = mRow.getEntry().getSbn().getNotification();
+        notification.contentIntent = mock(PendingIntent.class);
+        doReturn(true).when(mRow).startDragAndDrop(any(), any(), any(), anyInt());
         mGroupRow = mNotificationTestHelper.createGroup(4);
         when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
 
-        mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager);
+        mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager,
+                mShadeController);
     }
 
     @Test
@@ -86,10 +98,6 @@
         mRow.doLongClickCallback(0, 0);
         mRow.doDragCallback(0, 0);
         verify(controller).startDragAndDrop(mRow);
-
-        // Simulate the drag start
-        mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
-                null, null, false));
         verify(mHeadsUpManager, times(1)).releaseAllImmediately();
     }
 
@@ -98,14 +106,27 @@
         ExpandableNotificationRowDragController controller = createSpyController();
         mRow.setDragController(controller);
 
-        mDependency.get(ShadeController.class).instantExpandNotificationsPanel();
+        mRow.doDragCallback(0, 0);
+        verify(controller).startDragAndDrop(mRow);
+        verify(mShadeController).animateCollapsePanels(eq(0), eq(true),
+                eq(false), anyFloat());
+    }
+
+    @Test
+    public void testDoStartDrag_noLaunchIntent() throws Exception {
+        ExpandableNotificationRowDragController controller = createSpyController();
+        mRow.setDragController(controller);
+
+        // Clear the intents
+        Notification notification = mRow.getEntry().getSbn().getNotification();
+        notification.contentIntent = null;
+        notification.fullScreenIntent = null;
+
         mRow.doDragCallback(0, 0);
         verify(controller).startDragAndDrop(mRow);
 
-        // Simulate the drag start
-        mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
-                null, null, false));
-        verify(mDependency.get(ShadeController.class)).animateCollapsePanels(0, true);
+        // Verify that we never start the actual drag since there is no content
+        verify(mRow, never()).startDragAndDrop(any(), any(), any(), anyInt());
     }
 
     private ExpandableNotificationRowDragController createSpyController() {