diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index a8183f2acc805..ab035569fea24 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2092,7 +2092,6 @@ public class Activity extends ContextThemeWrapper if (params == null) { throw new IllegalArgumentException("Expected non-null picture-in-picture params"); } - updatePictureInPictureParamsForContentInsets(params); return ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken, params); } catch (RemoteException e) { return false; @@ -2116,7 +2115,6 @@ public class Activity extends ContextThemeWrapper if (params == null) { throw new IllegalArgumentException("Expected non-null picture-in-picture params"); } - updatePictureInPictureParamsForContentInsets(params); ActivityManagerNative.getDefault().setPictureInPictureParams(mToken, params); } catch (RemoteException e) { } @@ -2136,21 +2134,6 @@ public class Activity extends ContextThemeWrapper } } - /** - * Updates the provided {@param params} with the last known content insets for this activity, to - * be used with the source hint rect for the transition into PiP. - */ - private void updatePictureInPictureParamsForContentInsets(PictureInPictureParams params) { - if (params != null && params.hasSourceBoundsHint() && getWindow() != null && - getWindow().peekDecorView() != null && - getWindow().peekDecorView().getViewRootImpl() != null) { - params.setSourceRectHintInsets( - getWindow().peekDecorView().getViewRootImpl().getLastContentInsets()); - } else { - params.setSourceRectHintInsets(null); - } - } - void dispatchMovedToDisplay(int displayId, Configuration config) { updateDisplay(displayId); onMovedToDisplay(displayId, config); diff --git a/core/java/android/app/PictureInPictureArgs.java b/core/java/android/app/PictureInPictureArgs.java index d7317f4bd1dba..cbe8bb9deea18 100644 --- a/core/java/android/app/PictureInPictureArgs.java +++ b/core/java/android/app/PictureInPictureArgs.java @@ -160,9 +160,6 @@ public final class PictureInPictureArgs implements Parcelable { if (in.readInt() != 0) { mSourceRectHint = Rect.CREATOR.createFromParcel(in); } - if (in.readInt() != 0) { - mSourceRectHintInsets = Rect.CREATOR.createFromParcel(in); - } } private PictureInPictureArgs(Rational aspectRatio, List actions, @@ -220,9 +217,6 @@ public final class PictureInPictureArgs implements Parcelable { if (otherArgs.hasSourceBoundsHint()) { mSourceRectHint = new Rect(otherArgs.getSourceRectHint()); } - if (otherArgs.hasSourceBoundsHintInsets()) { - mSourceRectHintInsets = new Rect(otherArgs.getSourceRectHintInsets()); - } } /** @@ -346,12 +340,6 @@ public final class PictureInPictureArgs implements Parcelable { } else { out.writeInt(0); } - if (mSourceRectHintInsets != null) { - out.writeInt(1); - mSourceRectHintInsets.writeToParcel(out, 0); - } else { - out.writeInt(0); - } } public static final Creator CREATOR = diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java index 323a0fbaa5b14..7313b0d941e5a 100644 --- a/core/java/android/app/PictureInPictureParams.java +++ b/core/java/android/app/PictureInPictureParams.java @@ -135,13 +135,6 @@ public final class PictureInPictureParams implements Parcelable { @Nullable private Rect mSourceRectHint; - /** - * The content insets that are used with the source hint rect for the transition into PiP where - * the insets are removed at the beginning of the transition. - */ - @Nullable - private Rect mSourceRectHintInsets; - /** {@hide} */ PictureInPictureParams() { } @@ -158,9 +151,6 @@ public final class PictureInPictureParams implements Parcelable { if (in.readInt() != 0) { mSourceRectHint = Rect.CREATOR.createFromParcel(in); } - if (in.readInt() != 0) { - mSourceRectHintInsets = Rect.CREATOR.createFromParcel(in); - } } /** {@hide} */ @@ -185,9 +175,6 @@ public final class PictureInPictureParams implements Parcelable { if (otherArgs.hasSourceBoundsHint()) { mSourceRectHint = new Rect(otherArgs.getSourceRectHint()); } - if (otherArgs.hasSourceBoundsHintInsets()) { - mSourceRectHintInsets = new Rect(otherArgs.getSourceRectHintInsets()); - } } /** @@ -240,19 +227,6 @@ public final class PictureInPictureParams implements Parcelable { } } - /** - * Sets the insets to be used with the source rect hint bounds. - * @hide - */ - @Deprecated - public void setSourceRectHintInsets(Rect insets) { - if (insets == null) { - mSourceRectHintInsets = null; - } else { - mSourceRectHintInsets = new Rect(insets); - } - } - /** * @return the source rect hint * @hide @@ -261,14 +235,6 @@ public final class PictureInPictureParams implements Parcelable { return mSourceRectHint; } - /** - * @return the source rect hint insets. - * @hide - */ - public Rect getSourceRectHintInsets() { - return mSourceRectHintInsets; - } - /** * @return whether there are launch bounds set * @hide @@ -277,14 +243,6 @@ public final class PictureInPictureParams implements Parcelable { return mSourceRectHint != null && !mSourceRectHint.isEmpty(); } - /** - * @return whether there are source rect hint insets set - * @hide - */ - public boolean hasSourceBoundsHintInsets() { - return mSourceRectHintInsets != null; - } - @Override public int describeContents() { return 0; @@ -311,12 +269,6 @@ public final class PictureInPictureParams implements Parcelable { } else { out.writeInt(0); } - if (mSourceRectHintInsets != null) { - out.writeInt(1); - mSourceRectHintInsets.writeToParcel(out, 0); - } else { - out.writeInt(0); - } } public static final Creator CREATOR = @@ -328,4 +280,4 @@ public final class PictureInPictureParams implements Parcelable { return new PictureInPictureParams[size]; } }; -} \ No newline at end of file +} diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 109cac0bab126..511a2797f961e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1561,16 +1561,6 @@ public final class ViewRootImpl implements ViewParent, host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */)); } - /** - * @return the last content insets for use in adjusting the source hint rect for the - * picture-in-picture transition. - * - * @hide - */ - public Rect getLastContentInsets() { - return mAttachInfo.mContentInsets; - } - private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) { return lp.type == TYPE_STATUS_BAR_PANEL || lp.type == TYPE_INPUT_METHOD diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index df3208923899d..54b28d1584e07 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7914,12 +7914,6 @@ public class ActivityManagerService extends IActivityManager.Stub final List actions = r.pictureInPictureArgs.getActions(); // Adjust the source bounds by the insets for the transition down final Rect sourceBounds = new Rect(r.pictureInPictureArgs.getSourceRectHint()); - final Rect insets = r.pictureInPictureArgs.getSourceRectHintInsets(); - if (insets != null) { - sourceBounds.offsetTo(Math.max(0, sourceBounds.left - insets.left), - Math.max(0, sourceBounds.top - insets.top)); - } - mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, aspectRatio, true /* moveHomeStackToFront */, "enterPictureInPictureMode"); final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 0a999e65d3a23..27661e2ef0450 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -92,6 +92,12 @@ class Task extends WindowContainer implements DimLayer.DimLayerU private TaskDescription mTaskDescription; + // If set to true, the task will report that it is not in the floating + // state regardless of it's stack affilation. As the floating state drives + // production of content insets this can be used to preserve them across + // stack moves and we in fact do so when moving from full screen to pinned. + private boolean mPreserveNonFloatingState = false; + Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, boolean homeTask, TaskDescription taskDescription, @@ -194,6 +200,16 @@ class Task extends WindowContainer implements DimLayer.DimLayerU EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask"); final DisplayContent prevDisplayContent = getDisplayContent(); + // If we are moving from the fullscreen stack to the pinned stack + // then we want to preserve our insets so that there will not + // be a jump in the area covered by system decorations. We rely + // on the pinned animation to later unset this value. + if (stack.mStackId == PINNED_STACK_ID) { + mPreserveNonFloatingState = true; + } else { + mPreserveNonFloatingState = false; + } + getParent().removeChild(this); stack.addTask(this, position, showForAllUsers(), moveParents); @@ -593,7 +609,8 @@ class Task extends WindowContainer implements DimLayer.DimLayerU * we will have a jump at the end. */ boolean isFloating() { - return StackId.tasksAreFloating(mStack.mStackId) && !mStack.isAnimatingBoundsToFullscreen(); + return StackId.tasksAreFloating(mStack.mStackId) + && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState; } WindowState getTopVisibleAppMainWindow() { @@ -675,6 +692,10 @@ class Task extends WindowContainer implements DimLayer.DimLayerU return toShortString(); } + void clearPreserveNonFloatingState() { + mPreserveNonFloatingState = false; + } + @Override public String toShortString() { return "Task=" + mTaskId; diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index da7a9f0ec58ff..9d48ce58bb2a5 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -139,6 +139,8 @@ public class TaskStack extends WindowContainer implements DimLayer.DimLaye // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). private final Rect mBoundsAfterRotation = new Rect(); + Rect mPreAnimationBounds = new Rect(); + TaskStack(WindowManagerService service, int stackId) { mService = service; mStackId = stackId; @@ -336,6 +338,8 @@ public class TaskStack extends WindowContainer implements DimLayer.DimLaye } else { mBoundsAnimationSourceHintBounds.setEmpty(); } + + mPreAnimationBounds.set(mBounds); } /** @@ -1530,10 +1534,17 @@ public class TaskStack extends WindowContainer implements DimLayer.DimLaye // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mService.mWindowMap) { mBoundsAnimating = false; + for (int i = 0; i < mChildren.size(); i++) { + final Task t = mChildren.get(i); + t.clearPreserveNonFloatingState(); + } mService.requestTraversal(); } if (mStackId == PINNED_STACK_ID) { + // Update to the final bounds if requested. This is done here instead of in the bounds + // animator to allow us to coordinate this after we notify the PiP mode changed + final PinnedStackWindowController controller = (PinnedStackWindowController) getController(); if (schedulePipModeChangedCallback && controller != null) { @@ -1543,8 +1554,6 @@ public class TaskStack extends WindowContainer implements DimLayer.DimLaye mBoundsAnimationTarget); } - // Update to the final bounds if requested. This is done here instead of in the bounds - // animator to allow us to coordinate this after we notify the PiP mode changed if (finalStackSize != null) { setPinnedStackSize(finalStackSize, null); } @@ -1584,8 +1593,12 @@ public class TaskStack extends WindowContainer implements DimLayer.DimLaye return mBoundsAnimating; } + public boolean lastAnimatingBoundsWasToFullscreen() { + return mBoundsAnimatingToFullscreen; + } + public boolean isAnimatingBoundsToFullscreen() { - return mBoundsAnimating && mBoundsAnimatingToFullscreen; + return isAnimatingBounds() && lastAnimatingBoundsWasToFullscreen(); } public boolean pinnedStackResizeDisallowed() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 424f8a51daa33..54bfeb54242f4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2093,6 +2093,7 @@ public class WindowManagerService extends IWindowManager.Stub outFrame.set(win.mCompatFrame); outOverscanInsets.set(win.mOverscanInsets); outContentInsets.set(win.mContentInsets); + win.mLastRelayoutContentInsets.set(win.mContentInsets); outVisibleInsets.set(win.mVisibleInsets); outStableInsets.set(win.mStableInsets); outOutsets.set(win.mOutsets); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 25b6561b7575c..8c8f633094253 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -257,6 +257,16 @@ class WindowState extends WindowContainer implements WindowManagerP */ final Rect mContentInsets = new Rect(); final Rect mLastContentInsets = new Rect(); + + /** + * The last content insets returned to the client in relayout. We use + * these in the bounds animation to ensure we only observe inset changes + * at the same time that a client resizes it's surface so that we may use + * the geometryAppliesWithResize synchronization mechanism to keep + * the contents in place. + */ + final Rect mLastRelayoutContentInsets = new Rect(); + private boolean mContentInsetsChanged; /** diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 6cb4ddc14969f..8d3ef40b53251 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1374,7 +1374,23 @@ class WindowStateAnimator { int posX = mTmpSize.left; int posY = mTmpSize.top; task.mStack.getDimBounds(mTmpStackBounds); + + boolean allowStretching = false; task.mStack.getFinalAnimationSourceHintBounds(mTmpSourceBounds); + // If we don't have source bounds, we can attempt to use the content insets + // in the following scenario: + // 1. We have content insets. + // 2. We are not transitioning to full screen + // We have to be careful to check "lastAnimatingBoundsWasToFullscreen" rather than + // the mBoundsAnimating state, as we may have already left it and only be here + // because of the force-scale until resize state. + if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0 + || mWin.mLastRelayoutContentInsets.height() > 0) + && !task.mStack.lastAnimatingBoundsWasToFullscreen()) { + mTmpSourceBounds.set(task.mStack.mPreAnimationBounds); + mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets); + allowStretching = true; + } if (!mTmpSourceBounds.isEmpty()) { // Get the final target stack bounds, if we are not animating, this is just the // current stack bounds @@ -1384,14 +1400,24 @@ class WindowStateAnimator { // and source bounds float finalWidth = mTmpAnimatingBounds.width(); float initialWidth = mTmpSourceBounds.width(); - float t = (surfaceContentWidth - mTmpStackBounds.width()) + float tw = (surfaceContentWidth - mTmpStackBounds.width()) / (surfaceContentWidth - mTmpAnimatingBounds.width()); - mExtraHScale = (initialWidth + t * (finalWidth - initialWidth)) / initialWidth; - mExtraVScale = mExtraHScale; + float th = tw; + mExtraHScale = (initialWidth + tw * (finalWidth - initialWidth)) / initialWidth; + if (allowStretching) { + float finalHeight = mTmpAnimatingBounds.height(); + float initialHeight = mTmpSourceBounds.height(); + th = (surfaceContentHeight - mTmpStackBounds.height()) + / (surfaceContentHeight - mTmpAnimatingBounds.height()); + mExtraVScale = (initialHeight + tw * (finalHeight - initialHeight)) + / initialHeight; + } else { + mExtraVScale = mExtraHScale; + } // Adjust the position to account for the inset bounds - posX -= (int) (t * mExtraHScale * mTmpSourceBounds.left); - posY -= (int) (t * mExtraVScale * mTmpSourceBounds.top); + posX -= (int) (tw * mExtraHScale * mTmpSourceBounds.left); + posY -= (int) (th * mExtraVScale * mTmpSourceBounds.top); // Always clip to the stack bounds since the surface can be larger with the current // scale