Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3cfd7c15 authored by Jeremy Sim's avatar Jeremy Sim Committed by Android (Google) Code Review
Browse files

Merge "Flexible 2-app split: Pinned Taskbar" into main

parents a4dc88d7 30297458
Loading
Loading
Loading
Loading
+47 −26
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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 =
@@ -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
@@ -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);
@@ -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));
@@ -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
+50 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -523,6 +527,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
    @Override
    public void insetsChanged(InsetsState insetsState) {
        mInsetsState.set(insetsState);

        if (!mInitialized) {
            return;
        }
@@ -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) {
@@ -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,
@@ -683,6 +730,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
                mDividerSize,
                mIsLeftRightSplit,
                insets,
                mPinnedTaskbarInsets.toRect(),
                mIsLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
    }