Loading packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +52 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.view.View; import android.view.View.OnLayoutChangeListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; Loading Loading @@ -97,6 +98,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { private DisplayCutoutView mCutoutTop; private DisplayCutoutView mCutoutBottom; private SecureSetting mColorInversionSetting; private boolean mPendingRotationChange; @Override public void start() { Loading Loading @@ -130,6 +132,21 @@ public class ScreenDecorations extends SystemUI implements Tunable { @Override public void onDisplayChanged(int displayId) { if ((hasRoundedCorners() || shouldDrawCutout()) && mRotation != RotationUtils.getExactRotation(mContext)) { // We cannot immediately update the orientation. Otherwise // WindowManager is still deferring layout until it has finished dispatching // the config changes, which may cause divergence between what we draw // (new orientation), and where we are placed on the screen (old orientation). // Instead we wait until either: // - we are trying to redraw. This because WM resized our window and told us to. // - the config change has been dispatched, so WM is no longer deferring layout. mPendingRotationChange = true; mOverlay.getViewTreeObserver().addOnPreDrawListener( new RestartingPreDrawListener(mOverlay)); mBottomOverlay.getViewTreeObserver().addOnPreDrawListener( new RestartingPreDrawListener(mBottomOverlay)); } updateOrientation(); } }; Loading @@ -144,12 +161,12 @@ public class ScreenDecorations extends SystemUI implements Tunable { mOverlay = LayoutInflater.from(mContext) .inflate(R.layout.rounded_corners, null); mCutoutTop = new DisplayCutoutView(mContext, true, this::updateWindowVisibilities); this::updateWindowVisibilities, this); ((ViewGroup)mOverlay).addView(mCutoutTop); mBottomOverlay = LayoutInflater.from(mContext) .inflate(R.layout.rounded_corners, null); mCutoutBottom = new DisplayCutoutView(mContext, false, this::updateWindowVisibilities); this::updateWindowVisibilities, this); ((ViewGroup)mBottomOverlay).addView(mCutoutBottom); mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); Loading Loading @@ -229,6 +246,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { @Override protected void onConfigurationChanged(Configuration newConfig) { mPendingRotationChange = false; updateOrientation(); if (shouldDrawCutout() && mOverlay == null) { setupDecorations(); Loading @@ -236,6 +254,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { } protected void updateOrientation() { if (mPendingRotationChange) { return; } int newRotation = RotationUtils.getExactRotation(mContext); if (newRotation != mRotation) { mRotation = newRotation; Loading Loading @@ -451,15 +472,17 @@ public class ScreenDecorations extends SystemUI implements Tunable { private final int[] mLocation = new int[2]; private final boolean mInitialStart; private final Runnable mVisibilityChangedListener; private final ScreenDecorations mDecorations; private int mColor = Color.BLACK; private boolean mStart; private int mRotation; public DisplayCutoutView(Context context, boolean start, Runnable visibilityChangedListener) { Runnable visibilityChangedListener, ScreenDecorations decorations) { super(context); mInitialStart = start; mVisibilityChangedListener = visibilityChangedListener; mDecorations = decorations; setId(R.id.display_cutout); } Loading Loading @@ -522,10 +545,10 @@ public class ScreenDecorations extends SystemUI implements Tunable { } private void update() { mStart = isStart(); if (!isAttachedToWindow()) { if (!isAttachedToWindow() || mDecorations.mPendingRotationChange) { return; } mStart = isStart(); requestLayout(); getDisplay().getDisplayInfo(mInfo); mBounds.setEmpty(); Loading Loading @@ -688,4 +711,28 @@ public class ScreenDecorations extends SystemUI implements Tunable { return rotation == RotationUtils.ROTATION_LANDSCAPE || rotation == RotationUtils.ROTATION_SEASCAPE; } /** * A pre-draw listener, that cancels the draw and restarts the traversal with the updated * window attributes. */ private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener { private final View mView; private RestartingPreDrawListener(View view) { mView = view; } @Override public boolean onPreDraw() { mPendingRotationChange = false; mView.getViewTreeObserver().removeOnPreDrawListener(this); // This changes the window attributes - we need to restart the traversal for them to // take effect. updateOrientation(); mView.invalidate(); return false; } } } services/core/java/com/android/server/display/ColorFade.java +2 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.view.SurfaceSession; import libcore.io.Streams; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; /** * <p> Loading @@ -63,7 +64,7 @@ final class ColorFade { // The layer for the electron beam surface. // This is currently hardcoded to be one layer above the boot animation. private static final int COLOR_FADE_LAYER = 0x40000001; private static final int COLOR_FADE_LAYER = WindowManagerPolicy.COLOR_FADE_LAYER; // The number of frames to draw when preparing the animation so that it will // be ready to run smoothly. We use 3 frames because we are triple-buffered. Loading services/core/java/com/android/server/policy/WindowManagerPolicy.java +2 −0 Original line number Diff line number Diff line Loading @@ -157,6 +157,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004; /** Need to recompute animations */ int FINISH_LAYOUT_REDO_ANIM = 0x0008; /** Layer for the screen off animation */ int COLOR_FADE_LAYER = 0x40000001; /** * Register shortcuts for window manager to dispatch. Loading services/core/java/com/android/server/wm/DisplayContent.java +22 −0 Original line number Diff line number Diff line Loading @@ -1136,6 +1136,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } forAllWindows(w -> { w.forceSeamlesslyRotateIfAllowed(oldRotation, rotation); }, true /* traverseTopToBottom */); // TODO(b/111504081): Consolidate seamless rotation logic. if (rotateSeamlessly) { seamlesslyRotate(getPendingTransaction(), oldRotation, rotation); } Loading Loading @@ -3766,6 +3771,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo super(name, service); } @Override SurfaceControl.Builder makeChildSurface(WindowContainer child) { final SurfaceControl.Builder builder = super.makeChildSurface(child); if (child instanceof WindowToken && ((WindowToken) child).mRoundedCornerOverlay) { // To draw above the ColorFade layer during the screen off transition, the // rounded corner overlays need to be at the root of the surface hierarchy. // TODO: move the ColorLayer into the display overlay layer such that this is not // necessary anymore. builder.setParent(null); } return builder; } @Override void assignChildLayers(SurfaceControl.Transaction t) { assignChildLayers(t, null /* imeContainer */); Loading @@ -3782,6 +3800,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo wt.assignRelativeLayer(t, mTaskStackContainers.getSplitScreenDividerAnchor(), 1); continue; } if (wt.mRoundedCornerOverlay) { wt.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1); continue; } wt.assignLayer(t, j); wt.assignChildLayers(t); Loading services/core/java/com/android/server/wm/ForcedSeamlessRotator.java 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.graphics.Matrix; import android.view.DisplayInfo; import com.android.server.wm.utils.CoordinateTransforms; /** * Helper class for forced seamless rotation. * * Works by transforming the window token back into the old display rotation. * * Uses deferTransactionUntil instead of latching on the buffer size to allow for seamless 180 * degree rotations. * TODO(b/111504081): Consolidate seamless rotation logic. */ public class ForcedSeamlessRotator { private final Matrix mTransform = new Matrix(); private final float[] mFloat9 = new float[9]; public ForcedSeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) { 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(); CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, w, h, mTransform); CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); mTransform.postConcat(tmp); } /** * Applies a transform to the window token's surface that undoes the effect of the global * display rotation. */ public void unrotate(WindowToken token) { token.getPendingTransaction().setMatrix(token.getSurfaceControl(), mTransform, mFloat9); } /** * Removes the transform to the window token's surface that undoes the effect of the global * display rotation. * * Removing the transform and the result of the WindowState's layout are both tied to the * WindowState's next frame, such that they apply at the same time the client draws the * window in the new orientation. */ public void finish(WindowToken token, WindowState win) { mTransform.reset(); token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9); token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl, win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(), win.getFrameNumber()); win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl, win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(), win.getFrameNumber()); } } Loading
packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +52 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.view.View; import android.view.View.OnLayoutChangeListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; Loading Loading @@ -97,6 +98,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { private DisplayCutoutView mCutoutTop; private DisplayCutoutView mCutoutBottom; private SecureSetting mColorInversionSetting; private boolean mPendingRotationChange; @Override public void start() { Loading Loading @@ -130,6 +132,21 @@ public class ScreenDecorations extends SystemUI implements Tunable { @Override public void onDisplayChanged(int displayId) { if ((hasRoundedCorners() || shouldDrawCutout()) && mRotation != RotationUtils.getExactRotation(mContext)) { // We cannot immediately update the orientation. Otherwise // WindowManager is still deferring layout until it has finished dispatching // the config changes, which may cause divergence between what we draw // (new orientation), and where we are placed on the screen (old orientation). // Instead we wait until either: // - we are trying to redraw. This because WM resized our window and told us to. // - the config change has been dispatched, so WM is no longer deferring layout. mPendingRotationChange = true; mOverlay.getViewTreeObserver().addOnPreDrawListener( new RestartingPreDrawListener(mOverlay)); mBottomOverlay.getViewTreeObserver().addOnPreDrawListener( new RestartingPreDrawListener(mBottomOverlay)); } updateOrientation(); } }; Loading @@ -144,12 +161,12 @@ public class ScreenDecorations extends SystemUI implements Tunable { mOverlay = LayoutInflater.from(mContext) .inflate(R.layout.rounded_corners, null); mCutoutTop = new DisplayCutoutView(mContext, true, this::updateWindowVisibilities); this::updateWindowVisibilities, this); ((ViewGroup)mOverlay).addView(mCutoutTop); mBottomOverlay = LayoutInflater.from(mContext) .inflate(R.layout.rounded_corners, null); mCutoutBottom = new DisplayCutoutView(mContext, false, this::updateWindowVisibilities); this::updateWindowVisibilities, this); ((ViewGroup)mBottomOverlay).addView(mCutoutBottom); mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); Loading Loading @@ -229,6 +246,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { @Override protected void onConfigurationChanged(Configuration newConfig) { mPendingRotationChange = false; updateOrientation(); if (shouldDrawCutout() && mOverlay == null) { setupDecorations(); Loading @@ -236,6 +254,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { } protected void updateOrientation() { if (mPendingRotationChange) { return; } int newRotation = RotationUtils.getExactRotation(mContext); if (newRotation != mRotation) { mRotation = newRotation; Loading Loading @@ -451,15 +472,17 @@ public class ScreenDecorations extends SystemUI implements Tunable { private final int[] mLocation = new int[2]; private final boolean mInitialStart; private final Runnable mVisibilityChangedListener; private final ScreenDecorations mDecorations; private int mColor = Color.BLACK; private boolean mStart; private int mRotation; public DisplayCutoutView(Context context, boolean start, Runnable visibilityChangedListener) { Runnable visibilityChangedListener, ScreenDecorations decorations) { super(context); mInitialStart = start; mVisibilityChangedListener = visibilityChangedListener; mDecorations = decorations; setId(R.id.display_cutout); } Loading Loading @@ -522,10 +545,10 @@ public class ScreenDecorations extends SystemUI implements Tunable { } private void update() { mStart = isStart(); if (!isAttachedToWindow()) { if (!isAttachedToWindow() || mDecorations.mPendingRotationChange) { return; } mStart = isStart(); requestLayout(); getDisplay().getDisplayInfo(mInfo); mBounds.setEmpty(); Loading Loading @@ -688,4 +711,28 @@ public class ScreenDecorations extends SystemUI implements Tunable { return rotation == RotationUtils.ROTATION_LANDSCAPE || rotation == RotationUtils.ROTATION_SEASCAPE; } /** * A pre-draw listener, that cancels the draw and restarts the traversal with the updated * window attributes. */ private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener { private final View mView; private RestartingPreDrawListener(View view) { mView = view; } @Override public boolean onPreDraw() { mPendingRotationChange = false; mView.getViewTreeObserver().removeOnPreDrawListener(this); // This changes the window attributes - we need to restart the traversal for them to // take effect. updateOrientation(); mView.invalidate(); return false; } } }
services/core/java/com/android/server/display/ColorFade.java +2 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.view.SurfaceSession; import libcore.io.Streams; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; /** * <p> Loading @@ -63,7 +64,7 @@ final class ColorFade { // The layer for the electron beam surface. // This is currently hardcoded to be one layer above the boot animation. private static final int COLOR_FADE_LAYER = 0x40000001; private static final int COLOR_FADE_LAYER = WindowManagerPolicy.COLOR_FADE_LAYER; // The number of frames to draw when preparing the animation so that it will // be ready to run smoothly. We use 3 frames because we are triple-buffered. Loading
services/core/java/com/android/server/policy/WindowManagerPolicy.java +2 −0 Original line number Diff line number Diff line Loading @@ -157,6 +157,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004; /** Need to recompute animations */ int FINISH_LAYOUT_REDO_ANIM = 0x0008; /** Layer for the screen off animation */ int COLOR_FADE_LAYER = 0x40000001; /** * Register shortcuts for window manager to dispatch. Loading
services/core/java/com/android/server/wm/DisplayContent.java +22 −0 Original line number Diff line number Diff line Loading @@ -1136,6 +1136,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } forAllWindows(w -> { w.forceSeamlesslyRotateIfAllowed(oldRotation, rotation); }, true /* traverseTopToBottom */); // TODO(b/111504081): Consolidate seamless rotation logic. if (rotateSeamlessly) { seamlesslyRotate(getPendingTransaction(), oldRotation, rotation); } Loading Loading @@ -3766,6 +3771,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo super(name, service); } @Override SurfaceControl.Builder makeChildSurface(WindowContainer child) { final SurfaceControl.Builder builder = super.makeChildSurface(child); if (child instanceof WindowToken && ((WindowToken) child).mRoundedCornerOverlay) { // To draw above the ColorFade layer during the screen off transition, the // rounded corner overlays need to be at the root of the surface hierarchy. // TODO: move the ColorLayer into the display overlay layer such that this is not // necessary anymore. builder.setParent(null); } return builder; } @Override void assignChildLayers(SurfaceControl.Transaction t) { assignChildLayers(t, null /* imeContainer */); Loading @@ -3782,6 +3800,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo wt.assignRelativeLayer(t, mTaskStackContainers.getSplitScreenDividerAnchor(), 1); continue; } if (wt.mRoundedCornerOverlay) { wt.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1); continue; } wt.assignLayer(t, j); wt.assignChildLayers(t); Loading
services/core/java/com/android/server/wm/ForcedSeamlessRotator.java 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.graphics.Matrix; import android.view.DisplayInfo; import com.android.server.wm.utils.CoordinateTransforms; /** * Helper class for forced seamless rotation. * * Works by transforming the window token back into the old display rotation. * * Uses deferTransactionUntil instead of latching on the buffer size to allow for seamless 180 * degree rotations. * TODO(b/111504081): Consolidate seamless rotation logic. */ public class ForcedSeamlessRotator { private final Matrix mTransform = new Matrix(); private final float[] mFloat9 = new float[9]; public ForcedSeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) { 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(); CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, w, h, mTransform); CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); mTransform.postConcat(tmp); } /** * Applies a transform to the window token's surface that undoes the effect of the global * display rotation. */ public void unrotate(WindowToken token) { token.getPendingTransaction().setMatrix(token.getSurfaceControl(), mTransform, mFloat9); } /** * Removes the transform to the window token's surface that undoes the effect of the global * display rotation. * * Removing the transform and the result of the WindowState's layout are both tied to the * WindowState's next frame, such that they apply at the same time the client draws the * window in the new orientation. */ public void finish(WindowToken token, WindowState win) { mTransform.reset(); token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9); token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl, win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(), win.getFrameNumber()); win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl, win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(), win.getFrameNumber()); } }