summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/autofill/AutofillManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java195
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java33
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java8
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationController.java9
-rw-r--r--services/core/java/com/android/server/wm/ForcedSeamlessRotator.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
10 files changed, 237 insertions, 55 deletions
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 27ed35c384eb..1b8660c2556b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2299,7 +2299,15 @@ public final class AutofillManager {
@Override
public AccessibilityEvent onAccessibilityEvent(AccessibilityEvent event,
boolean accessibilityEnabled, int relevantEventTypes) {
- switch (event.getEventType()) {
+ final int type = event.getEventType();
+ if (sVerbose) {
+ // NOTE: this is waaay spammy, but that's life.
+ Log.v(TAG, "onAccessibilityEvent(" + AccessibilityEvent.eventTypeToString(type)
+ + "): virtualId="
+ + AccessibilityNodeInfo.getVirtualDescendantId(event.getSourceNodeId())
+ + ", client=" + getClient());
+ }
+ switch (type) {
case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
synchronized (mLock) {
if (mFocusedWindowId == event.getWindowId()
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 194679cc626e..71cf9b52a2db 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -39,10 +39,13 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.SystemProperties;
import android.provider.Settings.Secure;
import android.support.annotation.VisibleForTesting;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
@@ -57,6 +60,7 @@ import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.internal.util.Preconditions;
import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
@@ -74,6 +78,9 @@ import com.android.systemui.util.leak.RotationUtils;
* for antialiasing and emulation purposes.
*/
public class ScreenDecorations extends SystemUI implements Tunable {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "ScreenDecorations";
+
public static final String SIZE = "sysui_rounded_size";
public static final String PADDING = "sysui_rounded_content_padding";
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
@@ -93,9 +100,24 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private DisplayCutoutView mCutoutTop;
private DisplayCutoutView mCutoutBottom;
private boolean mPendingRotationChange;
+ private Handler mHandler;
@Override
public void start() {
+ mHandler = startHandlerThread();
+ mHandler.post(this::startOnScreenDecorationsThread);
+ setupStatusBarPaddingIfNeeded();
+ }
+
+ @VisibleForTesting
+ Handler startHandlerThread() {
+ HandlerThread thread = new HandlerThread("ScreenDecorations");
+ thread.start();
+ return thread.getThreadHandler();
+ }
+
+ private void startOnScreenDecorationsThread() {
+ mRotation = RotationUtils.getExactRotation(mContext);
mWindowManager = mContext.getSystemService(WindowManager.class);
mRoundedDefault = mContext.getResources().getDimensionPixelSize(
R.dimen.rounded_corner_radius);
@@ -107,12 +129,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
setupDecorations();
}
- int padding = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_content_padding);
- if (padding != 0) {
- setupPadding(padding);
- }
-
mDisplayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
@@ -126,8 +142,8 @@ public class ScreenDecorations extends SystemUI implements Tunable {
@Override
public void onDisplayChanged(int displayId) {
- if (mOverlay != null && mBottomOverlay != null
- && mRotation != RotationUtils.getExactRotation(mContext)) {
+ final int newRotation = RotationUtils.getExactRotation(mContext);
+ if (mOverlay != null && mBottomOverlay != null && mRotation != newRotation) {
// 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
@@ -136,20 +152,24 @@ public class ScreenDecorations extends SystemUI implements Tunable {
// - 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;
+ if (DEBUG) {
+ Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at "
+ + mRotation);
+ }
+
mOverlay.getViewTreeObserver().addOnPreDrawListener(
- new RestartingPreDrawListener(mOverlay));
+ new RestartingPreDrawListener(mOverlay, newRotation));
mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
- new RestartingPreDrawListener(mBottomOverlay));
-
+ new RestartingPreDrawListener(mBottomOverlay, newRotation));
}
updateOrientation();
}
};
- mRotation = -1;
mDisplayManager = (DisplayManager) mContext.getSystemService(
Context.DISPLAY_SERVICE);
- mDisplayManager.registerDisplayListener(mDisplayListener, null);
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ updateOrientation();
}
private void setupDecorations() {
@@ -179,10 +199,11 @@ public class ScreenDecorations extends SystemUI implements Tunable {
mWindowManager.getDefaultDisplay().getMetrics(metrics);
mDensity = metrics.density;
- Dependency.get(TunerService.class).addTunable(this, SIZE);
+ Dependency.get(Dependency.MAIN_HANDLER).post(
+ () -> Dependency.get(TunerService.class).addTunable(this, SIZE));
// Watch color inversion and invert the overlay as needed.
- SecureSetting setting = new SecureSetting(mContext, Dependency.get(Dependency.MAIN_HANDLER),
+ SecureSetting setting = new SecureSetting(mContext, mHandler,
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
@@ -215,18 +236,37 @@ public class ScreenDecorations extends SystemUI implements Tunable {
.start();
}
});
+
+ mOverlay.getViewTreeObserver().addOnPreDrawListener(
+ new ValidatingPreDrawListener(mOverlay));
+ mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
+ new ValidatingPreDrawListener(mBottomOverlay));
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
- mPendingRotationChange = false;
- updateOrientation();
- if (shouldDrawCutout() && mOverlay == null) {
- setupDecorations();
- }
+ mHandler.post(() -> {
+ int oldRotation = mRotation;
+ mPendingRotationChange = false;
+ updateOrientation();
+ if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
+ if (shouldDrawCutout() && mOverlay == null) {
+ setupDecorations();
+ }
+ if (mOverlay != null) {
+ // Updating the layout params ensures that ViewRootImpl will call relayoutWindow(),
+ // which ensures that the forced seamless rotation will end, even if we updated
+ // the rotation before window manager was ready (and was still waiting for sending
+ // the updated rotation).
+ updateLayoutParams();
+ }
+ });
}
- protected void updateOrientation() {
+ private void updateOrientation() {
+ Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(),
+ "must call on " + mHandler.getLooper().getThread()
+ + ", but was " + Thread.currentThread());
if (mPendingRotationChange) {
return;
}
@@ -306,7 +346,19 @@ public class ScreenDecorations extends SystemUI implements Tunable {
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
}
- private void setupPadding(int padding) {
+
+ private void setupStatusBarPaddingIfNeeded() {
+ // TODO: This should be moved to a more appropriate place, as it is not related to the
+ // screen decorations overlay.
+ int padding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.rounded_corner_content_padding);
+ if (padding != 0) {
+ setupStatusBarPadding(padding);
+ }
+
+ }
+
+ private void setupStatusBarPadding(int padding) {
// Add some padding to all the content near the edge of the screen.
StatusBar sb = getComponent(StatusBar.class);
View statusBar = (sb != null ? sb.getStatusBarWindow() : null);
@@ -375,30 +427,32 @@ public class ScreenDecorations extends SystemUI implements Tunable {
@Override
public void onTuningChanged(String key, String newValue) {
- if (mOverlay == null) return;
- if (SIZE.equals(key)) {
- int size = mRoundedDefault;
- int sizeTop = mRoundedDefaultTop;
- int sizeBottom = mRoundedDefaultBottom;
- if (newValue != null) {
- try {
- size = (int) (Integer.parseInt(newValue) * mDensity);
- } catch (Exception e) {
+ mHandler.post(() -> {
+ if (mOverlay == null) return;
+ if (SIZE.equals(key)) {
+ int size = mRoundedDefault;
+ int sizeTop = mRoundedDefaultTop;
+ int sizeBottom = mRoundedDefaultBottom;
+ if (newValue != null) {
+ try {
+ size = (int) (Integer.parseInt(newValue) * mDensity);
+ } catch (Exception e) {
+ }
}
- }
- if (sizeTop == 0) {
- sizeTop = size;
- }
- if (sizeBottom == 0) {
- sizeBottom = size;
- }
+ if (sizeTop == 0) {
+ sizeTop = size;
+ }
+ if (sizeBottom == 0) {
+ sizeBottom = size;
+ }
- setSize(mOverlay.findViewById(R.id.left), sizeTop);
- setSize(mOverlay.findViewById(R.id.right), sizeTop);
- setSize(mBottomOverlay.findViewById(R.id.left), sizeBottom);
- setSize(mBottomOverlay.findViewById(R.id.right), sizeBottom);
- }
+ setSize(mOverlay.findViewById(R.id.left), sizeTop);
+ setSize(mOverlay.findViewById(R.id.right), sizeTop);
+ setSize(mBottomOverlay.findViewById(R.id.left), sizeBottom);
+ setSize(mBottomOverlay.findViewById(R.id.right), sizeBottom);
+ }
+ });
}
private void setSize(View view, int pixelSize) {
@@ -457,6 +511,11 @@ public class ScreenDecorations extends SystemUI implements Tunable {
mVisibilityChangedListener = visibilityChangedListener;
mDecorations = decorations;
setId(R.id.display_cutout);
+ if (DEBUG) {
+ getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
+ (mInitialStart ? "OverlayTop" : "OverlayBottom")
+ + " drawn in rot " + mRotation));
+ }
}
public void setColor(int color) {
@@ -692,20 +751,66 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
private final View mView;
+ private final int mTargetRotation;
- private RestartingPreDrawListener(View view) {
+ private RestartingPreDrawListener(View view, int targetRotation) {
mView = view;
+ mTargetRotation = targetRotation;
}
@Override
public boolean onPreDraw() {
- mPendingRotationChange = false;
mView.getViewTreeObserver().removeOnPreDrawListener(this);
+
+ if (mTargetRotation == mRotation) {
+ if (DEBUG) {
+ Log.i(TAG, (mView == mOverlay ? "OverlayTop" : "OverlayBottom")
+ + " already in target rot "
+ + mTargetRotation + ", allow draw without restarting it");
+ }
+ return true;
+ }
+
+ mPendingRotationChange = false;
// This changes the window attributes - we need to restart the traversal for them to
// take effect.
updateOrientation();
+ if (DEBUG) {
+ Log.i(TAG, (mView == mOverlay ? "OverlayTop" : "OverlayBottom")
+ + " restarting listener fired, restarting draw for rot " + mRotation);
+ }
mView.invalidate();
return false;
}
}
+
+ /**
+ * A pre-draw listener, that validates that the rotation we draw in matches the displays
+ * rotation before continuing the draw.
+ *
+ * This is to prevent a race condition, where we have not received the display changed event
+ * yet, and would thus draw in an old orientation.
+ */
+ private class ValidatingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
+
+ private final View mView;
+
+ public ValidatingPreDrawListener(View view) {
+ mView = view;
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ final int displayRotation = RotationUtils.getExactRotation(mContext);
+ if (displayRotation != mRotation && !mPendingRotationChange) {
+ if (DEBUG) {
+ Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
+ + displayRotation + ". Restarting draw");
+ }
+ mView.invalidate();
+ return false;
+ }
+ return true;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 06f26c9cbc7c..469c3c2c60b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -667,9 +667,15 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
entry.row.getNotificationChildren();
for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow row = notificationChildren.get(i);
- if ((row.getStatusBarNotification().getNotification().flags
- & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
- // the child is a foreground service notification which we can't remove!
+ NotificationData.Entry childEntry = row.getEntry();
+ boolean isForeground = (row.getStatusBarNotification().getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE) != 0;
+ boolean keepForReply = FORCE_REMOTE_INPUT_HISTORY
+ && (shouldKeepForRemoteInput(childEntry)
+ || shouldKeepForSmartReply(childEntry));
+ if (isForeground || keepForReply) {
+ // the child is a foreground service notification which we can't remove or it's
+ // a child we're keeping around for reply!
continue;
}
row.setKeepInParent(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index f1bf31d7a58a..644c0b347bde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -34,8 +34,10 @@ import static org.mockito.Mockito.when;
import android.app.Fragment;
import android.content.res.Configuration;
+import android.os.Handler;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.View;
@@ -60,6 +62,7 @@ import org.junit.runner.RunWith;
@SmallTest
public class ScreenDecorationsTest extends SysuiTestCase {
+ private TestableLooper mTestableLooper;
private ScreenDecorations mScreenDecorations;
private StatusBar mStatusBar;
private WindowManager mWindowManager;
@@ -71,6 +74,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
@Before
public void setup() {
+ mTestableLooper = TestableLooper.get(this);
+ mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+ new Handler(mTestableLooper.getLooper()));
+
mStatusBar = mock(StatusBar.class);
mWindowManager = mock(WindowManager.class);
mView = spy(new StatusBarWindowView(mContext, null));
@@ -88,7 +95,31 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mTunerService = mDependency.injectMockDependency(TunerService.class);
- mScreenDecorations = new ScreenDecorations();
+
+ mScreenDecorations = new ScreenDecorations() {
+ @Override
+ public void start() {
+ super.start();
+ mTestableLooper.processAllMessages();
+ }
+
+ @Override
+ Handler startHandlerThread() {
+ return new Handler(mTestableLooper.getLooper());
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mTestableLooper.processAllMessages();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ super.onTuningChanged(key, newValue);
+ mTestableLooper.processAllMessages();
+ }
+ };
mScreenDecorations.mContext = mContext;
mScreenDecorations.mComponents = mContext.getComponents();
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index dc84498353ea..58823036212d 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -81,6 +81,13 @@ final class SaveUi {
void onDestroy();
}
+ /**
+ * Wrapper that guarantees that only one callback is triggered by ignoring further calls after
+ * it's destroyed.
+ *
+ * <p>It's needed becase {@link #onCancel(IntentSender)} is always called when the Save UI
+ * dialog is dismissed.
+ */
private class OneTimeListener implements OnSaveListener {
private final OnSaveListener mRealListener;
@@ -96,7 +103,6 @@ final class SaveUi {
if (mDone) {
return;
}
- mDone = true;
mRealListener.onSave();
}
@@ -106,7 +112,6 @@ final class SaveUi {
if (mDone) {
return;
}
- mDone = true;
mRealListener.onCancel(listener);
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 75f27231c976..60f79f720242 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -694,9 +694,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null;
if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
// Picture-in-picture mode changes also trigger a multi-window mode change as well, so
- // update that here in order
+ // update that here in order. Set the last reported MW state to the same as the PiP
+ // state since we haven't yet actually resized the task (these callbacks need to
+ // preceed the configuration change from the resiez.
+ // TODO(110009072): Once we move these callbacks to the client, remove all logic related
+ // to forcing the update of the picture-in-picture mode as a part of the PiP animation.
mLastReportedPictureInPictureMode = inPictureInPictureMode;
- mLastReportedMultiWindowMode = inMultiWindowMode();
+ mLastReportedMultiWindowMode = inPictureInPictureMode;
final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
targetStackBounds, null);
schedulePictureInPictureModeChanged(newConfig);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index b2a12bef5283..86f328d248db 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -31,11 +31,13 @@ import android.os.IBinder;
import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.Choreographer;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -112,6 +114,7 @@ public class BoundsAnimationController {
private final Interpolator mFastOutSlowInInterpolator;
private boolean mFinishAnimationAfterTransition = false;
private final AnimationHandler mAnimationHandler;
+ private Choreographer mChoreographer;
private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
@@ -123,6 +126,12 @@ public class BoundsAnimationController {
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
mAnimationHandler = animationHandler;
+ if (animationHandler != null) {
+ // If an animation handler is provided, then ensure that it runs on the sf vsync tick
+ handler.runWithScissors(() -> mChoreographer = Choreographer.getSfInstance(),
+ 0 /* timeout */);
+ animationHandler.setProvider(new SfVsyncFrameCallbackProvider(mChoreographer));
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
index bebc5656c284..efb43a6b90cf 100644
--- a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
@@ -21,6 +21,7 @@ import static android.view.Surface.ROTATION_90;
import android.graphics.Matrix;
import android.view.DisplayInfo;
+import android.view.Surface.Rotation;
import com.android.server.wm.utils.CoordinateTransforms;
@@ -65,6 +66,16 @@ public class ForcedSeamlessRotator {
}
/**
+ * Returns the rotation of the display before it started rotating.
+ *
+ * @return the old rotation of the display
+ */
+ @Rotation
+ public int getOldRotation() {
+ return mOldRotation;
+ }
+
+ /**
* Removes the transform to the window token's surface that undoes the effect of the global
* display rotation.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c4a0a6961136..8b4a2dd36e6c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1005,7 +1005,6 @@ public class WindowManagerService extends IWindowManager.Stub
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
final AnimationHandler animationHandler = new AnimationHandler();
- animationHandler.setProvider(new SfVsyncFrameCallbackProvider());
mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
AnimationThread.getHandler(), animationHandler);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 009f3930d02e..1ae680f793ca 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -681,6 +681,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void forceSeamlesslyRotateIfAllowed(int oldRotation, int rotation) {
if (mForceSeamlesslyRotate) {
+ if (mPendingForcedSeamlessRotate != null) {
+ oldRotation = mPendingForcedSeamlessRotate.getOldRotation();
+ }
+
mPendingForcedSeamlessRotate = new ForcedSeamlessRotator(
oldRotation, rotation, getDisplayInfo());
mPendingForcedSeamlessRotate.unrotate(this.mToken);