Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java +27 −13 Original line number Diff line number Diff line Loading @@ -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( Loading @@ -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); Loading Loading @@ -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, Loading @@ -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) { 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); Loading @@ -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)); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +1 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +37 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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) { Loading @@ -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 Loading Loading @@ -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. Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java +15 −3 Original line number Diff line number Diff line Loading @@ -141,14 +141,26 @@ public class SplitScreenUtils { return config.smallestScreenWidthDp >= LARGE_SCREEN_MIN_EDGE_DP; } /** * 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)); } /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +15 −0 Original line number Diff line number Diff line Loading @@ -1625,6 +1625,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) { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java +27 −13 Original line number Diff line number Diff line Loading @@ -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( Loading @@ -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); Loading Loading @@ -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, Loading @@ -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) { 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); Loading @@ -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)); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +1 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +37 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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) { Loading @@ -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 Loading Loading @@ -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. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java +15 −3 Original line number Diff line number Diff line Loading @@ -141,14 +141,26 @@ public class SplitScreenUtils { return config.smallestScreenWidthDp >= LARGE_SCREEN_MIN_EDGE_DP; } /** * 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)); } /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +15 −0 Original line number Diff line number Diff line Loading @@ -1625,6 +1625,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) { Loading