Merge "Adding source bounds hint to support better PiP transition."

This commit is contained in:
TreeHugger Robot
2017-03-22 21:27:36 +00:00
committed by Android (Google) Code Review
11 changed files with 166 additions and 53 deletions

View File

@@ -5667,6 +5667,7 @@ package android.app {
method public int describeContents();
method public void setActions(java.util.List<android.app.RemoteAction>);
method public void setAspectRatio(float);
method public void setSourceRectHint(android.graphics.Rect);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
}

View File

@@ -5859,6 +5859,7 @@ package android.app {
method public int describeContents();
method public void setActions(java.util.List<android.app.RemoteAction>);
method public void setAspectRatio(float);
method public void setSourceRectHint(android.graphics.Rect);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
}

View File

@@ -5678,6 +5678,7 @@ package android.app {
method public int describeContents();
method public void setActions(java.util.List<android.app.RemoteAction>);
method public void setAspectRatio(float);
method public void setSourceRectHint(android.graphics.Rect);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
}

View File

@@ -17,6 +17,7 @@
package android.app;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,11 +36,19 @@ public final class PictureInPictureArgs implements Parcelable {
private Float mAspectRatio;
/**
* The set of actions that are associated with this activity when in picture in picture.
* The set of actions that are associated with this activity when in picture-in-picture.
*/
@Nullable
private List<RemoteAction> mUserActions;
/**
* The source bounds hint used when entering picture-in-picture, relative to the window bounds.
* We can use this internally for the transition into picture-in-picture to ensure that a
* particular source rect is visible throughout the whole transition.
*/
@Nullable
private Rect mSourceRectHint;
PictureInPictureArgs(Parcel in) {
if (in.readInt() != 0) {
mAspectRatio = in.readFloat();
@@ -48,6 +57,9 @@ public final class PictureInPictureArgs implements Parcelable {
mUserActions = new ArrayList<>();
in.readParcelableList(mUserActions, RemoteAction.class.getClassLoader());
}
if (in.readInt() != 0) {
mSourceRectHint = Rect.CREATOR.createFromParcel(in);
}
}
/**
@@ -79,6 +91,9 @@ public final class PictureInPictureArgs implements Parcelable {
if (otherArgs.hasSetActions()) {
mUserActions = otherArgs.mUserActions;
}
if (otherArgs.hasSourceBoundsHint()) {
mSourceRectHint = new Rect(otherArgs.getSourceRectHint());
}
}
/**
@@ -137,9 +152,43 @@ public final class PictureInPictureArgs implements Parcelable {
return mUserActions != null;
}
/**
* Sets the source bounds hint. These bounds are only used when an activity first enters
* picture-in-picture, and describe the bounds in window coordinates of activity entering
* picture-in-picture that will be visible following the transition. For the best effect, these
* bounds should also match the aspect ratio in the arguments.
*/
public void setSourceRectHint(Rect launchBounds) {
if (launchBounds == null) {
mSourceRectHint = null;
} else {
mSourceRectHint = new Rect(launchBounds);
}
}
/**
* @return the launch bounds
* @hide
*/
public Rect getSourceRectHint() {
return mSourceRectHint;
}
/**
* @return whether there are launch bounds set
* @hide
*/
public boolean hasSourceBoundsHint() {
return mSourceRectHint != null && !mSourceRectHint.isEmpty();
}
@Override
public PictureInPictureArgs clone() {
return new PictureInPictureArgs(mAspectRatio, mUserActions);
PictureInPictureArgs args = new PictureInPictureArgs(mAspectRatio, mUserActions);
if (mSourceRectHint != null) {
args.setSourceRectHint(mSourceRectHint);
}
return args;
}
@Override
@@ -161,6 +210,12 @@ public final class PictureInPictureArgs implements Parcelable {
} else {
out.writeInt(0);
}
if (mSourceRectHint != null) {
out.writeInt(1);
mSourceRectHint.writeToParcel(out, 0);
} else {
out.writeInt(0);
}
}
public static final Creator<PictureInPictureArgs> CREATOR =

View File

@@ -7870,10 +7870,11 @@ public class ActivityManagerService extends IActivityManager.Stub
r.pictureInPictureArgs.copyOnlySet(args);
final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
final Rect bounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
final Rect sourceBounds = r.pictureInPictureArgs.getSourceRectHint();
final Rect destBounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
aspectRatio);
mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
bounds, true /* moveHomeStackToFront */);
mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, destBounds,
true /* moveHomeStackToFront */, "enterPictureInPictureMode");
final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
@@ -10525,7 +10526,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode,
boolean preserveWindows, boolean animate, int animationDuration) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
long ident = Binder.clearCallingIdentity();
@@ -10535,13 +10536,14 @@ public class ActivityManagerService extends IActivityManager.Stub
if (stackId == PINNED_STACK_ID) {
final PinnedActivityStack pinnedStack =
mStackSupervisor.getStack(PINNED_STACK_ID);
pinnedStack.animateResizePinnedStack(bounds, animationDuration);
pinnedStack.animateResizePinnedStack(null /* sourceBounds */, destBounds,
animationDuration);
} else {
throw new IllegalArgumentException("Stack: " + stackId
+ " doesn't support animated resize.");
}
} else {
mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
mStackSupervisor.resizeStackLocked(stackId, destBounds, null /* tempTaskBounds */,
null /* tempTaskInsetBounds */, preserveWindows,
allowResizeInDockedMode, !DEFER_RESUME);
}

View File

@@ -2794,7 +2794,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) {
boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect destBounds) {
final ActivityStack stack = getStack(stackId, !CREATE_IF_NEEDED, !ON_TOP);
if (stack == null) {
throw new IllegalArgumentException(
@@ -2815,13 +2815,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return false;
}
moveActivityToPinnedStackLocked(r, "moveTopActivityToPinnedStack", bounds,
true /* moveHomeStackToFront */);
moveActivityToPinnedStackLocked(r, null /* sourceBounds */, destBounds,
true /* moveHomeStackToFront */, "moveTopActivityToPinnedStack");
return true;
}
void moveActivityToPinnedStackLocked(ActivityRecord r, String reason, Rect bounds,
boolean moveHomeStackToFront) {
void moveActivityToPinnedStackLocked(ActivityRecord r, Rect sourceBounds, Rect destBounds,
boolean moveHomeStackToFront, String reason) {
mWindowManager.deferSurfaceLayout();
// Need to make sure the pinned stack exist so we can resize it below...
@@ -2889,7 +2890,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
stack.animateResizePinnedStack(bounds, -1 /* animationDuration */);
stack.animateResizePinnedStack(sourceBounds, destBounds, -1 /* animationDuration */);
mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName);
}

View File

@@ -41,8 +41,9 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController> {
return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds);
}
void animateResizePinnedStack(Rect bounds, int animationDuration) {
getWindowContainerController().animateResizePinnedStack(bounds, animationDuration);
void animateResizePinnedStack(Rect sourceBounds, Rect destBounds, int animationDuration) {
getWindowContainerController().animateResizePinnedStack(sourceBounds, destBounds,
animationDuration);
}
void setPictureInPictureAspectRatio(float aspectRatio) {

View File

@@ -121,8 +121,8 @@ public class BoundsAnimationController {
private final int mFrozenTaskWidth;
private final int mFrozenTaskHeight;
BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to,
boolean moveToFullScreen, boolean replacement) {
BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to, boolean moveToFullScreen,
boolean replacement) {
super();
mTarget = target;
mFrom.set(from);

View File

@@ -40,29 +40,30 @@ public class PinnedStackWindowController extends StackWindowController {
/**
* Animates the pinned stack.
*/
public void animateResizePinnedStack(Rect bounds, int animationDuration) {
public void animateResizePinnedStack(Rect sourceBounds, Rect destBounds,
int animationDuration) {
synchronized (mWindowMap) {
if (mContainer == null) {
throw new IllegalArgumentException("Pinned stack container not found :(");
}
// Get non-null fullscreen bounds if the bounds are null
final boolean moveToFullscreen = bounds == null;
bounds = getPinnedStackAnimationBounds(bounds);
final boolean moveToFullscreen = destBounds == null;
destBounds = getPinnedStackAnimationBounds(destBounds);
// If the bounds are truly null, then there was no fullscreen stack at this time, so
// animate this to the full display bounds
final Rect toBounds;
if (bounds == null) {
if (destBounds == null) {
toBounds = new Rect();
mContainer.getDisplayContent().getLogicalDisplayRect(toBounds);
} else {
toBounds = bounds;
toBounds = destBounds;
}
final Rect originalBounds = new Rect();
mContainer.getBounds(originalBounds);
mContainer.setAnimatingBounds(toBounds);
mContainer.setAnimatingBounds(sourceBounds, toBounds);
UiThread.getHandler().post(() -> {
if (mContainer == null) {
return;
@@ -82,13 +83,17 @@ public class PinnedStackWindowController extends StackWindowController {
return;
}
final int displayId = mContainer.getDisplayContent().getDisplayId();
final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
final Rect targetBounds = new Rect();
mContainer.getAnimatingBounds(targetBounds);
final PinnedStackController pinnedStackController =
mContainer.getDisplayContent().getPinnedStackController();
if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) {
final int displayId = mContainer.getDisplayContent().getDisplayId();
final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
animateResizePinnedStack(toBounds, -1 /* duration */);
if (!toBounds.equals(targetBounds)) {
animateResizePinnedStack(null /* sourceBounds */, toBounds, -1 /* duration */);
}
pinnedStackController.setAspectRatio(
pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
? aspectRatio : -1f);

View File

@@ -19,7 +19,6 @@ package com.android.server.wm;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -128,6 +127,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
private boolean mBoundsAnimating = false;
private boolean mBoundsAnimatingToFullscreen = false;
private Rect mBoundsAnimationTarget = new Rect();
private Rect mBoundsAnimationSourceBounds = new Rect();
// Temporary storage for the new bounds that should be used after the configuration change.
// Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
@@ -323,14 +323,30 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
* Sets the bounds animation target bounds. This can't currently be done in onAnimationStart()
* since that is started on the UiThread.
*/
void setAnimatingBounds(Rect bounds) {
if (bounds != null) {
mBoundsAnimationTarget.set(bounds);
void setAnimatingBounds(Rect sourceBounds, Rect destBounds) {
if (sourceBounds != null) {
mBoundsAnimationSourceBounds.set(sourceBounds);
} else {
mBoundsAnimationSourceBounds.setEmpty();
}
if (destBounds != null) {
mBoundsAnimationTarget.set(destBounds);
} else {
mBoundsAnimationTarget.setEmpty();
}
}
/**
* @return the source bounds for the bounds animation.
*/
void getAnimatingSourceBounds(Rect outBounds) {
if (mBoundsAnimationSourceBounds != null) {
outBounds.set(mBoundsAnimationSourceBounds);
return;
}
outBounds.setEmpty();
}
/**
* @return the bounds that the task stack is currently being animated towards, or the current
* stack bounds if there is no animation in progress.
@@ -1465,7 +1481,6 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
public void onAnimationEnd() {
synchronized (mService.mWindowMap) {
mBoundsAnimating = false;
mBoundsAnimationTarget.setEmpty();
mService.requestTraversal();
}

View File

@@ -67,8 +67,6 @@ import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import com.android.server.wm.WindowManagerService.H;
import java.io.PrintWriter;
import java.io.FileDescriptor;
@@ -156,6 +154,8 @@ class WindowStateAnimator {
Rect mLastClipRect = new Rect();
Rect mLastFinalClipRect = new Rect();
Rect mTmpStackBounds = new Rect();
private Rect mTmpAnimatingBounds = new Rect();
private Rect mTmpSourceBounds = new Rect();
/**
* This is rectangle of the window's surface that is not covered by
@@ -1282,6 +1282,7 @@ class WindowStateAnimator {
void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
final WindowState w = mWin;
final LayoutParams attrs = mWin.getAttrs();
final Task task = w.getTask();
// We got resized, so block all updates until we got the new surface.
@@ -1290,7 +1291,7 @@ class WindowStateAnimator {
}
mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
calculateSurfaceBounds(w, w.getAttrs());
calculateSurfaceBounds(w, attrs);
mExtraHScale = (float) 1.0;
mExtraVScale = (float) 1.0;
@@ -1329,23 +1330,59 @@ class WindowStateAnimator {
float surfaceHeight = mSurfaceController.getHeight();
if (isForceScaled()) {
int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
int hInsets = attrs.surfaceInsets.left + attrs.surfaceInsets.right;
int vInsets = attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
float surfaceContentWidth = surfaceWidth - hInsets;
float surfaceContentHeight = surfaceHeight - vInsets;
if (!mForceScaleUntilResize) {
mSurfaceController.forceScaleableInTransaction(true);
}
int posX = mTmpSize.left;
int posY = mTmpSize.top;
task.mStack.getDimBounds(mTmpStackBounds);
// We want to calculate the scaling based on the content area, not based on
// the entire surface, so that we scale in sync with windows that don't have insets.
mExtraHScale = mTmpStackBounds.width() / (float)(surfaceWidth - hInsets);
mExtraVScale = mTmpStackBounds.height() / (float)(surfaceHeight - vInsets);
task.mStack.getAnimatingSourceBounds(mTmpSourceBounds);
if (!mTmpSourceBounds.isEmpty()) {
// Get the final target stack bounds, if we are not animating, this is just the
// current stack bounds
task.mStack.getAnimatingBounds(mTmpAnimatingBounds);
// Calculate the current progress and interpolate the difference between the target
// and source bounds
float finalWidth = mTmpAnimatingBounds.width();
float initialWidth = mTmpSourceBounds.width();
float t = (surfaceContentWidth - mTmpStackBounds.width())
/ (surfaceContentWidth - mTmpAnimatingBounds.width());
mExtraHScale = (initialWidth + t * (finalWidth - initialWidth)) / initialWidth;
mExtraVScale = mExtraHScale;
// Adjust the position to account for the inset bounds
posX -= (int) (t * mExtraHScale * mTmpSourceBounds.left);
posY -= (int) (t * mExtraVScale * mTmpSourceBounds.top);
// Always clip to the stack bounds since the surface can be larger with the current
// scale
clipRect = null;
finalClipRect = mTmpStackBounds;
} else {
// We want to calculate the scaling based on the content area, not based on
// the entire surface, so that we scale in sync with windows that don't have insets.
mExtraHScale = mTmpStackBounds.width() / surfaceContentWidth;
mExtraVScale = mTmpStackBounds.height() / surfaceContentHeight;
// Since we are scaled to fit in our previously desired crop, we can now
// expose the whole window in buffer space, and not risk extending
// past where the system would have cropped us
clipRect = null;
finalClipRect = null;
}
// In the case of ForceScaleToStack we scale entire tasks together,
// and so we need to scale our offsets relative to the task bounds
// or parent and child windows would fall out of alignment.
int posX = (int) (mTmpSize.left - w.mAttrs.x * (1 - mExtraHScale));
int posY = (int) (mTmpSize.top - w.mAttrs.y * (1 - mExtraVScale));
posX -= (int) (attrs.x * (1 - mExtraHScale));
posY -= (int) (attrs.y * (1 - mExtraVScale));
// Imagine we are scaling down. As we scale the buffer down, we decrease the
// distance between the surface top left, and the start of the surface contents
// (previously it was surfaceInsets.left pixels in screen space but now it
@@ -1353,17 +1390,11 @@ class WindowStateAnimator {
// non inset content at the same position, we have to shift the whole window
// forward. Likewise for scaling up, we've increased this distance, and we need
// to shift by a negative number to compensate.
posX += w.getAttrs().surfaceInsets.left * (1 - mExtraHScale);
posY += w.getAttrs().surfaceInsets.top * (1 - mExtraVScale);
posX += attrs.surfaceInsets.left * (1 - mExtraHScale);
posY += attrs.surfaceInsets.top * (1 - mExtraVScale);
mSurfaceController.setPositionInTransaction((float)Math.floor(posX),
(float)Math.floor(posY), recoveringMemory);
// Since we are scaled to fit in our previously desired crop, we can now
// expose the whole window in buffer space, and not risk extending
// past where the system would have cropped us
clipRect = null;
finalClipRect = null;
mSurfaceController.setPositionInTransaction((float) Math.floor(posX),
(float) Math.floor(posY), recoveringMemory);
// Various surfaces in the scaled stack may resize at different times.
// We need to ensure for each surface, that we disable transformation matrix