PiP animation: Move window with resize when ending animation.

At the end of the animation (when going from larger to smaller),
we are left with a scaled surface, that we want to seamlessly
resize to an unscaled surface of the new size. Because we have scaled
the shadow region of the surface, the position of the content
will differ before and after the resize applies. We use new
SurfaceFlinger API to cause position updates to apply after
resize. Because we have to switch into SCALING_MODE_FREEZE,
we could end up prematurely cropping the window, so we
switch to using screen space crop for the pinned stack.

Bug: 28899837
Change-Id: I9b762a237413e4fa3d432e67d30c7125bfef484c
This commit is contained in:
Robert Carr
2016-06-03 13:28:48 -07:00
parent 3207d8f8a1
commit a9408d4a48
4 changed files with 63 additions and 7 deletions

View File

@@ -51,6 +51,7 @@ public class SurfaceControl {
private static native void nativeSetLayer(long nativeObject, int zorder);
private static native void nativeSetPosition(long nativeObject, float x, float y);
private static native void nativeSetPositionAppliesWithResize(long nativeObject);
private static native void nativeSetSize(long nativeObject, int w, int h);
private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
private static native void nativeSetAlpha(long nativeObject, float alpha);
@@ -407,6 +408,16 @@ public class SurfaceControl {
nativeSetPosition(mNativeObject, x, y);
}
/**
* If the size changes in this transaction, position updates specified
* in this transaction will not complete until a buffer of the new size
* arrives.
*/
public void setPositionAppliesWithResize() {
checkNotReleased();
nativeSetPositionAppliesWithResize(mNativeObject);
}
public void setSize(int w, int h) {
checkNotReleased();
nativeSetSize(mNativeObject, w, h);

View File

@@ -248,6 +248,15 @@ static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfl
}
}
static void nativeSetPositionAppliesWithResize(JNIEnv* env, jclass clazz,
jlong nativeObject) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->setPositionAppliesWithResize();
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->setSize(w, h);
@@ -658,6 +667,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetLayer },
{"nativeSetPosition", "(JFF)V",
(void*)nativeSetPosition },
{"nativeSetPositionAppliesWithResize", "(J)V",
(void*)nativeSetPositionAppliesWithResize },
{"nativeSetSize", "(JII)V",
(void*)nativeSetSize },
{"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",

View File

@@ -1314,7 +1314,6 @@ class WindowStateAnimator {
}
private int resolveStackClip() {
// App animation overrides window animation stack clip mode.
if (mAppAnimator != null && mAppAnimator.animation != null) {
return mAppAnimator.getStackClip();
@@ -1420,6 +1419,9 @@ class WindowStateAnimator {
// aren't observing known issues here outside of PiP resizing. (Typically
// the other windows that use -1 are PopupWindows which aren't likely
// to be rendering while we resize).
boolean wasForceScaled = mForceScaleUntilResize;
if (!w.inPinnedWorkspace() || (!w.mRelayoutCalled || w.mInRelayout)) {
mSurfaceResized = mSurfaceController.setSizeInTransaction(
mTmpSize.width(), mTmpSize.height(), recoveringMemory);
@@ -1428,13 +1430,17 @@ class WindowStateAnimator {
}
mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
float surfaceWidth = mSurfaceController.getWidth();
float surfaceHeight = mSurfaceController.getHeight();
if ((task != null && task.mStack.getForceScaleToCrop()) || mForceScaleUntilResize) {
int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
float surfaceWidth = mSurfaceController.getWidth();
float surfaceHeight = mSurfaceController.getHeight();
if (!mForceScaleUntilResize) {
mSurfaceController.forceScaleableInTransaction(true);
}
// 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 = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
@@ -1455,7 +1461,8 @@ class WindowStateAnimator {
posX += w.getAttrs().surfaceInsets.left * (1 - mExtraHScale);
posY += w.getAttrs().surfaceInsets.top * (1 - mExtraVScale);
mSurfaceController.setPositionInTransaction(posX, posY, recoveringMemory);
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
@@ -1467,7 +1474,7 @@ class WindowStateAnimator {
// We need to ensure for each surface, that we disable transformation matrix
// scaling in the same transaction which we resize the surface in.
// As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
// then take over the scaling until the new buffer arrives, and things
// then take over the scaling until the new buffer arrives, and things
// will be seamless.
mForceScaleUntilResize = true;
} else {
@@ -1475,6 +1482,22 @@ class WindowStateAnimator {
recoveringMemory);
}
// If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
// to prevent further updates until buffer latch. Normally position
// would continue to apply immediately. But we need a different position
// before and after resize (since we have scaled the shadows, as discussed
// above).
if (wasForceScaled && !mForceScaleUntilResize) {
mSurfaceController.setPositionAppliesWithResizeInTransaction(true);
mSurfaceController.forceScaleableInTransaction(false);
}
if (w.inPinnedWorkspace()) {
mTmpClipRect.set(0, 0, -1, -1);
task.mStack.getDimBounds(mTmpFinalClipRect);
mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
-w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
}
updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,

View File

@@ -176,7 +176,7 @@ class WindowSurfaceController {
if (SHOW_TRANSACTIONS) logSurface(
"CROP " + clipRect.toShortString(), null);
try {
if (clipRect.width() > 0 && clipRect.height() > 0) {
if (clipRect.width() != 0 && clipRect.height() != 0) {
mSurfaceControl.setWindowCrop(clipRect);
mHiddenForCrop = false;
updateVisibility();
@@ -236,6 +236,10 @@ class WindowSurfaceController {
}
}
void setPositionAppliesWithResizeInTransaction(boolean recoveringMemory) {
mSurfaceControl.setPositionAppliesWithResize();
}
void setMatrixInTransaction(float dsdx, float dtdx, float dsdy, float dtdy,
boolean recoveringMemory) {
try {
@@ -553,6 +557,13 @@ class WindowSurfaceController {
super.setPosition(x, y);
}
@Override
public void setPositionAppliesWithResize() {
if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setPositionAppliesWithResize(): OLD: "
+ this + ". Called by" + Debug.getCallers(9));
super.setPositionAppliesWithResize();
}
@Override
public void setSize(int w, int h) {
if (w != mSize.x || h != mSize.y) {