Merge "Defer rotation update during recent transition" into tm-dev am: bc9e4bec5a
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16966123 Change-Id: I9224bb70bdf4fe3b91a9ddb60bd214a37992b392
This commit is contained in:
@@ -6368,13 +6368,28 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Returns the fixed orientation requested by a transient launch (e.g. recents animation).
|
||||
* If it doesn't return SCREEN_ORIENTATION_UNSET, the rotation change should be deferred.
|
||||
*/
|
||||
boolean isTopFixedOrientationRecentsAnimating() {
|
||||
return mAnimatingRecents != null
|
||||
&& mAnimatingRecents.getRequestedConfigurationOrientation(true /* forDisplay */)
|
||||
!= ORIENTATION_UNDEFINED && !hasTopFixedRotationLaunchingApp();
|
||||
@ActivityInfo.ScreenOrientation int getTransientFixedOrientation() {
|
||||
ActivityRecord source = null;
|
||||
if (mTransitionController.isShellTransitionsEnabled()) {
|
||||
final ActivityRecord r = mFixedRotationLaunchingApp;
|
||||
if (r != null && mTransitionController.isTransientLaunch(r)) {
|
||||
source = r;
|
||||
}
|
||||
} else if (mAnimatingRecents != null && !hasTopFixedRotationLaunchingApp()) {
|
||||
source = mAnimatingRecents;
|
||||
}
|
||||
if (source == null || source.getRequestedConfigurationOrientation(
|
||||
true /* forDisplay */) == ORIENTATION_UNDEFINED) {
|
||||
return SCREEN_ORIENTATION_UNSET;
|
||||
}
|
||||
if (!mWmService.mPolicy.okToAnimate(false /* ignoreScreenOn */)) {
|
||||
// If screen is off or the device is going to sleep, then still allow to update.
|
||||
return SCREEN_ORIENTATION_UNSET;
|
||||
}
|
||||
return source.mOrientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -419,11 +419,8 @@ public class DisplayRotation {
|
||||
* THE SCREEN.
|
||||
*/
|
||||
boolean updateRotationUnchecked(boolean forceUpdate) {
|
||||
final boolean useShellTransitions =
|
||||
mDisplayContent.mTransitionController.isShellTransitionsEnabled();
|
||||
|
||||
final int displayId = mDisplayContent.getDisplayId();
|
||||
if (!forceUpdate && !useShellTransitions) {
|
||||
if (!forceUpdate) {
|
||||
if (mDeferredRotationPauseCount > 0) {
|
||||
// Rotation updates have been paused temporarily. Defer the update until updates
|
||||
// have been resumed.
|
||||
@@ -449,17 +446,16 @@ public class DisplayRotation {
|
||||
return false;
|
||||
}
|
||||
|
||||
final RecentsAnimationController recentsAnimController =
|
||||
mService.getRecentsAnimationController();
|
||||
if (recentsAnimController != null && mDisplayContent.mFixedRotationTransitionListener
|
||||
.isTopFixedOrientationRecentsAnimating()
|
||||
// If screen is off or the device is going to sleep, then still allow to update.
|
||||
&& mService.mPolicy.okToAnimate(false /* ignoreScreenOn */)) {
|
||||
final int transientFixedOrientation =
|
||||
mDisplayContent.mFixedRotationTransitionListener.getTransientFixedOrientation();
|
||||
if (transientFixedOrientation != SCREEN_ORIENTATION_UNSET) {
|
||||
// Makes sure that after the transition is finished, updateOrientation() can see
|
||||
// the difference from the latest orientation source.
|
||||
mLastOrientation = transientFixedOrientation;
|
||||
// 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.
|
||||
recentsAnimController.setCheckRotationAfterCleanup();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -513,7 +509,7 @@ public class DisplayRotation {
|
||||
|
||||
mDisplayContent.setLayoutNeeded();
|
||||
|
||||
if (useShellTransitions) {
|
||||
if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
|
||||
final boolean wasCollecting = mDisplayContent.mTransitionController.isCollecting();
|
||||
final TransitionRequestInfo.DisplayChange change = wasCollecting ? null
|
||||
: new TransitionRequestInfo.DisplayChange(mDisplayContent.getDisplayId(),
|
||||
|
||||
@@ -122,7 +122,6 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
private final int mDisplayId;
|
||||
private boolean mWillFinishToHome = false;
|
||||
private final Runnable mFailsafeRunnable = this::onFailsafe;
|
||||
private Runnable mCheckRotationAfterCleanup;
|
||||
|
||||
// The recents component app token that is shown behind the visibile tasks
|
||||
private ActivityRecord mTargetActivityRecord;
|
||||
@@ -919,24 +918,6 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
mCancelDeferredWithScreenshot = screenshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the display rotation change is ignored while recents animation is running, make sure that
|
||||
* the pending rotation change will be applied after the animation finishes.
|
||||
*/
|
||||
void setCheckRotationAfterCleanup() {
|
||||
if (mCheckRotationAfterCleanup != null) return;
|
||||
mCheckRotationAfterCleanup = () -> {
|
||||
synchronized (mService.mGlobalLock) {
|
||||
if (mDisplayContent.getDisplayRotation()
|
||||
.updateRotationAndSendNewConfigIfChanged()) {
|
||||
if (mTargetActivityRecord != null) {
|
||||
mTargetActivityRecord.finishFixedRotationTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether we should defer the cancel from a root task order change until the next app
|
||||
* transition.
|
||||
@@ -1037,10 +1018,6 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
if (mStatusBar != null) {
|
||||
mStatusBar.onRecentsAnimationStateChanged(false /* running */);
|
||||
}
|
||||
if (mCheckRotationAfterCleanup != null) {
|
||||
mService.mH.post(mCheckRotationAfterCleanup);
|
||||
mCheckRotationAfterCleanup = null;
|
||||
}
|
||||
}
|
||||
|
||||
void scheduleFailsafe() {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
@@ -440,16 +441,26 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
||||
public void testCheckRotationAfterCleanup() {
|
||||
mWm.setRecentsAnimationController(mController);
|
||||
spyOn(mDisplayContent.mFixedRotationTransitionListener);
|
||||
doReturn(true).when(mDisplayContent.mFixedRotationTransitionListener)
|
||||
.isTopFixedOrientationRecentsAnimating();
|
||||
final ActivityRecord recents = mock(ActivityRecord.class);
|
||||
recents.mOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
doReturn(ORIENTATION_PORTRAIT).when(recents)
|
||||
.getRequestedConfigurationOrientation(anyBoolean());
|
||||
mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recents);
|
||||
|
||||
// Rotation update is skipped while the recents animation is running.
|
||||
assertFalse(mDisplayContent.getDisplayRotation().updateOrientation(DisplayContentTests
|
||||
.getRotatedOrientation(mDefaultDisplay), false /* forceUpdate */));
|
||||
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
|
||||
final int topOrientation = DisplayContentTests.getRotatedOrientation(mDefaultDisplay);
|
||||
assertFalse(displayRotation.updateOrientation(topOrientation, false /* forceUpdate */));
|
||||
assertEquals(recents.mOrientation, displayRotation.getLastOrientation());
|
||||
final int prevRotation = mDisplayContent.getRotation();
|
||||
mWm.cleanupRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
|
||||
waitHandlerIdle(mWm.mH);
|
||||
|
||||
// In real case, it is called from RecentsAnimation#finishAnimation -> continueWindowLayout
|
||||
// -> handleAppTransitionReady -> add FINISH_LAYOUT_REDO_CONFIG, and DisplayContent#
|
||||
// applySurfaceChangesTransaction will call updateOrientation for FINISH_LAYOUT_REDO_CONFIG.
|
||||
assertTrue(displayRotation.updateOrientation(topOrientation, false /* forceUpdate */));
|
||||
// The display should be updated to the changed orientation after the animation is finished.
|
||||
assertNotEquals(mDisplayContent.getRotation(), prevRotation);
|
||||
assertNotEquals(displayRotation.getRotation(), prevRotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.wm;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
||||
@@ -33,13 +34,17 @@ import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
|
||||
import static android.window.TransitionInfo.isIndependent;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
@@ -659,6 +664,41 @@ public class TransitionTests extends WindowTestsBase {
|
||||
assertNull(mDisplayContent.getAsyncRotationController());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeferRotationForTransientLaunch() {
|
||||
final TestTransitionPlayer player = registerTestTransitionPlayer();
|
||||
assumeFalse(mDisplayContent.mTransitionController.useShellTransitionsRotation());
|
||||
final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
|
||||
final ActivityRecord home = new ActivityBuilder(mAtm)
|
||||
.setTask(mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask())
|
||||
.setScreenOrientation(SCREEN_ORIENTATION_NOSENSOR).setVisible(false).build();
|
||||
final Transition transition = home.mTransitionController.createTransition(TRANSIT_OPEN);
|
||||
final int prevRotation = mDisplayContent.getRotation();
|
||||
transition.setTransientLaunch(home, null /* restoreBelow */);
|
||||
home.mTransitionController.requestStartTransition(transition, home.getTask(),
|
||||
null /* remoteTransition */, null /* displayChange */);
|
||||
transition.collectExistenceChange(home);
|
||||
home.mVisibleRequested = true;
|
||||
mDisplayContent.setFixedRotationLaunchingAppUnchecked(home);
|
||||
doReturn(true).when(home).hasFixedRotationTransform(any());
|
||||
player.startTransition();
|
||||
player.onTransactionReady(mDisplayContent.getSyncTransaction());
|
||||
|
||||
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
|
||||
spyOn(displayRotation);
|
||||
doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
|
||||
doReturn(prevRotation + 1).when(displayRotation).rotationForOrientation(
|
||||
anyInt() /* orientation */, anyInt() /* lastRotation */);
|
||||
// Rotation update is skipped while the recents animation is running.
|
||||
assertFalse(mDisplayContent.updateRotationUnchecked());
|
||||
assertEquals(SCREEN_ORIENTATION_NOSENSOR, displayRotation.getLastOrientation());
|
||||
// Return to the app without fixed orientation from recents.
|
||||
app.moveFocusableActivityToTop("test");
|
||||
player.finish();
|
||||
// The display should be updated to the changed orientation after the animation is finish.
|
||||
assertNotEquals(mDisplayContent.getRotation(), prevRotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntermediateVisibility() {
|
||||
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
|
||||
|
||||
Reference in New Issue
Block a user