Merge "Draw rounded corners beside split divider bar" into sc-v2-dev am: bf71bb09b8

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

Change-Id: I3176e48ddcccb1258485115df9a0d2997165263f
This commit is contained in:
Jerry Chang
2021-08-31 04:03:42 +00:00
committed by Automerger Merge Worker
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_height="match_parent"
android:layout_width="match_parent"> android:layout_width="match_parent">
<View <FrameLayout
style="@style/DockedDividerBackground" android:id="@+id/divider_bar"
android:id="@+id/docked_divider_background"/> android:layout_width="match_parent"
android:layout_height="match_parent">
<com.android.wm.shell.common.split.DividerHandleView <View style="@style/DockedDividerTopLeftRoundCorner"/>
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle" <View
android:contentDescription="@string/accessibility_divider" style="@style/DockedDividerBackground"
android:background="@null"/> 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> </com.android.wm.shell.common.split.DividerView>

View File

@@ -28,6 +28,20 @@
<item name="android:layout_height">96dp</item> <item name="android:layout_height">96dp</item>
</style> </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"> <style name="DockedDividerMinimizedShadow">
<item name="android:layout_width">8dp</item> <item name="android:layout_width">8dp</item>
<item name="android:layout_height">match_parent</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_width">72dp</dimen>
<dimen name="split_divider_handle_height">3dp</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 --> <!-- One-Handed Mode -->
<!-- Threshold for dragging distance to enable one-handed mode --> <!-- Threshold for dragging distance to enable one-handed mode -->
<dimen name="gestures_onehanded_drag_threshold">20dp</dimen> <dimen name="gestures_onehanded_drag_threshold">20dp</dimen>

View File

@@ -32,11 +32,25 @@
<style name="DockedDividerBackground"> <style name="DockedDividerBackground">
<item name="android:layout_width">match_parent</item> <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:layout_gravity">center_vertical</item>
<item name="android:background">@color/split_divider_background</item> <item name="android:background">@color/split_divider_background</item>
</style> </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"> <style name="DockedDividerMinimizedShadow">
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>
<item name="android:layout_height">8dp</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. * control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
* @param packageName: Passes the top package name * @param packageName: Passes the top package name
*/ */
void topFocusedWindowChanged(String packageName); default void topFocusedWindowChanged(String packageName) {}
/** /**
* Called when the window insets configuration has changed. * 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. * Called when this window retrieved control over a specified set of insets sources.
*/ */
void insetsControlChanged(InsetsState insetsState, default void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls); InsetsSourceControl[] activeControls) {}
/** /**
* Called when a set of insets source window should be shown by policy. * 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 types internal insets types (WindowInsets.Type.InsetsType) to show
* @param fromIme true if this request originated from IME (InputMethodService). * @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. * 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 types internal insets types (WindowInsets.Type.InsetsType) to hide
* @param fromIme true if this request originated from IME (InputMethodService). * @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.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import android.animation.ObjectAnimator;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Property;
import android.util.TypedValue;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost;
import android.view.VelocityTracker; import android.view.VelocityTracker;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import androidx.annotation.NonNull; 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_ANIMATION_DURATION = 150;
public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; 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 final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
private SplitLayout mSplitLayout; private SplitLayout mSplitLayout;
@@ -58,6 +83,31 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private GestureDetector mDoubleTapDetector; private GestureDetector mDoubleTapDetector;
private boolean mInteractive; 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) { public DividerView(@NonNull Context context) {
super(context); super(context);
} }
@@ -79,14 +129,42 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
/** Sets up essential dependencies of the divider bar. */ /** Sets up essential dependencies of the divider bar. */
public void setup( public void setup(
SplitLayout layout, SplitLayout layout,
SurfaceControlViewHost viewHost) { SurfaceControlViewHost viewHost,
InsetsState insetsState) {
mSplitLayout = layout; mSplitLayout = layout;
mViewHost = viewHost; 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 @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
mDividerBar = findViewById(R.id.divider_bar);
mHandle = findViewById(R.id.docked_divider_handle); mHandle = findViewById(R.id.docked_divider_handle);
mBackground = findViewById(R.id.docked_divider_background); mBackground = findViewById(R.id.docked_divider_background);
mTouchElevation = getResources().getDimensionPixelSize( mTouchElevation = getResources().getDimensionPixelSize(

View File

@@ -40,6 +40,8 @@ import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.view.WindowManager; 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.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayImeController; 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 * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
* divide position changes. * 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. * 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 ImePositionProcessor mImePositionProcessor;
private final DismissingParallaxPolicy mDismissingParallaxPolicy; private final DismissingParallaxPolicy mDismissingParallaxPolicy;
private final ShellTaskOrganizer mTaskOrganizer; private final ShellTaskOrganizer mTaskOrganizer;
private final InsetsState mInsetsState = new InsetsState();
private Context mContext; private Context mContext;
private DividerSnapAlgorithm mDividerSnapAlgorithm; private DividerSnapAlgorithm mDividerSnapAlgorithm;
@@ -249,7 +253,7 @@ public final class SplitLayout {
public void init() { public void init() {
if (mInitialized) return; if (mInitialized) return;
mInitialized = true; mInitialized = true;
mSplitWindowManager.init(this); mSplitWindowManager.init(this, mInsetsState);
mDisplayImeController.addPositionProcessor(mImePositionProcessor); mDisplayImeController.addPositionProcessor(mImePositionProcessor);
} }
@@ -262,6 +266,23 @@ public final class SplitLayout {
mImePositionProcessor.reset(); 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 * Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits. * 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. * 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 * @param isLandscape indicates whether it's splitting horizontally or vertically
*/ */
void applyDividerPosition(int position, boolean isLandscape) { void applyDividerPosition(int position, boolean isLandscape) {
@@ -518,11 +539,11 @@ public final class SplitLayout {
if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) { if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP; mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
- mDividerSnapAlgorithm.getFirstSplitTarget().position; - mDividerSnapAlgorithm.getFirstSplitTarget().position;
} else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) { } else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM; mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
- mDividerSnapAlgorithm.getDismissEndTarget().position; - mDividerSnapAlgorithm.getDismissEndTarget().position;
} }
if (mDismissingSide != DOCKED_INVALID) { if (mDismissingSide != DOCKED_INVALID) {

View File

@@ -36,6 +36,7 @@ import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Slog; import android.util.Slog;
import android.view.IWindow; import android.view.IWindow;
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;
@@ -103,7 +104,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
} }
/** Inflates {@link DividerView} on to the root surface. */ /** Inflates {@link DividerView} on to the root surface. */
void init(SplitLayout splitLayout) { void init(SplitLayout splitLayout, InsetsState insetsState) {
if (mDividerView != null || mViewHost != null) { if (mDividerView != null || mViewHost != null) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Try to inflate divider view again without release first"); "Try to inflate divider view again without release first");
@@ -123,7 +124,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
lp.setTitle(mWindowName); lp.setTitle(mWindowName);
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
mViewHost.setView(mDividerView, lp); 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() { SurfaceControl getSurfaceControl() {
return mLeash; 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.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget; import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.SurfaceSession; import android.view.SurfaceSession;
import android.view.WindowManager;
import android.window.IRemoteTransition; import android.window.IRemoteTransition;
import android.window.WindowContainerTransaction; 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.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController; 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.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
@@ -68,7 +69,6 @@ import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
/** /**
@@ -87,6 +87,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
private final ShellExecutor mMainExecutor; private final ShellExecutor mMainExecutor;
private final SplitScreenImpl mImpl = new SplitScreenImpl(); private final SplitScreenImpl mImpl = new SplitScreenImpl();
private final DisplayImeController mDisplayImeController; private final DisplayImeController mDisplayImeController;
private final DisplayInsetsController mDisplayInsetsController;
private final Transitions mTransitions; private final Transitions mTransitions;
private final TransactionPool mTransactionPool; private final TransactionPool mTransactionPool;
private final SplitscreenEventLogger mLogger; private final SplitscreenEventLogger mLogger;
@@ -97,6 +98,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
SyncTransactionQueue syncQueue, Context context, SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, RootTaskDisplayAreaOrganizer rootTDAOrganizer,
ShellExecutor mainExecutor, DisplayImeController displayImeController, ShellExecutor mainExecutor, DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
Transitions transitions, TransactionPool transactionPool) { Transitions transitions, TransactionPool transactionPool) {
mTaskOrganizer = shellTaskOrganizer; mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue; mSyncQueue = syncQueue;
@@ -104,6 +106,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mRootTDAOrganizer = rootTDAOrganizer; mRootTDAOrganizer = rootTDAOrganizer;
mMainExecutor = mainExecutor; mMainExecutor = mainExecutor;
mDisplayImeController = displayImeController; mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mTransitions = transitions; mTransitions = transitions;
mTransactionPool = transactionPool; mTransactionPool = transactionPool;
mLogger = new SplitscreenEventLogger(); mLogger = new SplitscreenEventLogger();
@@ -127,8 +130,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
if (mStageCoordinator == null) { if (mStageCoordinator == null) {
// TODO: Multi-display // TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mTransitions, mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
mTransactionPool, mLogger); 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.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController; 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.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitLayout;
@@ -136,6 +137,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final Context mContext; private final Context mContext;
private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>(); private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
private final DisplayImeController mDisplayImeController; private final DisplayImeController mDisplayImeController;
private final DisplayInsetsController mDisplayInsetsController;
private final SplitScreenTransitions mSplitTransitions; private final SplitScreenTransitions mSplitTransitions;
private final SplitscreenEventLogger mLogger; private final SplitscreenEventLogger mLogger;
private boolean mExitSplitScreenOnHide; private boolean mExitSplitScreenOnHide;
@@ -163,7 +165,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
DisplayImeController displayImeController, Transitions transitions, DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, SplitscreenEventLogger logger) { TransactionPool transactionPool, SplitscreenEventLogger logger) {
mContext = context; mContext = context;
mDisplayId = displayId; mDisplayId = displayId;
@@ -185,6 +188,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSyncQueue, mSyncQueue,
mSurfaceSession); mSurfaceSession);
mDisplayImeController = displayImeController; mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mRootTDAOrganizer.registerListener(displayId, this); mRootTDAOrganizer.registerListener(displayId, this);
final DeviceStateManager deviceStateManager = final DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class); mContext.getSystemService(DeviceStateManager.class);
@@ -199,7 +203,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController, MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController,
SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger) { SplitscreenEventLogger logger) {
mContext = context; mContext = context;
mDisplayId = displayId; mDisplayId = displayId;
@@ -209,6 +214,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mMainStage = mainStage; mMainStage = mainStage;
mSideStage = sideStage; mSideStage = sideStage;
mDisplayImeController = displayImeController; mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mRootTDAOrganizer.registerListener(displayId, this); mRootTDAOrganizer.registerListener(displayId, this);
mSplitLayout = splitLayout; mSplitLayout = splitLayout;
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions, mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
@@ -832,6 +838,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDisplayAreaInfo.configuration, this, mDisplayAreaInfo.configuration, this,
b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b), b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b),
mDisplayImeController, mTaskOrganizer); 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.content.res.Configuration;
import android.graphics.Rect; import android.graphics.Rect;
import android.view.InsetsState;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import androidx.test.annotation.UiThreadTest; import androidx.test.annotation.UiThreadTest;
@@ -59,7 +60,7 @@ public class SplitWindowManagerTests extends ShellTestCase {
@Test @Test
@UiThreadTest @UiThreadTest
public void testInitRelease() { public void testInitRelease() {
mSplitWindowManager.init(mSplitLayout); mSplitWindowManager.init(mSplitLayout, new InsetsState());
assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull(); assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
mSplitWindowManager.release(); mSplitWindowManager.release();
assertThat(mSplitWindowManager.getSurfaceControl()).isNull(); 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.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController; 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.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitLayout;
@@ -65,10 +66,12 @@ public class SplitTestUtils {
TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
MainStage mainStage, SideStage sideStage, DisplayImeController imeController, MainStage mainStage, SideStage sideStage, DisplayImeController imeController,
SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, DisplayInsetsController insetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger) { SplitscreenEventLogger logger) {
super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage, 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. // Prepare default TaskDisplayArea for testing.
mDisplayAreaInfo = new DisplayAreaInfo( 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.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayImeController; 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.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.TransactionPool;
@@ -79,6 +80,7 @@ public class SplitTransitionTests extends ShellTestCase {
@Mock private SyncTransactionQueue mSyncQueue; @Mock private SyncTransactionQueue mSyncQueue;
@Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer; @Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
@Mock private DisplayImeController mDisplayImeController; @Mock private DisplayImeController mDisplayImeController;
@Mock private DisplayInsetsController mDisplayInsetsController;
@Mock private TransactionPool mTransactionPool; @Mock private TransactionPool mTransactionPool;
@Mock private Transitions mTransitions; @Mock private Transitions mTransitions;
@Mock private SurfaceSession mSurfaceSession; @Mock private SurfaceSession mSurfaceSession;
@@ -107,9 +109,10 @@ public class SplitTransitionTests extends ShellTestCase {
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession); StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface()); mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY, mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
mDisplayImeController, mSplitLayout, mTransitions, mTransactionPool, mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
mLogger); mTransactionPool,
mLogger);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions(); mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class)) doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any()); .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.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayImeController; 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.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.transition.Transitions;
@@ -57,6 +58,7 @@ public class StageCoordinatorTests extends ShellTestCase {
@Mock private MainStage mMainStage; @Mock private MainStage mMainStage;
@Mock private SideStage mSideStage; @Mock private SideStage mSideStage;
@Mock private DisplayImeController mDisplayImeController; @Mock private DisplayImeController mDisplayImeController;
@Mock private DisplayInsetsController mDisplayInsetsController;
@Mock private Transitions mTransitions; @Mock private Transitions mTransitions;
@Mock private TransactionPool mTransactionPool; @Mock private TransactionPool mTransactionPool;
@Mock private SplitscreenEventLogger mLogger; @Mock private SplitscreenEventLogger mLogger;
@@ -67,8 +69,8 @@ public class StageCoordinatorTests extends ShellTestCase {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY, mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
mDisplayImeController, null /* splitLayout */, mTransitions, mTransactionPool, mDisplayImeController, mDisplayInsetsController, null /* splitLayout */,
mLogger); mTransitions, mTransactionPool, mLogger);
} }
@Test @Test

View File

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