diff options
6 files changed, 71 insertions, 67 deletions
diff --git a/core/java/android/window/SnapshotDrawerUtils.java b/core/java/android/window/SnapshotDrawerUtils.java index e5658e63f7ec..29bb32e6443f 100644 --- a/core/java/android/window/SnapshotDrawerUtils.java +++ b/core/java/android/window/SnapshotDrawerUtils.java @@ -52,11 +52,9 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.GraphicBuffer; -import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.RectF; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.util.Log; @@ -98,11 +96,6 @@ public class SnapshotDrawerUtils { | FLAG_SECURE | FLAG_DIM_BEHIND; - private static final RectF sTmpSnapshotSize = new RectF(); - private static final RectF sTmpDstFrame = new RectF(); - - private static final Matrix sSnapshotMatrix = new Matrix(); - private static final float[] sTmpFloat9 = new float[9]; private static final Paint sBackgroundPaint = new Paint(); /** @@ -116,24 +109,27 @@ public class SnapshotDrawerUtils { private final CharSequence mTitle; private SystemBarBackgroundPainter mSystemBarBackgroundPainter; - private final Rect mTaskBounds; private final Rect mFrame = new Rect(); private final Rect mSystemBarInsets = new Rect(); + private final int mSnapshotW; + private final int mSnapshotH; private boolean mSizeMismatch; public SnapshotSurface(SurfaceControl rootSurface, TaskSnapshot snapshot, - CharSequence title, - Rect taskBounds) { + CharSequence title) { mRootSurface = rootSurface; mSnapshot = snapshot; mTitle = title; - mTaskBounds = taskBounds; + final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); + mSnapshotW = hwBuffer.getWidth(); + mSnapshotH = hwBuffer.getHeight(); } /** * Initiate system bar painter to draw the system bar background. */ - void initiateSystemBarPainter(int windowFlags, int windowPrivateFlags, + @VisibleForTesting + public void initiateSystemBarPainter(int windowFlags, int windowPrivateFlags, int appearance, ActivityManager.TaskDescription taskDescription, @WindowInsets.Type.InsetsType int requestedVisibleTypes) { mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags, @@ -143,14 +139,13 @@ public class SnapshotDrawerUtils { } /** - * Set frame size. + * Set frame size that the snapshot should fill. It is the bounds of a task or activity. */ - void setFrames(Rect frame, Rect systemBarInsets) { + @VisibleForTesting + public void setFrames(Rect frame, Rect systemBarInsets) { mFrame.set(frame); mSystemBarInsets.set(systemBarInsets); - final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer(); - mSizeMismatch = (mFrame.width() != snapshot.getWidth() - || mFrame.height() != snapshot.getHeight()); + mSizeMismatch = (mFrame.width() != mSnapshotW || mFrame.height() != mSnapshotH); mSystemBarBackgroundPainter.setInsets(systemBarInsets); } @@ -186,7 +181,7 @@ public class SnapshotDrawerUtils { // 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, mSnapshot); + boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshotW, mSnapshotH); // Keep a reference to it such that it doesn't get destroyed when finalized. SurfaceControl childSurfaceControl = new SurfaceControl.Builder(session) @@ -198,12 +193,14 @@ public class SnapshotDrawerUtils { .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; - final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); if (letterboxInsets.left != 0 || letterboxInsets.top != 0 || letterboxInsets.right != 0 || letterboxInsets.bottom != 0) { // Clip off letterbox. @@ -214,23 +211,27 @@ public class SnapshotDrawerUtils { // if letterbox doesn't match window frame, try crop by content insets if (aspectRatioMismatch) { // Clip off ugly navigation bar. - crop = calculateSnapshotCrop(mSnapshot.getContentInsets()); + final Rect contentInsets = mSnapshot.getContentInsets(); + crop = calculateSnapshotCrop(contentInsets); + offsetX = contentInsets.left; + offsetY = contentInsets.top; } frame = calculateSnapshotFrame(crop); - mTransaction.setWindowCrop(childSurfaceControl, crop); - mTransaction.setPosition(childSurfaceControl, frame.left, frame.top); - sTmpSnapshotSize.set(crop); - sTmpDstFrame.set(frame); + mTransaction.setCrop(childSurfaceControl, crop); } else { frame = null; - sTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight()); - sTmpDstFrame.set(mFrame); - sTmpDstFrame.offsetTo(0, 0); } - // Scale the mismatch dimensions to fill the task bounds - sSnapshotMatrix.setRectToRect(sTmpSnapshotSize, sTmpDstFrame, Matrix.ScaleToFit.FILL); - mTransaction.setMatrix(childSurfaceControl, sSnapshotMatrix, sTmpFloat9); + // 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); + } + // Scale the mismatch dimensions to fill the target frame. + final float scaleX = (float) mFrame.width() / mSnapshotW; + final float scaleY = (float) mFrame.height() / mSnapshotH; + mTransaction.setScale(childSurfaceControl, scaleX, scaleY); mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace()); mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer()); @@ -261,17 +262,17 @@ public class SnapshotDrawerUtils { * @param insets Content insets or Letterbox insets * @return crop rect in snapshot coordinate space. */ - Rect calculateSnapshotCrop(@NonNull Rect insets) { + @VisibleForTesting + public Rect calculateSnapshotCrop(@NonNull Rect insets) { final Rect rect = new Rect(); - final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer(); - rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight()); + rect.set(0, 0, mSnapshotW, mSnapshotH); - final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x; - final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y; + 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 = mTaskBounds.top == 0 && mFrame.top == 0; + final boolean isTop = mFrame.top == 0; rect.inset((int) (insets.left * scaleX), isTop ? 0 : (int) (insets.top * scaleY), (int) (insets.right * scaleX), @@ -284,10 +285,10 @@ public class SnapshotDrawerUtils { * * @param crop rect that is in snapshot coordinate space. */ - Rect calculateSnapshotFrame(Rect crop) { - final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer(); - final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x; - final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y; + @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, @@ -303,7 +304,8 @@ public class SnapshotDrawerUtils { /** * Draw status bar and navigation bar background. */ - void drawBackgroundAndBars(Canvas c, Rect frame) { + @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; @@ -320,33 +322,27 @@ public class SnapshotDrawerUtils { /** * Ask system bar background painter to draw status bar background. - * */ - void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) { + @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. - * */ - void drawNavigationBarBackground(Canvas c) { + @VisibleForTesting + public void drawNavigationBarBackground(Canvas c) { mSystemBarBackgroundPainter.drawNavigationBarBackground(c); } } - /** - * @return true if the aspect ratio match between a frame and a snapshot buffer. - */ - public static boolean isAspectRatioMatch(Rect frame, TaskSnapshot snapshot) { + private static boolean isAspectRatioMatch(Rect frame, int w, int h) { if (frame.isEmpty()) { return false; } - final HardwareBuffer buffer = snapshot.getHardwareBuffer(); - return Math.abs( - ((float) buffer.getWidth() / buffer.getHeight()) - - ((float) frame.width() / frame.height())) <= 0.01f; + return Math.abs(((float) w / h) - ((float) frame.width() / frame.height())) <= 0.01f; } private static boolean isAspectRatioMatch(Rect frame1, Rect frame2) { @@ -378,14 +374,14 @@ public class SnapshotDrawerUtils { */ public static void drawSnapshotOnSurface(StartingWindowInfo info, WindowManager.LayoutParams lp, SurfaceControl rootSurface, TaskSnapshot snapshot, - Rect configBounds, Rect windowBounds, InsetsState topWindowInsetsState, + Rect windowBounds, InsetsState topWindowInsetsState, 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(), configBounds); + rootSurface, snapshot, lp.getTitle()); final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams; final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo; diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index 260d9a82472f..72df343a2dbe 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.TaskInfo; import android.content.pm.ActivityInfo; +import android.graphics.Rect; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -79,11 +80,17 @@ public final class StartingWindowInfo implements Parcelable { /** * The {@link TaskInfo} from this task. - * @hide + * <p>Note that the configuration of this taskInfo could be from the top activity of its task. + * Because only activity contains persisted configuration (e.g. night mode, language). Besides, + * it can also be used for activity level snapshot. */ @NonNull public ActivityManager.RunningTaskInfo taskInfo; + /** The bounds of the target task. */ + @NonNull + public final Rect taskBounds = new Rect(); + /** * The {@link ActivityInfo} of the target activity which to create the starting window. * It can be null if the info is the same as the top in task info. @@ -253,6 +260,7 @@ public final class StartingWindowInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeTypedObject(taskInfo, flags); + taskBounds.writeToParcel(dest, flags); dest.writeTypedObject(targetActivityInfo, flags); dest.writeInt(startingWindowTypeParameter); dest.writeTypedObject(topOpaqueWindowInsetsState, flags); @@ -269,6 +277,7 @@ public final class StartingWindowInfo implements Parcelable { void readFromParcel(@NonNull Parcel source) { taskInfo = source.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); + taskBounds.readFromParcel(source); targetActivityInfo = source.readTypedObject(ActivityInfo.CREATOR); startingWindowTypeParameter = source.readInt(); topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR); diff --git a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java index 036154634ae7..6c8dcd39e223 100644 --- a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java +++ b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java @@ -77,7 +77,7 @@ public class SnapshotDrawerUtilsTest { Color.RED, Color.BLUE); mSnapshotSurface = new SnapshotDrawerUtils.SnapshotSurface( - new SurfaceControl(), snapshot, "Test", taskBounds); + new SurfaceControl(), snapshot, "Test"); mSnapshotSurface.initiateSystemBarPainter(windowFlags, 0, 0, taskDescription, WindowInsets.Type.defaultVisible()); } @@ -167,14 +167,16 @@ public class SnapshotDrawerUtilsTest { @Test public void testCalculateSnapshotCrop_taskNotOnTop() { final Rect contentInsets = new Rect(0, 10, 0, 10); - setupSurface(100, 100, contentInsets, 0, new Rect(0, 50, 100, 150)); + final Rect bounds = new Rect(0, 50, 100, 150); + setupSurface(100, 100, contentInsets, 0, bounds); + mSnapshotSurface.setFrames(bounds, contentInsets); assertEquals(new Rect(0, 10, 100, 90), mSnapshotSurface.calculateSnapshotCrop(contentInsets)); } @Test public void testCalculateSnapshotCrop_navBarLeft() { - final Rect contentInsets = new Rect(0, 10, 0, 0); + final Rect contentInsets = new Rect(10, 0, 0, 0); setupSurface(100, 100, contentInsets, 0, new Rect(0, 0, 100, 100)); assertEquals(new Rect(10, 0, 100, 100), mSnapshotSurface.calculateSnapshotCrop(contentInsets)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index ceac40d9ba95..5fec38dc23d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.graphics.Paint; -import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; @@ -100,8 +99,6 @@ public class TaskSnapshotWindow { return null; } - final Point taskSize = snapshot.getTaskSize(); - final Rect taskBounds = new Rect(0, 0, taskSize.x, taskSize.y); final int orientation = snapshot.getOrientation(); final int displayId = runningTaskInfo.displayId; @@ -150,7 +147,7 @@ public class TaskSnapshotWindow { } SnapshotDrawerUtils.drawSnapshotOnSurface(info, layoutParams, surfaceControl, snapshot, - taskBounds, tmpFrames.frame, topWindowInsetsState, true /* releaseAfterDraw */); + info.taskBounds, topWindowInsetsState, true /* releaseAfterDraw */); snapshotSurface.mHasDrawn = true; snapshotSurface.reportDrawn(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java index fed2f34b5e0c..5c814dcc9b16 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java @@ -23,7 +23,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.ActivityManager; import android.content.Context; -import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.view.Display; @@ -77,15 +76,13 @@ class WindowlessSnapshotWindowCreator { runningTaskInfo.configuration, rootSurface); final SurfaceControlViewHost mViewHost = new SurfaceControlViewHost( mContext, display, wlw, "WindowlessSnapshotWindowCreator"); - final Point taskSize = snapshot.getTaskSize(); - final Rect snapshotBounds = new Rect(0, 0, taskSize.x, taskSize.y); final Rect windowBounds = runningTaskInfo.configuration.windowConfiguration.getBounds(); final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState; final FrameLayout rootLayout = new FrameLayout( mSplashscreenContentDrawer.createViewContextWrapper(mContext)); mViewHost.setView(rootLayout, lp); SnapshotDrawerUtils.drawSnapshotOnSurface(info, lp, wlw.mChildSurface, snapshot, - snapshotBounds, windowBounds, topWindowInsetsState, false /* releaseAfterDraw */); + windowBounds, topWindowInsetsState, false /* releaseAfterDraw */); final ActivityManager.TaskDescription taskDescription = SnapshotDrawerUtils.getOrCreateTaskDescription(runningTaskInfo); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f23a440eb0ed..89b8e15b9461 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3689,6 +3689,9 @@ class Task extends TaskFragment { info.requestedVisibleTypes = topMainWin.getRequestedVisibleTypes(); } } + final Rect rotatedBounds = activity.getFixedRotationTransformDisplayBounds(); + info.taskBounds.set(rotatedBounds != null ? rotatedBounds + : info.taskInfo.configuration.windowConfiguration.getBounds()); // If the developer has persist a different configuration, we need to override it to the // starting window because persisted configuration does not effect to Task. info.taskInfo.configuration.setTo(activity.getConfiguration()); |