Only use one SurfaceControlWithBackground per AppToken.
In the past, if an app never renders to a SurfaceView, it will be invisible despite having FLAG_OPAQUE. This means an app could leave a totally empty SurfaceView (never drawing in to it) on top of a second SurfaceView, and expect the second one to be visible. This is probably buggy app behavior because FLAG_OPAQUE means if they ever draw anything at all in to the top SurfaceView the bottom one will become totally invisible. However this has worked in the past, so we have to preserve things for apps. To accomplish this we ensure only the bottom most visible SurfaceView for a given AppToken will receive a background. We achieve this by synchronizing through the app token whenever visibility or layering of a SurfaceView changes. Bug: 29580298 Change-Id: I0023326323cb961b56404fd49093384e7b72aa54
This commit is contained in:
@@ -134,6 +134,9 @@ class AppWindowToken extends WindowToken {
|
||||
boolean mAppStopped;
|
||||
int mPendingRelaunchCount;
|
||||
|
||||
private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds =
|
||||
new ArrayList<WindowSurfaceController.SurfaceControlWithBackground>();
|
||||
|
||||
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
|
||||
ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
|
||||
|
||||
@@ -720,6 +723,36 @@ class AppWindowToken extends WindowToken {
|
||||
service.mWindowPlacerLocked.performSurfacePlacement();
|
||||
}
|
||||
|
||||
void addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
|
||||
mSurfaceViewBackgrounds.add(background);
|
||||
}
|
||||
|
||||
void removeSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
|
||||
mSurfaceViewBackgrounds.remove(background);
|
||||
updateSurfaceViewBackgroundVisibilities();
|
||||
}
|
||||
|
||||
// We use DimLayers behind SurfaceViews to prevent holes while resizing and creating.
|
||||
// However, we need to ensure one SurfaceView doesn't cover another when they are both placed
|
||||
// below the main app window (as traditionally a SurfaceView which is never drawn
|
||||
// to is totally translucent). So we look at all our SurfaceView backgrounds and only enable
|
||||
// the background for the SurfaceView with lowest Z order
|
||||
void updateSurfaceViewBackgroundVisibilities() {
|
||||
WindowSurfaceController.SurfaceControlWithBackground bottom = null;
|
||||
int bottomLayer = Integer.MAX_VALUE;
|
||||
for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
|
||||
WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
|
||||
if (sc.mVisible && sc.mLayer < bottomLayer) {
|
||||
bottomLayer = sc.mLayer;
|
||||
bottom = sc;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
|
||||
WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
|
||||
sc.updateBackgroundVisibility(sc != bottom);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void dump(PrintWriter pw, String prefix) {
|
||||
super.dump(pw, prefix);
|
||||
|
||||
@@ -84,9 +84,10 @@ class WindowSurfaceController {
|
||||
// to a black-out layer placed one Z-layer below the surface.
|
||||
// This prevents holes to whatever app/wallpaper is underneath.
|
||||
if (animator.mWin.isChildWindow() &&
|
||||
animator.mWin.mSubLayer < 0) {
|
||||
animator.mWin.mSubLayer < 0 &&
|
||||
animator.mWin.mAppToken != null) {
|
||||
mSurfaceControl = new SurfaceControlWithBackground(s,
|
||||
name, w, h, format, flags);
|
||||
name, w, h, format, flags, animator.mWin.mAppToken);
|
||||
} else if (DEBUG_SURFACE_TRACE) {
|
||||
mSurfaceControl = new SurfaceTrace(
|
||||
s, name, w, h, format, flags);
|
||||
@@ -754,18 +755,25 @@ class WindowSurfaceController {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SurfaceControlWithBackground extends SurfaceControl {
|
||||
class SurfaceControlWithBackground extends SurfaceControl {
|
||||
private SurfaceControl mBackgroundControl;
|
||||
private boolean mOpaque = true;
|
||||
private boolean mVisible = false;
|
||||
private boolean mAppForcedInvisible = false;
|
||||
private AppWindowToken mAppToken;
|
||||
public boolean mVisible = false;
|
||||
public int mLayer = -1;
|
||||
|
||||
public SurfaceControlWithBackground(SurfaceSession s,
|
||||
String name, int w, int h, int format, int flags)
|
||||
String name, int w, int h, int format, int flags,
|
||||
AppWindowToken token)
|
||||
throws OutOfResourcesException {
|
||||
super(s, name, w, h, format, flags);
|
||||
mBackgroundControl = new SurfaceControl(s, name, w, h,
|
||||
PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
|
||||
mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
|
||||
mAppToken = token;
|
||||
|
||||
mAppToken.addSurfaceViewBackground(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -778,6 +786,10 @@ class WindowSurfaceController {
|
||||
public void setLayer(int zorder) {
|
||||
super.setLayer(zorder);
|
||||
mBackgroundControl.setLayer(zorder - 1);
|
||||
if (mLayer != zorder) {
|
||||
mLayer = zorder;
|
||||
mAppToken.updateSurfaceViewBackgroundVisibilities();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -814,7 +826,7 @@ class WindowSurfaceController {
|
||||
public void setOpaque(boolean isOpaque) {
|
||||
super.setOpaque(isOpaque);
|
||||
mOpaque = isOpaque;
|
||||
updateBackgroundVisibility();
|
||||
updateBackgroundVisibility(mAppForcedInvisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -830,23 +842,28 @@ class WindowSurfaceController {
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
mVisible = false;
|
||||
super.hide();
|
||||
updateBackgroundVisibility();
|
||||
if (mVisible) {
|
||||
mVisible = false;
|
||||
mAppToken.updateSurfaceViewBackgroundVisibilities();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
mVisible = true;
|
||||
super.show();
|
||||
updateBackgroundVisibility();
|
||||
if (!mVisible) {
|
||||
mVisible = true;
|
||||
mAppToken.updateSurfaceViewBackgroundVisibilities();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
mBackgroundControl.destroy();
|
||||
}
|
||||
mAppToken.removeSurfaceViewBackground(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
@@ -866,8 +883,9 @@ class WindowSurfaceController {
|
||||
mBackgroundControl.deferTransactionUntil(handle, frame);
|
||||
}
|
||||
|
||||
private void updateBackgroundVisibility() {
|
||||
if (mOpaque && mVisible) {
|
||||
void updateBackgroundVisibility(boolean forcedInvisible) {
|
||||
mAppForcedInvisible = forcedInvisible;
|
||||
if (mOpaque && mVisible && !mAppForcedInvisible) {
|
||||
mBackgroundControl.show();
|
||||
} else {
|
||||
mBackgroundControl.hide();
|
||||
|
||||
Reference in New Issue
Block a user