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
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.common.annotations.ShellSplashscreenThread;
|
||||||
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
|
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
|
||||||
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
|
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.draganddrop.DragAndDropController;
|
||||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||||
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
|
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
|
||||||
@@ -156,8 +157,16 @@ public abstract class WMShellBaseModule {
|
|||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static DragAndDropController provideDragAndDropController(Context context,
|
static DragAndDropController provideDragAndDropController(Context context,
|
||||||
DisplayController displayController, UiEventLogger uiEventLogger) {
|
DisplayController displayController, UiEventLogger uiEventLogger,
|
||||||
return new DragAndDropController(context, displayController, 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
|
@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.graphics.PixelFormat;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.Display;
|
|
||||||
import android.view.DragEvent;
|
import android.view.DragEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
@@ -53,8 +52,10 @@ import android.widget.FrameLayout;
|
|||||||
import com.android.internal.logging.InstanceId;
|
import com.android.internal.logging.InstanceId;
|
||||||
import com.android.internal.logging.UiEventLogger;
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.internal.protolog.common.ProtoLog;
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
|
import com.android.launcher3.icons.IconProvider;
|
||||||
import com.android.wm.shell.R;
|
import com.android.wm.shell.R;
|
||||||
import com.android.wm.shell.common.DisplayController;
|
import com.android.wm.shell.common.DisplayController;
|
||||||
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
|
|
||||||
@@ -71,16 +72,26 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
|
|||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final DisplayController mDisplayController;
|
private final DisplayController mDisplayController;
|
||||||
private final DragAndDropEventLogger mLogger;
|
private final DragAndDropEventLogger mLogger;
|
||||||
|
private final IconProvider mIconProvider;
|
||||||
private SplitScreenController mSplitScreen;
|
private SplitScreenController mSplitScreen;
|
||||||
|
private ShellExecutor mMainExecutor;
|
||||||
|
private DragAndDropImpl mImpl;
|
||||||
|
|
||||||
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
|
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
|
||||||
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
|
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
|
||||||
|
|
||||||
public DragAndDropController(Context context, DisplayController displayController,
|
public DragAndDropController(Context context, DisplayController displayController,
|
||||||
UiEventLogger uiEventLogger) {
|
UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mDisplayController = displayController;
|
mDisplayController = displayController;
|
||||||
mLogger = new DragAndDropEventLogger(uiEventLogger);
|
mLogger = new DragAndDropEventLogger(uiEventLogger);
|
||||||
|
mIconProvider = iconProvider;
|
||||||
|
mMainExecutor = mainExecutor;
|
||||||
|
mImpl = new DragAndDropImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DragAndDrop asDragAndDrop() {
|
||||||
|
return mImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(Optional<SplitScreenController> splitscreen) {
|
public void initialize(Optional<SplitScreenController> splitscreen) {
|
||||||
@@ -117,7 +128,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
|
|||||||
R.layout.global_drop_target, null);
|
R.layout.global_drop_target, null);
|
||||||
rootView.setOnDragListener(this);
|
rootView.setOnDragListener(this);
|
||||||
rootView.setVisibility(View.INVISIBLE);
|
rootView.setVisibility(View.INVISIBLE);
|
||||||
DragLayout dragLayout = new DragLayout(context, mSplitScreen);
|
DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
|
||||||
rootView.addView(dragLayout,
|
rootView.addView(dragLayout,
|
||||||
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
||||||
try {
|
try {
|
||||||
@@ -267,6 +278,18 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
|
|||||||
return mimeTypes;
|
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 {
|
private static class PerDisplay {
|
||||||
final int displayId;
|
final int displayId;
|
||||||
final Context context;
|
final Context context;
|
||||||
@@ -287,4 +310,21 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
|
|||||||
dragLayout = dl;
|
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;
|
package com.android.wm.shell.draganddrop;
|
||||||
|
|
||||||
import static com.android.wm.shell.animation.Interpolators.FAST_OUT_LINEAR_IN;
|
import static android.app.StatusBarManager.DISABLE_NONE;
|
||||||
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.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
|
||||||
import static com.android.wm.shell.animation.Interpolators.LINEAR_OUT_SLOW_IN;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.animation.ObjectAnimator;
|
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.ClipData;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.view.DragEvent;
|
import android.view.DragEvent;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.View;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.view.WindowInsets.Type;
|
import android.view.WindowInsets.Type;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.android.internal.logging.InstanceId;
|
import com.android.internal.logging.InstanceId;
|
||||||
import com.android.internal.protolog.common.ProtoLog;
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
|
import com.android.launcher3.icons.IconProvider;
|
||||||
import com.android.wm.shell.R;
|
import com.android.wm.shell.R;
|
||||||
import com.android.wm.shell.common.DisplayLayout;
|
import com.android.wm.shell.common.DisplayLayout;
|
||||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coordinates the visible drop targets for the current drag.
|
* 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 DragAndDropPolicy mPolicy;
|
||||||
|
private final SplitScreenController mSplitScreenController;
|
||||||
|
private final IconProvider mIconProvider;
|
||||||
|
private final StatusBarManager mStatusBarManager;
|
||||||
|
|
||||||
private DragAndDropPolicy.Target mCurrentTarget = null;
|
private DragAndDropPolicy.Target mCurrentTarget = null;
|
||||||
private DropOutlineDrawable mDropOutline;
|
private DropZoneView mDropZoneView1;
|
||||||
|
private DropZoneView mDropZoneView2;
|
||||||
|
|
||||||
private int mDisplayMargin;
|
private int mDisplayMargin;
|
||||||
private Insets mInsets = Insets.NONE;
|
private Insets mInsets = Insets.NONE;
|
||||||
|
|
||||||
private boolean mIsShowing;
|
private boolean mIsShowing;
|
||||||
private boolean mHasDropped;
|
private boolean mHasDropped;
|
||||||
|
|
||||||
public DragLayout(Context context, SplitScreenController splitscreen) {
|
@SuppressLint("WrongConstant")
|
||||||
|
public DragLayout(Context context, SplitScreenController splitScreenController,
|
||||||
|
IconProvider iconProvider) {
|
||||||
super(context);
|
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(
|
mDisplayMargin = context.getResources().getDimensionPixelSize(
|
||||||
R.dimen.drop_layout_display_margin);
|
R.dimen.drop_layout_display_margin);
|
||||||
mDropOutline = new DropOutlineDrawable(context);
|
|
||||||
setBackground(mDropOutline);
|
mDropZoneView1 = new DropZoneView(context);
|
||||||
setWillNotDraw(false);
|
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
|
@Override
|
||||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||||
mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout());
|
mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout());
|
||||||
recomputeDropTargets();
|
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);
|
return super.onApplyWindowInsets(insets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void onThemeChange() {
|
||||||
protected boolean verifyDrawable(@NonNull Drawable who) {
|
mDropZoneView1.onThemeChange();
|
||||||
return who == mDropOutline || super.verifyDrawable(who);
|
mDropZoneView2.onThemeChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void onConfigChanged(Configuration newConfig) {
|
||||||
protected void onDraw(Canvas canvas) {
|
final int orientation = getResources().getConfiguration().orientation;
|
||||||
if (mCurrentTarget != null) {
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
mDropOutline.draw(canvas);
|
&& 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);
|
mPolicy.start(displayLayout, initialData, loggerSessionId);
|
||||||
mHasDropped = false;
|
mHasDropped = false;
|
||||||
mCurrentTarget = null;
|
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() {
|
public void show() {
|
||||||
@@ -139,20 +236,14 @@ public class DragLayout extends View {
|
|||||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
// Animating to no target
|
// Animating to no target
|
||||||
mDropOutline.startVisibilityAnimation(false, LINEAR);
|
animateSplitContainers(false, null /* animCompleteCallback */);
|
||||||
Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
|
|
||||||
finalBounds.inset(mDisplayMargin, mDisplayMargin);
|
|
||||||
mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
|
|
||||||
} else if (mCurrentTarget == null) {
|
} else if (mCurrentTarget == null) {
|
||||||
// Animating to first target
|
// Animating to first target
|
||||||
mDropOutline.startVisibilityAnimation(true, LINEAR);
|
animateSplitContainers(true, null /* animCompleteCallback */);
|
||||||
Rect initialBounds = new Rect(target.drawRegion);
|
animateHighlight(target);
|
||||||
initialBounds.inset(mDisplayMargin, mDisplayMargin);
|
|
||||||
mDropOutline.setRegionBounds(initialBounds);
|
|
||||||
mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN);
|
|
||||||
} else {
|
} else {
|
||||||
// Bounds change
|
// Switching between targets
|
||||||
mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN);
|
animateHighlight(target);
|
||||||
}
|
}
|
||||||
mCurrentTarget = target;
|
mCurrentTarget = target;
|
||||||
}
|
}
|
||||||
@@ -163,26 +254,7 @@ public class DragLayout extends View {
|
|||||||
*/
|
*/
|
||||||
public void hide(DragEvent event, Runnable hideCompleteCallback) {
|
public void hide(DragEvent event, Runnable hideCompleteCallback) {
|
||||||
mIsShowing = false;
|
mIsShowing = false;
|
||||||
ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
|
animateSplitContainers(false, hideCompleteCallback);
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mCurrentTarget = null;
|
mCurrentTarget = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,4 +273,49 @@ public class DragLayout extends View {
|
|||||||
hide(event, dropCompleteCallback);
|
hide(event, dropCompleteCallback);
|
||||||
return handledDrop;
|
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;
|
&& mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @SplitPosition int getSplitPosition(int taskId) {
|
||||||
|
return mStageCoordinator.getSplitPosition(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
|
public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
|
||||||
return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
|
return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
|
||||||
new WindowContainerTransaction());
|
new WindowContainerTransaction());
|
||||||
|
|||||||
@@ -678,6 +678,16 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
outBottomOrRightBounds.set(mSplitLayout.getBounds2());
|
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) {
|
private void addActivityOptions(Bundle opts, StageTaskListener stage) {
|
||||||
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
|
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 androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.internal.logging.UiEventLogger;
|
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.DisplayController;
|
||||||
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -59,8 +61,8 @@ public class DragAndDropControllerTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws RemoteException {
|
public void setUp() throws RemoteException {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger,
|
||||||
mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger);
|
mock(IconProvider.class), mock(ShellExecutor.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -121,7 +121,8 @@ public class SystemUIFactory {
|
|||||||
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
|
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
|
||||||
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
|
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
|
||||||
.setRecentTasks(mWMComponent.getRecentTasks())
|
.setRecentTasks(mWMComponent.getRecentTasks())
|
||||||
.setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()));
|
.setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()))
|
||||||
|
.setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop()));
|
||||||
} else {
|
} else {
|
||||||
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
|
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
|
||||||
// is separating this logic into newly creating SystemUITestsFactory.
|
// is separating this logic into newly creating SystemUITestsFactory.
|
||||||
@@ -140,7 +141,8 @@ public class SystemUIFactory {
|
|||||||
.setStartingSurface(Optional.ofNullable(null))
|
.setStartingSurface(Optional.ofNullable(null))
|
||||||
.setTaskSurfaceHelper(Optional.ofNullable(null))
|
.setTaskSurfaceHelper(Optional.ofNullable(null))
|
||||||
.setRecentTasks(Optional.ofNullable(null))
|
.setRecentTasks(Optional.ofNullable(null))
|
||||||
.setSizeCompatUI(Optional.ofNullable(null));
|
.setSizeCompatUI(Optional.ofNullable(null))
|
||||||
|
.setDragAndDrop(Optional.ofNullable(null));
|
||||||
}
|
}
|
||||||
mSysUIComponent = builder.build();
|
mSysUIComponent = builder.build();
|
||||||
if (mInitializeComponents) {
|
if (mInitializeComponents) {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.android.wm.shell.TaskViewFactory;
|
|||||||
import com.android.wm.shell.apppairs.AppPairs;
|
import com.android.wm.shell.apppairs.AppPairs;
|
||||||
import com.android.wm.shell.bubbles.Bubbles;
|
import com.android.wm.shell.bubbles.Bubbles;
|
||||||
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
|
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.hidedisplaycutout.HideDisplayCutout;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
@@ -111,6 +112,9 @@ public interface SysUIComponent {
|
|||||||
@BindsInstance
|
@BindsInstance
|
||||||
Builder setSizeCompatUI(Optional<SizeCompatUI> s);
|
Builder setSizeCompatUI(Optional<SizeCompatUI> s);
|
||||||
|
|
||||||
|
@BindsInstance
|
||||||
|
Builder setDragAndDrop(Optional<DragAndDrop> d);
|
||||||
|
|
||||||
SysUIComponent build();
|
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.WMShellModule;
|
||||||
import com.android.wm.shell.dagger.WMSingleton;
|
import com.android.wm.shell.dagger.WMSingleton;
|
||||||
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
|
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.hidedisplaycutout.HideDisplayCutout;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
@@ -119,4 +120,7 @@ public interface WMComponent {
|
|||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
SizeCompatUI getSizeCompatUI();
|
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.ProtoTracer;
|
||||||
import com.android.systemui.tracing.nano.SystemUiTraceProto;
|
import com.android.systemui.tracing.nano.SystemUiTraceProto;
|
||||||
import com.android.wm.shell.ShellCommandHandler;
|
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.hidedisplaycutout.HideDisplayCutout;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
import com.android.wm.shell.nano.WmShellTraceProto;
|
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<HideDisplayCutout> mHideDisplayCutoutOptional;
|
||||||
private final Optional<ShellCommandHandler> mShellCommandHandler;
|
private final Optional<ShellCommandHandler> mShellCommandHandler;
|
||||||
private final Optional<SizeCompatUI> mSizeCompatUIOptional;
|
private final Optional<SizeCompatUI> mSizeCompatUIOptional;
|
||||||
|
private final Optional<DragAndDrop> mDragAndDropOptional;
|
||||||
|
|
||||||
private final CommandQueue mCommandQueue;
|
private final CommandQueue mCommandQueue;
|
||||||
private final ConfigurationController mConfigurationController;
|
private final ConfigurationController mConfigurationController;
|
||||||
@@ -142,6 +144,7 @@ public final class WMShell extends SystemUI
|
|||||||
Optional<HideDisplayCutout> hideDisplayCutoutOptional,
|
Optional<HideDisplayCutout> hideDisplayCutoutOptional,
|
||||||
Optional<ShellCommandHandler> shellCommandHandler,
|
Optional<ShellCommandHandler> shellCommandHandler,
|
||||||
Optional<SizeCompatUI> sizeCompatUIOptional,
|
Optional<SizeCompatUI> sizeCompatUIOptional,
|
||||||
|
Optional<DragAndDrop> dragAndDropOptional,
|
||||||
CommandQueue commandQueue,
|
CommandQueue commandQueue,
|
||||||
ConfigurationController configurationController,
|
ConfigurationController configurationController,
|
||||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||||
@@ -167,6 +170,7 @@ public final class WMShell extends SystemUI
|
|||||||
mProtoTracer = protoTracer;
|
mProtoTracer = protoTracer;
|
||||||
mShellCommandHandler = shellCommandHandler;
|
mShellCommandHandler = shellCommandHandler;
|
||||||
mSizeCompatUIOptional = sizeCompatUIOptional;
|
mSizeCompatUIOptional = sizeCompatUIOptional;
|
||||||
|
mDragAndDropOptional = dragAndDropOptional;
|
||||||
mSysUiMainExecutor = sysUiMainExecutor;
|
mSysUiMainExecutor = sysUiMainExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +186,7 @@ public final class WMShell extends SystemUI
|
|||||||
mOneHandedOptional.ifPresent(this::initOneHanded);
|
mOneHandedOptional.ifPresent(this::initOneHanded);
|
||||||
mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
|
mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
|
||||||
mSizeCompatUIOptional.ifPresent(this::initSizeCompatUi);
|
mSizeCompatUIOptional.ifPresent(this::initSizeCompatUi);
|
||||||
|
mDragAndDropOptional.ifPresent(this::initDragAndDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -396,6 +401,20 @@ public final class WMShell extends SystemUI
|
|||||||
mKeyguardUpdateMonitor.registerCallback(mSizeCompatUIKeyguardCallback);
|
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
|
@Override
|
||||||
public void writeToProto(SystemUiTraceProto proto) {
|
public void writeToProto(SystemUiTraceProto proto) {
|
||||||
if (proto.wmShell == null) {
|
if (proto.wmShell == null) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
|
|||||||
import com.android.systemui.tracing.ProtoTracer;
|
import com.android.systemui.tracing.ProtoTracer;
|
||||||
import com.android.wm.shell.ShellCommandHandler;
|
import com.android.wm.shell.ShellCommandHandler;
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
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.hidedisplaycutout.HideDisplayCutout;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
@@ -79,6 +80,7 @@ public class WMShellTest extends SysuiTestCase {
|
|||||||
@Mock ShellCommandHandler mShellCommandHandler;
|
@Mock ShellCommandHandler mShellCommandHandler;
|
||||||
@Mock SizeCompatUI mSizeCompatUI;
|
@Mock SizeCompatUI mSizeCompatUI;
|
||||||
@Mock ShellExecutor mSysUiMainExecutor;
|
@Mock ShellExecutor mSysUiMainExecutor;
|
||||||
|
@Mock DragAndDrop mDragAndDrop;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -87,6 +89,7 @@ public class WMShellTest extends SysuiTestCase {
|
|||||||
mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
|
mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
|
||||||
Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
|
Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
|
||||||
Optional.of(mShellCommandHandler), Optional.of(mSizeCompatUI),
|
Optional.of(mShellCommandHandler), Optional.of(mSizeCompatUI),
|
||||||
|
Optional.of(mDragAndDrop),
|
||||||
mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
|
mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
|
||||||
mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
|
mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
|
||||||
mWakefulnessLifecycle, mSysUiMainExecutor);
|
mWakefulnessLifecycle, mSysUiMainExecutor);
|
||||||
|
|||||||
Reference in New Issue
Block a user