Merge "Consolidate the behavior and style of side stage outline" into sc-v2-dev am: 49c02984b8

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15897951

Change-Id: I9a98cf4a2b13d153aeee45e30ab964a20249bb98
This commit is contained in:
Jerry Chang
2021-10-05 01:01:17 +00:00
committed by Automerger Merge Worker
11 changed files with 230 additions and 164 deletions

View File

@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<com.android.wm.shell.splitscreen.OutlineRoot <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@@ -23,4 +23,4 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_width="match_parent" /> android:layout_width="match_parent" />
</com.android.wm.shell.splitscreen.OutlineRoot> </FrameLayout>

View File

@@ -22,19 +22,23 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Binder; import android.os.Binder;
import android.view.IWindow; import android.view.IWindow;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost;
import android.view.WindowInsets; import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.WindowlessWindowManager; import android.view.WindowlessWindowManager;
import android.widget.FrameLayout;
import com.android.wm.shell.R; import com.android.wm.shell.R;
@@ -45,17 +49,22 @@ import com.android.wm.shell.R;
class OutlineManager extends WindowlessWindowManager { class OutlineManager extends WindowlessWindowManager {
private static final String WINDOW_NAME = "SplitOutlineLayer"; private static final String WINDOW_NAME = "SplitOutlineLayer";
private final Context mContext; private final Context mContext;
private final Rect mOutlineBounds = new Rect(); private final Rect mRootBounds = new Rect();
private final Rect mTmpBounds = new Rect(); private final Rect mTempRect = new Rect();
private final Rect mLastOutlineBounds = new Rect();
private final InsetsState mInsetsState = new InsetsState();
private final int mExpandedTaskBarHeight;
private OutlineView mOutlineView;
private SurfaceControlViewHost mViewHost; private SurfaceControlViewHost mViewHost;
private SurfaceControl mHostLeash; private SurfaceControl mHostLeash;
private SurfaceControl mLeash; private SurfaceControl mLeash;
private int mOutlineColor;
OutlineManager(Context context, Configuration configuration) { OutlineManager(Context context, Configuration configuration) {
super(configuration, null /* rootSurface */, null /* hostInputToken */); super(configuration, null /* rootSurface */, null /* hostInputToken */);
mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY, mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
null /* options */); null /* options */);
mExpandedTaskBarHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.taskbar_frame_height);
} }
@Override @Override
@@ -63,65 +72,110 @@ class OutlineManager extends WindowlessWindowManager {
b.setParent(mHostLeash); b.setParent(mHostLeash);
} }
boolean drawOutlineBounds(Rect rootBounds) { void inflate(SurfaceControl rootLeash, Rect rootBounds) {
if (mLeash == null || mViewHost == null) return false;
computeOutlineBounds(mContext, rootBounds, mTmpBounds);
if (mOutlineBounds.equals(mTmpBounds)) {
return false;
}
mOutlineBounds.set(mTmpBounds);
((OutlineRoot) mViewHost.getView()).updateOutlineBounds(mOutlineBounds, mOutlineColor);
final WindowManager.LayoutParams lp =
(WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
lp.width = rootBounds.width();
lp.height = rootBounds.height();
mViewHost.relayout(lp);
return true;
}
void inflate(SurfaceControl.Transaction t, SurfaceControl hostLeash, int color) {
if (mLeash != null || mViewHost != null) return; if (mLeash != null || mViewHost != null) return;
mHostLeash = hostLeash; mHostLeash = rootLeash;
mOutlineColor = color; mRootBounds.set(rootBounds);
mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext)
final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(mContext)
.inflate(R.layout.split_outline, null); .inflate(R.layout.split_outline, null);
mOutlineView = rootLayout.findViewById(R.id.split_outline);
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY, 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
lp.width = mRootBounds.width();
lp.height = mRootBounds.height();
lp.token = new Binder(); lp.token = new Binder();
lp.setTitle(WINDOW_NAME); lp.setTitle(WINDOW_NAME);
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
// TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
// TRUSTED_OVERLAY for windowless window without input channel. // TRUSTED_OVERLAY for windowless window without input channel.
mViewHost.setView(rootView, lp); mViewHost.setView(rootLayout, lp);
mLeash = getSurfaceControl(mViewHost.getWindowToken()); mLeash = getSurfaceControl(mViewHost.getWindowToken());
t.setLayer(mLeash, Integer.MAX_VALUE);
drawOutline();
} }
void release() { void release() {
if (mViewHost != null) { if (mViewHost != null) {
mViewHost.release(); mViewHost.release();
mViewHost = null;
}
mRootBounds.setEmpty();
mLastOutlineBounds.setEmpty();
mOutlineView = null;
mHostLeash = null;
mLeash = null;
}
@Nullable
SurfaceControl getOutlineLeash() {
return mLeash;
}
void setVisibility(boolean visible) {
if (mOutlineView != null) {
mOutlineView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
} }
} }
private static void computeOutlineBounds(Context context, Rect rootBounds, Rect outBounds) { void setRootBounds(Rect rootBounds) {
computeDisplayStableBounds(context, outBounds); if (mViewHost == null || mViewHost.getView() == null) {
outBounds.intersect(rootBounds); return;
}
if (!mRootBounds.equals(rootBounds)) {
WindowManager.LayoutParams lp =
(WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
lp.width = rootBounds.width();
lp.height = rootBounds.height();
mViewHost.relayout(lp);
mRootBounds.set(rootBounds);
drawOutline();
}
}
void onInsetsChanged(InsetsState insetsState) {
if (!mInsetsState.equals(insetsState)) {
mInsetsState.set(insetsState);
drawOutline();
}
}
private void computeOutlineBounds(Rect rootBounds, InsetsState insetsState, Rect outBounds) {
outBounds.set(rootBounds);
final InsetsSource taskBarInsetsSource =
insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
// Only insets the divider bar with task bar when it's expanded so that the rounded corners
// will be drawn against task bar.
if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
outBounds.inset(taskBarInsetsSource.calculateVisibleInsets(outBounds));
}
// Offset the coordinate from screen based to surface based. // Offset the coordinate from screen based to surface based.
outBounds.offset(-rootBounds.left, -rootBounds.top); outBounds.offset(-rootBounds.left, -rootBounds.top);
} }
private static void computeDisplayStableBounds(Context context, Rect outBounds) { void drawOutline() {
final WindowMetrics windowMetrics = if (mOutlineView == null) {
context.getSystemService(WindowManager.class).getMaximumWindowMetrics(); return;
outBounds.set(windowMetrics.getBounds()); }
outBounds.inset(windowMetrics.getWindowInsets().getInsets(
WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout())); computeOutlineBounds(mRootBounds, mInsetsState, mTempRect);
if (mTempRect.equals(mLastOutlineBounds)) {
return;
}
ViewGroup.MarginLayoutParams lp =
(ViewGroup.MarginLayoutParams) mOutlineView.getLayoutParams();
lp.leftMargin = mTempRect.left;
lp.topMargin = mTempRect.top;
lp.width = mTempRect.width();
lp.height = mTempRect.height();
mOutlineView.setLayoutParams(lp);
mLastOutlineBounds.set(mTempRect);
} }
} }

View File

@@ -1,62 +0,0 @@
/*
* 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.splitscreen;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.R;
/** Root layout for holding split outline. */
public class OutlineRoot extends FrameLayout {
public OutlineRoot(@NonNull Context context) {
super(context);
}
public OutlineRoot(@NonNull Context context,
@Nullable AttributeSet attrs) {
super(context, attrs);
}
public OutlineRoot(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public OutlineRoot(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private OutlineView mOutlineView;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mOutlineView = findViewById(R.id.split_outline);
}
void updateOutlineBounds(Rect bounds, int color) {
mOutlineView.updateOutlineBounds(bounds, color);
}
}

View File

@@ -16,13 +16,17 @@
package com.android.wm.shell.splitscreen; package com.android.wm.shell.splitscreen;
import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
import static android.view.RoundedCorner.POSITION_TOP_LEFT;
import static android.view.RoundedCorner.POSITION_TOP_RIGHT;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Path; import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.RoundedCorner;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -33,44 +37,46 @@ import com.android.internal.R;
/** View for drawing split outline. */ /** View for drawing split outline. */
public class OutlineView extends View { public class OutlineView extends View {
private final Paint mPaint = new Paint(); private final Paint mPaint = new Paint();
private final Rect mBounds = new Rect(); private final Path mPath = new Path();
private final float[] mRadii = new float[8];
public OutlineView(@NonNull Context context) { public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context);
}
public OutlineView(@NonNull Context context,
@Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(
public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { getResources().getDimension(R.dimen.accessibility_focus_highlight_stroke_width));
super(context, attrs, defStyleAttr); mPaint.setColor(getResources().getColor(R.color.system_accent1_100, null));
}
public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
} }
@Override @Override
protected void onFinishInflate() { protected void onAttachedToWindow() {
super.onFinishInflate(); // TODO(b/200850654): match the screen corners with the actual display decor.
mPaint.setStyle(Paint.Style.STROKE); mRadii[0] = mRadii[1] = getCornerRadius(POSITION_TOP_LEFT);
mPaint.setStrokeWidth(getResources() mRadii[2] = mRadii[3] = getCornerRadius(POSITION_TOP_RIGHT);
.getDimension(R.dimen.accessibility_focus_highlight_stroke_width)); mRadii[4] = mRadii[5] = getCornerRadius(POSITION_BOTTOM_RIGHT);
mRadii[6] = mRadii[7] = getCornerRadius(POSITION_BOTTOM_LEFT);
} }
void updateOutlineBounds(Rect bounds, int color) { private int getCornerRadius(@RoundedCorner.Position int position) {
if (mBounds.equals(bounds) && mPaint.getColor() == color) return; final RoundedCorner roundedCorner = getDisplay().getRoundedCorner(position);
mBounds.set(bounds); return roundedCorner == null ? 0 : roundedCorner.getRadius();
mPaint.setColor(color); }
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed) {
mPath.reset();
mPath.addRoundRect(0, 0, getWidth(), getHeight(), mRadii, Path.Direction.CW);
}
} }
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
if (mBounds.isEmpty()) return; canvas.drawPath(mPath, mPaint);
final Path path = new Region(mBounds).getBoundaryPath(); }
canvas.drawPath(path, mPaint);
@Override
public boolean hasOverlappingRendering() {
return false;
} }
} }

View File

@@ -17,15 +17,19 @@
package com.android.wm.shell.splitscreen; package com.android.wm.shell.splitscreen;
import android.annotation.CallSuper; import android.annotation.CallSuper;
import android.annotation.Nullable;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.content.Context; import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect; import android.graphics.Rect;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceSession; import android.view.SurfaceSession;
import android.window.WindowContainerToken; import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction; import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
/** /**
@@ -34,7 +38,8 @@ import com.android.wm.shell.common.SyncTransactionQueue;
* *
* @see StageCoordinator * @see StageCoordinator
*/ */
class SideStage extends StageTaskListener { class SideStage extends StageTaskListener implements
DisplayInsetsController.OnInsetsChangedListener {
private static final String TAG = SideStage.class.getSimpleName(); private static final String TAG = SideStage.class.getSimpleName();
private final Context mContext; private final Context mContext;
private OutlineManager mOutlineManager; private OutlineManager mOutlineManager;
@@ -77,33 +82,61 @@ class SideStage extends StageTaskListener {
return true; return true;
} }
void enableOutline(boolean enable) { @Nullable
if (enable) { public SurfaceControl getOutlineLeash() {
if (mOutlineManager == null && mRootTaskInfo != null) { return mOutlineManager.getOutlineLeash();
mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration);
mSyncQueue.runInSync(t -> mOutlineManager.inflate(t, mRootLeash, Color.YELLOW));
updateOutlineBounds();
}
} else {
if (mOutlineManager != null) {
mOutlineManager.release();
mOutlineManager = null;
}
}
} }
private void updateOutlineBounds() { @Override
if (mOutlineManager == null || mRootTaskInfo == null || !mRootTaskInfo.isVisible) return; @CallSuper
mOutlineManager.drawOutlineBounds( public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
mRootTaskInfo.configuration.windowConfiguration.getBounds()); super.onTaskAppeared(taskInfo, leash);
if (isRootTask(taskInfo)) {
mOutlineManager = new OutlineManager(mContext, taskInfo.configuration);
enableOutline(true);
}
} }
@Override @Override
@CallSuper @CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
super.onTaskInfoChanged(taskInfo); super.onTaskInfoChanged(taskInfo);
if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) { if (isRootTask(taskInfo)) {
updateOutlineBounds(); mOutlineManager.setRootBounds(taskInfo.configuration.windowConfiguration.getBounds());
} }
} }
private boolean isRootTask(ActivityManager.RunningTaskInfo taskInfo) {
return mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId;
}
void enableOutline(boolean enable) {
if (mOutlineManager == null) {
return;
}
if (enable) {
if (mRootTaskInfo != null) {
mOutlineManager.inflate(mRootLeash,
mRootTaskInfo.configuration.windowConfiguration.getBounds());
}
} else {
mOutlineManager.release();
}
}
void setOutlineVisibility(boolean visible) {
mOutlineManager.setVisibility(visible);
}
@Override
public void insetsChanged(InsetsState insetsState) {
mOutlineManager.onInsetsChanged(insetsState);
}
@Override
public void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) {
insetsChanged(insetsState);
}
} }

View File

@@ -257,11 +257,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
} }
} }
final RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget();
if (divider.leash != null) {
t.show(divider.leash);
}
t.apply(); t.apply();
if (finishedCallback != null) { if (finishedCallback != null) {
try { try {
@@ -300,7 +295,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
} }
transaction.apply(); transaction.apply();
transaction.close(); transaction.close();
return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()}; return new RemoteAnimationTarget[]{
mStageCoordinator.getDividerBarLegacyTarget(),
mStageCoordinator.getOutlineLegacyTarget()};
} }
/** /**

View File

@@ -201,6 +201,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSurfaceSession); mSurfaceSession);
mDisplayImeController = displayImeController; mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController; mDisplayInsetsController = displayInsetsController;
mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSideStage);
mRootTDAOrganizer.registerListener(displayId, this); mRootTDAOrganizer.registerListener(displayId, this);
final DeviceStateManager deviceStateManager = final DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class); mContext.getSystemService(DeviceStateManager.class);
@@ -682,6 +683,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
t.setVisibility(mSideStage.mRootLeash, bothStageVisible) t.setVisibility(mSideStage.mRootLeash, bothStageVisible)
.setVisibility(mMainStage.mRootLeash, bothStageVisible); .setVisibility(mMainStage.mRootLeash, bothStageVisible);
applyDividerVisibility(t); applyDividerVisibility(t);
applyOutlineVisibility(t);
} }
}); });
} }
@@ -703,6 +705,19 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} }
} }
private void applyOutlineVisibility(SurfaceControl.Transaction t) {
final SurfaceControl outlineLeash = mSideStage.getOutlineLeash();
if (outlineLeash == null) {
return;
}
if (mDividerVisible) {
t.show(outlineLeash).setLayer(outlineLeash, SPLIT_DIVIDER_LAYER);
} else {
t.hide(outlineLeash);
}
}
private void onStageHasChildrenChanged(StageListenerImpl stageListener) { private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
final boolean hasChildren = stageListener.mHasChildren; final boolean hasChildren = stageListener.mHasChildren;
final boolean isSideStage = stageListener == mSideStageListener; final boolean isSideStage = stageListener == mSideStageListener;
@@ -762,6 +777,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override @Override
public void onLayoutChanging(SplitLayout layout) { public void onLayoutChanging(SplitLayout layout) {
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
mSideStage.setOutlineVisibility(false);
} }
@Override @Override
@@ -770,6 +786,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
updateWindowBounds(layout, wct); updateWindowBounds(layout, wct);
mSyncQueue.queue(wct); mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
mSideStage.setOutlineVisibility(true);
mLogger.logResize(mSplitLayout.getDividerPositionAsFraction()); mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
} }
@@ -1145,6 +1162,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER); null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
} }
RemoteAnimationTarget getOutlineLegacyTarget() {
final Rect bounds = mSideStage.mRootTaskInfo.configuration.windowConfiguration.getBounds();
// Leverage TYPE_DOCK_DIVIDER type when wrapping outline remote animation target in order to
// distinguish as a split auxiliary target in Launcher.
return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */,
mSideStage.getOutlineLeash(), false /* isTranslucent */, null /* clipRect */,
null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
new android.graphics.Point(0, 0) /* position */, bounds, bounds,
new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */,
null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
}
@Override @Override
public void dump(@NonNull PrintWriter pw, String prefix) { public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " "; final String innerPrefix = prefix + " ";

View File

@@ -138,8 +138,11 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
mRootTaskInfo = taskInfo; mRootTaskInfo = taskInfo;
mCallbacks.onRootTaskAppeared(); mCallbacks.onRootTaskAppeared();
sendStatusChanged(); sendStatusChanged();
mSyncQueue.runInSync(t -> mDimLayer = mSyncQueue.runInSync(t -> {
SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession)); t.hide(mRootLeash);
mDimLayer =
SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession);
});
} else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
final int taskId = taskInfo.taskId; final int taskId = taskInfo.taskId;
mChildrenLeashes.put(taskId, leash); mChildrenLeashes.put(taskId, leash);

View File

@@ -29,6 +29,7 @@ import android.view.SurfaceControl;
import android.view.SurfaceSession; import android.view.SurfaceSession;
import android.window.WindowContainerTransaction; import android.window.WindowContainerTransaction;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -58,6 +59,7 @@ public class SideStageTests extends ShellTestCase {
private SideStage mSideStage; private SideStage mSideStage;
@Before @Before
@UiThreadTest
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mRootTask = new TestRunningTaskInfoBuilder().build(); mRootTask = new TestRunningTaskInfoBuilder().build();

View File

@@ -51,6 +51,7 @@ import android.window.TransitionInfo;
import android.window.TransitionRequestInfo; import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction; import android.window.WindowContainerTransaction;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
@@ -96,6 +97,7 @@ public class SplitTransitionTests extends ShellTestCase {
private ActivityManager.RunningTaskInfo mSideChild; private ActivityManager.RunningTaskInfo mSideChild;
@Before @Before
@UiThreadTest
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
final ShellExecutor mockExecutor = mock(ShellExecutor.class); final ShellExecutor mockExecutor = mock(ShellExecutor.class);

View File

@@ -62,6 +62,7 @@ public final class StageTaskListenerTests {
@Mock private SyncTransactionQueue mSyncQueue; @Mock private SyncTransactionQueue mSyncQueue;
@Captor private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor; @Captor private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor;
private SurfaceSession mSurfaceSession = new SurfaceSession(); private SurfaceSession mSurfaceSession = new SurfaceSession();
private SurfaceControl mSurfaceControl;
private ActivityManager.RunningTaskInfo mRootTask; private ActivityManager.RunningTaskInfo mRootTask;
private StageTaskListener mStageTaskListener; private StageTaskListener mStageTaskListener;
@@ -76,7 +77,8 @@ public final class StageTaskListenerTests {
mSurfaceSession); mSurfaceSession);
mRootTask = new TestRunningTaskInfoBuilder().build(); mRootTask = new TestRunningTaskInfoBuilder().build();
mRootTask.parentTaskId = INVALID_TASK_ID; mRootTask.parentTaskId = INVALID_TASK_ID;
mStageTaskListener.onTaskAppeared(mRootTask, new SurfaceControl()); mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession).setName("test").build();
mStageTaskListener.onTaskAppeared(mRootTask, mSurfaceControl);
} }
@Test @Test
@@ -103,7 +105,7 @@ public final class StageTaskListenerTests {
final ActivityManager.RunningTaskInfo childTask = final ActivityManager.RunningTaskInfo childTask =
new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build();
mStageTaskListener.onTaskAppeared(childTask, new SurfaceControl()); mStageTaskListener.onTaskAppeared(childTask, mSurfaceControl);
assertThat(mStageTaskListener.mChildrenTaskInfo.contains(childTask.taskId)).isTrue(); assertThat(mStageTaskListener.mChildrenTaskInfo.contains(childTask.taskId)).isTrue();
verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true)); verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true));