Ignore rotation update during recent animation.
During the recent animation, the closing app is still considered on top and its required orientation is used for the next rotation computation. When going to launcher and rotating the device at the same time, a rotation update is triggered by the sensor and if the closing app allows a change of orientation, the display ends up rotating at the end of the animation, which make the launcher rotate even if it is not supposed to do so. Test: atest WmTests: com.android.server.wm.DisplayContentTests#testRecentsNotRotatingWithFixedRotation Fixes: 157447718 Change-Id: I3f2a46ddfe5e76ad3200ea27ad272ae36b6bcc8d
This commit is contained in:
@@ -32,6 +32,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
|
||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
|
||||
import static android.os.Build.VERSION_CODES.N;
|
||||
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
||||
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
|
||||
@@ -1526,12 +1527,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the provided record to {@link mFixedRotationLaunchingApp} if possible to apply fixed
|
||||
* Sets the provided record to {@link #mFixedRotationLaunchingApp} if possible to apply fixed
|
||||
* rotation transform to it and indicate that the display may be rotated after it is launched.
|
||||
*/
|
||||
void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Surface.Rotation int rotation) {
|
||||
final WindowToken prevRotatedLaunchingApp = mFixedRotationLaunchingApp;
|
||||
if (prevRotatedLaunchingApp != null && prevRotatedLaunchingApp == r
|
||||
if (prevRotatedLaunchingApp == r
|
||||
&& r.getWindowConfiguration().getRotation() == rotation) {
|
||||
// The given launching app and target rotation are the same as the existing ones.
|
||||
return;
|
||||
@@ -5659,6 +5660,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if there is an ongoing animation to the "Recents" activity and this
|
||||
* activity as a fixed orientation so shouldn't be rotated.
|
||||
*/
|
||||
boolean isFixedOrientationRecentsAnimating() {
|
||||
return mAnimatingRecents != null
|
||||
&& mAnimatingRecents.getRequestedConfigurationOrientation()
|
||||
!= ORIENTATION_UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppTransitionFinishedLocked(IBinder token) {
|
||||
final ActivityRecord r = getActivityRecord(token);
|
||||
|
||||
@@ -430,6 +430,15 @@ public class DisplayRotation {
|
||||
"Deferring rotation, still finishing previous rotation");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mDisplayContent.mFixedRotationTransitionListener
|
||||
.isFixedOrientationRecentsAnimating()) {
|
||||
// During the recents animation, the closing app might still be considered on top.
|
||||
// In order to ignore its requested orientation to avoid a sensor led rotation (e.g
|
||||
// user rotating the device while the recents animation is running), we ignore
|
||||
// rotation update while the animation is running.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mService.mDisplayEnabled) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
@@ -79,6 +80,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityTaskManager;
|
||||
@@ -1230,12 +1232,30 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
assertTrue(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecentsNotRotatingWithFixedRotation() {
|
||||
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
|
||||
doCallRealMethod().when(displayRotation).updateRotationUnchecked(anyBoolean());
|
||||
doCallRealMethod().when(displayRotation).updateOrientation(anyInt(), anyBoolean());
|
||||
|
||||
final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent,
|
||||
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS);
|
||||
recentsActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
|
||||
|
||||
mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
|
||||
displayRotation.setRotation((displayRotation.getRotation() + 1) % 4);
|
||||
assertFalse(displayRotation.updateRotationUnchecked(false));
|
||||
|
||||
mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(false);
|
||||
assertTrue(displayRotation.updateRotationUnchecked(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteRotation() {
|
||||
DisplayContent dc = createNewDisplay();
|
||||
|
||||
final DisplayRotation dr = dc.getDisplayRotation();
|
||||
Mockito.doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
|
||||
doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
|
||||
Mockito.doReturn(ROTATION_90).when(dr).rotationForOrientation(anyInt(), anyInt());
|
||||
final boolean[] continued = new boolean[1];
|
||||
// TODO(display-merge): Remove cast
|
||||
|
||||
Reference in New Issue
Block a user