From 75bacc46d0ac0f4e797f917003a9d54d3c4e5275 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Fri, 10 Dec 2021 15:10:46 -0800 Subject: [PATCH 1/2] Fix how task info is retrieved for split screen Previously this was grabbing the top two tasks from the task list, but this isn't guaranteed to be what's on the screen. Instead, when already in split, use the taskInfo from the split controller. Test: manual - 1) have stuff in split 2) keep dragging different apps into split => verify the app icon shown in the non highlighted side matches the app on that side Bug: 209504662 Change-Id: Ib959f44bc9eaebfb5e3f640d69cb6f3ddccedfcf --- .../wm/shell/draganddrop/DragLayout.java | 64 +++++++++---------- .../splitscreen/SplitScreenController.java | 9 +++ .../shell/splitscreen/StageCoordinator.java | 8 +++ 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index 67f9062b0a66b..4d981f6aff503 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -18,6 +18,7 @@ package com.android.wm.shell.draganddrop; import static android.app.StatusBarManager.DISABLE_NONE; +import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import android.animation.Animator; @@ -165,41 +166,40 @@ public class DragLayout extends LinearLayout { mHasDropped = false; mCurrentTarget = null; - List 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 { + boolean alreadyInSplit = mSplitScreenController != null + && mSplitScreenController.isSplitScreenVisible(); + if (!alreadyInSplit) { + List tasks = null; + // Figure out the splashscreen info for the existing task. + try { + tasks = ActivityTaskManager.getService().getTasks(1, + 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); mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor1, icon1); } + } else { + // We're already in split so get taskInfo from the controller to populate icon / color. + ActivityManager.RunningTaskInfo topOrLeftTask = + mSplitScreenController.getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT); + ActivityManager.RunningTaskInfo bottomOrRightTask = + mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT); + if (topOrLeftTask != null && bottomOrRightTask != null) { + Drawable topOrLeftIcon = mIconProvider.getIcon(topOrLeftTask.topActivityInfo); + int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask); + Drawable bottomOrRightIcon = mIconProvider.getIcon( + bottomOrRightTask.topActivityInfo); + int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask); + mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon); + mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 05552aad23034..03dbc2b4ef535 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -184,6 +184,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return mStageCoordinator.isSplitScreenVisible(); } + @Nullable + public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) { + if (isSplitScreenVisible()) { + int taskId = mStageCoordinator.getTaskId(splitPosition); + return mTaskOrganizer.getRunningTaskInfo(taskId); + } + return null; + } + public boolean isTaskInSplitScreen(int taskId) { return isSplitScreenVisible() && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index e30e6c537c93a..8f4b2c878f7d7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -521,6 +521,14 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, return SplitLayout.reversePosition(mSideStagePosition); } + int getTaskId(@SplitPosition int splitPosition) { + if (mSideStagePosition == splitPosition) { + return mSideStage.getTopVisibleChildTaskId(); + } else { + return mMainStage.getTopVisibleChildTaskId(); + } + } + void setSideStagePosition(@SplitPosition int sideStagePosition, @Nullable WindowContainerTransaction wct) { setSideStagePosition(sideStagePosition, true /* updateBounds */, wct); From c57aa4a84ea596fedee8d9e12962a06607325a30 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Fri, 10 Dec 2021 20:05:57 -0800 Subject: [PATCH 2/2] Update dropzones to match the size of the existing split The dropzones were always split exactly in half on the screen which looks weird if you adjust the split to a different size and then drag new apps into split. This adjusts the dropzones to match the size of the existing split. It also fixes a bug where the existing split bounds weren't being properly calculated in the policy so the drag and drop highlight wouldn't switch to the correct side until you passed through the middle instead of where the divider actually is. Bug: 209504662 Test: manual - 1) have apps in split 2) adjust the divider 3) start dragging a new app into split, pass across the divider => the highlight should immediately switch => the highlight should match the size of the existing split 4) test in landscape & portrait Change-Id: I3c7a288625ad766d0c467d713a451fe8bfc1d669 --- .../shell/draganddrop/DragAndDropPolicy.java | 17 ++++-- .../wm/shell/draganddrop/DragLayout.java | 53 +++++++++++++++++-- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index b65a2e4ffca6a..8e6c05d83906f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -151,7 +151,13 @@ public class DragAndDropPolicy { final Rect rightHitRegion = new Rect(); final Rect rightDrawRegion = bottomOrRightBounds; - displayRegion.splitVertically(leftHitRegion, rightHitRegion); + // If we have existing split regions use those bounds, otherwise split it 50/50 + if (inSplitScreen) { + leftHitRegion.set(topOrLeftBounds); + rightHitRegion.set(bottomOrRightBounds); + } else { + displayRegion.splitVertically(leftHitRegion, rightHitRegion); + } mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, leftDrawRegion)); mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, rightDrawRegion)); @@ -162,8 +168,13 @@ public class DragAndDropPolicy { final Rect bottomHitRegion = new Rect(); final Rect bottomDrawRegion = bottomOrRightBounds; - displayRegion.splitHorizontally( - topHitRegion, bottomHitRegion); + // If we have existing split regions use those bounds, otherwise split it 50/50 + if (inSplitScreen) { + topHitRegion.set(topOrLeftBounds); + bottomHitRegion.set(bottomOrRightBounds); + } else { + displayRegion.splitHorizontally(topHitRegion, bottomHitRegion); + } mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topDrawRegion)); mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomDrawRegion)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index 4d981f6aff503..fd3be2b11c15a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -17,6 +17,7 @@ package com.android.wm.shell.draganddrop; import static android.app.StatusBarManager.DISABLE_NONE; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; @@ -33,11 +34,11 @@ import android.content.Context; 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.ViewGroup; import android.view.WindowInsets; import android.view.WindowInsets.Type; import android.widget.LinearLayout; @@ -74,6 +75,7 @@ public class DragLayout extends LinearLayout { private DropZoneView mDropZoneView2; private int mDisplayMargin; + private int mDividerSize; private Insets mInsets = Insets.NONE; private boolean mIsShowing; @@ -90,13 +92,15 @@ public class DragLayout extends LinearLayout { mDisplayMargin = context.getResources().getDimensionPixelSize( R.dimen.drop_layout_display_margin); + mDividerSize = context.getResources().getDimensionPixelSize( + R.dimen.split_divider_bar_width); 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)); + addView(mDropZoneView1, new LinearLayout.LayoutParams(MATCH_PARENT, + MATCH_PARENT)); + addView(mDropZoneView2, new LinearLayout.LayoutParams(MATCH_PARENT, + MATCH_PARENT)); ((LayoutParams) mDropZoneView1.getLayoutParams()).weight = 1; ((LayoutParams) mDropZoneView2.getLayoutParams()).weight = 1; updateContainerMargins(); @@ -184,6 +188,7 @@ public class DragLayout extends LinearLayout { int bgColor1 = getResizingBackgroundColor(taskInfo1); mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor1, icon1); + updateDropZoneSizes(null, null); // passing null splits the views evenly } } else { // We're already in split so get taskInfo from the controller to populate icon / color. @@ -200,9 +205,47 @@ public class DragLayout extends LinearLayout { mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon); mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon); } + + // Update the dropzones to match existing split sizes + Rect topOrLeftBounds = new Rect(); + Rect bottomOrRightBounds = new Rect(); + mSplitScreenController.getStageBounds(topOrLeftBounds, bottomOrRightBounds); + updateDropZoneSizes(topOrLeftBounds, bottomOrRightBounds); } } + /** + * Sets the size of the two drop zones based on the provided bounds. The divider sits between + * the views and its size is included in the calculations. + * + * @param bounds1 bounds to apply to the first dropzone view, null if split in half. + * @param bounds2 bounds to apply to the second dropzone view, null if split in half. + */ + private void updateDropZoneSizes(Rect bounds1, Rect bounds2) { + final int orientation = getResources().getConfiguration().orientation; + final boolean isPortrait = orientation == Configuration.ORIENTATION_PORTRAIT; + final int halfDivider = mDividerSize / 2; + final LinearLayout.LayoutParams dropZoneView1 = + (LayoutParams) mDropZoneView1.getLayoutParams(); + final LinearLayout.LayoutParams dropZoneView2 = + (LayoutParams) mDropZoneView2.getLayoutParams(); + if (isPortrait) { + dropZoneView1.width = MATCH_PARENT; + dropZoneView2.width = MATCH_PARENT; + dropZoneView1.height = bounds1 != null ? bounds1.height() + halfDivider : MATCH_PARENT; + dropZoneView2.height = bounds2 != null ? bounds2.height() + halfDivider : MATCH_PARENT; + } else { + dropZoneView1.width = bounds1 != null ? bounds1.width() + halfDivider : MATCH_PARENT; + dropZoneView2.width = bounds2 != null ? bounds2.width() + halfDivider : MATCH_PARENT; + dropZoneView1.height = MATCH_PARENT; + dropZoneView2.height = MATCH_PARENT; + } + dropZoneView1.weight = bounds1 != null ? 0 : 1; + dropZoneView2.weight = bounds2 != null ? 0 : 1; + mDropZoneView1.setLayoutParams(dropZoneView1); + mDropZoneView2.setLayoutParams(dropZoneView2); + } + public void show() { mIsShowing = true; recomputeDropTargets();