Loading core/java/android/window/IWindowOrganizerController.aidl +0 −11 Original line number Original line Diff line number Diff line Loading @@ -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. Loading core/java/android/window/WindowOrganizer.java +0 −23 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java 0 → 100644 +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; } } libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +22 −17 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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); Loading @@ -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); } } Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +0 −42 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()"); Loading Loading
core/java/android/window/IWindowOrganizerController.aidl +0 −11 Original line number Original line Diff line number Diff line Loading @@ -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. Loading
core/java/android/window/WindowOrganizer.java +0 −23 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java 0 → 100644 +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; } }
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +22 −17 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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); Loading @@ -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); } } Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +0 −42 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()"); Loading