Merge "Drag and drop to split transition" into sc-v2-dev
This commit is contained in:
19
libs/WindowManager/Shell/res/color/taskbar_background.xml
Normal file
19
libs/WindowManager/Shell/res/color/taskbar_background.xml
Normal file
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user