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>
This commit is contained in:
Mady Mellor
2022-04-19 17:52:59 +00:00
committed by Automerger Merge Worker
7 changed files with 118 additions and 12 deletions

View File

@@ -96,6 +96,7 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl; 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.OneHandedController;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback; import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.PinnedStackListenerForwarder;
@@ -214,6 +215,8 @@ public class BubbleController {
/** One handed mode controller to register transition listener. */ /** One handed mode controller to register transition listener. */
private Optional<OneHandedController> mOneHandedOptional; private Optional<OneHandedController> mOneHandedOptional;
/** Drag and drop controller to register listener for onDragStarted. */
private DragAndDropController mDragAndDropController;
/** /**
* Creates an instance of the BubbleController. * Creates an instance of the BubbleController.
@@ -230,6 +233,7 @@ public class BubbleController {
ShellTaskOrganizer organizer, ShellTaskOrganizer organizer,
DisplayController displayController, DisplayController displayController,
Optional<OneHandedController> oneHandedOptional, Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
ShellExecutor mainExecutor, ShellExecutor mainExecutor,
Handler mainHandler, Handler mainHandler,
TaskViewTransitions taskViewTransitions, TaskViewTransitions taskViewTransitions,
@@ -241,8 +245,8 @@ public class BubbleController {
new BubbleDataRepository(context, launcherApps, mainExecutor), new BubbleDataRepository(context, launcherApps, mainExecutor),
statusBarService, windowManager, windowManagerShellWrapper, launcherApps, statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
logger, taskStackListener, organizer, positioner, displayController, logger, taskStackListener, organizer, positioner, displayController,
oneHandedOptional, mainExecutor, mainHandler, taskViewTransitions, oneHandedOptional, dragAndDropController, mainExecutor, mainHandler,
syncQueue); taskViewTransitions, syncQueue);
} }
/** /**
@@ -264,6 +268,7 @@ public class BubbleController {
BubblePositioner positioner, BubblePositioner positioner,
DisplayController displayController, DisplayController displayController,
Optional<OneHandedController> oneHandedOptional, Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
ShellExecutor mainExecutor, ShellExecutor mainExecutor,
Handler mainHandler, Handler mainHandler,
TaskViewTransitions taskViewTransitions, TaskViewTransitions taskViewTransitions,
@@ -293,6 +298,7 @@ public class BubbleController {
mDisplayController = displayController; mDisplayController = displayController;
mTaskViewTransitions = taskViewTransitions; mTaskViewTransitions = taskViewTransitions;
mOneHandedOptional = oneHandedOptional; mOneHandedOptional = oneHandedOptional;
mDragAndDropController = dragAndDropController;
mSyncQueue = syncQueue; mSyncQueue = syncQueue;
} }
@@ -433,6 +439,7 @@ public class BubbleController {
}); });
mOneHandedOptional.ifPresent(this::registerOneHandedState); mOneHandedOptional.ifPresent(this::registerOneHandedState);
mDragAndDropController.addListener(this::collapseStack);
} }
@VisibleForTesting @VisibleForTesting
@@ -884,7 +891,6 @@ public class BubbleController {
return mBubbleData.isExpanded(); return mBubbleData.isExpanded();
} }
@VisibleForTesting
public void collapseStack() { public void collapseStack() {
mBubbleData.setExpanded(false /* expanded */); mBubbleData.setExpanded(false /* expanded */);
} }

View File

@@ -42,6 +42,7 @@ import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellMainThread; 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.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenUnfoldController; import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
@@ -110,6 +111,7 @@ public class WMShellModule {
ShellTaskOrganizer organizer, ShellTaskOrganizer organizer,
DisplayController displayController, DisplayController displayController,
@DynamicOverride Optional<OneHandedController> oneHandedOptional, @DynamicOverride Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
@ShellMainThread ShellExecutor mainExecutor, @ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler, @ShellMainThread Handler mainHandler,
TaskViewTransitions taskViewTransitions, TaskViewTransitions taskViewTransitions,
@@ -118,7 +120,7 @@ public class WMShellModule {
floatingContentCoordinator, statusBarService, windowManager, floatingContentCoordinator, statusBarService, windowManager,
windowManagerShellWrapper, launcherApps, taskStackListener, windowManagerShellWrapper, launcherApps, taskStackListener,
uiEventLogger, organizer, displayController, oneHandedOptional, uiEventLogger, organizer, displayController, oneHandedOptional,
mainExecutor, mainHandler, taskViewTransitions, syncQueue); dragAndDropController, mainExecutor, mainHandler, taskViewTransitions, syncQueue);
} }
// //

View File

@@ -35,9 +35,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 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.ClipDescription;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -52,17 +49,19 @@ import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId; import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLogger;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R; 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.DisplayController;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.ArrayList;
import java.util.Optional; import java.util.Optional;
/** /**
@@ -80,10 +79,19 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
private SplitScreenController mSplitScreen; private SplitScreenController mSplitScreen;
private ShellExecutor mMainExecutor; private ShellExecutor mMainExecutor;
private DragAndDropImpl mImpl; private DragAndDropImpl mImpl;
private ArrayList<DragAndDropListener> mListeners = new ArrayList<>();
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>(); private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); 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, public DragAndDropController(Context context, DisplayController displayController,
UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) { UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) {
mContext = context; mContext = context;
@@ -103,6 +111,22 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
mDisplayController.addDisplayWindowListener(this); 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 @Override
public void onDisplayAdded(int displayId) { public void onDisplayAdded(int displayId) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display added: %d", displayId); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display added: %d", displayId);
@@ -137,13 +161,19 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
try { try {
wm.addView(rootView, layoutParams); wm.addView(rootView, layoutParams);
mDisplayDropTargets.put(displayId, addDisplayDropTarget(displayId, context, wm, rootView, dragLayout);
new PerDisplay(displayId, context, wm, rootView, dragLayout));
} catch (WindowManager.InvalidDisplayException e) { } catch (WindowManager.InvalidDisplayException e) {
Slog.w(TAG, "Unable to add view for display id: " + displayId); 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 @Override
public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display changed: %d", displayId); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display changed: %d", displayId);
@@ -206,6 +236,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId), pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
event.getClipData(), loggerSessionId); event.getClipData(), loggerSessionId);
setDropTargetWindowVisibility(pd, View.VISIBLE); setDropTargetWindowVisibility(pd, View.VISIBLE);
notifyListeners();
break; break;
case ACTION_DRAG_ENTERED: case ACTION_DRAG_ENTERED:
pd.dragLayout.show(); pd.dragLayout.show();

View File

@@ -16,15 +16,28 @@
package com.android.wm.shell.draganddrop; 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.junit.Assert.assertFalse;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; 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.Context;
import android.content.Intent;
import android.os.RemoteException; import android.os.RemoteException;
import android.view.Display; import android.view.Display;
import android.view.DragEvent; import android.view.DragEvent;
import android.view.View; import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -33,6 +46,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -40,6 +54,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.Optional;
/** /**
* Tests for the drag and drop controller. * Tests for the drag and drop controller.
*/ */
@@ -56,6 +72,9 @@ public class DragAndDropControllerTest {
@Mock @Mock
private UiEventLogger mUiEventLogger; private UiEventLogger mUiEventLogger;
@Mock
private DragAndDropController.DragAndDropListener mDragAndDropListener;
private DragAndDropController mController; private DragAndDropController mController;
@Before @Before
@@ -63,6 +82,7 @@ public class DragAndDropControllerTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger, mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger,
mock(IconProvider.class), mock(ShellExecutor.class)); mock(IconProvider.class), mock(ShellExecutor.class));
mController.initialize(Optional.of(mock(SplitScreenController.class)));
} }
@Test @Test
@@ -77,4 +97,45 @@ public class DragAndDropControllerTest {
mController.onDisplayAdded(nonDefaultDisplayId); mController.onDisplayAdded(nonDefaultDisplayId);
assertFalse(mController.onDrag(dragLayout, mock(DragEvent.class))); 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);
}
} }

View File

@@ -133,6 +133,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerImpl; 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.OneHandedController;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@@ -367,6 +368,7 @@ public class BubblesTest extends SysuiTestCase {
mPositioner, mPositioner,
mock(DisplayController.class), mock(DisplayController.class),
mOneHandedOptional, mOneHandedOptional,
mock(DragAndDropController.class),
syncExecutor, syncExecutor,
mock(Handler.class), mock(Handler.class),
mTaskViewTransitions, mTaskViewTransitions,

View File

@@ -116,6 +116,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerImpl; 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.OneHandedController;
import org.junit.Before; import org.junit.Before;
@@ -332,6 +333,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mPositioner, mPositioner,
mock(DisplayController.class), mock(DisplayController.class),
mOneHandedOptional, mOneHandedOptional,
mock(DragAndDropController.class),
syncExecutor, syncExecutor,
mock(Handler.class), mock(Handler.class),
mTaskViewTransitions, mTaskViewTransitions,

View File

@@ -35,6 +35,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerImpl; 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.OneHandedController;
import java.util.Optional; import java.util.Optional;
@@ -59,6 +60,7 @@ public class TestableBubbleController extends BubbleController {
BubblePositioner positioner, BubblePositioner positioner,
DisplayController displayController, DisplayController displayController,
Optional<OneHandedController> oneHandedOptional, Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
ShellExecutor shellMainExecutor, ShellExecutor shellMainExecutor,
Handler shellMainHandler, Handler shellMainHandler,
TaskViewTransitions taskViewTransitions, TaskViewTransitions taskViewTransitions,
@@ -66,8 +68,8 @@ public class TestableBubbleController extends BubbleController {
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository, super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
statusBarService, windowManager, windowManagerShellWrapper, launcherApps, statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController, bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
oneHandedOptional, shellMainExecutor, shellMainHandler, taskViewTransitions, oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
syncQueue); taskViewTransitions, syncQueue);
setInflateSynchronously(true); setInflateSynchronously(true);
initialize(); initialize();
} }