diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index e3ff54d403165..9bc0bb4b38f77 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -305,6 +305,11 @@ interface IWindowManager */ boolean isRotationFrozen(); + /** + * Screenshot the current wallpaper layer, including the whole screen. + */ + Bitmap screenshotWallpaper(); + /** * Used only for assist -- request a screenshot of the current application. */ diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a725960623f4c..178aafba0fe27 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6168,6 +6168,21 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public Bitmap screenshotWallpaper() { + if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER, + "screenshotWallpaper()")) { + throw new SecurityException("Requires READ_FRAME_BUFFER permission"); + } + try { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); + return screenshotApplicationsInner(null, Display.DEFAULT_DISPLAY, -1, -1, true, 1f, + Bitmap.Config.ARGB_8888, true); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + } + /** * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. * In portrait mode, it grabs the upper region of the screen based on the vertical dimension @@ -6184,7 +6199,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void run() { Bitmap bm = screenshotApplicationsInner(null, Display.DEFAULT_DISPLAY, -1, -1, - true, 1f, Bitmap.Config.ARGB_8888); + true, 1f, Bitmap.Config.ARGB_8888, false); try { receiver.send(bm); } catch (RemoteException e) { @@ -6214,14 +6229,27 @@ public class WindowManagerService extends IWindowManager.Stub try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications"); return screenshotApplicationsInner(appToken, displayId, width, height, false, - frameScale, Bitmap.Config.RGB_565); + frameScale, Bitmap.Config.RGB_565, false); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } + /** + * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. + * In portrait mode, it grabs the full screenshot. + * + * @param displayId the Display to take a screenshot of. + * @param width the width of the target bitmap + * @param height the height of the target bitmap + * @param includeFullDisplay true if the screen should not be cropped before capture + * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1 + * @param config of the output bitmap + * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot + */ Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, int height, - boolean includeFullDisplay, float frameScale, Bitmap.Config config) { + boolean includeFullDisplay, float frameScale, Bitmap.Config config, + boolean wallpaperOnly) { final DisplayContent displayContent; synchronized(mWindowMap) { displayContent = getDisplayContentLocked(displayId); @@ -6248,7 +6276,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean screenshotReady; int minLayer; - if (appToken == null) { + if (appToken == null && !wallpaperOnly) { screenshotReady = true; minLayer = 0; } else { @@ -6288,11 +6316,20 @@ public class WindowManagerService extends IWindowManager.Stub if (ws.mLayer >= aboveAppLayer) { continue; } + if (wallpaperOnly && !ws.mIsWallpaper) { + continue; + } if (ws.mIsImWindow) { if (!includeImeInScreenshot) { continue; } } else if (ws.mIsWallpaper) { + // If this is the wallpaper layer and we're only looking for the wallpaper layer + // then the target window state is this one. + if (wallpaperOnly) { + appWin = ws; + } + if (appWin == null) { // We have not ran across the target window yet, so it is probably // behind the wallpaper. This can happen when the keyguard is up and @@ -6340,8 +6377,10 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (ws.mAppToken != null && ws.mAppToken.token == appToken && - ws.isDisplayedLw() && winAnim.getShown()) { + final boolean foundTargetWs = + (ws.mAppToken != null && ws.mAppToken.token == appToken) + || (appWin != null && wallpaperOnly); + if (foundTargetWs && ws.isDisplayedLw() && winAnim.getShown()) { screenshotReady = true; } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 4e4da8bb3f082..49ab9f9118331 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -590,4 +590,9 @@ public class IWindowManagerImpl implements IWindowManager { @Override public void removeWallpaperInputConsumer() throws RemoteException {} + + @Override + public Bitmap screenshotWallpaper() throws RemoteException { + return null; + } }