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

Commit 3ebff918 authored by Ikram Gabiyev's avatar Ikram Gabiyev
Browse files

Allow for resize into the same bounds

In PiP2, resizes are transitions, so we need
to make sure we do not schedule a no-op transition
that can be aborted. Hence we do the following:

For fling gestures: do not schedule a transition if
final motion bounds are invariant from the original bounds.

For pinch-resizing: if the final bounds are unvariant,
in order to have the animation after release
running as a part of a transition, use a trick where we offset
the destination bounds by 1 pixel away from the closes edge.

Also enable dump() callbacks in PiP2, for easier debugging and
state checks. Currently PipController and PipTouchHandler are
the entry points (since they are independent in PiP2).

Bug: 340883807
Test: atest WMShellUnitTests:PipTransitionStateTest
Test: enter PiP2, pinch resize to min bounds, and drag beyond bottom
right corner

Change-Id: I0ec15644d345bd8ca25aa42259ca938360ab54ad
parent 43f5ce26
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.wm.shell.pip2.phone.PipTouchHandler;
import com.android.wm.shell.pip2.phone.PipTransition;
import com.android.wm.shell.pip2.phone.PipTransitionState;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
@@ -82,6 +83,7 @@ public abstract class Pip2Module {
    @Provides
    static Optional<PipController> providePipController(Context context,
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            ShellController shellController,
            DisplayController displayController,
            DisplayInsetsController displayInsetsController,
@@ -97,9 +99,10 @@ public abstract class Pip2Module {
            return Optional.empty();
        } else {
            return Optional.ofNullable(PipController.create(
                    context, shellInit, shellController, displayController, displayInsetsController,
                    pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, pipScheduler,
                    taskStackListener, shellTaskOrganizer, pipTransitionState, mainExecutor));
                    context, shellInit, shellCommandHandler, shellController, displayController,
                    displayInsetsController, pipBoundsState, pipBoundsAlgorithm,
                    pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer,
                    pipTransitionState, mainExecutor));
        }
    }

@@ -129,6 +132,7 @@ public abstract class Pip2Module {
    @Provides
    static PipTouchHandler providePipTouchHandler(Context context,
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            PhonePipMenuController menuPhoneController,
            PipBoundsAlgorithm pipBoundsAlgorithm,
            @NonNull PipBoundsState pipBoundsState,
@@ -140,10 +144,10 @@ public abstract class Pip2Module {
            PipUiEventLogger pipUiEventLogger,
            @ShellMainThread ShellExecutor mainExecutor,
            Optional<PipPerfHintController> pipPerfHintControllerOptional) {
        return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
                pipBoundsState, pipTransitionState, pipScheduler, sizeSpecSource, pipMotionHelper,
                floatingContentCoordinator, pipUiEventLogger, mainExecutor,
                pipPerfHintControllerOptional);
        return new PipTouchHandler(context, shellInit, shellCommandHandler, menuPhoneController,
                pipBoundsAlgorithm, pipBoundsState, pipTransitionState, pipScheduler,
                sizeSpecSource, pipMotionHelper, floatingContentCoordinator, pipUiEventLogger,
                mainExecutor, pipPerfHintControllerOptional);
    }

    @WMSingleton
@@ -163,7 +167,7 @@ public abstract class Pip2Module {

    @WMSingleton
    @Provides
    static PipTransitionState providePipStackListenerController() {
        return new PipTransitionState();
    static PipTransitionState providePipTransitionState(@ShellMainThread Handler handler) {
        return new PipTransitionState(handler);
    }
}
+20 −4
Original line number Diff line number Diff line
@@ -58,9 +58,12 @@ import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;

import java.io.PrintWriter;

/**
 * Manages the picture-in-picture (PIP) UI and states for Phones.
 */
@@ -72,6 +75,7 @@ public class PipController implements ConfigurationChangeListener,
    private static final String SWIPE_TO_PIP_OVERLAY = "swipe_to_pip_overlay";

    private final Context mContext;
    private final ShellCommandHandler mShellCommandHandler;
    private final ShellController mShellController;
    private final DisplayController mDisplayController;
    private final DisplayInsetsController mDisplayInsetsController;
@@ -111,6 +115,7 @@ public class PipController implements ConfigurationChangeListener,

    private PipController(Context context,
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            ShellController shellController,
            DisplayController displayController,
            DisplayInsetsController displayInsetsController,
@@ -123,6 +128,7 @@ public class PipController implements ConfigurationChangeListener,
            PipTransitionState pipTransitionState,
            ShellExecutor mainExecutor) {
        mContext = context;
        mShellCommandHandler = shellCommandHandler;
        mShellController = shellController;
        mDisplayController = displayController;
        mDisplayInsetsController = displayInsetsController;
@@ -146,6 +152,7 @@ public class PipController implements ConfigurationChangeListener,
     */
    public static PipController create(Context context,
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            ShellController shellController,
            DisplayController displayController,
            DisplayInsetsController displayInsetsController,
@@ -162,13 +169,14 @@ public class PipController implements ConfigurationChangeListener,
                    "%s: Device doesn't support Pip feature", TAG);
            return null;
        }
        return new PipController(context, shellInit, shellController, displayController,
                displayInsetsController, pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState,
                pipScheduler, taskStackListener, shellTaskOrganizer, pipTransitionState,
                mainExecutor);
        return new PipController(context, shellInit, shellCommandHandler, shellController,
                displayController, displayInsetsController, pipBoundsState, pipBoundsAlgorithm,
                pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer,
                pipTransitionState, mainExecutor);
    }

    private void onInit() {
        mShellCommandHandler.addDumpCallback(this::dump, this);
        // Ensure that we have the display info in case we get calls to update the bounds before the
        // listener calls back
        mPipDisplayLayoutState.setDisplayId(mContext.getDisplayId());
@@ -338,6 +346,14 @@ public class PipController implements ConfigurationChangeListener,
        }
    }

    private void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = "  ";
        pw.println(TAG);
        mPipBoundsAlgorithm.dump(pw, innerPrefix);
        mPipBoundsState.dump(pw, innerPrefix);
        mPipDisplayLayoutState.dump(pw, innerPrefix);
    }

    /**
     * The interface for calls from outside the host process.
     */
+13 −0
Original line number Diff line number Diff line
@@ -696,6 +696,19 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
            case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
                if (!extra.getBoolean(FLING_BOUNDS_CHANGE)) break;

                if (mPipBoundsState.getBounds().equals(
                        mPipBoundsState.getMotionBoundsState().getBoundsInMotion())) {
                    // Avoid scheduling transitions for bounds that don't change, such transition is
                    // a no-op and would be aborted.
                    settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
                    cleanUpHighPerfSessionMaybe();
                    // SCHEDULED_BOUNDS_CHANGE can have multiple active listeners making
                    // actual changes (e.g. PipTouchHandler). So post state update onto handler,
                    // to run after synchronous dispatch is complete.
                    mPipTransitionState.postState(PipTransitionState.CHANGED_PIP_BOUNDS);
                    break;
                }

                // If touch is turned off and we are in a fling animation, schedule a transition.
                mWaitingForBoundsChangeTransition = true;
                mPipScheduler.scheduleAnimateResizePip(
+15 −4
Original line number Diff line number Diff line
@@ -514,6 +514,20 @@ public class PipResizeGestureHandler implements
        switch (newState) {
            case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
                if (!extra.getBoolean(RESIZE_BOUNDS_CHANGE)) break;

                if (mPipBoundsState.getBounds().equals(mLastResizeBounds)) {
                    // If the bounds are invariant move the destination bounds by a single pixel
                    // to top/bottom to avoid a no-op transition. This trick helps keep the
                    // animation a part of the transition.
                    float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
                            mPipBoundsState.getBounds());

                    // Move to the top if closer to the bottom edge and vice versa.
                    boolean inTopHalf = snapFraction < 1.5 || snapFraction > 3.5;
                    int offsetY = inTopHalf ? 1 : -1;
                    mLastResizeBounds.offset(0 /* dx */, offsetY);
                }

                mWaitingForBoundsChangeTransition = true;
                mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds);
                break;
@@ -527,17 +541,14 @@ public class PipResizeGestureHandler implements
                        PipTransition.PIP_START_TX, SurfaceControl.Transaction.class);
                Rect destinationBounds = extra.getParcelable(
                        PipTransition.PIP_DESTINATION_BOUNDS, Rect.class);
                startTx.setPosition(mPipTransitionState.mPinnedTaskLeash,
                        destinationBounds.left, destinationBounds.top);
                startTx.apply();

                // All motion operations have actually finished, so make bounds cache updates.
                mUpdateResizeBoundsCallback.accept(destinationBounds);
                cleanUpHighPerfSessionMaybe();

                // Setting state to CHANGED_PIP_BOUNDS applies finishTx and notifies Core.
                mPipTransitionState.setState(PipTransitionState.CHANGED_PIP_BOUNDS);

                mUpdateResizeBoundsCallback.accept(destinationBounds);
                break;
        }
    }
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;

import java.io.PrintWriter;
@@ -81,6 +82,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
    // Allow PIP to resize to a slightly bigger state upon touch
    private boolean mEnableResize;
    private final Context mContext;
    private final ShellCommandHandler mShellCommandHandler;
    private final PipBoundsAlgorithm mPipBoundsAlgorithm;
    @NonNull private final PipBoundsState mPipBoundsState;
    @NonNull private final PipTransitionState mPipTransitionState;
@@ -170,6 +172,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
    @SuppressLint("InflateParams")
    public PipTouchHandler(Context context,
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            PhonePipMenuController menuController,
            PipBoundsAlgorithm pipBoundsAlgorithm,
            @NonNull PipBoundsState pipBoundsState,
@@ -182,6 +185,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
            ShellExecutor mainExecutor,
            Optional<PipPerfHintController> pipPerfHintControllerOptional) {
        mContext = context;
        mShellCommandHandler = shellCommandHandler;
        mMainExecutor = mainExecutor;
        mPipPerfHintController = pipPerfHintControllerOptional.orElse(null);
        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -235,6 +239,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
        mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
        reloadResources();

        mShellCommandHandler.addDumpCallback(this::dump, this);
        mMotionHelper.init();
        mPipResizeGestureHandler.init();
        mPipDismissTargetHandler.init();
Loading