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

Commit e8f29edb authored by Jeremy Sim's avatar Jeremy Sim
Browse files

Apply parallax on offscreen tap animation

Previously, when the user tapped an offscreen app, the resulting "come back onscreen" animation did not have parallax effects applied. This created a slight (undesirable) shifting effect on the left/top side, due to the uneven contraction/expansion of surfaces as they moved on- and offscreen.

Fixed by adding a mid-animation state to SplitState, and applying different parallax effects during this state. This also contributes to an overall effort to have SplitState be the new source of truth regarding what is going on split -- including all mid-animation states.

Note that, interestingly, we need different parallax effects depending on if the user is dragging the divider from 10:90 to 90:10 or if the system is animating the divider along the same path. This is because in the user-controlled case, we don't know where the user plans to drag to, so we need to add a center-squeeze effect in case the user is going to 50:50.

Fixes: 402609970
Flag: com.android.wm.shell.enable_flexible_two_app_split
Test: Manually verified that the new animation looks better, and does not affect other transitions like user-controlled, launch_adjacent, etc. The landscape phone case also looks a lot better.
Change-Id: I89c7027071d79a366cabaddf2117eed253c87ea9
parent ed28223b
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -157,6 +157,12 @@ public class SplitScreenConstants {
     */
    public static final int SNAP_TO_3_10_45_45 = 7;

    /**
     * A transitional state where the user has tapped an offscreen app, and the offscreen app is
     * currently animating back onscreen.
     */
    public static final int ANIMATING_OFFSCREEN_TAP = 100;

    /**
     * These snap targets are used for split pairs in a stable, non-transient state. They may be
     * persisted in Launcher when the user saves an app pair. They are a subset of
@@ -176,7 +182,7 @@ public class SplitScreenConstants {

    /**
     * These are all the valid "states" that split screen can be in. It's the set of
     * {@link PersistentSnapPosition} + {@link #NOT_IN_SPLIT}.
     * {@link PersistentSnapPosition} + {@link #NOT_IN_SPLIT} + other mid-animation states.
     */
    @IntDef(value = {
            NOT_IN_SPLIT, // user is not in split screen
@@ -189,6 +195,7 @@ public class SplitScreenConstants {
            SNAP_TO_3_33_33_33,
            SNAP_TO_3_45_45_10,
            SNAP_TO_3_10_45_45,
            ANIMATING_OFFSCREEN_TAP // user tapped offscreen app to retrieve it
    })
    public @interface SplitScreenState {}

@@ -205,6 +212,7 @@ public class SplitScreenConstants {
            case SNAP_TO_3_33_33_33 -> "SNAP_TO_3_33_33_33";
            case SNAP_TO_3_45_45_10 -> "SNAP_TO_3_45_45_10";
            case SNAP_TO_3_10_45_45 -> "SNAP_TO_3_10_45_45";
            case ANIMATING_OFFSCREEN_TAP -> "ANIMATING_OFFSCREEN_TAP";
            default -> "UNKNOWN";
        };
    }
+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ public class CenterParallaxSpec implements ParallaxSpec {
    public void getParallax(Point retreatingOut, Point advancingOut, int position,
            DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
            Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
            Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
            Rect advancingContent, int dimmingSide, boolean topLeftShrink, SplitState splitState) {
        if (isLeftRightSplit) {
            retreatingOut.x = (retreatingSurface.width() - retreatingContent.width()) / 2;
        } else {
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ public class DismissingParallaxSpec implements ParallaxSpec {
    public void getParallax(Point retreatingOut, Point advancingOut, int position,
            DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
            Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
            Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
            Rect advancingContent, int dimmingSide, boolean topLeftShrink, SplitState splitState) {
        if (dimmingSide == DOCKED_INVALID) {
            return;
        }
+26 −8
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.view.WindowManager.DOCKED_TOP;
import static com.android.wm.shell.common.split.ResizingEffectPolicy.DEFAULT_OFFSCREEN_DIM;
import static com.android.wm.shell.shared.animation.Interpolators.DIM_INTERPOLATOR;
import static com.android.wm.shell.shared.animation.Interpolators.FAST_DIM_INTERPOLATOR;
import static com.android.wm.shell.shared.split.SplitScreenConstants.ANIMATING_OFFSCREEN_TAP;

import android.graphics.Point;
import android.graphics.Rect;
@@ -113,18 +114,35 @@ public class FlexParallaxSpec implements ParallaxSpec {
    public void getParallax(Point retreatingOut, Point advancingOut, int position,
            DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
            Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
            Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
            Rect advancingContent, int dimmingSide, boolean topLeftShrink,
            SplitState splitState) {
        // Whether an app is getting pushed offscreen by the divider.
        boolean isRetreatingOffscreen = !displayBounds.contains(retreatingSurface);
        // Whether an app was getting pulled onscreen at the beginning of the drag.
        boolean advancingSideStartedOffscreen = !displayBounds.contains(advancingContent);

        // The simpler case when an app gets pushed offscreen (e.g. 50:50 -> 90:10)
        if (isRetreatingOffscreen && !advancingSideStartedOffscreen) {
            // On the left side, we use parallax to simulate the contents sticking to the
            // divider. This is because surfaces naturally expand to the bottom and right,
            // so when a surface's area expands, the contents stick to the left. This is
            // correct behavior on the right-side surface, but not the left.
        // If this is during the offscreen-tap animation, we adjust the left-top app to simulate the
        // contents sticking to the divider. (Needed because the underlying surfaces are contracting
        // and expanding unevenly as they move on- and offscreen.)
        if (splitState.get() == ANIMATING_OFFSCREEN_TAP) {
            if (topLeftShrink) {
                if (isLeftRightSplit) {
                    retreatingOut.x = retreatingSurface.width() - retreatingContent.width();
                } else {
                    retreatingOut.y = retreatingSurface.height() - retreatingContent.height();
                }
            } else {
                if (isLeftRightSplit) {
                    advancingOut.x = advancingSurface.width() - advancingContent.width();
                } else {
                    advancingOut.y = advancingSurface.height() - advancingContent.height();
                }
            }
        } else if (isRetreatingOffscreen && !advancingSideStartedOffscreen) {
            // Simple user-controlled case when an app gets pushed offscreen (e.g. 50:50 -> 90:10).
            // On the left/top side, we use parallax to simulate the contents sticking to the
            // divider. (Not needed on the right/bottom side because of the natural left-top
            // alignment of content surfaces.)
            if (topLeftShrink) {
                if (isLeftRightSplit) {
                    retreatingOut.x = retreatingSurface.width() - retreatingContent.width();
@@ -132,8 +150,8 @@ public class FlexParallaxSpec implements ParallaxSpec {
                    retreatingOut.y = retreatingSurface.height() - retreatingContent.height();
                }
            }
            // All other cases (e.g. 10:90 -> 50:50, 10:90 -> 90:10, 10:90 -> dismiss)
        } else {
            // All other user-controlled cases (10:90 -> 50:50, 10:90 -> 90:10, 10:90 -> dismiss)
            mTempRect.set(retreatingSurface);
            Point rootOffset = new Point();
            // 10:90 -> 50:50, 10:90, or dismiss right
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ public class NoParallaxSpec implements ParallaxSpec {
    public void getParallax(Point retreatingOut, Point advancingOut, int position,
            DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
            Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
            Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
            Rect advancingContent, int dimmingSide, boolean topLeftShrink, SplitState splitState) {
        // no-op
    }
}
Loading