summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mady Mellor <madym@google.com> 2021-11-30 18:17:14 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2021-11-30 18:17:14 +0000
commitf42d0346ffc8945da543e34127930b24f7a4d4d1 (patch)
treea0445e1184faf95b5cbbbd805b08548ca65f7596
parent23ca5b62c95ad0fb443f15e0523e46138c719564 (diff)
parent8653f2eeb55fdd3848359d3b41f14934e4924c29 (diff)
Merge "Drag and drop to split transition" into sc-v2-dev am: 8653f2eeb5
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16224193 Change-Id: Ie294b6d276c9d9862869c54c520f9b898df0919c
-rw-r--r--libs/WindowManager/Shell/res/color/taskbar_background.xml19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java225
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java313
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java3
14 files changed, 643 insertions, 63 deletions
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
new file mode 100644
index 000000000000..329e5b9b31a0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
+</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 6b622044d25d..9500e8aecb57 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -56,6 +56,7 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
@@ -156,8 +157,16 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static DragAndDropController provideDragAndDropController(Context context,
- DisplayController displayController, UiEventLogger uiEventLogger) {
- return new DragAndDropController(context, displayController, uiEventLogger);
+ DisplayController displayController, UiEventLogger uiEventLogger,
+ IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) {
+ return new DragAndDropController(context, displayController, uiEventLogger, iconProvider,
+ mainExecutor);
+ }
+
+ @WMSingleton
+ @Provides
+ static DragAndDrop provideDragAndDrop(DragAndDropController dragAndDropController) {
+ return dragAndDropController.asDragAndDrop();
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
new file mode 100644
index 000000000000..edeff6e37182
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.wm.shell.draganddrop;
+
+import android.content.res.Configuration;
+
+import com.android.wm.shell.common.annotations.ExternalThread;
+
+/**
+ * Interface for telling DragAndDrop stuff.
+ */
+@ExternalThread
+public interface DragAndDrop {
+
+ /** Called when the theme changes. */
+ void onThemeChanged();
+
+ /** Called when the configuration changes. */
+ void onConfigChanged(Configuration newConfig);
+}
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 d2b4711d30af..101295d246bc 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
@@ -41,7 +41,6 @@ import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.Display;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
@@ -53,8 +52,10 @@ import android.widget.FrameLayout;
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.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -71,16 +72,26 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
private final Context mContext;
private final DisplayController mDisplayController;
private final DragAndDropEventLogger mLogger;
+ private final IconProvider mIconProvider;
private SplitScreenController mSplitScreen;
+ private ShellExecutor mMainExecutor;
+ private DragAndDropImpl mImpl;
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
public DragAndDropController(Context context, DisplayController displayController,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) {
mContext = context;
mDisplayController = displayController;
mLogger = new DragAndDropEventLogger(uiEventLogger);
+ mIconProvider = iconProvider;
+ mMainExecutor = mainExecutor;
+ mImpl = new DragAndDropImpl();
+ }
+
+ public DragAndDrop asDragAndDrop() {
+ return mImpl;
}
public void initialize(Optional<SplitScreenController> splitscreen) {
@@ -117,7 +128,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
R.layout.global_drop_target, null);
rootView.setOnDragListener(this);
rootView.setVisibility(View.INVISIBLE);
- DragLayout dragLayout = new DragLayout(context, mSplitScreen);
+ DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
rootView.addView(dragLayout,
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
try {
@@ -267,6 +278,18 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
return mimeTypes;
}
+ private void onThemeChange() {
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ mDisplayDropTargets.get(i).dragLayout.onThemeChange();
+ }
+ }
+
+ private void onConfigChanged(Configuration newConfig) {
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig);
+ }
+ }
+
private static class PerDisplay {
final int displayId;
final Context context;
@@ -287,4 +310,21 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
dragLayout = dl;
}
}
+
+ private class DragAndDropImpl implements DragAndDrop {
+
+ @Override
+ public void onThemeChanged() {
+ mMainExecutor.execute(() -> {
+ DragAndDropController.this.onThemeChange();
+ });
+ }
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mMainExecutor.execute(() -> {
+ DragAndDropController.this.onConfigChanged(newConfig);
+ });
+ }
+ }
}
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 efc9ed0f75b2..20d8054f6e90 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
@@ -16,78 +16,138 @@
package com.android.wm.shell.draganddrop;
-import static com.android.wm.shell.animation.Interpolators.FAST_OUT_LINEAR_IN;
-import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.wm.shell.animation.Interpolators.LINEAR;
-import static com.android.wm.shell.animation.Interpolators.LINEAR_OUT_SLOW_IN;
+import static android.app.StatusBarManager.DISABLE_NONE;
+
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.StatusBarManager;
import android.content.ClipData;
import android.content.Context;
-import android.graphics.Canvas;
+import android.content.res.Configuration;
+import android.graphics.Color;
import android.graphics.Insets;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
import android.view.DragEvent;
import android.view.SurfaceControl;
-import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowInsets.Type;
-
-import androidx.annotation.NonNull;
+import android.widget.LinearLayout;
import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.ArrayList;
+import java.util.List;
/**
* Coordinates the visible drop targets for the current drag.
*/
-public class DragLayout extends View {
+public class DragLayout extends LinearLayout {
+
+ // While dragging the status bar is hidden.
+ private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
+ | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+ | StatusBarManager.DISABLE_CLOCK
+ | StatusBarManager.DISABLE_SYSTEM_INFO;
private final DragAndDropPolicy mPolicy;
+ private final SplitScreenController mSplitScreenController;
+ private final IconProvider mIconProvider;
+ private final StatusBarManager mStatusBarManager;
private DragAndDropPolicy.Target mCurrentTarget = null;
- private DropOutlineDrawable mDropOutline;
+ private DropZoneView mDropZoneView1;
+ private DropZoneView mDropZoneView2;
+
private int mDisplayMargin;
private Insets mInsets = Insets.NONE;
private boolean mIsShowing;
private boolean mHasDropped;
- public DragLayout(Context context, SplitScreenController splitscreen) {
+ @SuppressLint("WrongConstant")
+ public DragLayout(Context context, SplitScreenController splitScreenController,
+ IconProvider iconProvider) {
super(context);
- mPolicy = new DragAndDropPolicy(context, splitscreen);
+ mSplitScreenController = splitScreenController;
+ mIconProvider = iconProvider;
+ mPolicy = new DragAndDropPolicy(context, splitScreenController);
+ mStatusBarManager = context.getSystemService(StatusBarManager.class);
+
mDisplayMargin = context.getResources().getDimensionPixelSize(
R.dimen.drop_layout_display_margin);
- mDropOutline = new DropOutlineDrawable(context);
- setBackground(mDropOutline);
- setWillNotDraw(false);
+
+ mDropZoneView1 = new DropZoneView(context);
+ mDropZoneView2 = new DropZoneView(context);
+ addView(mDropZoneView1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ addView(mDropZoneView2, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ ((LayoutParams) mDropZoneView1.getLayoutParams()).weight = 1;
+ ((LayoutParams) mDropZoneView2.getLayoutParams()).weight = 1;
+ updateContainerMargins();
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout());
recomputeDropTargets();
+
+ final int orientation = getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mDropZoneView1.setBottomInset(mInsets.bottom);
+ mDropZoneView2.setBottomInset(mInsets.bottom);
+ } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ mDropZoneView1.setBottomInset(0);
+ mDropZoneView2.setBottomInset(mInsets.bottom);
+ }
return super.onApplyWindowInsets(insets);
}
- @Override
- protected boolean verifyDrawable(@NonNull Drawable who) {
- return who == mDropOutline || super.verifyDrawable(who);
+ public void onThemeChange() {
+ mDropZoneView1.onThemeChange();
+ mDropZoneView2.onThemeChange();
}
- @Override
- protected void onDraw(Canvas canvas) {
- if (mCurrentTarget != null) {
- mDropOutline.draw(canvas);
+ public void onConfigChanged(Configuration newConfig) {
+ final int orientation = getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE
+ && getOrientation() != HORIZONTAL) {
+ setOrientation(LinearLayout.HORIZONTAL);
+ updateContainerMargins();
+ } else if (orientation == Configuration.ORIENTATION_PORTRAIT
+ && getOrientation() != VERTICAL) {
+ setOrientation(LinearLayout.VERTICAL);
+ updateContainerMargins();
+ }
+ }
+
+ private void updateContainerMargins() {
+ final int orientation = getResources().getConfiguration().orientation;
+ final float halfMargin = mDisplayMargin / 2f;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mDropZoneView1.setContainerMargin(
+ mDisplayMargin, mDisplayMargin, halfMargin, mDisplayMargin);
+ mDropZoneView2.setContainerMargin(
+ halfMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin);
+ } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ mDropZoneView1.setContainerMargin(
+ mDisplayMargin, mDisplayMargin, mDisplayMargin, halfMargin);
+ mDropZoneView2.setContainerMargin(
+ mDisplayMargin, halfMargin, mDisplayMargin, mDisplayMargin);
}
}
@@ -104,6 +164,43 @@ public class DragLayout extends View {
mPolicy.start(displayLayout, initialData, loggerSessionId);
mHasDropped = false;
mCurrentTarget = null;
+
+ List<ActivityManager.RunningTaskInfo> tasks = null;
+ // Figure out the splashscreen info for the existing task(s).
+ try {
+ tasks = ActivityTaskManager.getService().getTasks(2,
+ false /* filterOnlyVisibleRecents */,
+ false /* keepIntentExtra */);
+ } catch (RemoteException e) {
+ // don't show an icon / will just use the defaults
+ }
+ if (tasks != null && !tasks.isEmpty()) {
+ ActivityManager.RunningTaskInfo taskInfo1 = tasks.get(0);
+ Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
+ int bgColor1 = getResizingBackgroundColor(taskInfo1);
+
+ boolean alreadyInSplit = mSplitScreenController != null
+ && mSplitScreenController.isSplitScreenVisible();
+ if (alreadyInSplit && tasks.size() > 1) {
+ ActivityManager.RunningTaskInfo taskInfo2 = tasks.get(1);
+ Drawable icon2 = mIconProvider.getIcon(taskInfo2.topActivityInfo);
+ int bgColor2 = getResizingBackgroundColor(taskInfo2);
+
+ // figure out which task is on which side
+ int splitPosition1 = mSplitScreenController.getSplitPosition(taskInfo1.taskId);
+ boolean isTask1TopOrLeft = splitPosition1 == SPLIT_POSITION_TOP_OR_LEFT;
+ if (isTask1TopOrLeft) {
+ mDropZoneView1.setAppInfo(bgColor1, icon1);
+ mDropZoneView2.setAppInfo(bgColor2, icon2);
+ } else {
+ mDropZoneView2.setAppInfo(bgColor1, icon1);
+ mDropZoneView1.setAppInfo(bgColor2, icon2);
+ }
+ } else {
+ mDropZoneView1.setAppInfo(bgColor1, icon1);
+ mDropZoneView2.setAppInfo(bgColor1, icon1);
+ }
+ }
}
public void show() {
@@ -139,20 +236,14 @@ public class DragLayout extends View {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
if (target == null) {
// Animating to no target
- mDropOutline.startVisibilityAnimation(false, LINEAR);
- Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
- finalBounds.inset(mDisplayMargin, mDisplayMargin);
- mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
+ animateSplitContainers(false, null /* animCompleteCallback */);
} else if (mCurrentTarget == null) {
// Animating to first target
- mDropOutline.startVisibilityAnimation(true, LINEAR);
- Rect initialBounds = new Rect(target.drawRegion);
- initialBounds.inset(mDisplayMargin, mDisplayMargin);
- mDropOutline.setRegionBounds(initialBounds);
- mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN);
+ animateSplitContainers(true, null /* animCompleteCallback */);
+ animateHighlight(target);
} else {
- // Bounds change
- mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN);
+ // Switching between targets
+ animateHighlight(target);
}
mCurrentTarget = target;
}
@@ -163,26 +254,7 @@ public class DragLayout extends View {
*/
public void hide(DragEvent event, Runnable hideCompleteCallback) {
mIsShowing = false;
- ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
- ObjectAnimator boundsAnimator = null;
- if (mCurrentTarget != null) {
- Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
- finalBounds.inset(mDisplayMargin, mDisplayMargin);
- boundsAnimator = mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
- }
-
- if (hideCompleteCallback != null) {
- ObjectAnimator lastAnim = boundsAnimator != null
- ? boundsAnimator
- : alphaAnimator;
- lastAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- hideCompleteCallback.run();
- }
- });
- }
-
+ animateSplitContainers(false, hideCompleteCallback);
mCurrentTarget = null;
}
@@ -201,4 +273,49 @@ public class DragLayout extends View {
hide(event, dropCompleteCallback);
return handledDrop;
}
+
+ private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) {
+ mStatusBarManager.disable(visible
+ ? HIDE_STATUS_BAR_FLAGS
+ : DISABLE_NONE);
+ mDropZoneView1.setShowingMargin(visible);
+ mDropZoneView2.setShowingMargin(visible);
+ ObjectAnimator animator = mDropZoneView1.getAnimator();
+ if (animCompleteCallback != null) {
+ if (animator != null) {
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animCompleteCallback.run();
+ }
+ });
+ } else {
+ // If there's no animator the animation is done so run immediately
+ animCompleteCallback.run();
+ }
+ }
+ }
+
+ private void animateHighlight(DragAndDropPolicy.Target target) {
+ if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_LEFT
+ || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_TOP) {
+ mDropZoneView1.setShowingHighlight(true);
+ mDropZoneView1.setShowingSplash(false);
+
+ mDropZoneView2.setShowingHighlight(false);
+ mDropZoneView2.setShowingSplash(true);
+ } else if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT
+ || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM) {
+ mDropZoneView1.setShowingHighlight(false);
+ mDropZoneView1.setShowingSplash(true);
+
+ mDropZoneView2.setShowingHighlight(true);
+ mDropZoneView2.setShowingSplash(false);
+ }
+ }
+
+ private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
+ final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
+ return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
+ }
}
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
new file mode 100644
index 000000000000..2f47af57d496
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2021 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.wm.shell.draganddrop;
+
+import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.wm.shell.R;
+
+/**
+ * Renders a drop zone area for items being dragged.
+ */
+public class DropZoneView extends FrameLayout {
+
+ private static final int SPLASHSCREEN_ALPHA_INT = (int) (255 * 0.90f);
+ private static final int HIGHLIGHT_ALPHA_INT = 255;
+ private static final int MARGIN_ANIMATION_ENTER_DURATION = 400;
+ private static final int MARGIN_ANIMATION_EXIT_DURATION = 250;
+
+ private static final FloatProperty<DropZoneView> INSETS =
+ new FloatProperty<DropZoneView>("insets") {
+ @Override
+ public void setValue(DropZoneView v, float percent) {
+ v.setMarginPercent(percent);
+ }
+
+ @Override
+ public Float get(DropZoneView v) {
+ return v.getMarginPercent();
+ }
+ };
+
+ private static final IntProperty<ColorDrawable> SPLASHSCREEN_ALPHA =
+ new IntProperty<ColorDrawable>("splashscreen") {
+ @Override
+ public void setValue(ColorDrawable d, int alpha) {
+ d.setAlpha(alpha);
+ }
+
+ @Override
+ public Integer get(ColorDrawable d) {
+ return d.getAlpha();
+ }
+ };
+
+ private static final IntProperty<ColorDrawable> HIGHLIGHT_ALPHA =
+ new IntProperty<ColorDrawable>("highlight") {
+ @Override
+ public void setValue(ColorDrawable d, int alpha) {
+ d.setAlpha(alpha);
+ }
+
+ @Override
+ public Integer get(ColorDrawable d) {
+ return d.getAlpha();
+ }
+ };
+
+ private final Path mPath = new Path();
+ private final float[] mContainerMargin = new float[4];
+ private float mCornerRadius;
+ private float mBottomInset;
+ private int mMarginColor; // i.e. color used for negative space like the container insets
+ private int mHighlightColor;
+
+ private boolean mShowingHighlight;
+ private boolean mShowingSplash;
+ private boolean mShowingMargin;
+
+ // TODO: might be more seamless to animate between splash/highlight color instead of 2 separate
+ private ObjectAnimator mSplashAnimator;
+ private ObjectAnimator mHighlightAnimator;
+ private ObjectAnimator mMarginAnimator;
+ private float mMarginPercent;
+
+ // Renders a highlight or neutral transparent color
+ private ColorDrawable mDropZoneDrawable;
+ // Renders the translucent splashscreen with the app icon in the middle
+ private ImageView mSplashScreenView;
+ private ColorDrawable mSplashBackgroundDrawable;
+ // Renders the margin / insets around the dropzone container
+ private MarginView mMarginView;
+
+ public DropZoneView(Context context) {
+ this(context, null);
+ }
+
+ public DropZoneView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DropZoneView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public DropZoneView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ setContainerMargin(0, 0, 0, 0); // make sure it's populated
+
+ mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
+ mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
+
+ mDropZoneDrawable = new ColorDrawable();
+ mDropZoneDrawable.setColor(mHighlightColor);
+ mDropZoneDrawable.setAlpha(0);
+ setBackgroundDrawable(mDropZoneDrawable);
+
+ mSplashScreenView = new ImageView(context);
+ mSplashScreenView.setScaleType(ImageView.ScaleType.CENTER);
+ mSplashBackgroundDrawable = new ColorDrawable();
+ mSplashBackgroundDrawable.setColor(Color.WHITE);
+ mSplashBackgroundDrawable.setAlpha(SPLASHSCREEN_ALPHA_INT);
+ mSplashScreenView.setBackgroundDrawable(mSplashBackgroundDrawable);
+ addView(mSplashScreenView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ mSplashScreenView.setAlpha(0f);
+
+ mMarginView = new MarginView(context);
+ addView(mMarginView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ }
+
+ public void onThemeChange() {
+ mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(getContext());
+ mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
+
+ final int alpha = mDropZoneDrawable.getAlpha();
+ mDropZoneDrawable.setColor(mHighlightColor);
+ mDropZoneDrawable.setAlpha(alpha);
+
+ if (mMarginPercent > 0) {
+ mMarginView.invalidate();
+ }
+ }
+
+ /** Sets the desired margins around the drop zone container when fully showing. */
+ public void setContainerMargin(float left, float top, float right, float bottom) {
+ mContainerMargin[0] = left;
+ mContainerMargin[1] = top;
+ mContainerMargin[2] = right;
+ mContainerMargin[3] = bottom;
+ if (mMarginPercent > 0) {
+ mMarginView.invalidate();
+ }
+ }
+
+ /** Sets the bottom inset so the drop zones are above bottom navigation. */
+ public void setBottomInset(float bottom) {
+ mBottomInset = bottom;
+ ((LayoutParams) mSplashScreenView.getLayoutParams()).bottomMargin = (int) bottom;
+ if (mMarginPercent > 0) {
+ mMarginView.invalidate();
+ }
+ }
+
+ /** Sets the color and icon to use for the splashscreen when shown. */
+ public void setAppInfo(int splashScreenColor, Drawable appIcon) {
+ mSplashBackgroundDrawable.setColor(splashScreenColor);
+ mSplashScreenView.setImageDrawable(appIcon);
+ }
+
+ /** @return an active animator for this view if one exists. */
+ @Nullable
+ public ObjectAnimator getAnimator() {
+ if (mMarginAnimator != null && mMarginAnimator.isRunning()) {
+ return mMarginAnimator;
+ } else if (mHighlightAnimator != null && mHighlightAnimator.isRunning()) {
+ return mHighlightAnimator;
+ } else if (mSplashAnimator != null && mSplashAnimator.isRunning()) {
+ return mSplashAnimator;
+ }
+ return null;
+ }
+
+ /** Animates the splashscreen to show or hide. */
+ public void setShowingSplash(boolean showingSplash) {
+ if (mShowingSplash != showingSplash) {
+ mShowingSplash = showingSplash;
+ animateSplashToState();
+ }
+ }
+
+ /** Animates the highlight indicating the zone is hovered on or not. */
+ public void setShowingHighlight(boolean showingHighlight) {
+ if (mShowingHighlight != showingHighlight) {
+ mShowingHighlight = showingHighlight;
+ animateHighlightToState();
+ }
+ }
+
+ /** Animates the margins around the drop zone to show or hide. */
+ public void setShowingMargin(boolean visible) {
+ if (mShowingMargin != visible) {
+ mShowingMargin = visible;
+ animateMarginToState();
+ }
+ if (!mShowingMargin) {
+ setShowingHighlight(false);
+ setShowingSplash(false);
+ }
+ }
+
+ private void animateSplashToState() {
+ if (mSplashAnimator != null) {
+ mSplashAnimator.cancel();
+ }
+ mSplashAnimator = ObjectAnimator.ofInt(mSplashBackgroundDrawable,
+ SPLASHSCREEN_ALPHA,
+ mSplashBackgroundDrawable.getAlpha(),
+ mShowingSplash ? SPLASHSCREEN_ALPHA_INT : 0);
+ if (!mShowingSplash) {
+ mSplashAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+ }
+ mSplashAnimator.start();
+ mSplashScreenView.animate().alpha(mShowingSplash ? 1f : 0f).start();
+ }
+
+ private void animateHighlightToState() {
+ if (mHighlightAnimator != null) {
+ mHighlightAnimator.cancel();
+ }
+ mHighlightAnimator = ObjectAnimator.ofInt(mDropZoneDrawable,
+ HIGHLIGHT_ALPHA,
+ mDropZoneDrawable.getAlpha(),
+ mShowingHighlight ? HIGHLIGHT_ALPHA_INT : 0);
+ if (!mShowingHighlight) {
+ mHighlightAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+ }
+ mHighlightAnimator.start();
+ }
+
+ private void animateMarginToState() {
+ if (mMarginAnimator != null) {
+ mMarginAnimator.cancel();
+ }
+ mMarginAnimator = ObjectAnimator.ofFloat(this, INSETS,
+ mMarginPercent,
+ mShowingMargin ? 1f : 0f);
+ mMarginAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+ mMarginAnimator.setDuration(mShowingMargin
+ ? MARGIN_ANIMATION_ENTER_DURATION
+ : MARGIN_ANIMATION_EXIT_DURATION);
+ mMarginAnimator.start();
+ }
+
+ private void setMarginPercent(float percent) {
+ if (percent != mMarginPercent) {
+ mMarginPercent = percent;
+ mMarginView.invalidate();
+ }
+ }
+
+ private float getMarginPercent() {
+ return mMarginPercent;
+ }
+
+ /** Simple view that draws a rounded rect margin around its contents. **/
+ private class MarginView extends View {
+
+ MarginView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ mPath.reset();
+ mPath.addRoundRect(mContainerMargin[0] * mMarginPercent,
+ mContainerMargin[1] * mMarginPercent,
+ getWidth() - (mContainerMargin[2] * mMarginPercent),
+ getHeight() - (mContainerMargin[3] * mMarginPercent) - mBottomInset,
+ mCornerRadius * mMarginPercent,
+ mCornerRadius * mMarginPercent,
+ Path.Direction.CW);
+ mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+ canvas.clipPath(mPath);
+ canvas.drawColor(mMarginColor);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 262a9a1ba2be..d2e341d3c38c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -188,6 +188,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
&& mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
}
+ public @SplitPosition int getSplitPosition(int taskId) {
+ return mStageCoordinator.getSplitPosition(taskId);
+ }
+
public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
new WindowContainerTransaction());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a5579ae7dc25..8ad0f200d448 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -678,6 +678,16 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
outBottomOrRightBounds.set(mSplitLayout.getBounds2());
}
+ @SplitPosition
+ int getSplitPosition(int taskId) {
+ if (mSideStage.getTopVisibleChildTaskId() == taskId) {
+ return getSideStagePosition();
+ } else if (mMainStage.getTopVisibleChildTaskId() == taskId) {
+ return getMainStagePosition();
+ }
+ return SPLIT_POSITION_UNDEFINED;
+ }
+
private void addActivityOptions(Bundle opts, StageTaskListener stage) {
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
}
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 bfa2c92f6679..9f745208d3ed 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
@@ -30,7 +30,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
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 org.junit.Before;
import org.junit.Test;
@@ -59,8 +61,8 @@ public class DragAndDropControllerTest {
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
-
- mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger);
+ mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger,
+ mock(IconProvider.class), mock(ShellExecutor.class));
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index d37dcafde92a..bb0e79fe23a8 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -121,7 +121,8 @@ public class SystemUIFactory {
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
.setRecentTasks(mWMComponent.getRecentTasks())
- .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()));
+ .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()))
+ .setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop()));
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
// is separating this logic into newly creating SystemUITestsFactory.
@@ -140,7 +141,8 @@ public class SystemUIFactory {
.setStartingSurface(Optional.ofNullable(null))
.setTaskSurfaceHelper(Optional.ofNullable(null))
.setRecentTasks(Optional.ofNullable(null))
- .setSizeCompatUI(Optional.ofNullable(null));
+ .setSizeCompatUI(Optional.ofNullable(null))
+ .setDragAndDrop(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 5fdf026b86f3..c5d3a70676d0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -32,6 +32,7 @@ import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
@@ -111,6 +112,9 @@ public interface SysUIComponent {
@BindsInstance
Builder setSizeCompatUI(Optional<SizeCompatUI> s);
+ @BindsInstance
+ Builder setDragAndDrop(Optional<DragAndDrop> d);
+
SysUIComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 543ba8f9b854..90a3ad225f51 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -29,6 +29,7 @@ import com.android.wm.shell.dagger.TvWMShellModule;
import com.android.wm.shell.dagger.WMShellModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
@@ -119,4 +120,7 @@ public interface WMComponent {
@WMSingleton
SizeCompatUI getSizeCompatUI();
+
+ @WMSingleton
+ DragAndDrop getDragAndDrop();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a56c177ef9ae..b546edf428b8 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -56,6 +56,7 @@ import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.ShellCommandHandler;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.nano.WmShellTraceProto;
@@ -114,6 +115,7 @@ public final class WMShell extends SystemUI
private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
private final Optional<ShellCommandHandler> mShellCommandHandler;
private final Optional<SizeCompatUI> mSizeCompatUIOptional;
+ private final Optional<DragAndDrop> mDragAndDropOptional;
private final CommandQueue mCommandQueue;
private final ConfigurationController mConfigurationController;
@@ -142,6 +144,7 @@ public final class WMShell extends SystemUI
Optional<HideDisplayCutout> hideDisplayCutoutOptional,
Optional<ShellCommandHandler> shellCommandHandler,
Optional<SizeCompatUI> sizeCompatUIOptional,
+ Optional<DragAndDrop> dragAndDropOptional,
CommandQueue commandQueue,
ConfigurationController configurationController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -167,6 +170,7 @@ public final class WMShell extends SystemUI
mProtoTracer = protoTracer;
mShellCommandHandler = shellCommandHandler;
mSizeCompatUIOptional = sizeCompatUIOptional;
+ mDragAndDropOptional = dragAndDropOptional;
mSysUiMainExecutor = sysUiMainExecutor;
}
@@ -182,6 +186,7 @@ public final class WMShell extends SystemUI
mOneHandedOptional.ifPresent(this::initOneHanded);
mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
mSizeCompatUIOptional.ifPresent(this::initSizeCompatUi);
+ mDragAndDropOptional.ifPresent(this::initDragAndDrop);
}
@VisibleForTesting
@@ -396,6 +401,20 @@ public final class WMShell extends SystemUI
mKeyguardUpdateMonitor.registerCallback(mSizeCompatUIKeyguardCallback);
}
+ void initDragAndDrop(DragAndDrop dragAndDrop) {
+ mConfigurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ dragAndDrop.onConfigChanged(newConfig);
+ }
+
+ @Override
+ public void onThemeChanged() {
+ dragAndDrop.onThemeChanged();
+ }
+ });
+ }
+
@Override
public void writeToProto(SystemUiTraceProto proto) {
if (proto.wmShell == null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index ae7afcef57a6..1e15d2ae0bdb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
@@ -79,6 +80,7 @@ public class WMShellTest extends SysuiTestCase {
@Mock ShellCommandHandler mShellCommandHandler;
@Mock SizeCompatUI mSizeCompatUI;
@Mock ShellExecutor mSysUiMainExecutor;
+ @Mock DragAndDrop mDragAndDrop;
@Before
public void setUp() {
@@ -87,6 +89,7 @@ public class WMShellTest extends SysuiTestCase {
mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
Optional.of(mShellCommandHandler), Optional.of(mSizeCompatUI),
+ Optional.of(mDragAndDrop),
mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
mWakefulnessLifecycle, mSysUiMainExecutor);