Merge "Added takeScreenshot API to WindowOrganizer" into rvc-dev

This commit is contained in:
Chavi Weingarten
2020-04-27 18:59:49 +00:00
committed by Android (Google) Code Review
3 changed files with 76 additions and 0 deletions

View File

@@ -16,9 +16,12 @@
package android.window;
import android.view.SurfaceControl;
import android.window.IDisplayAreaOrganizerController;
import android.window.ITaskOrganizerController;
import android.window.IWindowContainerTransactionCallback;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
/** @hide */
@@ -47,4 +50,15 @@ interface IWindowOrganizerController {
/** @return An interface enabling the management of display area organizers. */
IDisplayAreaOrganizerController getDisplayAreaOrganizerController();
/**
* Take a screenshot of the requested Window token and place the content of the screenshot into
* outSurfaceControl. The SurfaceControl will be a child of the token's parent, so it will be
* a sibling of the token's window
* @param token The token for the WindowContainer that should get a screenshot taken.
* @param outSurfaceControl The SurfaceControl where the screenshot will be attached.
*
* @return true if the screenshot was successful, false otherwise.
*/
boolean takeScreenshot(in WindowContainerToken token, out SurfaceControl outSurfaceControl);
}

View File

@@ -17,11 +17,13 @@
package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.app.ActivityTaskManager;
import android.os.RemoteException;
import android.util.Singleton;
import android.view.SurfaceControl;
/**
* Base class for organizing specific types of windows like Tasks and DisplayAreas
@@ -63,6 +65,28 @@ public class WindowOrganizer {
}
}
/**
* Take a screenshot for a specified Window
* @param token The token for the WindowContainer that should get a screenshot taken.
* @return A SurfaceControl where the screenshot will be attached, or null if failed.
*
* @hide
*/
@Nullable
@RequiresPermission(android.Manifest.permission.READ_FRAME_BUFFER)
public static SurfaceControl takeScreenshot(@NonNull WindowContainerToken token) {
try {
SurfaceControl surfaceControl = new SurfaceControl();
if (getWindowOrganizerController().takeScreenshot(token, surfaceControl)) {
return surfaceControl;
} else {
return null;
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
static IWindowOrganizerController getWindowOrganizerController() {
return IWindowOrganizerControllerSingleton.get();

View File

@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
@@ -27,17 +28,20 @@ import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Slog;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.IDisplayAreaOrganizerController;
import android.window.ITaskOrganizerController;
import android.window.IWindowContainerTransactionCallback;
import android.window.IWindowOrganizerController;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -377,6 +381,40 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mTransactionCallbacksByPendingSyncId.remove(mSyncId);
}
@Override
public boolean takeScreenshot(WindowContainerToken token, SurfaceControl outSurfaceControl) {
mService.mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "takeScreenshot()");
final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
if (wc == null) {
throw new RuntimeException("Invalid token in screenshot transaction");
}
final Rect bounds = new Rect();
wc.getBounds(bounds);
bounds.offsetTo(0, 0);
SurfaceControl.ScreenshotGraphicBuffer buffer = SurfaceControl.captureLayers(
wc.getSurfaceControl(), bounds, 1);
if (buffer == null || buffer.getGraphicBuffer() == null) {
return false;
}
SurfaceControl screenshot = mService.mWindowManager.mSurfaceControlFactory.apply(null)
.setName(wc.getName() + " - Organizer Screenshot")
.setBufferSize(bounds.width(), bounds.height())
.setFormat(PixelFormat.TRANSLUCENT)
.setParent(wc.getParentSurfaceControl())
.build();
Surface surface = new Surface();
surface.copyFrom(screenshot);
surface.attachAndQueueBufferWithColorSpace(buffer.getGraphicBuffer(), null);
surface.release();
outSurfaceControl.copyFrom(screenshot);
return true;
}
private void enforceStackPermission(String func) {
mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
}