Merge "Take PIP snapshot in the shell and use bounds state size for crossfading" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
eea27600d3
@@ -77,17 +77,6 @@ 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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.app.ActivityTaskManager;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Singleton;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @hide
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,7 @@ import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.animation.Interpolators;
|
||||
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.SyncTransactionQueue;
|
||||
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,
|
||||
@PipAnimationController.TransitionDirection int direction,
|
||||
@PipAnimationController.AnimationType int type) {
|
||||
final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds());
|
||||
mPipBoundsState.setBounds(destinationBounds);
|
||||
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
|
||||
removePipImmediately();
|
||||
@@ -1142,23 +1144,26 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
&& mPictureInPictureParams != null
|
||||
&& !mPictureInPictureParams.isSeamlessResizeEnabled();
|
||||
if (animateCrossFadeResize) {
|
||||
// Take a snapshot of the PIP task and hide it. We'll show it and fade it out after
|
||||
// the wct transaction is applied and the activity is laid out again.
|
||||
final SurfaceControl snapshotSurface = mTaskOrganizer.takeScreenshot(mToken);
|
||||
mSurfaceTransactionHelper.reparentAndShowSurfaceSnapshot(
|
||||
mSurfaceControlTransactionFactory.getTransaction(), mLeash, snapshotSurface);
|
||||
mSyncTransactionQueue.queue(wct);
|
||||
mSyncTransactionQueue.runInSync(t -> {
|
||||
// Scale the snapshot from its pre-resize bounds to the post-resize bounds.
|
||||
final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(),
|
||||
snapshotSurface.getHeight());
|
||||
final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(),
|
||||
destinationBounds.height());
|
||||
mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);
|
||||
// Take a snapshot of the PIP task and show it. We'll fade it out after the wct
|
||||
// transaction is applied and the activity is laid out again.
|
||||
preResizeBounds.offsetTo(0, 0);
|
||||
final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(),
|
||||
destinationBounds.height());
|
||||
final SurfaceControl snapshotSurface = ScreenshotUtils.takeScreenshot(
|
||||
mSurfaceControlTransactionFactory.getTransaction(), mLeash, preResizeBounds);
|
||||
if (snapshotSurface != null) {
|
||||
mSyncTransactionQueue.queue(wct);
|
||||
mSyncTransactionQueue.runInSync(t -> {
|
||||
// Scale the snapshot from its pre-resize bounds to the post-resize bounds.
|
||||
mSurfaceTransactionHelper.scale(t, snapshotSurface, preResizeBounds,
|
||||
snapshotDest);
|
||||
|
||||
// Start animation to fade out the snapshot.
|
||||
fadeOutAndRemoveOverlay(snapshotSurface);
|
||||
});
|
||||
// Start animation to fade out the snapshot.
|
||||
fadeOutAndRemoveOverlay(snapshotSurface);
|
||||
});
|
||||
} else {
|
||||
applyFinishBoundsResize(wct, direction);
|
||||
}
|
||||
} else {
|
||||
applyFinishBoundsResize(wct, direction);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
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_LAUNCH_TASK;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
|
||||
@@ -37,8 +36,6 @@ import android.annotation.Nullable;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
@@ -53,7 +50,6 @@ import android.window.ITaskOrganizerController;
|
||||
import android.window.ITransitionPlayer;
|
||||
import android.window.IWindowContainerTransactionCallback;
|
||||
import android.window.IWindowOrganizerController;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -786,44 +782,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
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
|
||||
public void registerTransitionPlayer(ITransitionPlayer player) {
|
||||
enforceTaskPermission("registerTransitionPlayer()");
|
||||
|
||||
Reference in New Issue
Block a user