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

Commit eea27600 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Take PIP snapshot in the shell and use bounds state size for crossfading" into sc-dev

parents 3e2c6580 75e94750
Loading
Loading
Loading
Loading
+0 −11
Original line number Original line Diff line number Diff line
@@ -77,17 +77,6 @@ interface IWindowOrganizerController {
    /** @return An interface enabling the management of display area organizers. */
    /** @return An interface enabling the management of display area organizers. */
    IDisplayAreaOrganizerController getDisplayAreaOrganizerController();
    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);

    /**
    /**
     * Registers a transition player with Core. There is only one of these at a time and calling
     * Registers a transition player with Core. There is only one of these at a time and calling
     * this will replace the existing one if set.
     * this will replace the existing one if set.
+0 −23
Original line number Original line Diff line number Diff line
@@ -25,7 +25,6 @@ import android.app.ActivityTaskManager;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Singleton;
import android.util.Singleton;
import android.view.SurfaceControl;


/**
/**
 * Base class for organizing specific types of windows like Tasks and DisplayAreas
 * Base class for organizing specific types of windows like Tasks and DisplayAreas
@@ -111,28 +110,6 @@ 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 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();
        }
    }

    /**
    /**
     * Register an ITransitionPlayer to handle transition animations.
     * Register an ITransitionPlayer to handle transition animations.
     * @hide
     * @hide
+68 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.common;

import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.view.SurfaceControl;

/**
 * Helpers for working with screenshots.
 */
public class ScreenshotUtils {

    /**
     * Take a screenshot of the specified SurfaceControl.
     *
     * @param t the transaction used to set changes on the resulting screenshot.
     * @param sc the SurfaceControl to take a screenshot of
     * @param crop the crop to use when capturing the screenshot
     *
     * @return A SurfaceControl where the screenshot will be attached, or null if failed.
     */
    public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
            Rect crop) {
        final SurfaceControl.ScreenshotHardwareBuffer buffer = SurfaceControl.captureLayers(
                new SurfaceControl.LayerCaptureArgs.Builder(sc)
                        .setSourceCrop(crop)
                        .setCaptureSecureLayers(true)
                        .setAllowProtected(true)
                        .build()
        );
        if (buffer == null || buffer.getHardwareBuffer() == null) {
            return null;
        }
        final GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
                buffer.getHardwareBuffer());
        final SurfaceControl screenshot = new SurfaceControl.Builder()
                .setName("ScreenshotUtils screenshot")
                .setFormat(PixelFormat.TRANSLUCENT)
                .setSecure(buffer.containsSecureLayers())
                .setCallsite("ScreenshotUtils.takeScreenshot")
                .setBLASTLayer()
                .build();

        t.setBuffer(screenshot, graphicBuffer);
        t.setColorSpace(screenshot, buffer.getColorSpace());
        t.reparent(screenshot, sc);
        t.setLayer(screenshot, Integer.MAX_VALUE);
        t.show(screenshot);
        t.apply();
        return screenshot;
    }
}
+22 −17
Original line number Original line Diff line number Diff line
@@ -70,6 +70,7 @@ import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
@@ -1119,6 +1120,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
    private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
            @PipAnimationController.TransitionDirection int direction,
            @PipAnimationController.TransitionDirection int direction,
            @PipAnimationController.AnimationType int type) {
            @PipAnimationController.AnimationType int type) {
        final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds());
        mPipBoundsState.setBounds(destinationBounds);
        mPipBoundsState.setBounds(destinationBounds);
        if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
        if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
            removePipImmediately();
            removePipImmediately();
@@ -1142,19 +1144,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
                && mPictureInPictureParams != null
                && mPictureInPictureParams != null
                && !mPictureInPictureParams.isSeamlessResizeEnabled();
                && !mPictureInPictureParams.isSeamlessResizeEnabled();
        if (animateCrossFadeResize) {
        if (animateCrossFadeResize) {
            // Take a snapshot of the PIP task and hide it. We'll show it and fade it out after
            // Take a snapshot of the PIP task and show it. We'll fade it out after the wct
            // the wct transaction is applied and the activity is laid out again.
            // transaction is applied and the activity is laid out again.
            final SurfaceControl snapshotSurface = mTaskOrganizer.takeScreenshot(mToken);
            preResizeBounds.offsetTo(0, 0);
            mSurfaceTransactionHelper.reparentAndShowSurfaceSnapshot(
            final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(),
                    mSurfaceControlTransactionFactory.getTransaction(), mLeash, snapshotSurface);
                    destinationBounds.height());
            final SurfaceControl snapshotSurface = ScreenshotUtils.takeScreenshot(
                    mSurfaceControlTransactionFactory.getTransaction(), mLeash, preResizeBounds);
            if (snapshotSurface != null) {
                mSyncTransactionQueue.queue(wct);
                mSyncTransactionQueue.queue(wct);
                mSyncTransactionQueue.runInSync(t -> {
                mSyncTransactionQueue.runInSync(t -> {
                    // Scale the snapshot from its pre-resize bounds to the post-resize bounds.
                    // Scale the snapshot from its pre-resize bounds to the post-resize bounds.
                final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(),
                    mSurfaceTransactionHelper.scale(t, snapshotSurface, preResizeBounds,
                        snapshotSurface.getHeight());
                            snapshotDest);
                final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(),
                        destinationBounds.height());
                mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);


                    // Start animation to fade out the snapshot.
                    // Start animation to fade out the snapshot.
                    fadeOutAndRemoveOverlay(snapshotSurface);
                    fadeOutAndRemoveOverlay(snapshotSurface);
@@ -1162,6 +1164,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
            } else {
            } else {
                applyFinishBoundsResize(wct, direction);
                applyFinishBoundsResize(wct, direction);
            }
            }
        } else {
            applyFinishBoundsResize(wct, direction);
        }


        finishResizeForMenu(destinationBounds);
        finishResizeForMenu(destinationBounds);
    }
    }
+0 −42
Original line number Original line Diff line number Diff line
@@ -16,7 +16,6 @@


package com.android.server.wm;
package com.android.server.wm;


import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
@@ -37,8 +36,6 @@ import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Binder;
import android.os.Bundle;
import android.os.Bundle;
@@ -53,7 +50,6 @@ import android.window.ITaskOrganizerController;
import android.window.ITransitionPlayer;
import android.window.ITransitionPlayer;
import android.window.IWindowContainerTransactionCallback;
import android.window.IWindowContainerTransactionCallback;
import android.window.IWindowOrganizerController;
import android.window.IWindowOrganizerController;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
@@ -786,44 +782,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
        mTransactionCallbacksByPendingSyncId.remove(syncId);
        mTransactionCallbacksByPendingSyncId.remove(syncId);
    }
    }


    @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;
        }

        GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
                buffer.getHardwareBuffer());
        SurfaceControl screenshot = mService.mWindowManager.mSurfaceControlFactory.apply(null)
                .setName(wc.getName() + " - Organizer Screenshot")
                .setFormat(PixelFormat.TRANSLUCENT)
                .setParent(wc.getParentSurfaceControl())
                .setSecure(buffer.containsSecureLayers())
                .setCallsite("WindowOrganizerController.takeScreenshot")
                .setBLASTLayer()
                .build();

        SurfaceControl.Transaction transaction = mService.mWindowManager.mTransactionFactory.get();
        transaction.setBuffer(screenshot, graphicBuffer);
        transaction.setColorSpace(screenshot, buffer.getColorSpace());
        transaction.apply();

        outSurfaceControl.copyFrom(screenshot, "WindowOrganizerController.takeScreenshot");
        return true;
    }

    @Override
    @Override
    public void registerTransitionPlayer(ITransitionPlayer player) {
    public void registerTransitionPlayer(ITransitionPlayer player) {
        enforceTaskPermission("registerTransitionPlayer()");
        enforceTaskPermission("registerTransitionPlayer()");