Merge "Collapse bubbles when drag and drop is initiated" into tm-dev

This commit is contained in:
Mady Mellor
2022-04-19 17:08:36 +00:00
committed by Android (Google) Code Review
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.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 @@ public class BubbleController {
/** 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 @@ public class BubbleController {
ShellTaskOrganizer organizer,
DisplayController displayController,
Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
ShellExecutor mainExecutor,
Handler mainHandler,
TaskViewTransitions taskViewTransitions,
@@ -241,8 +245,8 @@ public class BubbleController {
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 @@ public class BubbleController {
BubblePositioner positioner,
DisplayController displayController,
Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
ShellExecutor mainExecutor,
Handler mainHandler,
TaskViewTransitions taskViewTransitions,
@@ -293,6 +298,7 @@ public class BubbleController {
mDisplayController = displayController;
mTaskViewTransitions = taskViewTransitions;
mOneHandedOptional = oneHandedOptional;
mDragAndDropController = dragAndDropController;
mSyncQueue = syncQueue;
}
@@ -433,6 +439,7 @@ public class BubbleController {
});
mOneHandedOptional.ifPresent(this::registerOneHandedState);
mDragAndDropController.addListener(this::collapseStack);
}
@VisibleForTesting
@@ -884,7 +891,6 @@ public class BubbleController {
return mBubbleData.isExpanded();
}
@VisibleForTesting
public void collapseStack() {
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.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;
@@ -108,6 +109,7 @@ public class WMShellModule {
ShellTaskOrganizer organizer,
DisplayController displayController,
@DynamicOverride Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
TaskViewTransitions taskViewTransitions,
@@ -116,7 +118,7 @@ public class WMShellModule {
floatingContentCoordinator, statusBarService, windowManager,
windowManagerShellWrapper, launcherApps, taskStackListener,
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.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.ViewGroup;
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 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
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 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
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 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
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 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
event.getClipData(), loggerSessionId);
setDropTargetWindowVisibility(pd, View.VISIBLE);
notifyListeners();
break;
case ACTION_DRAG_ENTERED:
pd.dragLayout.show();

View File

@@ -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.internal.logging.UiEventLogger;
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.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Optional;
/**
* Tests for the drag and drop controller.
*/
@@ -56,6 +72,9 @@ public class DragAndDropControllerTest {
@Mock
private UiEventLogger mUiEventLogger;
@Mock
private DragAndDropController.DragAndDropListener mDragAndDropListener;
private DragAndDropController mController;
@Before
@@ -63,6 +82,7 @@ public class DragAndDropControllerTest {
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 @@ public class DragAndDropControllerTest {
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);
}
}

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.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 @@ public class BubblesTest extends SysuiTestCase {
mPositioner,
mock(DisplayController.class),
mOneHandedOptional,
mock(DragAndDropController.class),
syncExecutor,
mock(Handler.class),
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.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 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mPositioner,
mock(DisplayController.class),
mOneHandedOptional,
mock(DragAndDropController.class),
syncExecutor,
mock(Handler.class),
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.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 @@ public class TestableBubbleController extends BubbleController {
BubblePositioner positioner,
DisplayController displayController,
Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
ShellExecutor shellMainExecutor,
Handler shellMainHandler,
TaskViewTransitions taskViewTransitions,
@@ -66,8 +68,8 @@ public class TestableBubbleController extends BubbleController {
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();
}