Draw rounded corners beside split divider bar

Draw rounded corners beside divider bar which inset with task bar if
the task bar is expanded.

Bug: 196272915
Bug: 182511830
Test: atest WMShellUnitTests
Test: manul check the rounded corners rendered in proper position.
Change-Id: I14c5a9416d52bf06b3e4c8ac843c5a65c0b940b8
This commit is contained in:
Jerry Chang
2021-08-26 11:31:56 +08:00
parent 5020a15a43
commit 5514e76d40
19 changed files with 324 additions and 39 deletions

View File

@@ -0,0 +1,30 @@
<!--
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/split_divider_corner_size"
android:height="@dimen/split_divider_corner_size"
android:viewportWidth="42"
android:viewportHeight="42">
<group android:pivotX="21"
android:pivotY="21"
android:rotation="180">
<path
android:fillColor="@color/split_divider_background"
android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
</group>
</vector>

View File

@@ -0,0 +1,30 @@
<!--
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/split_divider_corner_size"
android:height="@dimen/split_divider_corner_size"
android:viewportWidth="42"
android:viewportHeight="42">
<group android:pivotX="21"
android:pivotY="21"
android:rotation="-90">
<path
android:fillColor="@color/split_divider_background"
android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
</group>
</vector>

View File

@@ -0,0 +1,30 @@
<!--
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/split_divider_corner_size"
android:height="@dimen/split_divider_corner_size"
android:viewportWidth="42"
android:viewportHeight="42">
<group android:pivotX="21"
android:pivotY="21"
android:rotation="90">
<path
android:fillColor="@color/split_divider_background"
android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
</group>
</vector>

View File

@@ -0,0 +1,26 @@
<!--
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/split_divider_corner_size"
android:height="@dimen/split_divider_corner_size"
android:viewportWidth="42"
android:viewportHeight="42">
<path
android:fillColor="@color/split_divider_background"
android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
</vector>

View File

@@ -19,14 +19,25 @@
android:layout_height="match_parent"
android:layout_width="match_parent">
<View
style="@style/DockedDividerBackground"
android:id="@+id/docked_divider_background"/>
<FrameLayout
android:id="@+id/divider_bar"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.android.wm.shell.common.split.DividerHandleView
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle"
android:contentDescription="@string/accessibility_divider"
android:background="@null"/>
<View style="@style/DockedDividerTopLeftRoundCorner"/>
<View
style="@style/DockedDividerBackground"
android:id="@+id/docked_divider_background"/>
<View style="@style/DockedDividerBottomRightRoundCorner"/>
<com.android.wm.shell.common.split.DividerHandleView
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle"
android:contentDescription="@string/accessibility_divider"
android:background="@null"/>
</FrameLayout>
</com.android.wm.shell.common.split.DividerView>

View File

@@ -28,6 +28,20 @@
<item name="android:layout_height">96dp</item>
</style>
<style name="DockedDividerTopLeftRoundCorner">
<item name="android:layout_gravity">center_horizontal|top</item>
<item name="android:background">@drawable/split_rounded_top</item>
<item name="android:layout_width">@dimen/split_divider_corner_size</item>
<item name="android:layout_height">@dimen/split_divider_corner_size</item>
</style>
<style name="DockedDividerBottomRightRoundCorner">
<item name="android:layout_gravity">center_horizontal|bottom</item>
<item name="android:background">@drawable/split_rounded_bottom</item>
<item name="android:layout_width">@dimen/split_divider_corner_size</item>
<item name="android:layout_height">@dimen/split_divider_corner_size</item>
</style>
<style name="DockedDividerMinimizedShadow">
<item name="android:layout_width">8dp</item>
<item name="android:layout_height">match_parent</item>

View File

@@ -83,6 +83,9 @@
<dimen name="split_divider_handle_width">72dp</dimen>
<dimen name="split_divider_handle_height">3dp</dimen>
<dimen name="split_divider_bar_width">10dp</dimen>
<dimen name="split_divider_corner_size">42dp</dimen>
<!-- One-Handed Mode -->
<!-- Threshold for dragging distance to enable one-handed mode -->
<dimen name="gestures_onehanded_drag_threshold">20dp</dimen>

View File

@@ -32,11 +32,25 @@
<style name="DockedDividerBackground">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">10dp</item>
<item name="android:layout_height">@dimen/split_divider_bar_width</item>
<item name="android:layout_gravity">center_vertical</item>
<item name="android:background">@color/split_divider_background</item>
</style>
<style name="DockedDividerTopLeftRoundCorner">
<item name="android:layout_gravity">center_vertical|left</item>
<item name="android:background">@drawable/split_rounded_left</item>
<item name="android:layout_width">@dimen/split_divider_corner_size</item>
<item name="android:layout_height">@dimen/split_divider_corner_size</item>
</style>
<style name="DockedDividerBottomRightRoundCorner">
<item name="android:layout_gravity">center_vertical|right</item>
<item name="android:background">@drawable/split_rounded_right</item>
<item name="android:layout_width">@dimen/split_divider_corner_size</item>
<item name="android:layout_height">@dimen/split_divider_corner_size</item>
</style>
<style name="DockedDividerMinimizedShadow">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">8dp</item>

View File

@@ -233,18 +233,18 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan
* control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
* @param packageName: Passes the top package name
*/
void topFocusedWindowChanged(String packageName);
default void topFocusedWindowChanged(String packageName) {}
/**
* Called when the window insets configuration has changed.
*/
void insetsChanged(InsetsState insetsState);
default void insetsChanged(InsetsState insetsState) {}
/**
* Called when this window retrieved control over a specified set of insets sources.
*/
void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls);
default void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) {}
/**
* Called when a set of insets source window should be shown by policy.
@@ -252,7 +252,7 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan
* @param types internal insets types (WindowInsets.Type.InsetsType) to show
* @param fromIme true if this request originated from IME (InputMethodService).
*/
void showInsets(int types, boolean fromIme);
default void showInsets(int types, boolean fromIme) {}
/**
* Called when a set of insets source window should be hidden by policy.
@@ -260,6 +260,6 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan
* @param types internal insets types (WindowInsets.Type.InsetsType) to hide
* @param fromIme true if this request originated from IME (InputMethodService).
*/
void hideInsets(int types, boolean fromIme);
default void hideInsets(int types, boolean fromIme) {}
}
}

View File

@@ -19,15 +19,23 @@ package com.android.wm.shell.common.split;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Property;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.SurfaceControlViewHost;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -44,6 +52,23 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
public static final long TOUCH_ANIMATION_DURATION = 150;
public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
// TODO(b/191269755): use the value defined in InsetsController.
private static final Interpolator RESIZE_INTERPOLATOR = Interpolators.LINEAR;
// TODO(b/191269755): use the value defined in InsetsController.
private static final int ANIMATION_DURATION_RESIZE = 300;
/**
* The task bar height defined in launcher. Used to determine whether to insets divider bounds
* or not.
*/
private static final int EXPANDED_TASK_BAR_HEIGHT_IN_DP = 60;
/** The task bar expanded height. Used to determine whether to insets divider bounds or not. */
private final float mExpandedTaskBarHeight = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, EXPANDED_TASK_BAR_HEIGHT_IN_DP,
getResources().getDisplayMetrics());
private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
private SplitLayout mSplitLayout;
@@ -58,6 +83,31 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private GestureDetector mDoubleTapDetector;
private boolean mInteractive;
/**
* Tracks divider bar visible bounds in screen-based coordination. Used to calculate with
* insets.
*/
private final Rect mDividerBounds = new Rect();
private final Rect mTempRect = new Rect();
private FrameLayout mDividerBar;
static final Property<DividerView, Integer> DIVIDER_HEIGHT_PROPERTY =
new Property<DividerView, Integer>(Integer.class, "height") {
@Override
public Integer get(DividerView object) {
return object.mDividerBar.getLayoutParams().height;
}
@Override
public void set(DividerView object, Integer value) {
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
object.mDividerBar.getLayoutParams();
lp.height = value;
object.mDividerBar.setLayoutParams(lp);
}
};
public DividerView(@NonNull Context context) {
super(context);
}
@@ -79,14 +129,42 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
/** Sets up essential dependencies of the divider bar. */
public void setup(
SplitLayout layout,
SurfaceControlViewHost viewHost) {
SurfaceControlViewHost viewHost,
InsetsState insetsState) {
mSplitLayout = layout;
mViewHost = viewHost;
mDividerBounds.set(layout.getDividerBounds());
onInsetsChanged(insetsState, false /* animate */);
}
void onInsetsChanged(InsetsState insetsState, boolean animate) {
mTempRect.set(mSplitLayout.getDividerBounds());
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) {
mTempRect.inset(taskBarInsetsSource.calculateVisibleInsets(mTempRect));
}
if (!mTempRect.equals(mDividerBounds)) {
if (animate) {
ObjectAnimator animator = ObjectAnimator.ofInt(this,
DIVIDER_HEIGHT_PROPERTY, mDividerBounds.height(), mTempRect.height());
animator.setInterpolator(RESIZE_INTERPOLATOR);
animator.setDuration(ANIMATION_DURATION_RESIZE);
animator.start();
} else {
DIVIDER_HEIGHT_PROPERTY.set(this, mTempRect.height());
}
mDividerBounds.set(mTempRect);
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mDividerBar = findViewById(R.id.divider_bar);
mHandle = findViewById(R.id.docked_divider_handle);
mBackground = findViewById(R.id.docked_divider_background);
mTouchElevation = getResources().getDimensionPixelSize(

View File

@@ -40,6 +40,8 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -54,12 +56,13 @@ import com.android.internal.policy.DockedDividerUtils;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
/**
* Records and handles layout of splits. Helps to calculate proper bounds when configuration or
* divide position changes.
*/
public final class SplitLayout {
public final class SplitLayout implements DisplayInsetsController.OnInsetsChangedListener {
/**
* Split position isn't specified normally meaning to use what ever it is currently set to.
*/
@@ -102,6 +105,7 @@ public final class SplitLayout {
private final ImePositionProcessor mImePositionProcessor;
private final DismissingParallaxPolicy mDismissingParallaxPolicy;
private final ShellTaskOrganizer mTaskOrganizer;
private final InsetsState mInsetsState = new InsetsState();
private Context mContext;
private DividerSnapAlgorithm mDividerSnapAlgorithm;
@@ -249,7 +253,7 @@ public final class SplitLayout {
public void init() {
if (mInitialized) return;
mInitialized = true;
mSplitWindowManager.init(this);
mSplitWindowManager.init(this, mInsetsState);
mDisplayImeController.addPositionProcessor(mImePositionProcessor);
}
@@ -262,6 +266,23 @@ public final class SplitLayout {
mImePositionProcessor.reset();
}
@Override
public void insetsChanged(InsetsState insetsState) {
mInsetsState.set(insetsState);
if (!mInitialized) {
return;
}
mSplitWindowManager.onInsetsChanged(insetsState);
}
@Override
public void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) {
if (!mInsetsState.equals(insetsState)) {
insetsChanged(insetsState);
}
}
/**
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
@@ -506,7 +527,7 @@ public final class SplitLayout {
/**
* Applies a parallax to the task to hint dismissing progress.
*
* @param position the split position to apply dismissing parallax effect
* @param position the split position to apply dismissing parallax effect
* @param isLandscape indicates whether it's splitting horizontally or vertically
*/
void applyDividerPosition(int position, boolean isLandscape) {
@@ -518,11 +539,11 @@ public final class SplitLayout {
if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
- mDividerSnapAlgorithm.getFirstSplitTarget().position;
- mDividerSnapAlgorithm.getFirstSplitTarget().position;
} else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
- mDividerSnapAlgorithm.getDismissEndTarget().position;
- mDividerSnapAlgorithm.getDismissEndTarget().position;
}
if (mDismissingSide != DOCKED_INVALID) {

View File

@@ -36,6 +36,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import android.view.IWindow;
import android.view.InsetsState;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
@@ -103,7 +104,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
}
/** Inflates {@link DividerView} on to the root surface. */
void init(SplitLayout splitLayout) {
void init(SplitLayout splitLayout, InsetsState insetsState) {
if (mDividerView != null || mViewHost != null) {
throw new UnsupportedOperationException(
"Try to inflate divider view again without release first");
@@ -123,7 +124,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
lp.setTitle(mWindowName);
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
mViewHost.setView(mDividerView, lp);
mDividerView.setup(splitLayout, mViewHost);
mDividerView.setup(splitLayout, mViewHost, insetsState);
}
/**
@@ -169,4 +170,10 @@ public final class SplitWindowManager extends WindowlessWindowManager {
SurfaceControl getSurfaceControl() {
return mLeash;
}
void onInsetsChanged(InsetsState insetsState) {
if (mDividerView != null) {
mDividerView.onInsetsChanged(insetsState, true /* animate */);
}
}
}

View File

@@ -42,8 +42,8 @@ import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.SurfaceSession;
import android.view.WindowManager;
import android.window.IRemoteTransition;
import android.window.WindowContainerTransaction;
@@ -56,6 +56,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -68,7 +69,6 @@ import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.concurrent.Executor;
/**
@@ -87,6 +87,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
private final ShellExecutor mMainExecutor;
private final SplitScreenImpl mImpl = new SplitScreenImpl();
private final DisplayImeController mDisplayImeController;
private final DisplayInsetsController mDisplayInsetsController;
private final Transitions mTransitions;
private final TransactionPool mTransactionPool;
private final SplitscreenEventLogger mLogger;
@@ -97,6 +98,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
ShellExecutor mainExecutor, DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
Transitions transitions, TransactionPool transactionPool) {
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
@@ -104,6 +106,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mRootTDAOrganizer = rootTDAOrganizer;
mMainExecutor = mainExecutor;
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mTransitions = transitions;
mTransactionPool = transactionPool;
mLogger = new SplitscreenEventLogger();
@@ -127,8 +130,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
if (mStageCoordinator == null) {
// TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mTransitions,
mTransactionPool, mLogger);
mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
mDisplayInsetsController, mTransitions, mTransactionPool, mLogger);
}
}

View File

@@ -85,6 +85,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
@@ -136,6 +137,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final Context mContext;
private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
private final DisplayImeController mDisplayImeController;
private final DisplayInsetsController mDisplayInsetsController;
private final SplitScreenTransitions mSplitTransitions;
private final SplitscreenEventLogger mLogger;
private boolean mExitSplitScreenOnHide;
@@ -163,7 +165,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
DisplayImeController displayImeController, Transitions transitions,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, SplitscreenEventLogger logger) {
mContext = context;
mDisplayId = displayId;
@@ -185,6 +188,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSyncQueue,
mSurfaceSession);
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mRootTDAOrganizer.registerListener(displayId, this);
final DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class);
@@ -199,7 +203,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController,
SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool,
DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger) {
mContext = context;
mDisplayId = displayId;
@@ -209,6 +214,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mMainStage = mainStage;
mSideStage = sideStage;
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mRootTDAOrganizer.registerListener(displayId, this);
mSplitLayout = splitLayout;
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
@@ -832,6 +838,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDisplayAreaInfo.configuration, this,
b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b),
mDisplayImeController, mTaskOrganizer);
mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
}
}

View File

@@ -22,6 +22,7 @@ import static org.mockito.Mockito.when;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.InsetsState;
import android.view.SurfaceControl;
import androidx.test.annotation.UiThreadTest;
@@ -59,7 +60,7 @@ public class SplitWindowManagerTests extends ShellTestCase {
@Test
@UiThreadTest
public void testInitRelease() {
mSplitWindowManager.init(mSplitLayout);
mSplitWindowManager.init(mSplitLayout, new InsetsState());
assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
mSplitWindowManager.release();
assertThat(mSplitWindowManager.getSurfaceControl()).isNull();

View File

@@ -33,6 +33,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
@@ -65,10 +66,12 @@ public class SplitTestUtils {
TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
MainStage mainStage, SideStage sideStage, DisplayImeController imeController,
SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool,
DisplayInsetsController insetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger) {
super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage,
sideStage, imeController, splitLayout, transitions, transactionPool, logger);
sideStage, imeController, insetsController, splitLayout, transitions,
transactionPool, logger);
// Prepare default TaskDisplayArea for testing.
mDisplayAreaInfo = new DisplayAreaInfo(

View File

@@ -58,6 +58,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
@@ -79,6 +80,7 @@ public class SplitTransitionTests extends ShellTestCase {
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
@Mock private DisplayImeController mDisplayImeController;
@Mock private DisplayInsetsController mDisplayInsetsController;
@Mock private TransactionPool mTransactionPool;
@Mock private Transitions mTransitions;
@Mock private SurfaceSession mSurfaceSession;
@@ -107,9 +109,10 @@ public class SplitTransitionTests extends ShellTestCase {
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
mDisplayImeController, mSplitLayout, mTransitions, mTransactionPool,
mLogger);
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
mTransactionPool,
mLogger);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());

View File

@@ -37,6 +37,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.transition.Transitions;
@@ -57,6 +58,7 @@ public class StageCoordinatorTests extends ShellTestCase {
@Mock private MainStage mMainStage;
@Mock private SideStage mSideStage;
@Mock private DisplayImeController mDisplayImeController;
@Mock private DisplayInsetsController mDisplayInsetsController;
@Mock private Transitions mTransitions;
@Mock private TransactionPool mTransactionPool;
@Mock private SplitscreenEventLogger mLogger;
@@ -67,8 +69,8 @@ public class StageCoordinatorTests extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
mDisplayImeController, null /* splitLayout */, mTransitions, mTransactionPool,
mLogger);
mDisplayImeController, mDisplayInsetsController, null /* splitLayout */,
mTransitions, mTransactionPool, mLogger);
}
@Test

View File

@@ -377,11 +377,13 @@ public abstract class WMShellBaseModule {
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@ShellMainThread ShellExecutor mainExecutor,
DisplayImeController displayImeController, Transitions transitions,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool) {
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, transitions,
rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController,
displayInsetsController, transitions,
transactionPool));
} else {
return Optional.empty();