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

Commit e55c019c authored by Winson Chung's avatar Winson Chung
Browse files

Save PiP activity position on screen for next re-entry into PiP.

- Keep the last known PiP position when the user expands the activity to
  fullscreen until the activity is next hidden or destroyed.

Bug: 36520745
Test: android.server.cts.ActivityManagerPinnedStackTests
Test: #testEnterPictureInPictureSavePosition
Test: #testEnterPictureInPictureDiscardSavedPositionOnFinish
Change-Id: I32e2bec8baa000b854981a4492f44c636f083680
parent dc4cb146
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -3116,6 +3116,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        // Need to make sure the pinned stack exist so we can resize it below...
        stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP);

        // Calculate the target bounds here before the task is reparented back into pinned windowing
        // mode (which will reset the saved bounds)
        final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio);

        try {
            final TaskRecord task = r.getTask();
            // Resize the pinned stack to match the current size of the task the activity we are
@@ -3154,11 +3158,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            mWindowManager.continueSurfaceLayout();
        }

        // Calculate the default bounds (don't use existing stack bounds as we may have just created
        // the stack, and schedule the start of the animation into PiP (the bounds animator that
        // is triggered by this is posted on another thread)
        final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio);

        stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */,
                true /* fromFullscreen */);

+33 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
@@ -53,6 +56,7 @@ import static com.android.server.wm.proto.AppWindowTokenProto.WINDOW_TOKEN;

import android.annotation.CallSuper;
import android.app.Activity;
import android.app.WindowConfiguration.WindowingMode;
import android.content.res.Configuration;
import android.graphics.GraphicBuffer;
import android.graphics.Point;
@@ -1210,6 +1214,30 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        return mOrientation;
    }

    @Override
    public void onConfigurationChanged(Configuration newParentConfig) {
        final int prevWinMode = getWindowingMode();
        super.onConfigurationChanged(newParentConfig);
        final int winMode = getWindowingMode();

        if (prevWinMode == winMode) {
            return;
        }

        if (prevWinMode != WINDOWING_MODE_UNDEFINED && winMode == WINDOWING_MODE_PINNED) {
            // Entering PiP from fullscreen, reset the snap fraction
            mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
        } else if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED) {
            // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds
            // for the next re-entry into PiP (assuming the activity is not hidden or destroyed)
            final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
            if (pinnedStack != null) {
                mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this,
                        pinnedStack.mPreAnimationBounds);
            }
        }
    }

    @Override
    void checkAppWindowsReadyToShow() {
        if (allDrawn == mLastAllDrawn) {
@@ -1837,6 +1865,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
    @Override
    void setHidden(boolean hidden) {
        super.setHidden(hidden);

        if (hidden) {
            // Once the app window is hidden, reset the last saved PiP snap fraction
            mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
        }
        scheduleAnimation();
    }

+53 −9
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import com.android.internal.policy.PipSnapAlgorithm;
import com.android.server.UiThread;

import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

@@ -71,6 +72,7 @@ class PinnedStackController {

    private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;

    public static final float INVALID_SNAP_FRACTION = -1f;
    private final WindowManagerService mService;
    private final DisplayContent mDisplayContent;
    private final Handler mHandler = UiThread.getHandler();
@@ -101,6 +103,8 @@ class PinnedStackController {
    private float mDefaultAspectRatio;
    private Point mScreenEdgeInsets;
    private int mCurrentMinSize;
    private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
    private WeakReference<AppWindowToken> mLastPipActivity = null;

    // The aspect ratio bounds of the PIP.
    private float mMinAspectRatio;
@@ -113,6 +117,7 @@ class PinnedStackController {
    private final Rect mTmpAnimatingBoundsRect = new Rect();
    private final Point mTmpDisplaySize = new Point();


    /**
     * The callback object passed to listeners for them to notify the controller of state changes.
     */
@@ -249,10 +254,36 @@ class PinnedStackController {
        return stackBounds;
    }

    /**
     * Saves the current snap fraction for re-entry of the current activity into PiP.
     */
    void saveReentrySnapFraction(final AppWindowToken token, final Rect stackBounds) {
        mReentrySnapFraction = getSnapFraction(stackBounds);
        mLastPipActivity = new WeakReference<>(token);
    }

    /**
     * Resets the last saved snap fraction so that the default bounds will be returned.
     */
    void resetReentrySnapFraction(AppWindowToken token) {
        if (mLastPipActivity != null && mLastPipActivity.get() == token) {
            mReentrySnapFraction = INVALID_SNAP_FRACTION;
            mLastPipActivity = null;
        }
    }

    /**
     * @return the default bounds to show the PIP when there is no active PIP.
     */
    Rect getDefaultBounds() {
    Rect getDefaultOrLastSavedBounds() {
        return getDefaultBounds(mReentrySnapFraction);
    }

    /**
     * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
     * will apply the default bounds to the provided snap fraction.
     */
    Rect getDefaultBounds(float snapFraction) {
        synchronized (mService.mWindowMap) {
            final Rect insetBounds = new Rect();
            getInsetBounds(insetBounds);
@@ -260,8 +291,14 @@ class PinnedStackController {
            final Rect defaultBounds = new Rect();
            final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
                    mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
            if (snapFraction != INVALID_SNAP_FRACTION) {
                defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
                final Rect movementBounds = getMovementBounds(defaultBounds);
                mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
            } else {
                Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
                        0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
            }
            return defaultBounds;
        }
    }
@@ -299,9 +336,7 @@ class PinnedStackController {
            final Rect postChangeStackBounds = mTmpRect;

            // Calculate the snap fraction of the current stack along the old movement bounds
            final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds);
            final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds,
                    preChangeMovementBounds);
            final float snapFraction = getSnapFraction(postChangeStackBounds);
            mDisplayInfo.copyFrom(displayInfo);

            // Calculate the stack bounds in the new orientation to the same same fraction along the
@@ -414,7 +449,7 @@ class PinnedStackController {
            try {
                final Rect insetBounds = new Rect();
                getInsetBounds(insetBounds);
                final Rect normalBounds = getDefaultBounds();
                final Rect normalBounds = getDefaultBounds(INVALID_SNAP_FRACTION);
                if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
                    transformBoundsToAspectRatio(normalBounds, mAspectRatio,
                            false /* useCurrentMinEdgeSize */);
@@ -485,6 +520,14 @@ class PinnedStackController {
        }
    }

    /**
     * @return the default snap fraction to apply instead of the default gravity when calculating
     *         the default stack bounds when first entering PiP.
     */
    private float getSnapFraction(Rect stackBounds) {
        return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
    }

    /**
     * @return the pixels for a given dp value.
     */
@@ -494,7 +537,8 @@ class PinnedStackController {

    void dump(String prefix, PrintWriter pw) {
        pw.println(prefix + "PinnedStackController");
        pw.print(prefix + "  defaultBounds="); getDefaultBounds().printShortString(pw);
        pw.print(prefix + "  defaultBounds=");
        getDefaultBounds(INVALID_SNAP_FRACTION).printShortString(pw);
        pw.println();
        mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
        pw.print(prefix + "  movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
@@ -516,7 +560,7 @@ class PinnedStackController {

    void writeToProto(ProtoOutputStream proto, long fieldId) {
        final long token = proto.start(fieldId);
        getDefaultBounds().writeToProto(proto, DEFAULT_BOUNDS);
        getDefaultBounds(INVALID_SNAP_FRACTION).writeToProto(proto, DEFAULT_BOUNDS);
        mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
        getMovementBounds(mTmpRect).writeToProto(proto, MOVEMENT_BOUNDS);
        proto.end(token);
+2 −2
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ public class PinnedStackWindowController extends StackWindowController {
                    displayContent.getPinnedStackController();
            if (stackBounds == null) {
                // Calculate the aspect ratio bounds from the default bounds
                stackBounds = pinnedStackController.getDefaultBounds();
                stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
            }

            if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {