Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24d88747 authored by Craig Mautner's avatar Craig Mautner
Browse files

Reduce situations where black thumbnail occurs.

Pause and retry capturing a thumbnail if the window hasn't yet
been drawn. Still will show black thumbnails if recents is pressed
before window has anything drawn.

Improves bug 7552304.

Change-Id: I550c5a60510bfc4547bbb44451d57b4bc9f49880
parent fd81f910
Loading
Loading
Loading
Loading
+181 −103
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -282,6 +283,8 @@ public class WindowManagerService extends IWindowManager.Stub
    private static final String SYSTEM_SECURE = "ro.secure";
    private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";

    private static final int MAX_SCREENSHOT_RETRIES = 3;

    final private KeyguardDisableHandler mKeyguardDisableHandler;

    private final boolean mHeadless;
@@ -5277,18 +5280,36 @@ public class WindowManagerService extends IWindowManager.Stub
            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
        }

        Bitmap rawss;
        Bitmap rawss = null;

        int maxLayer = 0;
        final Rect frame = new Rect();

        float scale;
        float scale = 0;
        int dw, dh;
        int rot;
        int rot = Surface.ROTATION_0;

        synchronized(mWindowMap) {
            long ident = Binder.clearCallingIdentity();
        boolean screenshotReady;
        int minLayer;
        if (appToken == null) {
            screenshotReady = true;
            minLayer = 0;
        } else {
            screenshotReady = false;
            minLayer = Integer.MAX_VALUE;
        }

        int retryCount = 0;
        WindowState appWin = null;

        do {
            if (retryCount++ > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            synchronized(mWindowMap) {
                final DisplayContent displayContent = getDisplayContentLocked(displayId);
                if (displayContent == null) {
                    return null;
@@ -5308,6 +5329,7 @@ public class WindowManagerService extends IWindowManager.Stub

                // Figure out the part of the screen that is actually the app.
                boolean including = false;
                appWin = null;
                final WindowList windows = displayContent.getWindowList();
                for (int i = windows.size() - 1; i >= 0; i--) {
                    WindowState ws = windows.get(i);
@@ -5330,15 +5352,18 @@ public class WindowManagerService extends IWindowManager.Stub
                            if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
                                continue;
                            }
                            appWin = ws;
                        }
                    }

                    // We keep on including windows until we go past a full-screen
                    // window.
                including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
                    boolean fullscreen = ws.isFullscreen(dw, dh);
                    including = !ws.mIsImWindow && !fullscreen;

                if (maxLayer < ws.mWinAnimator.mSurfaceLayer) {
                    maxLayer = ws.mWinAnimator.mSurfaceLayer;
                    final WindowStateAnimator winAnim = ws.mWinAnimator;
                    if (maxLayer < winAnim.mSurfaceLayer) {
                        maxLayer = winAnim.mSurfaceLayer;
                    }

                    // Don't include wallpaper in bounds calculation
@@ -5351,13 +5376,41 @@ public class WindowManagerService extends IWindowManager.Stub
                        int bottom = wf.bottom - cr.bottom;
                        frame.union(left, top, right, bottom);
                    }

                    if (ws.mAppToken != null && ws.mAppToken.token == appToken) {
                        if (minLayer > ws.mWinAnimator.mSurfaceLayer) {
                            minLayer = ws.mWinAnimator.mSurfaceLayer;
                        }
                        if (ws.isDisplayedLw()) {
                            screenshotReady = true;
                        }
                        if (fullscreen) {
                            // No point in continuing down through windows.
                            break;
                        }
                    }
                }

                if (appToken != null && appWin == null) {
                    // Can't find a window to snapshot.
                    if (DEBUG_SCREENSHOT) Slog.i(TAG,
                            "Screenshot: Couldn't find a surface matching " + appToken);
                    return null;
                }
                if (!screenshotReady) {
                    // Delay and hope that window gets drawn.
                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken
                            + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState);
                    continue;
                }
            Binder.restoreCallingIdentity(ident);

                // Constrain frame to the screen size.
                frame.intersect(0, 0, dw, dh);

                if (frame.isEmpty() || maxLayer == 0) {
                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken
                            + ": returning null frame=" + frame.toShortString() + " maxLayer="
                            + maxLayer);
                    return null;
                }

@@ -5396,7 +5449,8 @@ public class WindowManagerService extends IWindowManager.Stub
                    rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
                }
                if (DEBUG_SCREENSHOT) {
                Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer);
                    Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
                            + maxLayer + " appToken=" + appToken);
                    for (int i = 0; i < windows.size(); i++) {
                        WindowState win = windows.get(i);
                        Slog.i(TAG, win + ": " + win.mLayer
@@ -5404,7 +5458,13 @@ public class WindowManagerService extends IWindowManager.Stub
                                + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
                    }
                }
            rawss = SurfaceControl.screenshot(dw, dh, 0, maxLayer);
                rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
            }
        } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
        if (DEBUG_SCREENSHOT && retryCount > MAX_SCREENSHOT_RETRIES) {
            Slog.i(TAG, "Screenshot max retries " + retryCount + " of " + appToken + " appWin="
                    + (appWin == null ? "null" : (appWin + " drawState="
                            + appWin.mWinAnimator.mDrawState)));
        }

        if (rawss == null) {
@@ -5421,6 +5481,23 @@ public class WindowManagerService extends IWindowManager.Stub
        canvas.drawBitmap(rawss, matrix, null);
        canvas.setBitmap(null);

        if (DEBUG_SCREENSHOT) {
            // TEST IF IT's ALL BLACK
            int[] buffer = new int[bm.getWidth() * bm.getHeight()];
            bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
            boolean allBlack = true;
            for (int i = 0; i < buffer.length; i++) {
                if (buffer[i] != Color.BLACK) {
                    allBlack = false;
                    break;
                }
            }
            if (allBlack) {
                Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
                        (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null"));
            }
        }

        rawss.recycle();
        return bm;
    }
@@ -7408,6 +7485,7 @@ public class WindowManagerService extends IWindowManager.Stub
        performLayoutAndPlaceSurfacesLocked();
    }

    @Override
    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=