From 449e06dffc47b2a3e231f79da5a2c46bc72f7d33 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 9 Feb 2022 00:56:39 -0800 Subject: [PATCH] SurfaceControlViewHost: Basic child window support WindowlessWindowManager already has some support for multiple windows so the main thing we need to do is just ensure that the Windowless session is injected in to the ViewRoot of things attached to our token. We can do this via some somewhat unsightly glue code in WindowManagerGlobal. Bug: 218615203 Test: SurfaceControlViewHostTests Change-Id: Icce97c02b6155a7ef368821670db26728b95b6b9 --- .../android/view/SurfaceControlViewHost.java | 20 +++++++++-- core/java/android/view/ViewRootImpl.java | 4 +++ .../android/view/WindowManagerGlobal.java | 36 ++++++++++++++++++- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 7e0d887a8f797..3fb0fe7ff0474 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -27,8 +27,10 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; +import android.util.Log; import android.view.accessibility.IAccessibilityEmbeddedConnection; import android.view.InsetsState; +import android.view.WindowManagerGlobal; import java.util.Objects; @@ -43,11 +45,13 @@ import java.util.Objects; * {@link SurfaceView#setChildSurfacePackage}. */ public class SurfaceControlViewHost { + private final static String TAG = "SurfaceControlViewHost"; private final ViewRootImpl mViewRoot; private WindowlessWindowManager mWm; private SurfaceControl mSurfaceControl; private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection; + private boolean mReleased = false; private final class ISurfaceControlViewHostImpl extends ISurfaceControlViewHost.Stub { @Override @@ -268,6 +272,8 @@ public class SurfaceControlViewHost { @NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) { mWm = wwm; mViewRoot = new ViewRootImpl(c, d, mWm, useSfChoreographer); + WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot); + mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection(); } @@ -292,7 +298,10 @@ public class SurfaceControlViewHost { .build(); mWm = new WindowlessWindowManager(context.getResources().getConfiguration(), mSurfaceControl, hostToken); + mViewRoot = new ViewRootImpl(context, display, mWm); + WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot); + mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection(); } @@ -301,12 +310,15 @@ public class SurfaceControlViewHost { */ @Override protected void finalize() throws Throwable { - // We aren't on the UI thread here so we need to pass false to - // doDie + if (mReleased) { + return; + } + Log.e(TAG, "SurfaceControlViewHost finalized without being released: " + this); + // We aren't on the UI thread here so we need to pass false to doDie mViewRoot.die(false /* immediate */); + WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot); } - /** * Return a SurfacePackage for the root SurfaceControl of the embedded hierarchy. * Rather than be directly reparented using {@link SurfaceControl.Transaction} this @@ -413,5 +425,7 @@ public class SurfaceControlViewHost { public void release() { // ViewRoot will release mSurfaceControl for us. mViewRoot.die(true /* immediate */); + WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot); + mReleased = true; } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 777e89d145b2d..649b1d69973be 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -10851,4 +10851,8 @@ public final class ViewRootImpl implements ViewParent, mLastGivenInsets.reset(); requestLayout(); } + + IWindowSession getWindowSession() { + return mWindowSession; + } } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index c92a3a086a8bf..93cb0dd7a2348 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -159,6 +159,8 @@ public final class WindowManagerGlobal { new ArrayList(); private final ArraySet mDyingViews = new ArraySet(); + private final ArrayList mWindowlessRoots = new ArrayList(); + private Runnable mSystemPropertyUpdater; private WindowManagerGlobal() { @@ -387,7 +389,25 @@ public final class WindowManagerGlobal { } } - root = new ViewRootImpl(view.getContext(), display); + IWindowSession windowlessSession = null; + // If there is a parent set, but we can't find it, it may be coming + // from a SurfaceControlViewHost hierarchy. + if (wparams.token != null && panelParentView == null) { + for (int i = 0; i < mWindowlessRoots.size(); i++) { + ViewRootImpl maybeParent = mWindowlessRoots.get(i); + if (maybeParent.getWindowToken() == wparams.token) { + windowlessSession = maybeParent.getWindowSession(); + break; + } + } + } + + if (windowlessSession == null) { + root = new ViewRootImpl(view.getContext(), display); + } else { + root = new ViewRootImpl(view.getContext(), display, + windowlessSession); + } view.setLayoutParams(wparams); @@ -720,6 +740,20 @@ public final class WindowManagerGlobal { throw e.rethrowFromSystemServer(); } } + + /** @hide */ + public void addWindowlessRoot(ViewRootImpl impl) { + synchronized (mLock) { + mWindowlessRoots.add(impl); + } + } + + /** @hide */ + public void removeWindowlessRoot(ViewRootImpl impl) { + synchronized (mLock) { + mWindowlessRoots.remove(impl); + } + } } final class WindowLeaked extends AndroidRuntimeException {