Loading core/java/android/window/SnapshotDrawerUtils.java +21 −219 Original line number Diff line number Diff line Loading @@ -44,20 +44,16 @@ import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_AT import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getNavigationBarRect; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; import android.content.Context; import android.graphics.Canvas; import android.graphics.GraphicBuffer; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.util.Log; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.ViewGroup; import android.view.WindowInsets; Loading @@ -66,7 +62,6 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; import com.android.window.flags.Flags; /** * Utils class to help draw a snapshot on a surface. Loading Loading @@ -103,8 +98,6 @@ public class SnapshotDrawerUtils { | FLAG_SECURE | FLAG_DIM_BEHIND; private static final Paint sBackgroundPaint = new Paint(); /** * The internal object to hold the surface and drawing on it. */ Loading @@ -115,54 +108,29 @@ public class SnapshotDrawerUtils { private final TaskSnapshot mSnapshot; private final CharSequence mTitle; private SystemBarBackgroundPainter mSystemBarBackgroundPainter; private final Rect mFrame = new Rect(); private final Rect mSystemBarInsets = new Rect(); private final int mSnapshotW; private final int mSnapshotH; private boolean mSizeMismatch; private final int mContainerW; private final int mContainerH; public SnapshotSurface(SurfaceControl rootSurface, TaskSnapshot snapshot, CharSequence title) { Rect windowBounds, CharSequence title) { mRootSurface = rootSurface; mSnapshot = snapshot; mTitle = title; final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); mSnapshotW = hwBuffer.getWidth(); mSnapshotH = hwBuffer.getHeight(); mContainerW = windowBounds.width(); mContainerH = windowBounds.height(); } /** * Initiate system bar painter to draw the system bar background. */ @VisibleForTesting public void initiateSystemBarPainter(int windowFlags, int windowPrivateFlags, int appearance, ActivityManager.TaskDescription taskDescription, @WindowInsets.Type.InsetsType int requestedVisibleTypes) { mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags, windowPrivateFlags, appearance, taskDescription, 1f, requestedVisibleTypes); int backgroundColor = taskDescription.getBackgroundColor(); sBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE); } /** * Set frame size that the snapshot should fill. It is the bounds of a task or activity. */ @VisibleForTesting public void setFrames(Rect frame, Rect systemBarInsets) { mFrame.set(frame); private void drawSnapshot(boolean releaseAfterDraw) { final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); mSizeMismatch = (mFrame.width() != mSnapshotW || mFrame.height() != mSnapshotH) final boolean sizeMismatch = mContainerW != mSnapshotW || mContainerH != mSnapshotH || letterboxInsets.left != 0 || letterboxInsets.top != 0; if (!Flags.drawSnapshotAspectRatioMatch() && systemBarInsets != null) { mSystemBarInsets.set(systemBarInsets); mSystemBarBackgroundPainter.setInsets(systemBarInsets); } } private void drawSnapshot(boolean releaseAfterDraw) { Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + mSizeMismatch); if (mSizeMismatch) { Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + sizeMismatch); if (sizeMismatch) { // The dimensions of the buffer and the window don't match, so attaching the buffer // will fail. Better create a child window with the exact dimensions and fill the // parent window with the background color! Loading @@ -189,11 +157,6 @@ public class SnapshotDrawerUtils { private void drawSizeMismatchSnapshot() { final HardwareBuffer buffer = mSnapshot.getHardwareBuffer(); // We consider nearly matched dimensions as there can be rounding errors and the user // won't notice very minute differences from scaling one dimension more than the other boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshotW, mSnapshotH) && !Flags.drawSnapshotAspectRatioMatch(); // Keep a reference to it such that it doesn't get destroyed when finalized. SurfaceControl childSurfaceControl = new SurfaceControl.Builder() .setName(mTitle + " - task-snapshot-surface") Loading @@ -203,166 +166,28 @@ public class SnapshotDrawerUtils { .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot") .build(); final Rect frame; final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); float offsetX = letterboxInsets.left; float offsetY = letterboxInsets.top; // We can just show the surface here as it will still be hidden as the parent is // still hidden. mTransaction.show(childSurfaceControl); if (aspectRatioMismatch) { Rect crop = null; if (letterboxInsets.left != 0 || letterboxInsets.top != 0 || letterboxInsets.right != 0 || letterboxInsets.bottom != 0) { // Clip off letterbox. crop = calculateSnapshotCrop(letterboxInsets); // If the snapshot can cover the frame, then no need to draw background. aspectRatioMismatch = !isAspectRatioMatch(mFrame, crop); } // if letterbox doesn't match window frame, try crop by content insets if (aspectRatioMismatch) { // Clip off ugly navigation bar. final Rect contentInsets = mSnapshot.getContentInsets(); crop = calculateSnapshotCrop(contentInsets); offsetX = contentInsets.left; offsetY = contentInsets.top; } frame = calculateSnapshotFrame(crop); mTransaction.setCrop(childSurfaceControl, crop); } else { frame = null; } // Align the snapshot with content area. if (offsetX != 0f || offsetY != 0f) { mTransaction.setPosition(childSurfaceControl, -offsetX * mFrame.width() / mSnapshot.getTaskSize().x, -offsetY * mFrame.height() / mSnapshot.getTaskSize().y); -offsetX * mContainerW / mSnapshot.getTaskSize().x, -offsetY * mContainerH / mSnapshot.getTaskSize().y); } // Scale the mismatch dimensions to fill the target frame. final float scaleX = (float) mFrame.width() / mSnapshotW; final float scaleY = (float) mFrame.height() / mSnapshotH; final float scaleX = (float) mContainerW / mSnapshotW; final float scaleY = (float) mContainerH / mSnapshotH; mTransaction.setScale(childSurfaceControl, scaleX, scaleY); mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace()); mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer()); if (aspectRatioMismatch) { GraphicBuffer background = GraphicBuffer.create(mFrame.width(), mFrame.height(), PixelFormat.RGBA_8888, GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER | GraphicBuffer.USAGE_SW_WRITE_RARELY); final Canvas c = background != null ? background.lockCanvas() : null; if (c == null) { Log.e(TAG, "Unable to draw snapshot: failed to allocate graphic buffer for " + mTitle); mTransaction.clear(); childSurfaceControl.release(); return; } drawBackgroundAndBars(c, frame); background.unlockCanvasAndPost(c); mTransaction.setBuffer(mRootSurface, HardwareBuffer.createFromGraphicBuffer(background)); } mTransaction.apply(); childSurfaceControl.release(); } /** * Calculates the snapshot crop in snapshot coordinate space. * @param insets Content insets or Letterbox insets * @return crop rect in snapshot coordinate space. */ @VisibleForTesting public Rect calculateSnapshotCrop(@NonNull Rect insets) { final Rect rect = new Rect(); rect.set(0, 0, mSnapshotW, mSnapshotH); final float scaleX = (float) mSnapshotW / mSnapshot.getTaskSize().x; final float scaleY = (float) mSnapshotH / mSnapshot.getTaskSize().y; // Let's remove all system decorations except the status bar, but only if the task is at // the very top of the screen. final boolean isTop = mFrame.top == 0; rect.inset((int) (insets.left * scaleX), isTop ? 0 : (int) (insets.top * scaleY), (int) (insets.right * scaleX), (int) (insets.bottom * scaleY)); return rect; } /** * Calculates the snapshot frame in window coordinate space from crop. * * @param crop rect that is in snapshot coordinate space. */ @VisibleForTesting public Rect calculateSnapshotFrame(Rect crop) { final float scaleX = (float) mSnapshotW / mSnapshot.getTaskSize().x; final float scaleY = (float) mSnapshotH / mSnapshot.getTaskSize().y; // Rescale the frame from snapshot to window coordinate space final Rect frame = new Rect(0, 0, (int) (crop.width() / scaleX + 0.5f), (int) (crop.height() / scaleY + 0.5f) ); // However, we also need to make space for the navigation bar on the left side. frame.offset(mSystemBarInsets.left, 0); return frame; } /** * Draw status bar and navigation bar background. */ @VisibleForTesting public void drawBackgroundAndBars(Canvas c, Rect frame) { final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight(); final boolean fillHorizontally = c.getWidth() > frame.right; final boolean fillVertically = c.getHeight() > frame.bottom; if (fillHorizontally) { c.drawRect(frame.right, alpha(mSystemBarBackgroundPainter.mStatusBarColor) == 0xFF ? statusBarHeight : 0, c.getWidth(), fillVertically ? frame.bottom : c.getHeight(), sBackgroundPaint); } if (fillVertically) { c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), sBackgroundPaint); } mSystemBarBackgroundPainter.drawDecors(c, frame); } /** * Ask system bar background painter to draw status bar background. */ @VisibleForTesting public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) { mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame, mSystemBarBackgroundPainter.getStatusBarColorViewHeight()); } /** * Ask system bar background painter to draw navigation bar background. */ @VisibleForTesting public void drawNavigationBarBackground(Canvas c) { mSystemBarBackgroundPainter.drawNavigationBarBackground(c); } } private static boolean isAspectRatioMatch(Rect frame, int w, int h) { if (frame.isEmpty()) { return false; } return Math.abs(((float) w / h) - ((float) frame.width() / frame.height())) <= 0.01f; } private static boolean isAspectRatioMatch(Rect frame1, Rect frame2) { if (frame1.isEmpty() || frame2.isEmpty()) { return false; } return Math.abs( ((float) frame2.width() / frame2.height()) - ((float) frame1.width() / frame1.height())) <= 0.01f; } /** Loading @@ -383,28 +208,15 @@ public class SnapshotDrawerUtils { /** * Help method to draw the snapshot on a surface. */ public static void drawSnapshotOnSurface(StartingWindowInfo info, WindowManager.LayoutParams lp, public static void drawSnapshotOnSurface(WindowManager.LayoutParams lp, SurfaceControl rootSurface, TaskSnapshot snapshot, Rect windowBounds, InsetsState topWindowInsetsState, boolean releaseAfterDraw) { Rect windowBounds, boolean releaseAfterDraw) { if (windowBounds.isEmpty()) { Log.e(TAG, "Unable to draw snapshot on an empty windowBounds"); return; } final SnapshotSurface drawSurface = new SnapshotSurface( rootSurface, snapshot, lp.getTitle()); final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo; final ActivityManager.TaskDescription taskDescription = getOrCreateTaskDescription(runningTaskInfo); Rect systemBarInsets = null; if (!Flags.drawSnapshotAspectRatioMatch()) { drawSurface.initiateSystemBarPainter(lp.flags, lp.privateFlags, attrs.insetsFlags.appearance, taskDescription, info.requestedVisibleTypes); systemBarInsets = getSystemBarInsets(windowBounds, topWindowInsetsState); } drawSurface.setFrames(windowBounds, systemBarInsets); rootSurface, snapshot, windowBounds, lp.getTitle()); drawSurface.drawSnapshot(releaseAfterDraw); } Loading @@ -414,10 +226,8 @@ public class SnapshotDrawerUtils { public static WindowManager.LayoutParams createLayoutParameters(StartingWindowInfo info, CharSequence title, @WindowManager.LayoutParams.WindowType int windowType, int pixelFormat, IBinder token) { final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams; if (attrs == null || mainWindowParams == null) { final WindowManager.LayoutParams attrs = info.mainWindowLayoutParams; if (attrs == null) { Log.w(TAG, "unable to create taskSnapshot surface "); return null; } Loading @@ -427,9 +237,9 @@ public class SnapshotDrawerUtils { final int windowFlags = attrs.flags; final int windowPrivateFlags = attrs.privateFlags; layoutParams.packageName = mainWindowParams.packageName; layoutParams.windowAnimations = mainWindowParams.windowAnimations; layoutParams.dimAmount = mainWindowParams.dimAmount; layoutParams.packageName = attrs.packageName; layoutParams.windowAnimations = attrs.windowAnimations; layoutParams.dimAmount = attrs.dimAmount; layoutParams.type = windowType; layoutParams.format = pixelFormat; layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES) Loading Loading @@ -460,14 +270,6 @@ public class SnapshotDrawerUtils { return layoutParams; } static Rect getSystemBarInsets(Rect frame, @Nullable InsetsState state) { if (state == null) { return new Rect(); } return state.calculateInsets(frame, WindowInsets.Type.systemBars(), false /* ignoreVisibility */).toRect(); } /** * Helper class to draw the background of the system bars in regions the task snapshot isn't * filling the window. Loading core/java/android/window/StartingWindowInfo.java +0 −22 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; Loading Loading @@ -99,20 +98,6 @@ public final class StartingWindowInfo implements Parcelable { @Nullable public ActivityInfo targetActivityInfo; /** * InsetsState of TopFullscreenOpaqueWindow * @hide */ @Nullable public InsetsState topOpaqueWindowInsetsState; /** * LayoutParams of TopFullscreenOpaqueWindow * @hide */ @Nullable public WindowManager.LayoutParams topOpaqueWindowLayoutParams; /** * LayoutParams of MainWindow * @hide Loading Loading @@ -263,8 +248,6 @@ public final class StartingWindowInfo implements Parcelable { taskBounds.writeToParcel(dest, flags); dest.writeTypedObject(targetActivityInfo, flags); dest.writeInt(startingWindowTypeParameter); dest.writeTypedObject(topOpaqueWindowInsetsState, flags); dest.writeTypedObject(topOpaqueWindowLayoutParams, flags); dest.writeTypedObject(mainWindowLayoutParams, flags); dest.writeInt(splashScreenThemeResId); dest.writeBoolean(isKeyguardOccluded); Loading @@ -280,9 +263,6 @@ public final class StartingWindowInfo implements Parcelable { taskBounds.readFromParcel(source); targetActivityInfo = source.readTypedObject(ActivityInfo.CREATOR); startingWindowTypeParameter = source.readInt(); topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR); topOpaqueWindowLayoutParams = source.readTypedObject( WindowManager.LayoutParams.CREATOR); mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR); splashScreenThemeResId = source.readInt(); isKeyguardOccluded = source.readBoolean(); Loading @@ -302,8 +282,6 @@ public final class StartingWindowInfo implements Parcelable { + " topActivityType=" + taskInfo.topActivityType + " preferredStartingWindowType=" + Integer.toHexString(startingWindowTypeParameter) + " insetsState=" + topOpaqueWindowInsetsState + " topWindowLayoutParams=" + topOpaqueWindowLayoutParams + " mainWindowLayoutParams=" + mainWindowLayoutParams + " splashScreenThemeResId " + Integer.toHexString(splashScreenThemeResId); } Loading core/java/android/window/flags/windowing_frontend.aconfig +0 −11 Original line number Diff line number Diff line Loading @@ -242,17 +242,6 @@ flag { is_fixed_read_only: true } flag { name: "draw_snapshot_aspect_ratio_match" namespace: "windowing_frontend" description: "The aspect ratio should always match when drawing snapshot" bug: "341020277" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { name: "system_ui_post_animation_end" namespace: "windowing_frontend" Loading core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java +17 −162 File changed.Preview size limit exceeded, changes collapsed. Show changes libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +2 −4 Original line number Diff line number Diff line Loading @@ -89,8 +89,6 @@ public class TaskSnapshotWindow { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId); final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState; final WindowManager.LayoutParams layoutParams = SnapshotDrawerUtils.createLayoutParameters( info, TITLE_FORMAT + taskId, TYPE_APPLICATION_STARTING, snapshot.getHardwareBuffer().getFormat(), appToken); Loading Loading @@ -152,8 +150,8 @@ public class TaskSnapshotWindow { return null; } SnapshotDrawerUtils.drawSnapshotOnSurface(info, layoutParams, surfaceControl, snapshot, info.taskBounds, topWindowInsetsState, true /* releaseAfterDraw */); SnapshotDrawerUtils.drawSnapshotOnSurface(layoutParams, surfaceControl, snapshot, info.taskBounds, true /* releaseAfterDraw */); snapshotSurface.mHasDrawn = true; snapshotSurface.reportDrawn(); Loading Loading
core/java/android/window/SnapshotDrawerUtils.java +21 −219 Original line number Diff line number Diff line Loading @@ -44,20 +44,16 @@ import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_AT import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getNavigationBarRect; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; import android.content.Context; import android.graphics.Canvas; import android.graphics.GraphicBuffer; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.util.Log; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.ViewGroup; import android.view.WindowInsets; Loading @@ -66,7 +62,6 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; import com.android.window.flags.Flags; /** * Utils class to help draw a snapshot on a surface. Loading Loading @@ -103,8 +98,6 @@ public class SnapshotDrawerUtils { | FLAG_SECURE | FLAG_DIM_BEHIND; private static final Paint sBackgroundPaint = new Paint(); /** * The internal object to hold the surface and drawing on it. */ Loading @@ -115,54 +108,29 @@ public class SnapshotDrawerUtils { private final TaskSnapshot mSnapshot; private final CharSequence mTitle; private SystemBarBackgroundPainter mSystemBarBackgroundPainter; private final Rect mFrame = new Rect(); private final Rect mSystemBarInsets = new Rect(); private final int mSnapshotW; private final int mSnapshotH; private boolean mSizeMismatch; private final int mContainerW; private final int mContainerH; public SnapshotSurface(SurfaceControl rootSurface, TaskSnapshot snapshot, CharSequence title) { Rect windowBounds, CharSequence title) { mRootSurface = rootSurface; mSnapshot = snapshot; mTitle = title; final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); mSnapshotW = hwBuffer.getWidth(); mSnapshotH = hwBuffer.getHeight(); mContainerW = windowBounds.width(); mContainerH = windowBounds.height(); } /** * Initiate system bar painter to draw the system bar background. */ @VisibleForTesting public void initiateSystemBarPainter(int windowFlags, int windowPrivateFlags, int appearance, ActivityManager.TaskDescription taskDescription, @WindowInsets.Type.InsetsType int requestedVisibleTypes) { mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags, windowPrivateFlags, appearance, taskDescription, 1f, requestedVisibleTypes); int backgroundColor = taskDescription.getBackgroundColor(); sBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE); } /** * Set frame size that the snapshot should fill. It is the bounds of a task or activity. */ @VisibleForTesting public void setFrames(Rect frame, Rect systemBarInsets) { mFrame.set(frame); private void drawSnapshot(boolean releaseAfterDraw) { final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); mSizeMismatch = (mFrame.width() != mSnapshotW || mFrame.height() != mSnapshotH) final boolean sizeMismatch = mContainerW != mSnapshotW || mContainerH != mSnapshotH || letterboxInsets.left != 0 || letterboxInsets.top != 0; if (!Flags.drawSnapshotAspectRatioMatch() && systemBarInsets != null) { mSystemBarInsets.set(systemBarInsets); mSystemBarBackgroundPainter.setInsets(systemBarInsets); } } private void drawSnapshot(boolean releaseAfterDraw) { Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + mSizeMismatch); if (mSizeMismatch) { Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + sizeMismatch); if (sizeMismatch) { // The dimensions of the buffer and the window don't match, so attaching the buffer // will fail. Better create a child window with the exact dimensions and fill the // parent window with the background color! Loading @@ -189,11 +157,6 @@ public class SnapshotDrawerUtils { private void drawSizeMismatchSnapshot() { final HardwareBuffer buffer = mSnapshot.getHardwareBuffer(); // We consider nearly matched dimensions as there can be rounding errors and the user // won't notice very minute differences from scaling one dimension more than the other boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshotW, mSnapshotH) && !Flags.drawSnapshotAspectRatioMatch(); // Keep a reference to it such that it doesn't get destroyed when finalized. SurfaceControl childSurfaceControl = new SurfaceControl.Builder() .setName(mTitle + " - task-snapshot-surface") Loading @@ -203,166 +166,28 @@ public class SnapshotDrawerUtils { .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot") .build(); final Rect frame; final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); float offsetX = letterboxInsets.left; float offsetY = letterboxInsets.top; // We can just show the surface here as it will still be hidden as the parent is // still hidden. mTransaction.show(childSurfaceControl); if (aspectRatioMismatch) { Rect crop = null; if (letterboxInsets.left != 0 || letterboxInsets.top != 0 || letterboxInsets.right != 0 || letterboxInsets.bottom != 0) { // Clip off letterbox. crop = calculateSnapshotCrop(letterboxInsets); // If the snapshot can cover the frame, then no need to draw background. aspectRatioMismatch = !isAspectRatioMatch(mFrame, crop); } // if letterbox doesn't match window frame, try crop by content insets if (aspectRatioMismatch) { // Clip off ugly navigation bar. final Rect contentInsets = mSnapshot.getContentInsets(); crop = calculateSnapshotCrop(contentInsets); offsetX = contentInsets.left; offsetY = contentInsets.top; } frame = calculateSnapshotFrame(crop); mTransaction.setCrop(childSurfaceControl, crop); } else { frame = null; } // Align the snapshot with content area. if (offsetX != 0f || offsetY != 0f) { mTransaction.setPosition(childSurfaceControl, -offsetX * mFrame.width() / mSnapshot.getTaskSize().x, -offsetY * mFrame.height() / mSnapshot.getTaskSize().y); -offsetX * mContainerW / mSnapshot.getTaskSize().x, -offsetY * mContainerH / mSnapshot.getTaskSize().y); } // Scale the mismatch dimensions to fill the target frame. final float scaleX = (float) mFrame.width() / mSnapshotW; final float scaleY = (float) mFrame.height() / mSnapshotH; final float scaleX = (float) mContainerW / mSnapshotW; final float scaleY = (float) mContainerH / mSnapshotH; mTransaction.setScale(childSurfaceControl, scaleX, scaleY); mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace()); mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer()); if (aspectRatioMismatch) { GraphicBuffer background = GraphicBuffer.create(mFrame.width(), mFrame.height(), PixelFormat.RGBA_8888, GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER | GraphicBuffer.USAGE_SW_WRITE_RARELY); final Canvas c = background != null ? background.lockCanvas() : null; if (c == null) { Log.e(TAG, "Unable to draw snapshot: failed to allocate graphic buffer for " + mTitle); mTransaction.clear(); childSurfaceControl.release(); return; } drawBackgroundAndBars(c, frame); background.unlockCanvasAndPost(c); mTransaction.setBuffer(mRootSurface, HardwareBuffer.createFromGraphicBuffer(background)); } mTransaction.apply(); childSurfaceControl.release(); } /** * Calculates the snapshot crop in snapshot coordinate space. * @param insets Content insets or Letterbox insets * @return crop rect in snapshot coordinate space. */ @VisibleForTesting public Rect calculateSnapshotCrop(@NonNull Rect insets) { final Rect rect = new Rect(); rect.set(0, 0, mSnapshotW, mSnapshotH); final float scaleX = (float) mSnapshotW / mSnapshot.getTaskSize().x; final float scaleY = (float) mSnapshotH / mSnapshot.getTaskSize().y; // Let's remove all system decorations except the status bar, but only if the task is at // the very top of the screen. final boolean isTop = mFrame.top == 0; rect.inset((int) (insets.left * scaleX), isTop ? 0 : (int) (insets.top * scaleY), (int) (insets.right * scaleX), (int) (insets.bottom * scaleY)); return rect; } /** * Calculates the snapshot frame in window coordinate space from crop. * * @param crop rect that is in snapshot coordinate space. */ @VisibleForTesting public Rect calculateSnapshotFrame(Rect crop) { final float scaleX = (float) mSnapshotW / mSnapshot.getTaskSize().x; final float scaleY = (float) mSnapshotH / mSnapshot.getTaskSize().y; // Rescale the frame from snapshot to window coordinate space final Rect frame = new Rect(0, 0, (int) (crop.width() / scaleX + 0.5f), (int) (crop.height() / scaleY + 0.5f) ); // However, we also need to make space for the navigation bar on the left side. frame.offset(mSystemBarInsets.left, 0); return frame; } /** * Draw status bar and navigation bar background. */ @VisibleForTesting public void drawBackgroundAndBars(Canvas c, Rect frame) { final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight(); final boolean fillHorizontally = c.getWidth() > frame.right; final boolean fillVertically = c.getHeight() > frame.bottom; if (fillHorizontally) { c.drawRect(frame.right, alpha(mSystemBarBackgroundPainter.mStatusBarColor) == 0xFF ? statusBarHeight : 0, c.getWidth(), fillVertically ? frame.bottom : c.getHeight(), sBackgroundPaint); } if (fillVertically) { c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), sBackgroundPaint); } mSystemBarBackgroundPainter.drawDecors(c, frame); } /** * Ask system bar background painter to draw status bar background. */ @VisibleForTesting public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) { mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame, mSystemBarBackgroundPainter.getStatusBarColorViewHeight()); } /** * Ask system bar background painter to draw navigation bar background. */ @VisibleForTesting public void drawNavigationBarBackground(Canvas c) { mSystemBarBackgroundPainter.drawNavigationBarBackground(c); } } private static boolean isAspectRatioMatch(Rect frame, int w, int h) { if (frame.isEmpty()) { return false; } return Math.abs(((float) w / h) - ((float) frame.width() / frame.height())) <= 0.01f; } private static boolean isAspectRatioMatch(Rect frame1, Rect frame2) { if (frame1.isEmpty() || frame2.isEmpty()) { return false; } return Math.abs( ((float) frame2.width() / frame2.height()) - ((float) frame1.width() / frame1.height())) <= 0.01f; } /** Loading @@ -383,28 +208,15 @@ public class SnapshotDrawerUtils { /** * Help method to draw the snapshot on a surface. */ public static void drawSnapshotOnSurface(StartingWindowInfo info, WindowManager.LayoutParams lp, public static void drawSnapshotOnSurface(WindowManager.LayoutParams lp, SurfaceControl rootSurface, TaskSnapshot snapshot, Rect windowBounds, InsetsState topWindowInsetsState, boolean releaseAfterDraw) { Rect windowBounds, boolean releaseAfterDraw) { if (windowBounds.isEmpty()) { Log.e(TAG, "Unable to draw snapshot on an empty windowBounds"); return; } final SnapshotSurface drawSurface = new SnapshotSurface( rootSurface, snapshot, lp.getTitle()); final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo; final ActivityManager.TaskDescription taskDescription = getOrCreateTaskDescription(runningTaskInfo); Rect systemBarInsets = null; if (!Flags.drawSnapshotAspectRatioMatch()) { drawSurface.initiateSystemBarPainter(lp.flags, lp.privateFlags, attrs.insetsFlags.appearance, taskDescription, info.requestedVisibleTypes); systemBarInsets = getSystemBarInsets(windowBounds, topWindowInsetsState); } drawSurface.setFrames(windowBounds, systemBarInsets); rootSurface, snapshot, windowBounds, lp.getTitle()); drawSurface.drawSnapshot(releaseAfterDraw); } Loading @@ -414,10 +226,8 @@ public class SnapshotDrawerUtils { public static WindowManager.LayoutParams createLayoutParameters(StartingWindowInfo info, CharSequence title, @WindowManager.LayoutParams.WindowType int windowType, int pixelFormat, IBinder token) { final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams; if (attrs == null || mainWindowParams == null) { final WindowManager.LayoutParams attrs = info.mainWindowLayoutParams; if (attrs == null) { Log.w(TAG, "unable to create taskSnapshot surface "); return null; } Loading @@ -427,9 +237,9 @@ public class SnapshotDrawerUtils { final int windowFlags = attrs.flags; final int windowPrivateFlags = attrs.privateFlags; layoutParams.packageName = mainWindowParams.packageName; layoutParams.windowAnimations = mainWindowParams.windowAnimations; layoutParams.dimAmount = mainWindowParams.dimAmount; layoutParams.packageName = attrs.packageName; layoutParams.windowAnimations = attrs.windowAnimations; layoutParams.dimAmount = attrs.dimAmount; layoutParams.type = windowType; layoutParams.format = pixelFormat; layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES) Loading Loading @@ -460,14 +270,6 @@ public class SnapshotDrawerUtils { return layoutParams; } static Rect getSystemBarInsets(Rect frame, @Nullable InsetsState state) { if (state == null) { return new Rect(); } return state.calculateInsets(frame, WindowInsets.Type.systemBars(), false /* ignoreVisibility */).toRect(); } /** * Helper class to draw the background of the system bars in regions the task snapshot isn't * filling the window. Loading
core/java/android/window/StartingWindowInfo.java +0 −22 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; Loading Loading @@ -99,20 +98,6 @@ public final class StartingWindowInfo implements Parcelable { @Nullable public ActivityInfo targetActivityInfo; /** * InsetsState of TopFullscreenOpaqueWindow * @hide */ @Nullable public InsetsState topOpaqueWindowInsetsState; /** * LayoutParams of TopFullscreenOpaqueWindow * @hide */ @Nullable public WindowManager.LayoutParams topOpaqueWindowLayoutParams; /** * LayoutParams of MainWindow * @hide Loading Loading @@ -263,8 +248,6 @@ public final class StartingWindowInfo implements Parcelable { taskBounds.writeToParcel(dest, flags); dest.writeTypedObject(targetActivityInfo, flags); dest.writeInt(startingWindowTypeParameter); dest.writeTypedObject(topOpaqueWindowInsetsState, flags); dest.writeTypedObject(topOpaqueWindowLayoutParams, flags); dest.writeTypedObject(mainWindowLayoutParams, flags); dest.writeInt(splashScreenThemeResId); dest.writeBoolean(isKeyguardOccluded); Loading @@ -280,9 +263,6 @@ public final class StartingWindowInfo implements Parcelable { taskBounds.readFromParcel(source); targetActivityInfo = source.readTypedObject(ActivityInfo.CREATOR); startingWindowTypeParameter = source.readInt(); topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR); topOpaqueWindowLayoutParams = source.readTypedObject( WindowManager.LayoutParams.CREATOR); mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR); splashScreenThemeResId = source.readInt(); isKeyguardOccluded = source.readBoolean(); Loading @@ -302,8 +282,6 @@ public final class StartingWindowInfo implements Parcelable { + " topActivityType=" + taskInfo.topActivityType + " preferredStartingWindowType=" + Integer.toHexString(startingWindowTypeParameter) + " insetsState=" + topOpaqueWindowInsetsState + " topWindowLayoutParams=" + topOpaqueWindowLayoutParams + " mainWindowLayoutParams=" + mainWindowLayoutParams + " splashScreenThemeResId " + Integer.toHexString(splashScreenThemeResId); } Loading
core/java/android/window/flags/windowing_frontend.aconfig +0 −11 Original line number Diff line number Diff line Loading @@ -242,17 +242,6 @@ flag { is_fixed_read_only: true } flag { name: "draw_snapshot_aspect_ratio_match" namespace: "windowing_frontend" description: "The aspect ratio should always match when drawing snapshot" bug: "341020277" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { name: "system_ui_post_animation_end" namespace: "windowing_frontend" Loading
core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java +17 −162 File changed.Preview size limit exceeded, changes collapsed. Show changes
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +2 −4 Original line number Diff line number Diff line Loading @@ -89,8 +89,6 @@ public class TaskSnapshotWindow { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId); final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState; final WindowManager.LayoutParams layoutParams = SnapshotDrawerUtils.createLayoutParameters( info, TITLE_FORMAT + taskId, TYPE_APPLICATION_STARTING, snapshot.getHardwareBuffer().getFormat(), appToken); Loading Loading @@ -152,8 +150,8 @@ public class TaskSnapshotWindow { return null; } SnapshotDrawerUtils.drawSnapshotOnSurface(info, layoutParams, surfaceControl, snapshot, info.taskBounds, topWindowInsetsState, true /* releaseAfterDraw */); SnapshotDrawerUtils.drawSnapshotOnSurface(layoutParams, surfaceControl, snapshot, info.taskBounds, true /* releaseAfterDraw */); snapshotSurface.mHasDrawn = true; snapshotSurface.reportDrawn(); Loading