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:
@@ -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>
|
||||
30
libs/WindowManager/Shell/res/drawable/split_rounded_left.xml
Normal file
30
libs/WindowManager/Shell/res/drawable/split_rounded_left.xml
Normal 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>
|
||||
@@ -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>
|
||||
26
libs/WindowManager/Shell/res/drawable/split_rounded_top.xml
Normal file
26
libs/WindowManager/Shell/res/drawable/split_rounded_top.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user