From a9408d4a4809dd229fb7fb8f9594cb6db4b1da64 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 3 Jun 2016 13:28:48 -0700 Subject: [PATCH] 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 --- core/java/android/view/SurfaceControl.java | 11 ++++++ core/jni/android_view_SurfaceControl.cpp | 11 ++++++ .../server/wm/WindowStateAnimator.java | 35 +++++++++++++++---- .../server/wm/WindowSurfaceController.java | 13 ++++++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b4131b44263aa..415e70ca03fdf 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -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); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index a9ed9dce590e9..ff75677536c48 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -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(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(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", diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index e46ed8d2ac1fb..881fc10c88dec 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -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, diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 9646a49b8a88f..c30da141d9853 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -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) {