Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java +47 −26 Original line number Diff line number Diff line Loading @@ -71,6 +71,11 @@ public class DividerSnapAlgorithm { */ private static final int SNAP_MODE_MINIMIZED = 3; /** * A mode where apps can be "flexibly offscreen" on smaller displays. */ private static final int SNAP_FLEXIBLE_SPLIT = 4; private final float mMinFlingVelocityPxPerSecond; private final float mMinDismissVelocityPxPerSecond; private final int mDisplayWidth; Loading @@ -78,6 +83,7 @@ public class DividerSnapAlgorithm { private final int mDividerSize; private final ArrayList<SnapTarget> mTargets = new ArrayList<>(); private final Rect mInsets = new Rect(); private final Rect mPinnedTaskbarInsets = new Rect(); private final int mSnapMode; private final boolean mFreeSnapMode; private final int mMinimalSizeResizableTask; Loading @@ -88,6 +94,8 @@ public class DividerSnapAlgorithm { /** Allows split ratios that go offscreen (a.k.a. "flexible split") */ private final boolean mAllowOffscreenRatios; private final boolean mIsLeftRightSplit; /** In SNAP_MODE_MINIMIZED, the side of the screen on which an app will "dock" when minimized */ private final int mDockSide; /** The first target which is still splitting the screen */ private final SnapTarget mFirstSplitTarget; Loading @@ -101,14 +109,14 @@ public class DividerSnapAlgorithm { public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, boolean isLeftRightSplit, Rect insets, int dockSide) { boolean isLeftRightSplit, Rect insets, Rect pinnedTaskbarInsets, int dockSide) { this(res, displayWidth, displayHeight, dividerSize, isLeftRightSplit, insets, dockSide, false /* minimized */, true /* resizable */); pinnedTaskbarInsets, dockSide, false /* minimized */, true /* resizable */); } public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, boolean isLeftRightSplit, Rect insets, int dockSide, boolean isMinimizedMode, boolean isHomeResizable) { boolean isLeftRightSplit, Rect insets, Rect pinnedTaskbarInsets, int dockSide, boolean isMinimizedMode, boolean isHomeResizable) { mMinFlingVelocityPxPerSecond = MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density; mMinDismissVelocityPxPerSecond = Loading @@ -117,10 +125,11 @@ public class DividerSnapAlgorithm { mDisplayWidth = displayWidth; mDisplayHeight = displayHeight; mIsLeftRightSplit = isLeftRightSplit; mDockSide = dockSide; mInsets.set(insets); mPinnedTaskbarInsets.set(pinnedTaskbarInsets); if (Flags.enableFlexibleTwoAppSplit()) { // In flexible split, we always use a fixed ratio (50%, 66%, or 90%) for splitting mSnapMode = SNAP_FIXED_RATIO; mSnapMode = SNAP_FLEXIBLE_SPLIT; } else { // Set SNAP_MODE_MINIMIZED, SNAP_MODE_16_9, or SNAP_FIXED_RATIO depending on config mSnapMode = isMinimizedMode Loading @@ -140,7 +149,7 @@ public class DividerSnapAlgorithm { mAllowOffscreenRatios = SplitScreenUtils.allowOffscreenRatios(res); mTaskHeightInMinimizedMode = isHomeResizable ? res.getDimensionPixelSize( com.android.internal.R.dimen.task_height_of_minimized_mode) : 0; calculateTargets(isLeftRightSplit, dockSide); calculateTargets(); mFirstSplitTarget = mTargets.get(1); mLastSplitTarget = mTargets.get(mTargets.size() - 2); mDismissStartTarget = mTargets.get(0); Loading Loading @@ -276,28 +285,31 @@ public class DividerSnapAlgorithm { return mTargets.get(minIndex); } private void calculateTargets(boolean isLeftRightSplit, int dockedSide) { private void calculateTargets() { mTargets.clear(); int dividerMax = isLeftRightSplit int dividerMax = mIsLeftRightSplit ? mDisplayWidth : mDisplayHeight; int startPos = -mDividerSize; if (dockedSide == DOCKED_RIGHT) { if (mDockSide == DOCKED_RIGHT) { startPos += mInsets.left; } mTargets.add(new SnapTarget(startPos, SNAP_TO_START_AND_DISMISS, 0.35f)); switch (mSnapMode) { case SNAP_MODE_16_9: addRatio16_9Targets(isLeftRightSplit, dividerMax); addRatio16_9Targets(mIsLeftRightSplit, dividerMax); break; case SNAP_FIXED_RATIO: addFixedDivisionTargets(isLeftRightSplit, dividerMax); addFixedDivisionTargets(mIsLeftRightSplit, dividerMax); break; case SNAP_ONLY_1_1: addMiddleTarget(isLeftRightSplit); addMiddleTarget(mIsLeftRightSplit); break; case SNAP_MODE_MINIMIZED: addMinimizedTarget(isLeftRightSplit, dockedSide); addMinimizedTarget(mIsLeftRightSplit, mDockSide); break; case SNAP_FLEXIBLE_SPLIT: addFlexSplitTargets(mIsLeftRightSplit, dividerMax); break; } mTargets.add(new SnapTarget(dividerMax, SNAP_TO_END_AND_DISMISS, 0.35f)); Loading @@ -321,25 +333,34 @@ public class DividerSnapAlgorithm { ? mDisplayWidth - mInsets.right : mDisplayHeight - mInsets.bottom; 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; int 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); } private void addFlexSplitTargets(boolean isLeftRightSplit, int dividerMax) { int start = 0; int end = isLeftRightSplit ? mDisplayWidth : mDisplayHeight; int pinnedTaskbarShiftStart = isLeftRightSplit ? mPinnedTaskbarInsets.left : mPinnedTaskbarInsets.top; int pinnedTaskbarShiftEnd = isLeftRightSplit ? mPinnedTaskbarInsets.right : mPinnedTaskbarInsets.bottom; float ratio = areOffscreenRatiosSupported() ? SplitLayout.OFFSCREEN_ASYMMETRIC_RATIO : SplitLayout.ONSCREEN_ONLY_ASYMMETRIC_RATIO; int size = (int) (ratio * (end - start)) - mDividerSize / 2; int leftTopPosition = start + pinnedTaskbarShiftStart + size; int rightBottomPosition = end - pinnedTaskbarShiftEnd - size - mDividerSize; addNonDismissingTargets(isLeftRightSplit, leftTopPosition, rightBottomPosition, dividerMax); } private void addRatio16_9Targets(boolean isLeftRightSplit, int dividerMax) { int start = isLeftRightSplit ? mInsets.left : mInsets.top; int end = isLeftRightSplit Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +50 −2 Original line number Diff line number Diff line Loading @@ -49,10 +49,13 @@ import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; import android.view.Display; import android.view.InsetsController; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.RoundedCorner; Loading Loading @@ -153,6 +156,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private final ResizingEffectPolicy mSurfaceEffectPolicy; private final ShellTaskOrganizer mTaskOrganizer; private final InsetsState mInsetsState = new InsetsState(); private Insets mPinnedTaskbarInsets = Insets.NONE; private Context mContext; @VisibleForTesting DividerSnapAlgorithm mDividerSnapAlgorithm; Loading Loading @@ -523,6 +527,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange @Override public void insetsChanged(InsetsState insetsState) { mInsetsState.set(insetsState); if (!mInitialized) { return; } Loading @@ -531,9 +536,51 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange // flicker. return; } // Check to see if insets changed in such a way that the divider algorithm needs to be // recalculated. Insets pinnedTaskbarInsets = calculatePinnedTaskbarInsets(insetsState); if (!mPinnedTaskbarInsets.equals(pinnedTaskbarInsets)) { mPinnedTaskbarInsets = pinnedTaskbarInsets; // Refresh the DividerSnapAlgorithm. mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); // If the divider is no longer placed on a snap point, animate it to the nearest one. DividerSnapAlgorithm.SnapTarget snapTarget = findSnapTarget(mDividerPosition, 0, false /* hardDismiss */); if (snapTarget.position != mDividerPosition) { snapToTarget(mDividerPosition, snapTarget, InsetsController.ANIMATION_DURATION_RESIZE, InsetsController.RESIZE_INTERPOLATOR); } } mSplitWindowManager.onInsetsChanged(insetsState); } /** * Calculates the insets that might trigger a divider algorithm recalculation. Currently, only * pinned Taskbar does this, and only when the IME is not showing. */ private Insets calculatePinnedTaskbarInsets(InsetsState insetsState) { if (insetsState.isSourceOrDefaultVisible(InsetsSource.ID_IME, WindowInsets.Type.ime())) { return Insets.NONE; } // If IME is not showing... for (int i = insetsState.sourceSize() - 1; i >= 0; i--) { final InsetsSource source = insetsState.sourceAt(i); // and Taskbar is pinned... if (source.getType() == WindowInsets.Type.navigationBars() && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) { // Return Insets representing the pinned taskbar state. return source.calculateVisibleInsets(mRootBounds); } } // Else, divider can calculate based on the full display. return Insets.NONE; } @Override public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls) { Loading Loading @@ -631,8 +678,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } /** * Same as {@link #snapToTarget(int, SnapTarget)}, with default animation duration and * interpolator. * Same as {@link #snapToTarget(int, SnapTarget, int, Interpolator)}, with default animation * duration and interpolator. */ public void snapToTarget(int currentPosition, SnapTarget snapTarget) { snapToTarget(currentPosition, snapTarget, FLING_RESIZE_DURATION, Loading Loading @@ -683,6 +730,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mDividerSize, mIsLeftRightSplit, insets, mPinnedTaskbarInsets.toRect(), mIsLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP /* dockSide */); } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java +47 −26 Original line number Diff line number Diff line Loading @@ -71,6 +71,11 @@ public class DividerSnapAlgorithm { */ private static final int SNAP_MODE_MINIMIZED = 3; /** * A mode where apps can be "flexibly offscreen" on smaller displays. */ private static final int SNAP_FLEXIBLE_SPLIT = 4; private final float mMinFlingVelocityPxPerSecond; private final float mMinDismissVelocityPxPerSecond; private final int mDisplayWidth; Loading @@ -78,6 +83,7 @@ public class DividerSnapAlgorithm { private final int mDividerSize; private final ArrayList<SnapTarget> mTargets = new ArrayList<>(); private final Rect mInsets = new Rect(); private final Rect mPinnedTaskbarInsets = new Rect(); private final int mSnapMode; private final boolean mFreeSnapMode; private final int mMinimalSizeResizableTask; Loading @@ -88,6 +94,8 @@ public class DividerSnapAlgorithm { /** Allows split ratios that go offscreen (a.k.a. "flexible split") */ private final boolean mAllowOffscreenRatios; private final boolean mIsLeftRightSplit; /** In SNAP_MODE_MINIMIZED, the side of the screen on which an app will "dock" when minimized */ private final int mDockSide; /** The first target which is still splitting the screen */ private final SnapTarget mFirstSplitTarget; Loading @@ -101,14 +109,14 @@ public class DividerSnapAlgorithm { public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, boolean isLeftRightSplit, Rect insets, int dockSide) { boolean isLeftRightSplit, Rect insets, Rect pinnedTaskbarInsets, int dockSide) { this(res, displayWidth, displayHeight, dividerSize, isLeftRightSplit, insets, dockSide, false /* minimized */, true /* resizable */); pinnedTaskbarInsets, dockSide, false /* minimized */, true /* resizable */); } public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, boolean isLeftRightSplit, Rect insets, int dockSide, boolean isMinimizedMode, boolean isHomeResizable) { boolean isLeftRightSplit, Rect insets, Rect pinnedTaskbarInsets, int dockSide, boolean isMinimizedMode, boolean isHomeResizable) { mMinFlingVelocityPxPerSecond = MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density; mMinDismissVelocityPxPerSecond = Loading @@ -117,10 +125,11 @@ public class DividerSnapAlgorithm { mDisplayWidth = displayWidth; mDisplayHeight = displayHeight; mIsLeftRightSplit = isLeftRightSplit; mDockSide = dockSide; mInsets.set(insets); mPinnedTaskbarInsets.set(pinnedTaskbarInsets); if (Flags.enableFlexibleTwoAppSplit()) { // In flexible split, we always use a fixed ratio (50%, 66%, or 90%) for splitting mSnapMode = SNAP_FIXED_RATIO; mSnapMode = SNAP_FLEXIBLE_SPLIT; } else { // Set SNAP_MODE_MINIMIZED, SNAP_MODE_16_9, or SNAP_FIXED_RATIO depending on config mSnapMode = isMinimizedMode Loading @@ -140,7 +149,7 @@ public class DividerSnapAlgorithm { mAllowOffscreenRatios = SplitScreenUtils.allowOffscreenRatios(res); mTaskHeightInMinimizedMode = isHomeResizable ? res.getDimensionPixelSize( com.android.internal.R.dimen.task_height_of_minimized_mode) : 0; calculateTargets(isLeftRightSplit, dockSide); calculateTargets(); mFirstSplitTarget = mTargets.get(1); mLastSplitTarget = mTargets.get(mTargets.size() - 2); mDismissStartTarget = mTargets.get(0); Loading Loading @@ -276,28 +285,31 @@ public class DividerSnapAlgorithm { return mTargets.get(minIndex); } private void calculateTargets(boolean isLeftRightSplit, int dockedSide) { private void calculateTargets() { mTargets.clear(); int dividerMax = isLeftRightSplit int dividerMax = mIsLeftRightSplit ? mDisplayWidth : mDisplayHeight; int startPos = -mDividerSize; if (dockedSide == DOCKED_RIGHT) { if (mDockSide == DOCKED_RIGHT) { startPos += mInsets.left; } mTargets.add(new SnapTarget(startPos, SNAP_TO_START_AND_DISMISS, 0.35f)); switch (mSnapMode) { case SNAP_MODE_16_9: addRatio16_9Targets(isLeftRightSplit, dividerMax); addRatio16_9Targets(mIsLeftRightSplit, dividerMax); break; case SNAP_FIXED_RATIO: addFixedDivisionTargets(isLeftRightSplit, dividerMax); addFixedDivisionTargets(mIsLeftRightSplit, dividerMax); break; case SNAP_ONLY_1_1: addMiddleTarget(isLeftRightSplit); addMiddleTarget(mIsLeftRightSplit); break; case SNAP_MODE_MINIMIZED: addMinimizedTarget(isLeftRightSplit, dockedSide); addMinimizedTarget(mIsLeftRightSplit, mDockSide); break; case SNAP_FLEXIBLE_SPLIT: addFlexSplitTargets(mIsLeftRightSplit, dividerMax); break; } mTargets.add(new SnapTarget(dividerMax, SNAP_TO_END_AND_DISMISS, 0.35f)); Loading @@ -321,25 +333,34 @@ public class DividerSnapAlgorithm { ? mDisplayWidth - mInsets.right : mDisplayHeight - mInsets.bottom; 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; int 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); } private void addFlexSplitTargets(boolean isLeftRightSplit, int dividerMax) { int start = 0; int end = isLeftRightSplit ? mDisplayWidth : mDisplayHeight; int pinnedTaskbarShiftStart = isLeftRightSplit ? mPinnedTaskbarInsets.left : mPinnedTaskbarInsets.top; int pinnedTaskbarShiftEnd = isLeftRightSplit ? mPinnedTaskbarInsets.right : mPinnedTaskbarInsets.bottom; float ratio = areOffscreenRatiosSupported() ? SplitLayout.OFFSCREEN_ASYMMETRIC_RATIO : SplitLayout.ONSCREEN_ONLY_ASYMMETRIC_RATIO; int size = (int) (ratio * (end - start)) - mDividerSize / 2; int leftTopPosition = start + pinnedTaskbarShiftStart + size; int rightBottomPosition = end - pinnedTaskbarShiftEnd - size - mDividerSize; addNonDismissingTargets(isLeftRightSplit, leftTopPosition, rightBottomPosition, dividerMax); } private void addRatio16_9Targets(boolean isLeftRightSplit, int dividerMax) { int start = isLeftRightSplit ? mInsets.left : mInsets.top; int end = isLeftRightSplit Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +50 −2 Original line number Diff line number Diff line Loading @@ -49,10 +49,13 @@ import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; import android.view.Display; import android.view.InsetsController; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.RoundedCorner; Loading Loading @@ -153,6 +156,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private final ResizingEffectPolicy mSurfaceEffectPolicy; private final ShellTaskOrganizer mTaskOrganizer; private final InsetsState mInsetsState = new InsetsState(); private Insets mPinnedTaskbarInsets = Insets.NONE; private Context mContext; @VisibleForTesting DividerSnapAlgorithm mDividerSnapAlgorithm; Loading Loading @@ -523,6 +527,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange @Override public void insetsChanged(InsetsState insetsState) { mInsetsState.set(insetsState); if (!mInitialized) { return; } Loading @@ -531,9 +536,51 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange // flicker. return; } // Check to see if insets changed in such a way that the divider algorithm needs to be // recalculated. Insets pinnedTaskbarInsets = calculatePinnedTaskbarInsets(insetsState); if (!mPinnedTaskbarInsets.equals(pinnedTaskbarInsets)) { mPinnedTaskbarInsets = pinnedTaskbarInsets; // Refresh the DividerSnapAlgorithm. mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); // If the divider is no longer placed on a snap point, animate it to the nearest one. DividerSnapAlgorithm.SnapTarget snapTarget = findSnapTarget(mDividerPosition, 0, false /* hardDismiss */); if (snapTarget.position != mDividerPosition) { snapToTarget(mDividerPosition, snapTarget, InsetsController.ANIMATION_DURATION_RESIZE, InsetsController.RESIZE_INTERPOLATOR); } } mSplitWindowManager.onInsetsChanged(insetsState); } /** * Calculates the insets that might trigger a divider algorithm recalculation. Currently, only * pinned Taskbar does this, and only when the IME is not showing. */ private Insets calculatePinnedTaskbarInsets(InsetsState insetsState) { if (insetsState.isSourceOrDefaultVisible(InsetsSource.ID_IME, WindowInsets.Type.ime())) { return Insets.NONE; } // If IME is not showing... for (int i = insetsState.sourceSize() - 1; i >= 0; i--) { final InsetsSource source = insetsState.sourceAt(i); // and Taskbar is pinned... if (source.getType() == WindowInsets.Type.navigationBars() && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) { // Return Insets representing the pinned taskbar state. return source.calculateVisibleInsets(mRootBounds); } } // Else, divider can calculate based on the full display. return Insets.NONE; } @Override public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls) { Loading Loading @@ -631,8 +678,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } /** * Same as {@link #snapToTarget(int, SnapTarget)}, with default animation duration and * interpolator. * Same as {@link #snapToTarget(int, SnapTarget, int, Interpolator)}, with default animation * duration and interpolator. */ public void snapToTarget(int currentPosition, SnapTarget snapTarget) { snapToTarget(currentPosition, snapTarget, FLING_RESIZE_DURATION, Loading Loading @@ -683,6 +730,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mDividerSize, mIsLeftRightSplit, insets, mPinnedTaskbarInsets.toRect(), mIsLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP /* dockSide */); } Loading