Loading services/core/java/com/android/server/wm/DisplayContent.java +1 −4 Original line number Diff line number Diff line Loading @@ -1107,10 +1107,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } if (rotateSeamlessly) { forAllWindows(w -> { w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(), oldRotation, rotation); }, true /* traverseTopToBottom */); seamlesslyRotate(getPendingTransaction(), oldRotation, rotation); } mService.mDisplayManagerInternal.performTraversal(getPendingTransaction()); Loading services/core/java/com/android/server/wm/WindowContainer.java +14 −0 Original line number Diff line number Diff line Loading @@ -735,6 +735,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return candidate; } /** * Seamlessly rotates the container, by recomputing the location in the new * rotation, and rotating buffers until they are updated for the new rotation. * * @param t the transaction to perform the seamless rotation in * @param oldRotation the rotation we are rotating from * @param newRotation the rotation we are rotating to */ void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) { for (int i = mChildren.size() - 1; i >= 0; --i) { mChildren.get(i).seamlesslyRotate(t, oldRotation, newRotation); } } /** * Returns true if this container is opaque and fills all the space made available by its parent * container. Loading services/core/java/com/android/server/wm/WindowState.java +27 −1 Original line number Diff line number Diff line Loading @@ -152,6 +152,8 @@ import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY; import static com.android.server.wm.WindowStateProto.VISIBLE_FRAME; import static com.android.server.wm.WindowStateProto.VISIBLE_INSETS; import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER; import static com.android.server.wm.utils.CoordinateTransforms.transformRect; import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; import android.annotation.CallSuper; import android.app.AppOpsManager; Loading Loading @@ -1813,7 +1815,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0 && !isDragResizing() && !adjustedForMinimizedDockOrIme && getWindowConfiguration().hasMovementAnimations() && !mWinAnimator.mLastHidden) { && !mWinAnimator.mLastHidden && !mSeamlesslyRotated) { startMoveAnimation(left, top); } Loading Loading @@ -4860,6 +4863,29 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mFrameNumber = frameNumber; } @Override void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) { if (!isVisibleNow() || mIsWallpaper) { return; } final Matrix transform = mTmpMatrix; mService.markForSeamlessRotation(this, true); // We rotated the screen, but have not performed a new layout pass yet. In the mean time, // we recompute the coordinates of mFrame in the new orientation, so the surface can be // properly placed. transformToRotation(oldRotation, newRotation, getDisplayInfo(), transform); transformRect(transform, mFrame, null /* tmpRectF */); updateSurfacePosition(t); mWinAnimator.seamlesslyRotate(t, oldRotation, newRotation); // Dispatch to children only after mFrame has been updated, as it's needed in the // child's updateSurfacePosition. super.seamlesslyRotate(t, oldRotation, newRotation); } private final class MoveAnimationSpec implements AnimationSpec { private final long mDuration; Loading services/core/java/com/android/server/wm/WindowStateAnimator.java +5 −31 Original line number Diff line number Diff line Loading @@ -46,13 +46,13 @@ import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE; import static com.android.server.wm.WindowStateAnimatorProto.LAST_CLIP_RECT; import static com.android.server.wm.WindowStateAnimatorProto.SURFACE; import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT; import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; import android.content.Context; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Debug; import android.os.Trace; Loading Loading @@ -1497,40 +1497,14 @@ class WindowStateAnimator { } } void seamlesslyRotateWindow(SurfaceControl.Transaction t, int oldRotation, int newRotation) { void seamlesslyRotate(SurfaceControl.Transaction t, int oldRotation, int newRotation) { final WindowState w = mWin; if (!w.isVisibleNow() || w.mIsWallpaper) { return; } final Rect cropRect = mService.mTmpRect; final Rect displayRect = mService.mTmpRect2; final RectF frameRect = mService.mTmpRectF; // We rotated the screen, but have not received a new buffer with the correct size yet. In // the mean time, we rotate the buffer we have to the new orientation. final Matrix transform = mService.mTmpTransform; final float x = w.mFrame.left; final float y = w.mFrame.top; final float width = w.mFrame.width(); final float height = w.mFrame.height(); mService.getDefaultDisplayContentLocked().getBounds(displayRect); final float displayWidth = displayRect.width(); final float displayHeight = displayRect.height(); // Compute a transform matrix to undo the coordinate space transformation, // and present the window at the same physical position it previously occupied. final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation); DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight, transformToRotation(oldRotation, newRotation, w.mFrame.width(), w.mFrame.height(), transform); // We just need to apply a rotation matrix to the window. For example // if we have a portrait window and rotate to landscape, the window is still portrait // and now extends off the bottom of the screen (and only halfway across). Essentially we // apply a transform to display the current buffer at it's old position // (in the new coordinate space). We then freeze layer updates until the resize // occurs, at which point we undo, them. mService.markForSeamlessRotation(w, true); transform.getValues(mService.mTmpFloats); float DsDx = mService.mTmpFloats[Matrix.MSCALE_X]; Loading services/core/java/com/android/server/wm/utils/CoordinateTransforms.java +93 −0 Original line number Diff line number Diff line Loading @@ -22,7 +22,11 @@ import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.annotation.Dimension; import android.annotation.Nullable; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.view.DisplayInfo; import android.view.Surface.Rotation; public class CoordinateTransforms { Loading Loading @@ -59,4 +63,93 @@ public class CoordinateTransforms { throw new IllegalArgumentException("Unknown rotation: " + rotation); } } /** * Sets a matrix such that given a rotation, it transforms that rotation's logical coordinates * to physical coordinates. * * @param rotation the rotation to which the matrix should transform * @param out the matrix to be set */ public static void transformLogicalToPhysicalCoordinates(@Rotation int rotation, @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) { switch (rotation) { case ROTATION_0: out.reset(); break; case ROTATION_90: out.setRotate(90); out.preTranslate(0, -physicalWidth); break; case ROTATION_180: out.setRotate(180); out.preTranslate(-physicalWidth, -physicalHeight); break; case ROTATION_270: out.setRotate(270); out.preTranslate(-physicalHeight, 0); break; default: throw new IllegalArgumentException("Unknown rotation: " + rotation); } } /** * Sets a matrix such that given a two rotations, that it transforms coordinates given in the * old rotation to coordinates that refer to the same physical location in the new rotation. * * @param oldRotation the rotation to transform from * @param newRotation the rotation to transform to * @param info the display info * @param out a matrix that will be set to the transform */ public static void transformToRotation(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info, Matrix out) { final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270; final int h = flipped ? info.logicalWidth : info.logicalHeight; final int w = flipped ? info.logicalHeight : info.logicalWidth; final Matrix tmp = new Matrix(); transformLogicalToPhysicalCoordinates(oldRotation, w, h, out); transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); out.postConcat(tmp); } /** * Sets a matrix such that given a two rotations, that it transforms coordinates given in the * old rotation to coordinates that refer to the same physical location in the new rotation. * * @param oldRotation the rotation to transform from * @param newRotation the rotation to transform to * @param newWidth the width of the area to transform, in the new rotation * @param newHeight the height of the area to transform, in the new rotation * @param out a matrix that will be set to the transform */ public static void transformToRotation(@Rotation int oldRotation, @Rotation int newRotation, int newWidth, int newHeight, Matrix out) { final boolean flipped = newRotation == ROTATION_90 || newRotation == ROTATION_270; final int h = flipped ? newWidth : newHeight; final int w = flipped ? newHeight : newWidth; final Matrix tmp = new Matrix(); transformLogicalToPhysicalCoordinates(oldRotation, w, h, out); transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); out.postConcat(tmp); } /** * Transforms a rect using a transformation matrix * * @param transform the transformation to apply to the rect * @param inOutRect the rect to transform * @param tmp a temporary value, if null the function will allocate its own. */ public static void transformRect(Matrix transform, Rect inOutRect, @Nullable RectF tmp) { if (tmp == null) { tmp = new RectF(); } tmp.set(inOutRect); transform.mapRect(tmp); inOutRect.set((int) tmp.left, (int) tmp.top, (int) tmp.right, (int) tmp.bottom); } } Loading
services/core/java/com/android/server/wm/DisplayContent.java +1 −4 Original line number Diff line number Diff line Loading @@ -1107,10 +1107,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } if (rotateSeamlessly) { forAllWindows(w -> { w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(), oldRotation, rotation); }, true /* traverseTopToBottom */); seamlesslyRotate(getPendingTransaction(), oldRotation, rotation); } mService.mDisplayManagerInternal.performTraversal(getPendingTransaction()); Loading
services/core/java/com/android/server/wm/WindowContainer.java +14 −0 Original line number Diff line number Diff line Loading @@ -735,6 +735,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return candidate; } /** * Seamlessly rotates the container, by recomputing the location in the new * rotation, and rotating buffers until they are updated for the new rotation. * * @param t the transaction to perform the seamless rotation in * @param oldRotation the rotation we are rotating from * @param newRotation the rotation we are rotating to */ void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) { for (int i = mChildren.size() - 1; i >= 0; --i) { mChildren.get(i).seamlesslyRotate(t, oldRotation, newRotation); } } /** * Returns true if this container is opaque and fills all the space made available by its parent * container. Loading
services/core/java/com/android/server/wm/WindowState.java +27 −1 Original line number Diff line number Diff line Loading @@ -152,6 +152,8 @@ import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY; import static com.android.server.wm.WindowStateProto.VISIBLE_FRAME; import static com.android.server.wm.WindowStateProto.VISIBLE_INSETS; import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER; import static com.android.server.wm.utils.CoordinateTransforms.transformRect; import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; import android.annotation.CallSuper; import android.app.AppOpsManager; Loading Loading @@ -1813,7 +1815,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0 && !isDragResizing() && !adjustedForMinimizedDockOrIme && getWindowConfiguration().hasMovementAnimations() && !mWinAnimator.mLastHidden) { && !mWinAnimator.mLastHidden && !mSeamlesslyRotated) { startMoveAnimation(left, top); } Loading Loading @@ -4860,6 +4863,29 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mFrameNumber = frameNumber; } @Override void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) { if (!isVisibleNow() || mIsWallpaper) { return; } final Matrix transform = mTmpMatrix; mService.markForSeamlessRotation(this, true); // We rotated the screen, but have not performed a new layout pass yet. In the mean time, // we recompute the coordinates of mFrame in the new orientation, so the surface can be // properly placed. transformToRotation(oldRotation, newRotation, getDisplayInfo(), transform); transformRect(transform, mFrame, null /* tmpRectF */); updateSurfacePosition(t); mWinAnimator.seamlesslyRotate(t, oldRotation, newRotation); // Dispatch to children only after mFrame has been updated, as it's needed in the // child's updateSurfacePosition. super.seamlesslyRotate(t, oldRotation, newRotation); } private final class MoveAnimationSpec implements AnimationSpec { private final long mDuration; Loading
services/core/java/com/android/server/wm/WindowStateAnimator.java +5 −31 Original line number Diff line number Diff line Loading @@ -46,13 +46,13 @@ import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE; import static com.android.server.wm.WindowStateAnimatorProto.LAST_CLIP_RECT; import static com.android.server.wm.WindowStateAnimatorProto.SURFACE; import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT; import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; import android.content.Context; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Debug; import android.os.Trace; Loading Loading @@ -1497,40 +1497,14 @@ class WindowStateAnimator { } } void seamlesslyRotateWindow(SurfaceControl.Transaction t, int oldRotation, int newRotation) { void seamlesslyRotate(SurfaceControl.Transaction t, int oldRotation, int newRotation) { final WindowState w = mWin; if (!w.isVisibleNow() || w.mIsWallpaper) { return; } final Rect cropRect = mService.mTmpRect; final Rect displayRect = mService.mTmpRect2; final RectF frameRect = mService.mTmpRectF; // We rotated the screen, but have not received a new buffer with the correct size yet. In // the mean time, we rotate the buffer we have to the new orientation. final Matrix transform = mService.mTmpTransform; final float x = w.mFrame.left; final float y = w.mFrame.top; final float width = w.mFrame.width(); final float height = w.mFrame.height(); mService.getDefaultDisplayContentLocked().getBounds(displayRect); final float displayWidth = displayRect.width(); final float displayHeight = displayRect.height(); // Compute a transform matrix to undo the coordinate space transformation, // and present the window at the same physical position it previously occupied. final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation); DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight, transformToRotation(oldRotation, newRotation, w.mFrame.width(), w.mFrame.height(), transform); // We just need to apply a rotation matrix to the window. For example // if we have a portrait window and rotate to landscape, the window is still portrait // and now extends off the bottom of the screen (and only halfway across). Essentially we // apply a transform to display the current buffer at it's old position // (in the new coordinate space). We then freeze layer updates until the resize // occurs, at which point we undo, them. mService.markForSeamlessRotation(w, true); transform.getValues(mService.mTmpFloats); float DsDx = mService.mTmpFloats[Matrix.MSCALE_X]; Loading
services/core/java/com/android/server/wm/utils/CoordinateTransforms.java +93 −0 Original line number Diff line number Diff line Loading @@ -22,7 +22,11 @@ import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.annotation.Dimension; import android.annotation.Nullable; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.view.DisplayInfo; import android.view.Surface.Rotation; public class CoordinateTransforms { Loading Loading @@ -59,4 +63,93 @@ public class CoordinateTransforms { throw new IllegalArgumentException("Unknown rotation: " + rotation); } } /** * Sets a matrix such that given a rotation, it transforms that rotation's logical coordinates * to physical coordinates. * * @param rotation the rotation to which the matrix should transform * @param out the matrix to be set */ public static void transformLogicalToPhysicalCoordinates(@Rotation int rotation, @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) { switch (rotation) { case ROTATION_0: out.reset(); break; case ROTATION_90: out.setRotate(90); out.preTranslate(0, -physicalWidth); break; case ROTATION_180: out.setRotate(180); out.preTranslate(-physicalWidth, -physicalHeight); break; case ROTATION_270: out.setRotate(270); out.preTranslate(-physicalHeight, 0); break; default: throw new IllegalArgumentException("Unknown rotation: " + rotation); } } /** * Sets a matrix such that given a two rotations, that it transforms coordinates given in the * old rotation to coordinates that refer to the same physical location in the new rotation. * * @param oldRotation the rotation to transform from * @param newRotation the rotation to transform to * @param info the display info * @param out a matrix that will be set to the transform */ public static void transformToRotation(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info, Matrix out) { final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270; final int h = flipped ? info.logicalWidth : info.logicalHeight; final int w = flipped ? info.logicalHeight : info.logicalWidth; final Matrix tmp = new Matrix(); transformLogicalToPhysicalCoordinates(oldRotation, w, h, out); transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); out.postConcat(tmp); } /** * Sets a matrix such that given a two rotations, that it transforms coordinates given in the * old rotation to coordinates that refer to the same physical location in the new rotation. * * @param oldRotation the rotation to transform from * @param newRotation the rotation to transform to * @param newWidth the width of the area to transform, in the new rotation * @param newHeight the height of the area to transform, in the new rotation * @param out a matrix that will be set to the transform */ public static void transformToRotation(@Rotation int oldRotation, @Rotation int newRotation, int newWidth, int newHeight, Matrix out) { final boolean flipped = newRotation == ROTATION_90 || newRotation == ROTATION_270; final int h = flipped ? newWidth : newHeight; final int w = flipped ? newHeight : newWidth; final Matrix tmp = new Matrix(); transformLogicalToPhysicalCoordinates(oldRotation, w, h, out); transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); out.postConcat(tmp); } /** * Transforms a rect using a transformation matrix * * @param transform the transformation to apply to the rect * @param inOutRect the rect to transform * @param tmp a temporary value, if null the function will allocate its own. */ public static void transformRect(Matrix transform, Rect inOutRect, @Nullable RectF tmp) { if (tmp == null) { tmp = new RectF(); } tmp.set(inOutRect); transform.mapRect(tmp); inOutRect.set((int) tmp.left, (int) tmp.top, (int) tmp.right, (int) tmp.bottom); } }