From f7645aa9a968e2da227f1edceaa2b83054b451dd Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 18 Jun 2019 11:14:01 -0700 Subject: [PATCH] Prevent SurfaceView from drawing over parent surface insets Parent SurfaceView to a bounds layer that enforces a crop preventing it from drawing over the surface insets. The bounds layer crop is set to the surface insets and updated when the parent surface size changes or the parent surface insets change. If the SurfaceView children are reparented to another client surface then ensure the SurfaceView relative layer info is updated correctly. Bug: 132205507 Test: go/wm-smoke Test: test preserve surfaces codepath with split screen and ensure relative z is preserved Test: test surfaceview apps, youtube, maps & camera. Test: try to repro maps pip issue described in bug Change-Id: I14c2f7603345ad89f0af4db48150b05d8ada602a --- .../service/wallpaper/WallpaperService.java | 50 ++++---- core/java/android/view/IWindowSession.aidl | 26 ++-- core/java/android/view/SurfaceControl.java | 8 ++ core/java/android/view/SurfaceView.java | 54 +++++--- core/java/android/view/ViewRootImpl.java | 117 +++++++++++------- .../android/internal/view/BaseIWindow.java | 2 +- core/jni/android_view_SurfaceControl.cpp | 1 + .../java/com/android/server/wm/Session.java | 6 +- .../server/wm/TaskSnapshotSurface.java | 2 +- .../server/wm/WindowManagerService.java | 5 +- .../server/wm/WindowStateAnimator.java | 27 +++- 11 files changed, 192 insertions(+), 106 deletions(-) diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index d645e3f746d78..60dbf84d555cc 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -105,7 +105,7 @@ public abstract class WallpaperService extends Service { static final String TAG = "WallpaperService"; static final boolean DEBUG = false; - + private static final int DO_ATTACH = 10; private static final int DO_DETACH = 20; private static final int DO_SET_DESIRED_SIZE = 30; @@ -126,7 +126,7 @@ public abstract class WallpaperService extends Service { private final ArrayList mActiveEngines = new ArrayList(); - + static final class WallpaperCommand { String action; int x; @@ -145,7 +145,7 @@ public abstract class WallpaperService extends Service { */ public class Engine { IWallpaperEngineWrapper mIWallpaperEngine; - + // Copies from mIWallpaperEngine. HandlerCaller mCaller; IWallpaperConnection mConnection; @@ -155,7 +155,7 @@ public abstract class WallpaperService extends Service { boolean mVisible; boolean mReportedVisible; boolean mDestroyed; - + // Current window state. boolean mCreated; boolean mSurfaceCreated; @@ -258,7 +258,7 @@ public abstract class WallpaperService extends Service { } super.setFixedSize(width, height); } - + public void setKeepScreenOn(boolean screenOn) { throw new UnsupportedOperationException( "Wallpapers do not support keep screen on"); @@ -403,14 +403,14 @@ public abstract class WallpaperService extends Service { mClockFunction = clockFunction; mHandler = handler; } - + /** * Provides access to the surface in which this wallpaper is drawn. */ public SurfaceHolder getSurfaceHolder() { return mSurfaceHolder; } - + /** * Convenience for {@link WallpaperManager#getDesiredMinimumWidth() * WallpaperManager.getDesiredMinimumWidth()}, returning the width @@ -419,7 +419,7 @@ public abstract class WallpaperService extends Service { public int getDesiredMinimumWidth() { return mIWallpaperEngine.mReqWidth; } - + /** * Convenience for {@link WallpaperManager#getDesiredMinimumHeight() * WallpaperManager.getDesiredMinimumHeight()}, returning the height @@ -437,7 +437,7 @@ public abstract class WallpaperService extends Service { public boolean isVisible() { return mReportedVisible; } - + /** * Returns true if this engine is running in preview mode -- that is, * it is being shown to the user before they select it as the actual @@ -456,7 +456,7 @@ public abstract class WallpaperService extends Service { public boolean isInAmbientMode() { return mIsInAmbientMode; } - + /** * Control whether this wallpaper will receive raw touch events * from the window manager as the user interacts with the window @@ -557,7 +557,7 @@ public abstract class WallpaperService extends Service { * {@link WallpaperManager#sendWallpaperCommand}. * The default implementation does nothing, and always returns null * as the result. - * + * * @param action The name of the command to perform. This tells you * what to do and how to interpret the rest of the arguments. * @param x Generic integer parameter. @@ -794,7 +794,7 @@ public abstract class WallpaperService extends Service { } mLayout.format = mFormat; - + mCurWindowFlags = mWindowFlags; mLayout.flags = mWindowFlags | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS @@ -1020,7 +1020,7 @@ public abstract class WallpaperService extends Service { mIsCreating = false; mSurfaceCreated = true; if (redrawNeeded) { - mSession.finishDrawing(mWindow); + mSession.finishDrawing(mWindow, null /* postDrawTransaction */); } mIWallpaperEngine.reportShown(); } @@ -1045,7 +1045,7 @@ public abstract class WallpaperService extends Service { mSurfaceHolder.setSizeFromLayout(); mInitializing = true; mSession = WindowManagerGlobal.getWindowSession(); - + mWindow.setSession(mSession); mLayout.packageName = getPackageName(); @@ -1149,7 +1149,7 @@ public abstract class WallpaperService extends Service { } } } - + void doOffsetsChanged(boolean always) { if (mDestroyed) { return; @@ -1187,7 +1187,7 @@ public abstract class WallpaperService extends Service { mOffsetsChanged = true; } } - + if (sync) { try { if (DEBUG) Log.v(TAG, "Reporting offsets change complete"); @@ -1196,7 +1196,7 @@ public abstract class WallpaperService extends Service { } } } - + void doCommand(WallpaperCommand cmd) { Bundle result; if (!mDestroyed) { @@ -1213,7 +1213,7 @@ public abstract class WallpaperService extends Service { } } } - + void reportSurfaceDestroyed() { if (mSurfaceCreated) { mSurfaceCreated = false; @@ -1229,12 +1229,12 @@ public abstract class WallpaperService extends Service { onSurfaceDestroyed(mSurfaceHolder); } } - + void detach() { if (mDestroyed) { return; } - + mDestroyed = true; if (mIWallpaperEngine.mDisplayManager != null) { @@ -1246,9 +1246,9 @@ public abstract class WallpaperService extends Service { if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this); onVisibilityChanged(false); } - + reportSurfaceDestroyed(); - + if (DEBUG) Log.v(TAG, "onDestroy(): " + this); onDestroy(); @@ -1256,18 +1256,18 @@ public abstract class WallpaperService extends Service { try { if (DEBUG) Log.v(TAG, "Removing window and destroying surface " + mSurfaceHolder.getSurface() + " of: " + this); - + if (mInputEventReceiver != null) { mInputEventReceiver.dispose(); mInputEventReceiver = null; } - + mSession.remove(mWindow); } catch (RemoteException e) { } mSurfaceHolder.mSurface.release(); mCreated = false; - + // Dispose the input channel after removing the window so the Window Manager // doesn't interpret the input channel being closed as an abnormal termination. if (mInputChannel != null) { diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index caab00c3863e4..37b6f1317fbfc 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -2,15 +2,15 @@ ** ** Copyright 2006, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -31,6 +31,7 @@ import android.view.WindowManager; import android.view.InsetsState; import android.view.Surface; import android.view.SurfaceControl; +import android.view.Transaction; import java.util.List; @@ -57,7 +58,7 @@ interface IWindowSession { * position should be ignored) and surface of the window. The surface * will be invalid if the window is currently hidden, else you can use it * to draw the window's contents. - * + * * @param window The window being modified. * @param seq Ordering sequence number. * @param attrs If non-null, new attributes to apply to the window. @@ -147,8 +148,15 @@ interface IWindowSession { */ void getDisplayFrame(IWindow window, out Rect outDisplayFrame); + /** + * Called when the client has finished drawing the surface, if needed. + * + * @param postDrawTransaction transaction filled by the client that can be + * used to synchronize any post draw transactions with the server. Transaction + * is null if there is no sync required. + */ @UnsupportedAppUsage - void finishDrawing(IWindow window); + void finishDrawing(IWindow window, in Transaction postDrawTransaction); @UnsupportedAppUsage void setInTouchMode(boolean showFocus); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index bb169e01bbace..c1633ae507ad7 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -2693,6 +2693,14 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * Writes the transaction to parcel, clearing the transaction as if it had been applied so + * it can be used to store future transactions. It's the responsibility of the parcel + * reader to apply the original transaction. + * + * @param dest parcel to write the transaction to + * @param flags + */ @Override public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) { if (mNativeObject == 0) { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 3535447790863..4891b43c829e9 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -98,7 +98,8 @@ import java.util.concurrent.locks.ReentrantLock; * artifacts may occur on previous versions of the platform when its window is * positioned asynchronously.

*/ -public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback { +public class SurfaceView extends View + implements ViewRootImpl.WindowStoppedCallback, ViewRootImpl.SurfaceChangedCallback { private static final String TAG = "SurfaceView"; private static final boolean DEBUG = false; @@ -120,7 +121,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb boolean mDrawFinished = false; final Rect mScreenRect = new Rect(); - SurfaceSession mSurfaceSession; + final SurfaceSession mSurfaceSession = new SurfaceSession(); SurfaceControl mSurfaceControl; // In the case of format changes we switch out the surface in-place @@ -266,11 +267,22 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb updateSurface(); } + /** @hide */ + @Override + public void surfaceChangedCallback(SurfaceControl.Transaction transaction) { + if (getViewRootImpl() != null && mBackgroundControl != null && mSurfaceControl != null) { + SurfaceControl sc = getViewRootImpl().getSurfaceControl(); + transaction.setRelativeLayer(mBackgroundControl, sc, Integer.MIN_VALUE); + transaction.setRelativeLayer(mSurfaceControl, sc, mSubLayer); + } + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewRootImpl().addWindowStoppedCallback(this); + getViewRootImpl().addSurfaceChangedCallback(this); mWindowStopped = false; mViewVisibility = getVisibility() == VISIBLE; @@ -356,6 +368,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb // the SurfaceHolder forward, most live wallpapers do it. if (viewRoot != null) { viewRoot.removeWindowStoppedCallback(this); + viewRoot.removeSurfaceChangedCallback(this); } mAttachedToWindow = false; @@ -637,21 +650,34 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); if (creating) { - viewRoot.createBoundsSurface(mSubLayer); - mSurfaceSession = new SurfaceSession(); mDeferredDestroySurfaceControl = mSurfaceControl; updateOpaqueFlag(); + // SurfaceView hierarchy + // ViewRootImpl surface + // - bounds layer (crops all child surfaces to parent surface insets) + // - SurfaceView surface (drawn relative to ViewRootImpl surface) + // - Background color layer (drawn behind all SurfaceView surfaces) + // + // The bounds layer is used to crop the surface view so it does not draw into + // the parent surface inset region. Since there can be multiple surface views + // below or above the parent surface, one option is to create multiple bounds + // layer for each z order. The other option, the one implement is to create + // a single bounds layer and set z order for each child surface relative to the + // parent surface. + // When creating the surface view, we parent it to the bounds layer and then + // set the relative z order. When the parent surface changes, we have to + // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback. final String name = "SurfaceView - " + viewRoot.getTitle().toString(); - - mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) - .setName(name) - .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) - .setBufferSize(mSurfaceWidth, mSurfaceHeight) - .setFormat(mFormat) - .setParent(viewRoot.getSurfaceControl()) - .setFlags(mSurfaceFlags) - .build(); + mSurfaceControl = + new SurfaceControl.Builder(mSurfaceSession) + .setName(name) + .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) + .setBufferSize(mSurfaceWidth, mSurfaceHeight) + .setFormat(mFormat) + .setParent(viewRoot.getBoundsLayer()) + .setFlags(mSurfaceFlags) + .build(); mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for -" + name) .setOpaque(true) @@ -674,7 +700,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb SurfaceControl.openTransaction(); try { - mSurfaceControl.setLayer(mSubLayer); + mSurfaceControl.setRelativeLayer(viewRoot.getSurfaceControl(), mSubLayer); if (mViewVisibility) { mSurfaceControl.show(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 30bb2bbd33852..16de906b1085a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -68,6 +68,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -476,17 +477,19 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage public final Surface mSurface = new Surface(); private final SurfaceControl mSurfaceControl = new SurfaceControl(); + private IBinder mPreviousSurfaceControlHandle = null; + + private final Transaction mChangeSurfaceTransaction = new Transaction(); + private final SurfaceSession mSurfaceSession = new SurfaceSession(); /** - * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds - * are set to the parent's bounds adjusted for surface insets. This surface is created when - * {@link ViewRootImpl#createBoundsSurface(int)} is called. - * By parenting to this bounds surface, child surfaces can ensure they do not draw into the - * surface inset regions set by the parent window. + * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to + * the surface insets. This surface is created only if a client requests it via {@link + * #getBoundsLayer()}. By parenting to this bounds surface, child surfaces can ensure they do + * not draw into the surface inset regions set by the parent window. */ - public final Surface mBoundsSurface = new Surface(); - private SurfaceSession mSurfaceSession; - private SurfaceControl mBoundsSurfaceControl; + private SurfaceControl mBoundsLayer; + private final Transaction mTransaction = new Transaction(); @UnsupportedAppUsage @@ -1576,65 +1579,76 @@ public final class ViewRootImpl implements ViewParent, } } - /** - * Creates a surface as a child of {@code mSurface} with the same bounds as its parent and - * crop bounds set to the parent's bounds adjusted for surface insets. - * - * @param zOrderLayer Z order relative to the parent surface. - */ - public void createBoundsSurface(int zOrderLayer) { - if (mSurfaceSession == null) { - mSurfaceSession = new SurfaceSession(); - } - if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) { - return; // surface control for bounds surface already exists. - } + /** Register callback to be notified when the ViewRootImpl surface changes. */ + interface SurfaceChangedCallback { + void surfaceChangedCallback(SurfaceControl.Transaction transaction); + } - mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) + private final ArrayList mSurfaceChangedCallbacks = new ArrayList<>(); + void addSurfaceChangedCallback(SurfaceChangedCallback c) { + mSurfaceChangedCallbacks.add(c); + } + + void removeSurfaceChangedCallback(SurfaceChangedCallback c) { + mSurfaceChangedCallbacks.remove(c); + } + + private void notifySurfaceChanged(SurfaceControl.Transaction transaction) { + for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { + mSurfaceChangedCallbacks.get(i).surfaceChangedCallback(transaction); + } + } + + /** + * Returns a child layer with the same bounds as its parent {@code mSurface} and cropped to the + * surface insets. If the layer does not exist, it is created. + * + *

Parenting to this layer will ensure that its children are cropped by the view's surface + * insets. + */ + public SurfaceControl getBoundsLayer() { + if (mBoundsLayer == null) { + mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession) + .setContainerLayer() .setName("Bounds for - " + getTitle().toString()) .setParent(mSurfaceControl) .build(); - setBoundsSurfaceCrop(); - mTransaction.setLayer(mBoundsSurfaceControl, zOrderLayer) - .show(mBoundsSurfaceControl) - .apply(); - mBoundsSurface.copyFrom(mBoundsSurfaceControl); + setBoundsLayerCrop(mTransaction); + mTransaction.show(mBoundsLayer).apply(); + } + return mBoundsLayer; } - private void setBoundsSurfaceCrop() { + private void setBoundsLayerCrop(Transaction t) { // mWinFrame is already adjusted for surface insets. So offset it and use it as // the cropping bounds. mTempBoundsRect.set(mWinFrame); mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left, mWindowAttributes.surfaceInsets.top); - mTransaction.setWindowCrop(mBoundsSurfaceControl, mTempBoundsRect); + t.setWindowCrop(mBoundsLayer, mTempBoundsRect); } /** - * Called after window layout to update the bounds surface. If the surface insets have - * changed or the surface has resized, update the bounds surface. + * Called after window layout to update the bounds surface. If the surface insets have changed + * or the surface has resized, update the bounds surface. */ - private void updateBoundsSurface() { - if (mBoundsSurfaceControl != null && mSurface.isValid()) { - setBoundsSurfaceCrop(); - mTransaction.deferTransactionUntilSurface(mBoundsSurfaceControl, + private void updateBoundsLayer() { + if (mBoundsLayer != null) { + setBoundsLayerCrop(mTransaction); + mTransaction.deferTransactionUntilSurface(mBoundsLayer, mSurface, mSurface.getNextFrameNumber()) .apply(); } } private void destroySurface() { + if (mBoundsLayer != null) { + mBoundsLayer.release(); + mBoundsLayer = null; + } mSurface.release(); mSurfaceControl.release(); - - mSurfaceSession = null; - - if (mBoundsSurfaceControl != null) { - mBoundsSurfaceControl.remove(); - mBoundsSurface.release(); - mBoundsSurfaceControl = null; - } } /** @@ -2598,7 +2612,7 @@ public final class ViewRootImpl implements ViewParent, } if (surfaceSizeChanged) { - updateBoundsSurface(); + updateBoundsLayer(); } final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); @@ -3438,7 +3452,9 @@ public final class ViewRootImpl implements ViewParent, private void reportDrawFinished() { try { mDrawsNeededToReport = 0; - mWindowSession.finishDrawing(mWindow); + if (mSurfaceControl.isValid()) { + mWindowSession.finishDrawing(mWindow, mChangeSurfaceTransaction); + } } catch (RemoteException e) { // Have fun! } @@ -7089,6 +7105,9 @@ public final class ViewRootImpl implements ViewParent, frameNumber = mSurface.getNextFrameNumber(); } + mPreviousSurfaceControlHandle = mSurfaceControl.isValid() + ? mSurfaceControl.getHandle() : null; + int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params, (int) (mView.getMeasuredWidth() * appScale + 0.5f), (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility, @@ -7102,6 +7121,11 @@ public final class ViewRootImpl implements ViewParent, destroySurface(); } + if (mPreviousSurfaceControlHandle != null && mSurfaceControl.isValid() + && mPreviousSurfaceControlHandle != mSurfaceControl.getHandle()) { + notifySurfaceChanged(mChangeSurfaceTransaction); + } + mPendingAlwaysConsumeSystemBars = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0; @@ -7326,7 +7350,8 @@ public final class ViewRootImpl implements ViewParent, try { if ((relayoutWindow(mWindowAttributes, viewVisibility, false) & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { - mWindowSession.finishDrawing(mWindow); + mWindowSession.finishDrawing( + mWindow, null /* postDrawTransaction */); } } catch (RemoteException e) { } diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index f9cdf3d0be614..dfd6f95c00af5 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -49,7 +49,7 @@ public class BaseIWindow extends IWindow.Stub { DisplayCutout.ParcelableWrapper displayCutout) { if (reportDraw) { try { - mSession.finishDrawing(this); + mSession.finishDrawing(this, null /* postDrawTransaction */); } catch (RemoteException e) { } } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index f55f81de68f30..f55077a653096 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1266,6 +1266,7 @@ static void nativeWriteTransactionToParcel(JNIEnv* env, jclass clazz, jlong nati reinterpret_cast(nativeObject); if (self != nullptr) { self->writeToParcel(parcel); + self->clear(); } } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index ecb0941b4bd0c..8d1cc71f7a6f1 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -28,6 +28,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITION import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.Nullable; import android.content.ClipData; import android.graphics.Rect; import android.graphics.Region; @@ -225,10 +226,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } @Override - public void finishDrawing(IWindow window) { + public void finishDrawing(IWindow window, + @Nullable SurfaceControl.Transaction postDrawTransaction) { if (WindowManagerService.localLOGV) Slog.v( TAG_WM, "IWindow finishDrawing called for " + window); - mService.finishDrawingWindow(this, window); + mService.finishDrawingWindow(this, window, postDrawTransaction); } @Override diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 5d99db5a00de1..306e7f44102ed 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -418,7 +418,7 @@ class TaskSnapshotSurface implements StartingSurface { private void reportDrawn() { try { - mSession.finishDrawing(mWindow); + mSession.finishDrawing(mWindow, null /* postDrawTransaction */); } catch (RemoteException e) { // Local call. } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0019d606764a5..24f3103ceb60c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2356,14 +2356,15 @@ public class WindowManagerService extends IWindowManager.Stub } } - void finishDrawingWindow(Session session, IWindow client) { + void finishDrawingWindow(Session session, IWindow client, + @Nullable SurfaceControl.Transaction postDrawTransaction) { final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { WindowState win = windowForClientLocked(session, client, false); if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "finishDrawingWindow: " + win + " mDrawState=" + (win != null ? win.mWinAnimator.drawStateToString() : "null")); - if (win != null && win.mWinAnimator.finishDrawingLocked()) { + if (win != null && win.mWinAnimator.finishDrawingLocked(postDrawTransaction)) { if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { win.getDisplayContent().pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index dc94d16e13080..4cd6731fc5b4f 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -220,7 +220,16 @@ class WindowStateAnimator { private final Rect mTmpSize = new Rect(); - private final SurfaceControl.Transaction mReparentTransaction = new SurfaceControl.Transaction(); + /** + * Handles surface changes synchronized to after the client has drawn the surface. This + * transaction is currently used to reparent the old surface children to the new surface once + * the client has completed drawing to the new surface. + * This transaction is also used to merge transactions parceled in by the client. The client + * uses the transaction to update the relative z of its children from the old parent surface + * to the new parent surface once window manager reparents its children. + */ + private final SurfaceControl.Transaction mPostDrawTransaction = + new SurfaceControl.Transaction(); // Used to track whether we have called detach children on the way to invisibility, in which // case we need to give the client a new Surface if it lays back out to a visible state. @@ -301,7 +310,7 @@ class WindowStateAnimator { SurfaceControl.mergeToGlobalTransaction(mTmpTransaction); } - boolean finishDrawingLocked() { + boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction) { final boolean startingWindow = mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; if (DEBUG_STARTING_WINDOW && startingWindow) { @@ -321,6 +330,9 @@ class WindowStateAnimator { mDrawState = COMMIT_DRAW_PENDING; layoutNeeded = true; } + if (postDrawTransaction != null) { + mPostDrawTransaction.merge(postDrawTransaction); + } return layoutNeeded; } @@ -385,7 +397,7 @@ class WindowStateAnimator { // child layers need to be reparented to the new surface to make this // transparent to the app. if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) { - mReparentTransaction.reparentChildren(mPendingDestroySurface.mSurfaceControl, + mPostDrawTransaction.reparentChildren(mPendingDestroySurface.mSurfaceControl, mSurfaceController.mSurfaceControl.getHandle()) .apply(); } @@ -1150,7 +1162,7 @@ class WindowStateAnimator { // LogicalDisplay. mAnimator.setPendingLayoutChanges(w.getDisplayId(), FINISH_LAYOUT_REDO_ANIM); - if (DEBUG_LAYOUT_REPEATS) { + if (DEBUG_LAYOUT_REPEATS) { mService.mWindowPlacerLocked.debugLayoutRepeats( "showSurfaceRobustlyLocked " + w, mAnimator.getPendingLayoutChanges(w.getDisplayId())); @@ -1281,10 +1293,13 @@ class WindowStateAnimator { // If we had a preserved surface it's no longer needed, and it may be harmful // if we are transparent. if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) { - mPendingDestroySurface.mSurfaceControl.hide(); - mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController); + final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl; + mPostDrawTransaction.hide(pendingSurfaceControl); + mPostDrawTransaction.reparentChildren(pendingSurfaceControl, + mSurfaceController.getHandle()); } + mPostDrawTransaction.apply(); return true; }