summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java15
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java2
6 files changed, 96 insertions, 28 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
index 85921703d559..b29e49a48428 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
@@ -118,8 +118,16 @@ public class DividerSnapAlgorithm {
mDisplayHeight = displayHeight;
mIsLeftRightSplit = isLeftRightSplit;
mInsets.set(insets);
- mSnapMode = isMinimizedMode ? SNAP_MODE_MINIMIZED :
- res.getInteger(com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+ if (Flags.enableFlexibleTwoAppSplit()) {
+ // In flexible split, we always use a fixed ratio (50%, 66%, or 90%) for splitting
+ mSnapMode = SNAP_FIXED_RATIO;
+ } else {
+ // Set SNAP_MODE_MINIMIZED, SNAP_MODE_16_9, or SNAP_FIXED_RATIO depending on config
+ mSnapMode = isMinimizedMode
+ ? SNAP_MODE_MINIMIZED
+ : res.getInteger(
+ com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+ }
mFreeSnapMode = res.getBoolean(
com.android.internal.R.bool.config_dockedStackDividerFreeSnapMode);
mFixedRatio = res.getFraction(
@@ -129,8 +137,7 @@ public class DividerSnapAlgorithm {
mCalculateRatiosBasedOnAvailableSpace = res.getBoolean(
com.android.internal.R.bool.config_flexibleSplitRatios);
// If this is a small screen or a foldable, use offscreen ratios
- mAllowOffscreenRatios =
- Flags.enableFlexibleTwoAppSplit() && SplitScreenUtils.allowOffscreenRatios(res);
+ mAllowOffscreenRatios = SplitScreenUtils.allowOffscreenRatios(res);
mTaskHeightInMinimizedMode = isHomeResizable ? res.getDimensionPixelSize(
com.android.internal.R.dimen.task_height_of_minimized_mode) : 0;
calculateTargets(isLeftRightSplit, dockSide);
@@ -299,9 +306,9 @@ public class DividerSnapAlgorithm {
private void addNonDismissingTargets(boolean isLeftRightSplit, int topPosition,
int bottomPosition, int dividerMax) {
@PersistentSnapPosition int firstTarget =
- mAllowOffscreenRatios ? SNAP_TO_2_10_90 : SNAP_TO_2_33_66;
+ areOffscreenRatiosSupported() ? SNAP_TO_2_10_90 : SNAP_TO_2_33_66;
@PersistentSnapPosition int lastTarget =
- mAllowOffscreenRatios ? SNAP_TO_2_90_10 : SNAP_TO_2_66_33;
+ areOffscreenRatiosSupported() ? SNAP_TO_2_90_10 : SNAP_TO_2_66_33;
maybeAddTarget(topPosition, topPosition - getStartInset(), firstTarget);
addMiddleTarget(isLeftRightSplit);
maybeAddTarget(bottomPosition,
@@ -313,14 +320,21 @@ public class DividerSnapAlgorithm {
int end = isLeftRightSplit
? mDisplayWidth - mInsets.right
: mDisplayHeight - mInsets.bottom;
- int size = (int) (mFixedRatio * (end - start)) - mDividerSize / 2;
- if (mAllowOffscreenRatios) {
- // TODO (b/349828130): This is a placeholder value, real measurements to come
- size = (int) (0.3f * (end - start)) - mDividerSize / 2;
- } else if (mCalculateRatiosBasedOnAvailableSpace) {
- size = Math.max(size, mMinimalSizeResizableTask);
+ int size;
+ if (Flags.enableFlexibleTwoAppSplit()) {
+ float ratio = areOffscreenRatiosSupported()
+ ? SplitLayout.OFFSCREEN_ASYMMETRIC_RATIO
+ : SplitLayout.ONSCREEN_ONLY_ASYMMETRIC_RATIO;
+ size = (int) (ratio * (end - start)) - mDividerSize / 2;
+ } else {
+ size = (int) (mFixedRatio * (end - start)) - mDividerSize / 2;
+
+ if (mCalculateRatiosBasedOnAvailableSpace) {
+ size = Math.max(size, mMinimalSizeResizableTask);
+ }
}
+
int topPosition = start + size;
int bottomPosition = end - size - mDividerSize;
addNonDismissingTargets(isLeftRightSplit, topPosition, bottomPosition, dividerMax);
@@ -347,7 +361,7 @@ public class DividerSnapAlgorithm {
* meets the minimal size requirement.
*/
private void maybeAddTarget(int position, int smallerSize, @SnapPosition int snapPosition) {
- if (smallerSize >= mMinimalSizeResizableTask || mAllowOffscreenRatios) {
+ if (smallerSize >= mMinimalSizeResizableTask || areOffscreenRatiosSupported()) {
mTargets.add(new SnapTarget(position, snapPosition));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index e7848e27d7ed..cf858deb0327 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -480,6 +480,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mLastDraggingPosition,
position,
mSplitLayout.FLING_RESIZE_DURATION,
+ Interpolators.FAST_OUT_SLOW_IN,
() -> mSplitLayout.setDividerPosition(position, true /* applyLayoutChange */));
mMoving = false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f73065ea8eb8..b1e0e9eab5d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -28,6 +28,7 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLIT_SCREEN_
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLIT_SCREEN_RESIZE;
import static com.android.wm.shell.shared.animation.Interpolators.DIM_INTERPOLATOR;
import static com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED;
+import static com.android.wm.shell.shared.animation.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.wm.shell.shared.animation.Interpolators.LINEAR;
import static com.android.wm.shell.shared.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
@@ -77,7 +78,6 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.common.split.DividerSnapAlgorithm.SnapTarget;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.shared.split.SplitScreenConstants.SnapPosition;
@@ -100,6 +100,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public static final int FLING_RESIZE_DURATION = 250;
private static final int FLING_ENTER_DURATION = 450;
private static final int FLING_EXIT_DURATION = 450;
+ private static final int FLING_OFFSCREEN_DURATION = 500;
+
+ /** A split ratio used on larger screens, where we can fit both apps onscreen. */
+ public static final float ONSCREEN_ONLY_ASYMMETRIC_RATIO = 0.33f;
+ /** A split ratio used on smaller screens, where we place one app mostly offscreen. */
+ public static final float OFFSCREEN_ASYMMETRIC_RATIO = 0.1f;
// Here are some (arbitrarily decided) layer definitions used during animations to make sure the
// layers stay in order. Note: This does not affect any other layer numbering systems because
@@ -604,25 +610,35 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
* Sets new divider position and updates bounds correspondingly. Notifies listener if the new
* target indicates dismissing split.
*/
- public void snapToTarget(int currentPosition, SnapTarget snapTarget) {
+ public void snapToTarget(int currentPosition, SnapTarget snapTarget, int duration,
+ Interpolator interpolator) {
switch (snapTarget.snapPosition) {
case SNAP_TO_START_AND_DISMISS:
- flingDividerPosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
+ flingDividerPosition(currentPosition, snapTarget.position, duration, interpolator,
() -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
case SNAP_TO_END_AND_DISMISS:
- flingDividerPosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
+ flingDividerPosition(currentPosition, snapTarget.position, duration, interpolator,
() -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
default:
- flingDividerPosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
+ flingDividerPosition(currentPosition, snapTarget.position, duration, interpolator,
() -> setDividerPosition(snapTarget.position, true /* applyLayoutChange */));
break;
}
}
+ /**
+ * Same as {@link #snapToTarget(int, SnapTarget)}, with default animation duration and
+ * interpolator.
+ */
+ public void snapToTarget(int currentPosition, SnapTarget snapTarget) {
+ snapToTarget(currentPosition, snapTarget, FLING_RESIZE_DURATION,
+ FAST_OUT_SLOW_IN);
+ }
+
void onStartDragging() {
mInteractionJankMonitor.begin(getDividerLeash(), mContext, mHandler,
CUJ_SPLIT_SCREEN_RESIZE);
@@ -674,14 +690,14 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void flingDividerToDismiss(boolean toEnd, int reason) {
final int target = toEnd ? mDividerSnapAlgorithm.getDismissEndTarget().position
: mDividerSnapAlgorithm.getDismissStartTarget().position;
- flingDividerPosition(getDividerPosition(), target, FLING_EXIT_DURATION,
+ flingDividerPosition(getDividerPosition(), target, FLING_EXIT_DURATION, FAST_OUT_SLOW_IN,
() -> mSplitLayoutHandler.onSnappedToDismiss(toEnd, reason));
}
/** Fling divider from current position to center position. */
public void flingDividerToCenter(@Nullable Runnable finishCallback) {
final int pos = mDividerSnapAlgorithm.getMiddleTarget().position;
- flingDividerPosition(getDividerPosition(), pos, FLING_ENTER_DURATION,
+ flingDividerPosition(getDividerPosition(), pos, FLING_ENTER_DURATION, FAST_OUT_SLOW_IN,
() -> {
setDividerPosition(pos, true /* applyLayoutChange */);
if (finishCallback != null) {
@@ -699,14 +715,16 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void flingDividerToOtherSide(@PersistentSnapPosition int currentSnapPosition) {
switch (currentSnapPosition) {
case SNAP_TO_2_10_90 ->
- snapToTarget(mDividerPosition, mDividerSnapAlgorithm.getLastSplitTarget());
+ snapToTarget(mDividerPosition, mDividerSnapAlgorithm.getLastSplitTarget(),
+ FLING_OFFSCREEN_DURATION, EMPHASIZED);
case SNAP_TO_2_90_10 ->
- snapToTarget(mDividerPosition, mDividerSnapAlgorithm.getFirstSplitTarget());
+ snapToTarget(mDividerPosition, mDividerSnapAlgorithm.getFirstSplitTarget(),
+ FLING_OFFSCREEN_DURATION, EMPHASIZED);
}
}
@VisibleForTesting
- void flingDividerPosition(int from, int to, int duration,
+ void flingDividerPosition(int from, int to, int duration, Interpolator interpolator,
@Nullable Runnable flingFinishedCallback) {
if (from == to) {
if (flingFinishedCallback != null) {
@@ -724,7 +742,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mDividerFlingAnimator = ValueAnimator
.ofInt(from, to)
.setDuration(duration);
- mDividerFlingAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mDividerFlingAnimator.setInterpolator(interpolator);
// If the divider is being physically controlled by the user, we use a cool parallax effect
// on the task windows. So if this "snap" animation is an extension of a user-controlled
@@ -1048,6 +1066,14 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return (int) (minWidth / density);
}
+ public int getDisplayWidth() {
+ return mRootBounds.width();
+ }
+
+ public int getDisplayHeight() {
+ return mRootBounds.height();
+ }
+
/**
* Shift configuration bounds to prevent client apps get configuration changed or relaunch. And
* restore shifted configuration bounds if it's no longer shifted.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index 65bf389f3819..9113c0a53178 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -142,13 +142,25 @@ public class SplitScreenUtils {
}
/**
+ * Convenience function for {@link #isLargeScreen(Configuration)}.
+ */
+ public static boolean isLargeScreen(Resources res) {
+ return isLargeScreen(res.getConfiguration());
+ }
+
+ /**
+ * Returns whether the current device is a foldable
+ */
+ public static boolean isFoldable(Resources res) {
+ return res.getIntArray(com.android.internal.R.array.config_foldedDeviceStates).length != 0;
+ }
+
+ /**
* Returns whether we should allow split ratios to go offscreen or not. If the device is a phone
* or a foldable (either screen), we allow it.
*/
public static boolean allowOffscreenRatios(Resources res) {
- return !isLargeScreen(res.getConfiguration())
- ||
- res.getIntArray(com.android.internal.R.array.config_foldedDeviceStates).length != 0;
+ return Flags.enableFlexibleTwoAppSplit() && (!isLargeScreen(res) || isFoldable(res));
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 3e76403de51b..fd6f72a0192e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1629,6 +1629,21 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
leftTopTaskId = mainStageTopTaskId;
rightBottomTaskId = sideStageTopTaskId;
}
+
+ if (Flags.enableFlexibleTwoAppSplit()) {
+ // Split screen can be laid out in such a way that some of the apps are offscreen.
+ // For the purposes of passing SplitBounds up to launcher (for use in thumbnails
+ // etc.), we crop the bounds down to the screen size.
+ topLeftBounds.left =
+ Math.max(topLeftBounds.left, 0);
+ topLeftBounds.top =
+ Math.max(topLeftBounds.top, 0);
+ bottomRightBounds.right =
+ Math.min(bottomRightBounds.right, mSplitLayout.getDisplayWidth());
+ bottomRightBounds.top =
+ Math.min(bottomRightBounds.top, mSplitLayout.getDisplayHeight());
+ }
+
SplitBounds splitBounds = new SplitBounds(topLeftBounds, bottomRightBounds,
leftTopTaskId, rightBottomTaskId, mSplitLayout.calculateCurrentSnapPosition());
if (mainStageTopTaskId != INVALID_TASK_ID && sideStageTopTaskId != INVALID_TASK_ID) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index c52d9dd24165..dc0f213338be 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -190,7 +190,7 @@ public class SplitLayoutTests extends ShellTestCase {
}
private void waitDividerFlingFinished() {
- verify(mSplitLayout).flingDividerPosition(anyInt(), anyInt(), anyInt(),
+ verify(mSplitLayout).flingDividerPosition(anyInt(), anyInt(), anyInt(), any(),
mRunnableCaptor.capture());
mRunnableCaptor.getValue().run();
}