Modify SurfaceView to use SurfaceFlinger child surfaces.
Here we have SurfaceView bypass the WindowManager and speak
directly to SurfaceFlinger using child surfaces. We also
implement some logic in the WM to handle child surfaces
in various Surface replacement scenarios.
Bug: 28858420
Bug: 31518219
Bug: 34888808
Bug: 35588318
Bug: 35396882
Test: Existing tests still pass (except for the ones that don't and will be deleted).
Change-Id: Icb7259365b51ebe8c7f6c7cd4f9ba29f9fce08a4
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2263042..379e3ce 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -762,6 +762,16 @@
if (canFreezeBounds()) {
freezeBounds();
}
+
+ // In the process of tearing down before relaunching, the app will
+ // try and clean up it's child surfaces. We need to prevent this from
+ // happening, so we sever the children, transfering their ownership
+ // from the client it-self to the parent surface (owned by us).
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowState w = mChildren.get(i);
+ w.mWinAnimator.detachChildren();
+ }
+
mPendingRelaunchCount++;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2f1aab6..184c82f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2199,6 +2199,15 @@
if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) {
mAccessibilityController.onWindowTransitionLocked(win, transit);
}
+
+ // When we start the exit animation we take the Surface from the client
+ // so it will stop perturbing it. We need to likewise takeaway the SurfaceFlinger
+ // side child surfaces, so they will remain preserved in their current state
+ // (rather than be cleaned up immediately by the app code).
+ SurfaceControl.openTransaction();
+ winAnimator.detachChildren();
+ SurfaceControl.closeTransaction();
+
return focusMayChange;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 98598e1..4b71338 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -566,6 +566,20 @@
if (!mDestroyPreservedSurfaceUponRedraw) {
return;
}
+ if (mSurfaceController != null) {
+ if (mPendingDestroySurface != null) {
+ // If we are preserving a surface but we aren't relaunching that means
+ // we are just doing an in-place switch. In that case any SurfaceFlinger side
+ // 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) {
+ SurfaceControl.openTransaction();
+ mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
destroyDeferredSurfaceLocked();
mDestroyPreservedSurfaceUponRedraw = false;
}
@@ -1965,4 +1979,10 @@
}
return mForceScaleUntilResize;
}
+
+ void detachChildren() {
+ if (mSurfaceController != null) {
+ mSurfaceController.detachChildren();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f8e7428..f7d3343 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -135,6 +135,20 @@
}
}
+ void reparentChildrenInTransaction(WindowSurfaceController other) {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other);
+ if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) {
+ mSurfaceControl.reparentChildren(other.getHandle());
+ }
+ }
+
+ void detachChildren() {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN");
+ if (mSurfaceControl != null) {
+ mSurfaceControl.detachChildren();
+ }
+ }
+
void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;