Merge "Collapse bubbles when drag and drop is initiated" into tm-dev am: ef1cc8850f am: 4437048f1a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17715693

Change-Id: I0407669dd09567eb74318522d1ec8faa66dab63f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 5ef2413..806c395 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -96,6 +96,7 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
@@ -214,6 +215,8 @@
 
     /** One handed mode controller to register transition listener. */
     private Optional<OneHandedController> mOneHandedOptional;
+    /** Drag and drop controller to register listener for onDragStarted. */
+    private DragAndDropController mDragAndDropController;
 
     /**
      * Creates an instance of the BubbleController.
@@ -230,6 +233,7 @@
             ShellTaskOrganizer organizer,
             DisplayController displayController,
             Optional<OneHandedController> oneHandedOptional,
+            DragAndDropController dragAndDropController,
             ShellExecutor mainExecutor,
             Handler mainHandler,
             TaskViewTransitions taskViewTransitions,
@@ -241,8 +245,8 @@
                 new BubbleDataRepository(context, launcherApps, mainExecutor),
                 statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
                 logger, taskStackListener, organizer, positioner, displayController,
-                oneHandedOptional, mainExecutor, mainHandler, taskViewTransitions,
-                syncQueue);
+                oneHandedOptional, dragAndDropController, mainExecutor, mainHandler,
+                taskViewTransitions, syncQueue);
     }
 
     /**
@@ -264,6 +268,7 @@
             BubblePositioner positioner,
             DisplayController displayController,
             Optional<OneHandedController> oneHandedOptional,
+            DragAndDropController dragAndDropController,
             ShellExecutor mainExecutor,
             Handler mainHandler,
             TaskViewTransitions taskViewTransitions,
@@ -293,6 +298,7 @@
         mDisplayController = displayController;
         mTaskViewTransitions = taskViewTransitions;
         mOneHandedOptional = oneHandedOptional;
+        mDragAndDropController = dragAndDropController;
         mSyncQueue = syncQueue;
     }
 
@@ -433,6 +439,7 @@
                 });
 
         mOneHandedOptional.ifPresent(this::registerOneHandedState);
+        mDragAndDropController.addListener(this::collapseStack);
     }
 
     @VisibleForTesting
@@ -884,7 +891,6 @@
         return mBubbleData.isExpanded();
     }
 
-    @VisibleForTesting
     public void collapseStack() {
         mBubbleData.setExpanded(false /* expanded */);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 4fa5a10..a3fdffa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -42,6 +42,7 @@
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.freeform.FreeformTaskListener;
 import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
@@ -110,6 +111,7 @@
             ShellTaskOrganizer organizer,
             DisplayController displayController,
             @DynamicOverride Optional<OneHandedController> oneHandedOptional,
+            DragAndDropController dragAndDropController,
             @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler,
             TaskViewTransitions taskViewTransitions,
@@ -118,7 +120,7 @@
                 floatingContentCoordinator, statusBarService, windowManager,
                 windowManagerShellWrapper, launcherApps, taskStackListener,
                 uiEventLogger, organizer, displayController, oneHandedOptional,
-                mainExecutor, mainHandler, taskViewTransitions, syncQueue);
+                dragAndDropController, mainExecutor, mainHandler, taskViewTransitions, syncQueue);
     }
 
     //
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 11ecc91..95de2dc 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,9 +35,6 @@
 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;
@@ -52,17 +49,19 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEventLogger;
 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;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
+import java.util.ArrayList;
 import java.util.Optional;
 
 /**
@@ -80,10 +79,19 @@
     private SplitScreenController mSplitScreen;
     private ShellExecutor mMainExecutor;
     private DragAndDropImpl mImpl;
+    private ArrayList<DragAndDropListener> mListeners = new ArrayList<>();
 
     private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
     private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
 
+    /**
+     * Listener called during drag events, currently just onDragStarted.
+     */
+    public interface DragAndDropListener {
+        /** Called when a drag has started. */
+        void onDragStarted();
+    }
+
     public DragAndDropController(Context context, DisplayController displayController,
             UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) {
         mContext = context;
@@ -103,6 +111,22 @@
         mDisplayController.addDisplayWindowListener(this);
     }
 
+    /** Adds a listener to be notified of drag and drop events. */
+    public void addListener(DragAndDropListener listener) {
+        mListeners.add(listener);
+    }
+
+    /** Removes a drag and drop listener. */
+    public void removeListener(DragAndDropListener listener) {
+        mListeners.remove(listener);
+    }
+
+    private void notifyListeners() {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onDragStarted();
+        }
+    }
+
     @Override
     public void onDisplayAdded(int displayId) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display added: %d", displayId);
@@ -137,13 +161,19 @@
                 new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
         try {
             wm.addView(rootView, layoutParams);
-            mDisplayDropTargets.put(displayId,
-                    new PerDisplay(displayId, context, wm, rootView, dragLayout));
+            addDisplayDropTarget(displayId, context, wm, rootView, dragLayout);
         } catch (WindowManager.InvalidDisplayException e) {
             Slog.w(TAG, "Unable to add view for display id: " + displayId);
         }
     }
 
+    @VisibleForTesting
+    void addDisplayDropTarget(int displayId, Context context, WindowManager wm,
+            FrameLayout rootView, DragLayout dragLayout) {
+        mDisplayDropTargets.put(displayId,
+                new PerDisplay(displayId, context, wm, rootView, dragLayout));
+    }
+
     @Override
     public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display changed: %d", displayId);
@@ -206,6 +236,7 @@
                 pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
                         event.getClipData(), loggerSessionId);
                 setDropTargetWindowVisibility(pd, View.VISIBLE);
+                notifyListeners();
                 break;
             case ACTION_DRAG_ENTERED:
                 pd.dragLayout.show();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
index 9f74520..aaeebef 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
@@ -16,15 +16,28 @@
 
 package com.android.wm.shell.draganddrop;
 
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DragEvent.ACTION_DRAG_STARTED;
+
 import static org.junit.Assert.assertFalse;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
+import android.content.ClipData;
+import android.content.ClipDescription;
 import android.content.Context;
+import android.content.Intent;
 import android.os.RemoteException;
 import android.view.Display;
 import android.view.DragEvent;
 import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -33,6 +46,7 @@
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.splitscreen.SplitScreenController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -40,6 +54,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 /**
  * Tests for the drag and drop controller.
  */
@@ -56,6 +72,9 @@
     @Mock
     private UiEventLogger mUiEventLogger;
 
+    @Mock
+    private DragAndDropController.DragAndDropListener mDragAndDropListener;
+
     private DragAndDropController mController;
 
     @Before
@@ -63,6 +82,7 @@
         MockitoAnnotations.initMocks(this);
         mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger,
                 mock(IconProvider.class), mock(ShellExecutor.class));
+        mController.initialize(Optional.of(mock(SplitScreenController.class)));
     }
 
     @Test
@@ -77,4 +97,45 @@
         mController.onDisplayAdded(nonDefaultDisplayId);
         assertFalse(mController.onDrag(dragLayout, mock(DragEvent.class)));
     }
+
+    @Test
+    public void testListenerOnDragStarted() {
+        final View dragLayout = mock(View.class);
+        final Display display = mock(Display.class);
+        doReturn(display).when(dragLayout).getDisplay();
+        doReturn(DEFAULT_DISPLAY).when(display).getDisplayId();
+
+        final ClipData clipData = createClipData();
+        final DragEvent event = mock(DragEvent.class);
+        doReturn(ACTION_DRAG_STARTED).when(event).getAction();
+        doReturn(clipData).when(event).getClipData();
+        doReturn(clipData.getDescription()).when(event).getClipDescription();
+
+        mController.addListener(mDragAndDropListener);
+
+        // Ensure there's a target so that onDrag will execute
+        mController.addDisplayDropTarget(0, mContext, mock(WindowManager.class),
+                mock(FrameLayout.class), mock(DragLayout.class));
+
+        // Verify the listener is called on a valid drag action.
+        mController.onDrag(dragLayout, event);
+        verify(mDragAndDropListener, times(1)).onDragStarted();
+
+        // Verify the listener isn't called after removal.
+        reset(mDragAndDropListener);
+        mController.removeListener(mDragAndDropListener);
+        mController.onDrag(dragLayout, event);
+        verify(mDragAndDropListener, never()).onDragStarted();
+    }
+
+    private ClipData createClipData() {
+        ClipDescription clipDescription = new ClipDescription(MIMETYPE_APPLICATION_SHORTCUT,
+                new String[] { MIMETYPE_APPLICATION_SHORTCUT });
+        Intent i = new Intent();
+        i.putExtra(Intent.EXTRA_PACKAGE_NAME, "pkg");
+        i.putExtra(Intent.EXTRA_SHORTCUT_ID, "shortcutId");
+        i.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
+        ClipData.Item item = new ClipData.Item(i);
+        return new ClipData(clipDescription, item);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index ca67bd2..193879e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -133,6 +133,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.onehanded.OneHandedController;
 
 import com.google.common.collect.ImmutableList;
@@ -367,6 +368,7 @@
                 mPositioner,
                 mock(DisplayController.class),
                 mOneHandedOptional,
+                mock(DragAndDropController.class),
                 syncExecutor,
                 mock(Handler.class),
                 mTaskViewTransitions,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index ce7924a..02d8691 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -116,6 +116,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.onehanded.OneHandedController;
 
 import org.junit.Before;
@@ -332,6 +333,7 @@
                 mPositioner,
                 mock(DisplayController.class),
                 mOneHandedOptional,
+                mock(DragAndDropController.class),
                 syncExecutor,
                 mock(Handler.class),
                 mTaskViewTransitions,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 83f5987..9646edf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -35,6 +35,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.onehanded.OneHandedController;
 
 import java.util.Optional;
@@ -59,6 +60,7 @@
             BubblePositioner positioner,
             DisplayController displayController,
             Optional<OneHandedController> oneHandedOptional,
+            DragAndDropController dragAndDropController,
             ShellExecutor shellMainExecutor,
             Handler shellMainHandler,
             TaskViewTransitions taskViewTransitions,
@@ -66,8 +68,8 @@
         super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
                 statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
                 bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
-                oneHandedOptional, shellMainExecutor, shellMainHandler, taskViewTransitions,
-                syncQueue);
+                oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
+                taskViewTransitions, syncQueue);
         setInflateSynchronously(true);
         initialize();
     }