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

Commit cc2ca8b9 authored by Jerry Chang's avatar Jerry Chang Committed by Android (Google) Code Review
Browse files

Merge "Add back dismissing parallax and dimming value to stage split" into sc-v2-dev

parents 7e59a8f1 a88bf04c
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -62,4 +62,10 @@ public class Interpolators {
     */
    public static final Interpolator PANEL_CLOSE_ACCELERATED =
            new PathInterpolator(0.3f, 0, 0.5f, 1);

    public static final PathInterpolator SLOWDOWN_INTERPOLATOR =
            new PathInterpolator(0.5f, 1f, 0.5f, 1f);

    public static final PathInterpolator DIM_INTERPOLATOR =
            new PathInterpolator(.23f, .87f, .52f, -0.11f);
}
+188 −36
Original line number Diff line number Diff line
@@ -18,11 +18,16 @@ package com.android.wm.shell.common.split;

import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;

import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -32,6 +37,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.SurfaceControl;
import android.view.WindowInsets;
@@ -81,6 +87,7 @@ public final class SplitLayout {
    private final int mDividerInsets;
    private final int mDividerSize;

    private final Rect mTempRect = new Rect();
    private final Rect mRootBounds = new Rect();
    private final Rect mDividerBounds = new Rect();
    private final Rect mBounds1 = new Rect();
@@ -89,6 +96,7 @@ public final class SplitLayout {
    private final SplitWindowManager mSplitWindowManager;
    private final DisplayImeController mDisplayImeController;
    private final ImePositionProcessor mImePositionProcessor;
    private final DismissingParallaxPolicy mDismissingParallaxPolicy;
    private final ShellTaskOrganizer mTaskOrganizer;

    private Context mContext;
@@ -111,6 +119,7 @@ public final class SplitLayout {
                windowName, mContext, configuration, parentContainerCallbacks);
        mTaskOrganizer = taskOrganizer;
        mImePositionProcessor = new ImePositionProcessor(mContext.getDisplayId());
        mDismissingParallaxPolicy = new DismissingParallaxPolicy();

        final Resources resources = context.getResources();
        mDividerWindowWidth = resources.getDimensionPixelSize(
@@ -188,7 +197,8 @@ public final class SplitLayout {
        mDividerBounds.set(mRootBounds);
        mBounds1.set(mRootBounds);
        mBounds2.set(mRootBounds);
        if (isLandscape(mRootBounds)) {
        final boolean isLandscape = isLandscape(mRootBounds);
        if (isLandscape) {
            position += mRootBounds.left;
            mDividerBounds.left = position - mDividerInsets;
            mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth;
@@ -201,6 +211,7 @@ public final class SplitLayout {
            mBounds1.bottom = position;
            mBounds2.top = mBounds1.bottom + mDividerSize;
        }
        mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
    }

    /** Inflates {@link DividerView} on the root surface. */
@@ -240,6 +251,7 @@ public final class SplitLayout {
    /** Resets divider position. */
    public void resetDividerPosition() {
        mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
        mSplitWindowManager.setResizingSplits(false);
        updateBounds(mDividePosition);
    }

@@ -333,30 +345,34 @@ public final class SplitLayout {
    /** Apply recorded surface layout to the {@link SurfaceControl.Transaction}. */
    public void applySurfaceChanges(SurfaceControl.Transaction t, SurfaceControl leash1,
            SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
        final Rect dividerBounds = mImePositionProcessor.adjustForIme(mDividerBounds);
        final Rect bounds1 = mImePositionProcessor.adjustForIme(mBounds1);
        final Rect bounds2 = mImePositionProcessor.adjustForIme(mBounds2);
        final SurfaceControl dividerLeash = getDividerLeash();
        if (dividerLeash != null) {
            t.setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
            t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top);
            // Resets layer of divider bar to make sure it is always on top.
                    .setLayer(dividerLeash, Integer.MAX_VALUE);
            t.setLayer(dividerLeash, Integer.MAX_VALUE);
        }
        t.setPosition(leash1, mBounds1.left, mBounds1.top)
                .setWindowCrop(leash1, mBounds1.width(), mBounds1.height());
        t.setPosition(leash2, mBounds2.left, mBounds2.top)
                .setWindowCrop(leash2, mBounds2.width(), mBounds2.height());

        t.setPosition(leash1, bounds1.left, bounds1.top)
                .setWindowCrop(leash1, bounds1.width(), bounds1.height());

        t.setPosition(leash2, bounds2.left, bounds2.top)
                .setWindowCrop(leash2, bounds2.width(), bounds2.height());
        if (mImePositionProcessor.adjustSurfaceLayoutForIme(
                t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
            return;
        }

        mImePositionProcessor.applySurfaceDimValues(t, dimLayer1, dimLayer2);
        mDismissingParallaxPolicy.adjustDismissingSurface(t, leash1, leash2, dimLayer1, dimLayer2);
    }

    /** Apply recorded task layout to the {@link WindowContainerTransaction}. */
    public void applyTaskChanges(WindowContainerTransaction wct,
            ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
        wct.setBounds(task1.token, mImePositionProcessor.adjustForIme(mBounds1))
                .setBounds(task2.token, mImePositionProcessor.adjustForIme(mBounds2));
        if (mImePositionProcessor.applyTaskLayoutForIme(wct, task1.token, task2.token)) {
            return;
        }

        wct.setBounds(task1.token, mBounds1)
                .setBounds(task2.token, mBounds2);
    }

    /**
@@ -376,23 +392,22 @@ public final class SplitLayout {
            wct.setScreenSizeDp(taskInfo2.token,
                    SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
        } else {
            final Rect bounds = new Rect();
            bounds.set(taskInfo1.configuration.windowConfiguration.getBounds());
            bounds.offset(offsetX, offsetY);
            wct.setBounds(taskInfo1.token, bounds);
            bounds.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
            bounds.offset(offsetX, offsetY);
            wct.setAppBounds(taskInfo1.token, bounds);
            mTempRect.set(taskInfo1.configuration.windowConfiguration.getBounds());
            mTempRect.offset(offsetX, offsetY);
            wct.setBounds(taskInfo1.token, mTempRect);
            mTempRect.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
            mTempRect.offset(offsetX, offsetY);
            wct.setAppBounds(taskInfo1.token, mTempRect);
            wct.setScreenSizeDp(taskInfo1.token,
                    taskInfo1.configuration.screenWidthDp,
                    taskInfo1.configuration.screenHeightDp);

            bounds.set(taskInfo2.configuration.windowConfiguration.getBounds());
            bounds.offset(offsetX, offsetY);
            wct.setBounds(taskInfo2.token, bounds);
            bounds.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
            bounds.offset(offsetX, offsetY);
            wct.setAppBounds(taskInfo2.token, bounds);
            mTempRect.set(taskInfo2.configuration.windowConfiguration.getBounds());
            mTempRect.offset(offsetX, offsetY);
            wct.setBounds(taskInfo2.token, mTempRect);
            mTempRect.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
            mTempRect.offset(offsetX, offsetY);
            wct.setAppBounds(taskInfo2.token, mTempRect);
            wct.setScreenSizeDp(taskInfo2.token,
                    taskInfo2.configuration.screenWidthDp,
                    taskInfo2.configuration.screenHeightDp);
@@ -428,6 +443,106 @@ public final class SplitLayout {
        int getSplitItemPosition(WindowContainerToken token);
    }

    /**
     * Calculates and applies proper dismissing parallax offset and dimming value to hint users
     * dismissing gesture.
     */
    private class DismissingParallaxPolicy {
        // The current dismissing side.
        int mDismissingSide = DOCKED_INVALID;

        // The parallax offset to hint the dismissing side and progress.
        final Point mDismissingParallaxOffset = new Point();

        // The dimming value to hint the dismissing side and progress.
        float mDismissingDimValue = 0.0f;

        /**
         * Applies a parallax to the task to hint dismissing progress.
         *
         * @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) {
            mDismissingSide = DOCKED_INVALID;
            mDismissingParallaxOffset.set(0, 0);
            mDismissingDimValue = 0;

            int totalDismissingDistance = 0;
            if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
                mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
                totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
                                - mDividerSnapAlgorithm.getFirstSplitTarget().position;
            } else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
                mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
                totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
                                - mDividerSnapAlgorithm.getDismissEndTarget().position;
            }

            if (mDismissingSide != DOCKED_INVALID) {
                float fraction = Math.max(0,
                        Math.min(mDividerSnapAlgorithm.calculateDismissingFraction(position), 1f));
                mDismissingDimValue = DIM_INTERPOLATOR.getInterpolation(fraction);
                fraction = calculateParallaxDismissingFraction(fraction, mDismissingSide);
                if (isLandscape) {
                    mDismissingParallaxOffset.x = (int) (fraction * totalDismissingDistance);
                } else {
                    mDismissingParallaxOffset.y = (int) (fraction * totalDismissingDistance);
                }
            }
        }

        /**
         * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
         * slowing down parallax effect
         */
        private float calculateParallaxDismissingFraction(float fraction, int dockSide) {
            float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;

            // Less parallax at the top, just because.
            if (dockSide == WindowManager.DOCKED_TOP) {
                result /= 2f;
            }
            return result;
        }

        /** Applies parallax offset and dimming value to the root surface at the dismissing side. */
        boolean adjustDismissingSurface(SurfaceControl.Transaction t,
                SurfaceControl leash1, SurfaceControl leash2,
                SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
            SurfaceControl targetLeash, targetDimLayer;
            switch (mDismissingSide) {
                case DOCKED_TOP:
                case DOCKED_LEFT:
                    targetLeash = leash1;
                    targetDimLayer = dimLayer1;
                    mTempRect.set(mBounds1);
                    break;
                case DOCKED_BOTTOM:
                case DOCKED_RIGHT:
                    targetLeash = leash2;
                    targetDimLayer = dimLayer2;
                    mTempRect.set(mBounds2);
                    break;
                case DOCKED_INVALID:
                default:
                    t.setAlpha(dimLayer1, 0).hide(dimLayer1);
                    t.setAlpha(dimLayer2, 0).hide(dimLayer2);
                    return false;
            }

            t.setPosition(targetLeash,
                    mTempRect.left + mDismissingParallaxOffset.x,
                    mTempRect.top + mDismissingParallaxOffset.y);
            // Transform the screen-based split bounds to surface-based crop bounds.
            mTempRect.offsetTo(-mDismissingParallaxOffset.x, -mDismissingParallaxOffset.y);
            t.setWindowCrop(targetLeash, mTempRect);
            t.setAlpha(targetDimLayer, mDismissingDimValue)
                    .setVisibility(targetDimLayer, mDismissingDimValue > 0.001f);
            return true;
        }
    }

    /** Records IME top offset changes and updates SplitLayout correspondingly. */
    private class ImePositionProcessor implements DisplayImeController.ImePositionProcessor {
        /**
@@ -558,24 +673,61 @@ public final class SplitLayout {
            return start + (end - start) * progress;
        }

        private void reset() {
        void reset() {
            mImeShown = false;
            mYOffsetForIme = mLastYOffset = mTargetYOffset = 0;
            mDimValue1 = mLastDim1 = mTargetDim1 = 0.0f;
            mDimValue2 = mLastDim2 = mTargetDim2 = 0.0f;
        }

        /* Adjust bounds with IME offset. */
        private Rect adjustForIme(Rect bounds) {
            final Rect temp = new Rect(bounds);
            if (mYOffsetForIme != 0) temp.offset(0, mYOffsetForIme);
            return temp;
        /**
         * Applies adjusted task layout for showing IME.
         *
         * @return {@code false} if there's no need to adjust, otherwise {@code true}
         */
        boolean applyTaskLayoutForIme(WindowContainerTransaction wct,
                WindowContainerToken token1, WindowContainerToken token2) {
            if (mYOffsetForIme == 0) return false;

            mTempRect.set(mBounds1);
            mTempRect.offset(0, mYOffsetForIme);
            wct.setBounds(token1, mTempRect);

            mTempRect.set(mBounds2);
            mTempRect.offset(0, mYOffsetForIme);
            wct.setBounds(token2, mTempRect);

            return true;
        }

        private void applySurfaceDimValues(SurfaceControl.Transaction t, SurfaceControl dimLayer1,
                SurfaceControl dimLayer2) {
        /**
         * Adjusts surface layout while showing IME.
         *
         * @return {@code false} if there's no need to adjust, otherwise {@code true}
         */
        boolean adjustSurfaceLayoutForIme(SurfaceControl.Transaction t,
                SurfaceControl dividerLeash, SurfaceControl leash1, SurfaceControl leash2,
                SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
            if (mYOffsetForIme == 0) return false;

            if (dividerLeash != null) {
                mTempRect.set(mDividerBounds);
                mTempRect.offset(0, mYOffsetForIme);
                t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
            }

            mTempRect.set(mBounds1);
            mTempRect.offset(0, mYOffsetForIme);
            t.setPosition(leash1, mTempRect.left, mTempRect.top);

            mTempRect.set(mBounds2);
            mTempRect.offset(0, mYOffsetForIme);
            t.setPosition(leash2, mTempRect.left, mTempRect.top);

            t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f);
            t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f);

            return true;
        }
    }
}
+2 −4
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
import static android.view.WindowManager.DOCKED_RIGHT;

import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION;
import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION;

@@ -100,10 +102,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
    private static final float MINIMIZE_DOCK_SCALE = 0f;
    private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;

    private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
            new PathInterpolator(0.5f, 1f, 0.5f, 1f);
    private static final PathInterpolator DIM_INTERPOLATOR =
            new PathInterpolator(.23f, .87f, .52f, -0.11f);
    private static final Interpolator IME_ADJUST_INTERPOLATOR =
            new PathInterpolator(0.2f, 0f, 0.1f, 1f);