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

Commit 094d34ac authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Android (Google) Code Review
Browse files

Merge "Added takeScreenshot API to WindowOrganizer"

parents 524b051a 292f63b5
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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);
}
+24 −0
Original line number Diff line number Diff line
@@ -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();
+38 −0
Original line number Diff line number Diff line
@@ -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.ScreenshotHardwareBuffer buffer = SurfaceControl.captureLayers(
                wc.getSurfaceControl(), bounds, 1);

        if (buffer == null || buffer.getHardwareBuffer() == 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.getHardwareBuffer(), null);
        surface.release();

        outSurfaceControl.copyFrom(screenshot);
        return true;
    }

    private void enforceStackPermission(String func) {
        mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
    }