From 4abf3f987f1d7c1ca909c4b4008796e1a5851951 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 6 Dec 2012 22:27:59 -0800 Subject: [PATCH] Call setSize to sync Surface to SurfaceFlinger. DO NOT MERGE RecentsActivity screenshots are called for very quickly after WindowStateAnimator prepareSurface(). Without enough delay the Surface.setLayer call does not propagate to the SurfaceFlinger and the screenshot is incorrect (black) because it stops sampling the layers too early. This fix calls Surface.setSize() for each sampled Surface in screenshots. setSize forces the SurfaceFlinger to process all transactions queued before returning from closeTransaction. Bug 7552304 fixed. Change-Id: I1911dfa0b09cab713c55f5ba0c612496337a77df Conflicts: services/java/com/android/server/wm/WindowManagerService.java --- core/java/android/view/Surface.java | 19 +++- .../server/am/ActivityManagerService.java | 2 +- .../server/wm/WindowManagerService.java | 90 +++++++++++-------- 3 files changed, 71 insertions(+), 40 deletions(-) diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 550a740195d71..0a81a71e154cd 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -225,6 +225,9 @@ public class Surface implements Parcelable { // non compatibility mode. private Matrix mCompatibleMatrix; + private int mWidth; + private int mHeight; + private native void nativeCreate(SurfaceSession session, String name, int w, int h, int format, int flags) throws OutOfResourcesException; @@ -330,6 +333,8 @@ public class Surface implements Parcelable { checkHeadless(); mName = name; + mWidth = w; + mHeight = h; nativeCreate(session, name, w, h, format, flags); mCloseGuard.open("release"); @@ -538,7 +543,7 @@ public class Surface implements Parcelable { /** @hide */ public void setPosition(int x, int y) { - nativeSetPosition((float)x, (float)y); + nativeSetPosition(x, y); } /** @hide */ @@ -548,9 +553,21 @@ public class Surface implements Parcelable { /** @hide */ public void setSize(int w, int h) { + mWidth = w; + mHeight = h; nativeSetSize(w, h); } + /** @hide */ + public int getWidth() { + return mWidth; + } + + /** @hide */ + public int getHeight() { + return mHeight; + } + /** @hide */ public void hide() { nativeSetFlags(SURFACE_HIDDEN, SURFACE_HIDDEN); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 409480f81ac2c..49dc220769039 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -12327,7 +12327,7 @@ public final class ActivityManagerService extends ActivityManagerNative } newConfig.seq = mConfigurationSeq; mConfiguration = newConfig; - Slog.i(TAG, "Config changed: " + newConfig); + Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig); final Configuration configCopy = new Configuration(mConfiguration); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 003f4dbfb86a3..746254e94a9f9 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -5800,50 +5800,64 @@ public class WindowManagerService extends IWindowManager.Stub // Figure out the part of the screen that is actually the app. boolean including = false; final WindowList windows = displayContent.getWindowList(); - for (int i = windows.size() - 1; i >= 0; i--) { - WindowState ws = windows.get(i); - if (!ws.mHasSurface) { - continue; - } - if (ws.mLayer >= aboveAppLayer) { - continue; - } - // When we will skip windows: when we are not including - // ones behind a window we didn't skip, and we are actually - // taking a screenshot of a specific app. - if (!including && appToken != null) { - // Also, we can possibly skip this window if it is not - // an IME target or the application for the screenshot - // is not the current IME target. - if (!ws.mIsImWindow || !isImeTarget) { - // And finally, this window is of no interest if it - // is not associated with the screenshot app. - if (ws.mAppToken == null || ws.mAppToken.token != appToken) { - continue; + try { + Surface.openTransaction(); + for (int i = windows.size() - 1; i >= 0; i--) { + WindowState ws = windows.get(i); + if (!ws.mHasSurface) { + continue; + } + if (ws.mLayer >= aboveAppLayer) { + continue; + } + // When we will skip windows: when we are not including + // ones behind a window we didn't skip, and we are actually + // taking a screenshot of a specific app. + if (!including && appToken != null) { + // Also, we can possibly skip this window if it is not + // an IME target or the application for the screenshot + // is not the current IME target. + if (!ws.mIsImWindow || !isImeTarget) { + // And finally, this window is of no interest if it + // is not associated with the screenshot app. + if (ws.mAppToken == null || ws.mAppToken.token != appToken) { + continue; + } } } - } - // We keep on including windows until we go past a full-screen - // window. - including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh); + // We keep on including windows until we go past a full-screen + // window. + including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh); - if (maxLayer < ws.mWinAnimator.mSurfaceLayer) { - maxLayer = ws.mWinAnimator.mSurfaceLayer; - } - - // Don't include wallpaper in bounds calculation - if (!ws.mIsWallpaper) { - final Rect wf = ws.mFrame; - final Rect cr = ws.mContentInsets; - int left = wf.left + cr.left; - int top = wf.top + cr.top; - int right = wf.right - cr.right; - int bottom = wf.bottom - cr.bottom; - frame.union(left, top, right, bottom); + final WindowStateAnimator winAnimator = ws.mWinAnimator; + + // The setSize() method causes all previous Surface transactions to sync to + // the SurfaceFlinger. This will force any outstanding setLayer calls to be + // synced as well for screen capture. Without this we can get black bitmaps. + Surface surface = winAnimator.mSurface; + surface.setSize(surface.getWidth(), surface.getHeight()); + + + if (maxLayer < winAnimator.mSurfaceLayer) { + maxLayer = winAnimator.mSurfaceLayer; + } + + // Don't include wallpaper in bounds calculation + if (!ws.mIsWallpaper) { + final Rect wf = ws.mFrame; + final Rect cr = ws.mContentInsets; + int left = wf.left + cr.left; + int top = wf.top + cr.top; + int right = wf.right - cr.right; + int bottom = wf.bottom - cr.bottom; + frame.union(left, top, right, bottom); + } } + } finally { + Surface.closeTransaction(); + Binder.restoreCallingIdentity(ident); } - Binder.restoreCallingIdentity(ident); // Constrain frame to the screen size. frame.intersect(0, 0, dw, dh);