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. */
|
/** @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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.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,23 +1144,26 @@ 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());
|
||||||
mSyncTransactionQueue.queue(wct);
|
final SurfaceControl snapshotSurface = ScreenshotUtils.takeScreenshot(
|
||||||
mSyncTransactionQueue.runInSync(t -> {
|
mSurfaceControlTransactionFactory.getTransaction(), mLeash, preResizeBounds);
|
||||||
// Scale the snapshot from its pre-resize bounds to the post-resize bounds.
|
if (snapshotSurface != null) {
|
||||||
final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(),
|
mSyncTransactionQueue.queue(wct);
|
||||||
snapshotSurface.getHeight());
|
mSyncTransactionQueue.runInSync(t -> {
|
||||||
final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(),
|
// Scale the snapshot from its pre-resize bounds to the post-resize bounds.
|
||||||
destinationBounds.height());
|
mSurfaceTransactionHelper.scale(t, snapshotSurface, preResizeBounds,
|
||||||
mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);
|
snapshotDest);
|
||||||
|
|
||||||
// Start animation to fade out the snapshot.
|
// Start animation to fade out the snapshot.
|
||||||
fadeOutAndRemoveOverlay(snapshotSurface);
|
fadeOutAndRemoveOverlay(snapshotSurface);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
applyFinishBoundsResize(wct, direction);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
applyFinishBoundsResize(wct, direction);
|
applyFinishBoundsResize(wct, direction);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()");
|
||||||
|
|||||||
Reference in New Issue
Block a user