summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java57
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java3
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java22
-rw-r--r--services/core/java/com/android/server/wm/ForcedSeamlessRotator.java78
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java26
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java2
10 files changed, 203 insertions, 17 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index bbbc71fe8c1c..520e40aa1e56 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -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;
@@ -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() {
@@ -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();
}
};
@@ -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);
@@ -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();
@@ -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;
@@ -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);
}
@@ -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();
@@ -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;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 4f53ed49002b..33525fdc52d2 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -46,6 +46,7 @@ import android.view.SurfaceSession;
import libcore.io.Streams;
import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
/**
* <p>
@@ -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.
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 7ea620039026..3b568e895e46 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -156,6 +156,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.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index efe4d6f48da1..fb090929c00c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -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);
}
@@ -3767,6 +3772,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
@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 */);
}
@@ -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);
diff --git a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
new file mode 100644
index 000000000000..546edaad6a62
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
@@ -0,0 +1,78 @@
+/*
+ * 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());
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f315999356a8..3cdda7467e24 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1893,6 +1893,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
win.setFrameNumber(frameNumber);
+
+ // TODO(b/111504081): Consolidate seamless rotation logic.
+ if (win.mPendingForcedSeamlessRotate != null && !mWaitingForConfig) {
+ win.mPendingForcedSeamlessRotate.finish(win.mToken, win);
+ win.mPendingForcedSeamlessRotate = null;
+ }
+
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fb0c3bcb1e8f..ff4a5830e7cf 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -282,6 +282,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean mDragResizing;
private boolean mDragResizingChangeReported = true;
private int mResizeMode;
+ /**
+ * Special mode that is intended only for the rounded corner overlay: during rotation
+ * transition, we un-rotate the window token such that the window appears as it did before the
+ * rotation.
+ * TODO(b/111504081): Consolidate seamless rotation logic.
+ */
+ final boolean mForceSeamlesslyRotate;
+ ForcedSeamlessRotator mPendingForcedSeamlessRotate;
private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
@@ -671,6 +679,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
+ void forceSeamlesslyRotateIfAllowed(int oldRotation, int rotation) {
+ if (mForceSeamlesslyRotate) {
+ mPendingForcedSeamlessRotate = new ForcedSeamlessRotator(
+ oldRotation, rotation, getDisplayInfo());
+ mPendingForcedSeamlessRotate.unrotate(this.mToken);
+ }
+ }
+
interface PowerManagerWrapper {
void wakeUp(long time, String reason);
@@ -717,6 +733,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mSeq = seq;
mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
mPowerManagerWrapper = powerManagerWrapper;
+ mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
if (localLOGV) Slog.v(
TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -4710,7 +4727,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition);
- if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) {
+ // Freeze position while we're unrotated, so the surface remains at the position it was
+ // prior to the rotation.
+ if (!mSurfaceAnimator.hasLeash() && mPendingForcedSeamlessRotate == null &&
+ !mLastSurfacePosition.equals(mSurfacePosition)) {
t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) {
@@ -4865,7 +4885,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) {
- if (!isVisibleNow() || mIsWallpaper) {
+ // Invisible windows, the wallpaper, and force seamlessly rotated windows do not participate
+ // in the regular seamless rotation animation.
+ if (!isVisibleNow() || mIsWallpaper || mForceSeamlesslyRotate) {
return;
}
final Matrix transform = mTmpMatrix;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 14e0e13414a9..1673270a1509 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -686,8 +686,12 @@ class WindowStateAnimator {
final int displayId = mWin.getDisplayId();
final ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(displayId);
- final boolean screenAnimation =
- screenRotationAnimation != null && screenRotationAnimation.isAnimating();
+ // TODO(b/111504081): Consolidate seamless rotation logic.
+ final boolean windowParticipatesInScreenRotationAnimation =
+ !mWin.mForceSeamlesslyRotate;
+ final boolean screenAnimation = screenRotationAnimation != null
+ && screenRotationAnimation.isAnimating()
+ && windowParticipatesInScreenRotationAnimation;
if (screenAnimation) {
// cache often used attributes locally
@@ -799,6 +803,13 @@ class WindowStateAnimator {
return false;
}
+ // During forced seamless rotation, the surface bounds get updated with the crop in the
+ // new rotation, which is not compatible with showing the surface in the old rotation.
+ // To work around that we disable cropping for such windows, as it is not necessary anyways.
+ if (w.mForceSeamlesslyRotate) {
+ return false;
+ }
+
// If we're animating, the wallpaper should only
// be updated at the end of the animation.
if (w.mAttrs.type == TYPE_WALLPAPER) {
@@ -1498,6 +1509,8 @@ class WindowStateAnimator {
}
}
+ // TODO(b/111504081): Consolidate seamless rotation logic.
+ @Deprecated
void seamlesslyRotate(SurfaceControl.Transaction t, int oldRotation, int newRotation) {
final WindowState w = mWin;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index b97460ae9eb8..e411c0adc75f 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -270,12 +270,6 @@ class WindowToken extends WindowContainer<WindowState> {
dc.reParentWindowToken(this);
mDisplayContent = dc;
- // The rounded corner overlay should not be rotated. We ensure that by moving it outside
- // the windowing layer.
- if (mRoundedCornerOverlay) {
- mDisplayContent.reparentToOverlay(mPendingTransaction, mSurfaceControl);
- }
-
// TODO(b/36740756): One day this should perhaps be hooked
// up with goodToGo, so we don't move a window
// to another display before the window behind
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
index 361522cfc880..f82b01224f96 100644
--- a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
@@ -99,7 +99,7 @@ public class CoordinateTransformsTest {
checkPoint(0, W).transformsTo(0, 0);
checkPoint(H, 0).transformsTo(W, H);
-}
+ }
@Test
public void transformLogicalToPhysicalCoordinates_rot180() {