Loading core/java/android/window/SnapshotDrawerUtils.java +34 −15 Original line number Diff line number Diff line Loading @@ -118,9 +118,14 @@ public class SnapshotDrawerUtils { mRootSurface = rootSurface; mSnapshot = snapshot; mTitle = title; if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshotH = snapshot.getHardwareBufferHeight(); mSnapshotW = snapshot.getHardwareBufferWidth(); } else { final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); mSnapshotW = hwBuffer.getWidth(); mSnapshotH = hwBuffer.getHeight(); } mContainerW = windowBounds.width(); mContainerH = windowBounds.height(); } Loading @@ -140,31 +145,41 @@ public class SnapshotDrawerUtils { } // In case window manager leaks us, make sure we don't retain the snapshot. if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshot.closeBuffer(); } else { if (mSnapshot.getHardwareBuffer() != null) { mSnapshot.getHardwareBuffer().close(); } } if (releaseAfterDraw) { mRootSurface.release(); } } private void drawSizeMatchSnapshot() { mTransaction.setBuffer(mRootSurface, mSnapshot.getHardwareBuffer()) .setColorSpace(mRootSurface, mSnapshot.getColorSpace()) .apply(); if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshot.setBufferToSurface(mTransaction, mRootSurface); } else { mTransaction.setBuffer(mRootSurface, mSnapshot.getHardwareBuffer()); } mTransaction.setColorSpace(mRootSurface, mSnapshot.getColorSpace()).apply(); } private void drawSizeMismatchSnapshot() { final HardwareBuffer buffer = mSnapshot.getHardwareBuffer(); // Keep a reference to it such that it doesn't get destroyed when finalized. SurfaceControl childSurfaceControl = new SurfaceControl.Builder() final SurfaceControl.Builder builder = new SurfaceControl.Builder() .setName(mTitle + " - task-snapshot-surface") .setBLASTLayer() .setFormat(buffer.getFormat()) .setParent(mRootSurface) .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot") .build(); .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot"); if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { builder.setFormat(mSnapshot.getHardwareBufferFormat()); } else { final HardwareBuffer buffer = mSnapshot.getHardwareBuffer(); builder.setFormat(buffer.getFormat()); } SurfaceControl childSurfaceControl = builder.build(); final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); float offsetX = letterboxInsets.left; Loading @@ -184,7 +199,11 @@ public class SnapshotDrawerUtils { final float scaleY = (float) mContainerH / mSnapshotH; mTransaction.setScale(childSurfaceControl, scaleX, scaleY); mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace()); if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshot.setBufferToSurface(mTransaction, childSurfaceControl); } else { mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer()); } mTransaction.apply(); childSurfaceControl.release(); } Loading core/java/android/window/TaskSnapshot.java +109 −0 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package android.window; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.Point; Loading @@ -33,8 +35,12 @@ import android.os.Parcelable; import android.os.SystemClock; import android.util.DisplayMetrics; import android.view.Surface; import android.view.SurfaceControl; import android.view.WindowInsetsController; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.TransitionAnimation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.function.Consumer; Loading Loading @@ -185,19 +191,122 @@ public class TaskSnapshot implements Parcelable { * * Note: Prefer {@link #getHardwareBuffer}, which returns the internal object. This version * creates a new object. * * @deprecated Do not access hardware buffer directly. */ @UnsupportedAppUsage @Deprecated public GraphicBuffer getSnapshot() { return GraphicBuffer.createFromHardwareBuffer(mSnapshot); } /** * @return The hardware buffer representing the screenshot. * @deprecated Do not access hardware buffer directly. */ @Deprecated public HardwareBuffer getHardwareBuffer() { return mSnapshot; } /** * Returns the width from the hardware buffer. */ public int getHardwareBufferWidth() { return mSnapshot.getWidth(); } /** * Returns the height from the hardware buffer. */ public int getHardwareBufferHeight() { return mSnapshot.getHeight(); } /** * Returns the format from the hardware buffer. */ public @HardwareBuffer.Format int getHardwareBufferFormat() { return mSnapshot.getFormat(); } /** * Sets hardware buffer to a SurfaceControl. */ public void setBufferToSurface(SurfaceControl.Transaction t, SurfaceControl surface) { if (!isBufferValid()) { return; } t.setBuffer(surface, mSnapshot); } /** * Creates a bitmap from the hardware buffer, this can return null if the hardware buffer is * closed or not exists. */ public Bitmap wrapToBitmap() { if (!isBufferValid()) { return null; } return Bitmap.wrapHardwareBuffer(mSnapshot, mColorSpace); } /** * Creates a bitmap from the hardware buffer with specific ColorSpace. This can return null if * the hardware buffer is closed or not exists. */ public Bitmap wrapToBitmap(@Nullable ColorSpace colorSpace) { if (!isBufferValid()) { return null; } return Bitmap.wrapHardwareBuffer(mSnapshot, colorSpace); } /** * Actively close hardware buffer. */ public void closeBuffer() { if (isBufferValid()) { mSnapshot.close(); } } /** * Returns whether the hardware buffer is valid. */ public boolean isBufferValid() { return mSnapshot != null && !mSnapshot.isClosed(); } /** * Returns whether the hardware buffer has protected content. */ public boolean hasProtectedContent() { if (!isBufferValid()) { return false; } return TransitionAnimation.hasProtectedContent(mSnapshot); } /** * Attach the hardware buffer and color space to a Surface. */ public void attachAndQueueBufferWithColorSpace(@NonNull Surface surface) { if (!isBufferValid()) { return; } surface.attachAndQueueBufferWithColorSpace(mSnapshot, mColorSpace); } /** * Test only */ @VisibleForTesting public boolean isSameHardwareBuffer(@NonNull HardwareBuffer buffer) { return buffer == mSnapshot; } /** * @return The color space of hardware buffer representing the screenshot. */ Loading core/java/android/window/TaskSnapshotManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.window; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.app.ActivityTaskManager; import android.os.RemoteException; import android.util.Singleton; Loading Loading @@ -139,6 +140,8 @@ public class TaskSnapshotManager { private static final Singleton<ITaskSnapshotManager> ISnapshotManagerSingleton = new Singleton<ITaskSnapshotManager>() { @RequiresPermission(allOf = {android.Manifest.permission.MANAGE_ACTIVITY_TASKS, android.Manifest.permission.READ_FRAME_BUFFER}) @Override protected ITaskSnapshotManager create() { try { Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java +17 −5 Original line number Diff line number Diff line Loading @@ -143,13 +143,25 @@ public abstract class PipContentOverlay { @Override public void attach(SurfaceControl.Transaction tx, SurfaceControl parentLeash) { final float taskSnapshotScaleX = (float) mSnapshot.getTaskSize().x / mSnapshot.getHardwareBuffer().getWidth(); final float taskSnapshotScaleY = (float) mSnapshot.getTaskSize().y / mSnapshot.getHardwareBuffer().getHeight(); final float taskSnapshotScaleX; final float taskSnapshotScaleY; if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { taskSnapshotScaleX = (float) mSnapshot.getTaskSize().x / mSnapshot.getHardwareBufferWidth(); taskSnapshotScaleY = (float) mSnapshot.getTaskSize().y / mSnapshot.getHardwareBufferHeight(); mSnapshot.setBufferToSurface(tx, mLeash); } else { final HardwareBuffer hw = mSnapshot.getHardwareBuffer(); taskSnapshotScaleX = (float) mSnapshot.getTaskSize().x / hw.getWidth(); taskSnapshotScaleY = (float) mSnapshot.getTaskSize().y / hw.getHeight(); tx.setBuffer(mLeash, hw); } tx.show(mLeash); tx.setLayer(mLeash, Integer.MAX_VALUE); tx.setBuffer(mLeash, mSnapshot.getHardwareBuffer()); // Relocate the content to parentLeash's coordinates. tx.setPosition(mLeash, -mSourceRectHint.left, -mSourceRectHint.top); tx.setScale(mLeash, taskSnapshotScaleX, taskSnapshotScaleY); Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +4 −1 Original line number Diff line number Diff line Loading @@ -86,9 +86,12 @@ public class TaskSnapshotWindow { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId); final int format = com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage() ? snapshot.getHardwareBufferFormat() : snapshot.getHardwareBuffer().getFormat(); final WindowManager.LayoutParams layoutParams = SnapshotDrawerUtils.createLayoutParameters( info, TITLE_FORMAT + taskId, TYPE_APPLICATION_STARTING, snapshot.getHardwareBuffer().getFormat(), appToken); format, appToken); if (layoutParams == null) { Slog.e(TAG, "TaskSnapshotWindow no layoutParams"); return null; Loading Loading
core/java/android/window/SnapshotDrawerUtils.java +34 −15 Original line number Diff line number Diff line Loading @@ -118,9 +118,14 @@ public class SnapshotDrawerUtils { mRootSurface = rootSurface; mSnapshot = snapshot; mTitle = title; if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshotH = snapshot.getHardwareBufferHeight(); mSnapshotW = snapshot.getHardwareBufferWidth(); } else { final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); mSnapshotW = hwBuffer.getWidth(); mSnapshotH = hwBuffer.getHeight(); } mContainerW = windowBounds.width(); mContainerH = windowBounds.height(); } Loading @@ -140,31 +145,41 @@ public class SnapshotDrawerUtils { } // In case window manager leaks us, make sure we don't retain the snapshot. if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshot.closeBuffer(); } else { if (mSnapshot.getHardwareBuffer() != null) { mSnapshot.getHardwareBuffer().close(); } } if (releaseAfterDraw) { mRootSurface.release(); } } private void drawSizeMatchSnapshot() { mTransaction.setBuffer(mRootSurface, mSnapshot.getHardwareBuffer()) .setColorSpace(mRootSurface, mSnapshot.getColorSpace()) .apply(); if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshot.setBufferToSurface(mTransaction, mRootSurface); } else { mTransaction.setBuffer(mRootSurface, mSnapshot.getHardwareBuffer()); } mTransaction.setColorSpace(mRootSurface, mSnapshot.getColorSpace()).apply(); } private void drawSizeMismatchSnapshot() { final HardwareBuffer buffer = mSnapshot.getHardwareBuffer(); // Keep a reference to it such that it doesn't get destroyed when finalized. SurfaceControl childSurfaceControl = new SurfaceControl.Builder() final SurfaceControl.Builder builder = new SurfaceControl.Builder() .setName(mTitle + " - task-snapshot-surface") .setBLASTLayer() .setFormat(buffer.getFormat()) .setParent(mRootSurface) .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot") .build(); .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot"); if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { builder.setFormat(mSnapshot.getHardwareBufferFormat()); } else { final HardwareBuffer buffer = mSnapshot.getHardwareBuffer(); builder.setFormat(buffer.getFormat()); } SurfaceControl childSurfaceControl = builder.build(); final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); float offsetX = letterboxInsets.left; Loading @@ -184,7 +199,11 @@ public class SnapshotDrawerUtils { final float scaleY = (float) mContainerH / mSnapshotH; mTransaction.setScale(childSurfaceControl, scaleX, scaleY); mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace()); if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { mSnapshot.setBufferToSurface(mTransaction, childSurfaceControl); } else { mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer()); } mTransaction.apply(); childSurfaceControl.release(); } Loading
core/java/android/window/TaskSnapshot.java +109 −0 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package android.window; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.Point; Loading @@ -33,8 +35,12 @@ import android.os.Parcelable; import android.os.SystemClock; import android.util.DisplayMetrics; import android.view.Surface; import android.view.SurfaceControl; import android.view.WindowInsetsController; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.TransitionAnimation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.function.Consumer; Loading Loading @@ -185,19 +191,122 @@ public class TaskSnapshot implements Parcelable { * * Note: Prefer {@link #getHardwareBuffer}, which returns the internal object. This version * creates a new object. * * @deprecated Do not access hardware buffer directly. */ @UnsupportedAppUsage @Deprecated public GraphicBuffer getSnapshot() { return GraphicBuffer.createFromHardwareBuffer(mSnapshot); } /** * @return The hardware buffer representing the screenshot. * @deprecated Do not access hardware buffer directly. */ @Deprecated public HardwareBuffer getHardwareBuffer() { return mSnapshot; } /** * Returns the width from the hardware buffer. */ public int getHardwareBufferWidth() { return mSnapshot.getWidth(); } /** * Returns the height from the hardware buffer. */ public int getHardwareBufferHeight() { return mSnapshot.getHeight(); } /** * Returns the format from the hardware buffer. */ public @HardwareBuffer.Format int getHardwareBufferFormat() { return mSnapshot.getFormat(); } /** * Sets hardware buffer to a SurfaceControl. */ public void setBufferToSurface(SurfaceControl.Transaction t, SurfaceControl surface) { if (!isBufferValid()) { return; } t.setBuffer(surface, mSnapshot); } /** * Creates a bitmap from the hardware buffer, this can return null if the hardware buffer is * closed or not exists. */ public Bitmap wrapToBitmap() { if (!isBufferValid()) { return null; } return Bitmap.wrapHardwareBuffer(mSnapshot, mColorSpace); } /** * Creates a bitmap from the hardware buffer with specific ColorSpace. This can return null if * the hardware buffer is closed or not exists. */ public Bitmap wrapToBitmap(@Nullable ColorSpace colorSpace) { if (!isBufferValid()) { return null; } return Bitmap.wrapHardwareBuffer(mSnapshot, colorSpace); } /** * Actively close hardware buffer. */ public void closeBuffer() { if (isBufferValid()) { mSnapshot.close(); } } /** * Returns whether the hardware buffer is valid. */ public boolean isBufferValid() { return mSnapshot != null && !mSnapshot.isClosed(); } /** * Returns whether the hardware buffer has protected content. */ public boolean hasProtectedContent() { if (!isBufferValid()) { return false; } return TransitionAnimation.hasProtectedContent(mSnapshot); } /** * Attach the hardware buffer and color space to a Surface. */ public void attachAndQueueBufferWithColorSpace(@NonNull Surface surface) { if (!isBufferValid()) { return; } surface.attachAndQueueBufferWithColorSpace(mSnapshot, mColorSpace); } /** * Test only */ @VisibleForTesting public boolean isSameHardwareBuffer(@NonNull HardwareBuffer buffer) { return buffer == mSnapshot; } /** * @return The color space of hardware buffer representing the screenshot. */ Loading
core/java/android/window/TaskSnapshotManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.window; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.app.ActivityTaskManager; import android.os.RemoteException; import android.util.Singleton; Loading Loading @@ -139,6 +140,8 @@ public class TaskSnapshotManager { private static final Singleton<ITaskSnapshotManager> ISnapshotManagerSingleton = new Singleton<ITaskSnapshotManager>() { @RequiresPermission(allOf = {android.Manifest.permission.MANAGE_ACTIVITY_TASKS, android.Manifest.permission.READ_FRAME_BUFFER}) @Override protected ITaskSnapshotManager create() { try { Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java +17 −5 Original line number Diff line number Diff line Loading @@ -143,13 +143,25 @@ public abstract class PipContentOverlay { @Override public void attach(SurfaceControl.Transaction tx, SurfaceControl parentLeash) { final float taskSnapshotScaleX = (float) mSnapshot.getTaskSize().x / mSnapshot.getHardwareBuffer().getWidth(); final float taskSnapshotScaleY = (float) mSnapshot.getTaskSize().y / mSnapshot.getHardwareBuffer().getHeight(); final float taskSnapshotScaleX; final float taskSnapshotScaleY; if (com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage()) { taskSnapshotScaleX = (float) mSnapshot.getTaskSize().x / mSnapshot.getHardwareBufferWidth(); taskSnapshotScaleY = (float) mSnapshot.getTaskSize().y / mSnapshot.getHardwareBufferHeight(); mSnapshot.setBufferToSurface(tx, mLeash); } else { final HardwareBuffer hw = mSnapshot.getHardwareBuffer(); taskSnapshotScaleX = (float) mSnapshot.getTaskSize().x / hw.getWidth(); taskSnapshotScaleY = (float) mSnapshot.getTaskSize().y / hw.getHeight(); tx.setBuffer(mLeash, hw); } tx.show(mLeash); tx.setLayer(mLeash, Integer.MAX_VALUE); tx.setBuffer(mLeash, mSnapshot.getHardwareBuffer()); // Relocate the content to parentLeash's coordinates. tx.setPosition(mLeash, -mSourceRectHint.left, -mSourceRectHint.top); tx.setScale(mLeash, taskSnapshotScaleX, taskSnapshotScaleY); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +4 −1 Original line number Diff line number Diff line Loading @@ -86,9 +86,12 @@ public class TaskSnapshotWindow { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId); final int format = com.android.window.flags.Flags.reduceTaskSnapshotMemoryUsage() ? snapshot.getHardwareBufferFormat() : snapshot.getHardwareBuffer().getFormat(); final WindowManager.LayoutParams layoutParams = SnapshotDrawerUtils.createLayoutParameters( info, TITLE_FORMAT + taskId, TYPE_APPLICATION_STARTING, snapshot.getHardwareBuffer().getFormat(), appToken); format, appToken); if (layoutParams == null) { Slog.e(TAG, "TaskSnapshotWindow no layoutParams"); return null; Loading