Merge changes Ic134c432,I5c5c1233 into rvc-qpr-dev

* changes:
  Allow to replace fixed rotation state
  Finish fixed rotation after recents moved to top
This commit is contained in:
TreeHugger Robot
2020-08-27 15:06:01 +00:00
committed by Android (Google) Code Review
6 changed files with 87 additions and 18 deletions

View File

@@ -1573,7 +1573,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// the heavy operations. This also benefits that the states of multiple activities // the heavy operations. This also benefits that the states of multiple activities
// are handled together. // are handled together.
r.linkFixedRotationTransform(prevRotatedLaunchingApp); r.linkFixedRotationTransform(prevRotatedLaunchingApp);
setFixedRotationLaunchingAppUnchecked(r, rotation); if (r != mFixedRotationTransitionListener.mAnimatingRecents) {
// Only update the record for normal activity so the display orientation can be
// updated when the transition is done if it becomes the top. And the case of
// recents can be handled when the recents animation is finished.
setFixedRotationLaunchingAppUnchecked(r, rotation);
}
return; return;
} }
@@ -5642,6 +5647,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/ */
private ActivityRecord mAnimatingRecents; private ActivityRecord mAnimatingRecents;
/** Whether {@link #mAnimatingRecents} is going to be the top activity. */
private boolean mRecentsWillBeTop;
/** /**
* If the recents activity has a fixed orientation which is different from the current top * If the recents activity has a fixed orientation which is different from the current top
* activity, it will be rotated before being shown so we avoid a screen rotation animation * activity, it will be rotated before being shown so we avoid a screen rotation animation
@@ -5667,10 +5675,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* If {@link #mAnimatingRecents} still has fixed rotation, it should be moved to top so we * If {@link #mAnimatingRecents} still has fixed rotation, it should be moved to top so we
* don't clear {@link #mFixedRotationLaunchingApp} that will be handled by transition. * don't clear {@link #mFixedRotationLaunchingApp} that will be handled by transition.
*/ */
void onFinishRecentsAnimation(boolean moveRecentsToBack) { void onFinishRecentsAnimation() {
final ActivityRecord animatingRecents = mAnimatingRecents; final ActivityRecord animatingRecents = mAnimatingRecents;
final boolean recentsWillBeTop = mRecentsWillBeTop;
mAnimatingRecents = null; mAnimatingRecents = null;
if (!moveRecentsToBack) { mRecentsWillBeTop = false;
if (recentsWillBeTop) {
// The recents activity will be the top, such as staying at recents list or // The recents activity will be the top, such as staying at recents list or
// returning to home (if home and recents are the same activity). // returning to home (if home and recents are the same activity).
return; return;
@@ -5693,6 +5703,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
} }
} }
void notifyRecentsWillBeTop() {
mRecentsWillBeTop = true;
}
/** /**
* Return {@code true} if there is an ongoing animation to the "Recents" activity and this * 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. * activity as a fixed orientation so shouldn't be rotated.
@@ -5713,6 +5727,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (r == null || r == mAnimatingRecents) { if (r == null || r == mAnimatingRecents) {
return; return;
} }
if (mAnimatingRecents != null && mRecentsWillBeTop) {
// The activity is not the recents and it should be moved to back later, so it is
// better to keep its current appearance for the next transition. Otherwise the
// display orientation may be updated too early and the layout procedures at the
// end of finishing recents animation is skipped. That causes flickering because
// the surface of closing app hasn't updated to invisible.
return;
}
if (mFixedRotationLaunchingApp == null) { if (mFixedRotationLaunchingApp == null) {
// In most cases this is a no-op if the activity doesn't have fixed rotation. // In most cases this is a no-op if the activity doesn't have fixed rotation.
// Otherwise it could be from finishing recents animation while the display has // Otherwise it could be from finishing recents animation while the display has

View File

@@ -702,6 +702,11 @@ public class RecentsAnimationController implements DeathRecipient {
"cleanupAnimation(): Notify animation finished mPendingAnimations=%d " "cleanupAnimation(): Notify animation finished mPendingAnimations=%d "
+ "reorderMode=%d", + "reorderMode=%d",
mPendingAnimations.size(), reorderMode); mPendingAnimations.size(), reorderMode);
if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION) {
// Notify the state at the beginning because the removeAnimation may notify the
// transition is finished. This is a signal that there will be a next transition.
mDisplayContent.mFixedRotationTransitionListener.notifyRecentsWillBeTop();
}
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i); final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) { if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
@@ -742,8 +747,7 @@ public class RecentsAnimationController implements DeathRecipient {
mTargetActivityRecord.token); mTargetActivityRecord.token);
} }
} }
mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation( mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION /* moveRecentsToBack */);
// Notify that the animation has ended // Notify that the animation has ended
if (mStatusBar != null) { if (mStatusBar != null) {

View File

@@ -531,7 +531,7 @@ class WindowToken extends WindowContainer<WindowState> {
void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
Configuration config) { Configuration config) {
if (mFixedRotationTransformState != null) { if (mFixedRotationTransformState != null) {
return; cleanUpFixedRotationTransformState(true /* replacing */);
} }
mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
new Configuration(config), mDisplayContent.getRotation()); new Configuration(config), mDisplayContent.getRotation());
@@ -548,12 +548,12 @@ class WindowToken extends WindowContainer<WindowState> {
* one. This takes the same effect as {@link #applyFixedRotationTransform}. * one. This takes the same effect as {@link #applyFixedRotationTransform}.
*/ */
void linkFixedRotationTransform(WindowToken other) { void linkFixedRotationTransform(WindowToken other) {
if (mFixedRotationTransformState != null) { final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState;
if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) {
return; return;
} }
final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; if (mFixedRotationTransformState != null) {
if (fixedRotationState == null) { cleanUpFixedRotationTransformState(true /* replacing */);
return;
} }
mFixedRotationTransformState = fixedRotationState; mFixedRotationTransformState = fixedRotationState;
fixedRotationState.mAssociatedTokens.add(this); fixedRotationState.mAssociatedTokens.add(this);
@@ -609,11 +609,17 @@ class WindowToken extends WindowContainer<WindowState> {
// The state is cleared at the end, because it is used to indicate that other windows can // The state is cleared at the end, because it is used to indicate that other windows can
// use seamless rotation when applying rotation to display. // use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(); state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(
false /* replacing */);
} }
} }
private void cleanUpFixedRotationTransformState() { private void cleanUpFixedRotationTransformState(boolean replacing) {
if (replacing && mFixedRotationTransformState.mAssociatedTokens.size() > 1) {
// The state is not only used by self. Make sure to leave the influence by others.
mFixedRotationTransformState.mAssociatedTokens.remove(this);
mFixedRotationTransformState.mRotatedContainers.remove(this);
}
mFixedRotationTransformState = null; mFixedRotationTransformState = null;
notifyFixedRotationTransform(false /* enabled */); notifyFixedRotationTransform(false /* enabled */);
} }

View File

@@ -1282,7 +1282,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertFalse(displayRotation.updateRotationUnchecked(false)); assertFalse(displayRotation.updateRotationUnchecked(false));
// Rotation can be updated if the recents animation is finished. // Rotation can be updated if the recents animation is finished.
mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(false); mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
assertTrue(displayRotation.updateRotationUnchecked(false)); assertTrue(displayRotation.updateRotationUnchecked(false));
// Rotation can be updated if the recents animation is animating but it is not on top, e.g. // Rotation can be updated if the recents animation is animating but it is not on top, e.g.

View File

@@ -363,12 +363,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
assertFalse(homeActivity.hasFixedRotationTransform()); assertFalse(homeActivity.hasFixedRotationTransform());
} }
@Test private ActivityRecord prepareFixedRotationLaunchingAppWithRecentsAnim() {
public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
final ActivityRecord homeActivity = createHomeActivity(); final ActivityRecord homeActivity = createHomeActivity();
homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final ActivityRecord activity = createActivityRecord(mDefaultDisplay, final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
// Add a window so it can be animated by the recents.
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
activity.addWindow(win);
// Assume an activity is launching to different rotation. // Assume an activity is launching to different rotation.
mDefaultDisplay.setFixedRotationLaunchingApp(activity, mDefaultDisplay.setFixedRotationLaunchingApp(activity,
(mDefaultDisplay.getRotation() + 1) % 4); (mDefaultDisplay.getRotation() + 1) % 4);
@@ -379,6 +381,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Before the transition is done, the recents animation is triggered. // Before the transition is done, the recents animation is triggered.
initializeRecentsAnimationController(mController, homeActivity); initializeRecentsAnimationController(mController, homeActivity);
assertFalse(homeActivity.hasFixedRotationTransform()); assertFalse(homeActivity.hasFixedRotationTransform());
assertTrue(mController.isAnimatingTask(activity.getTask()));
return activity;
}
@Test
public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim();
// Simulate giving up the swipe up gesture to keep the original activity as top. // Simulate giving up the swipe up gesture to keep the original activity as top.
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
@@ -387,6 +397,21 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp()); assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp());
} }
@Test
public void testKeepFixedRotationWhenMovingRecentsToTop() {
final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim();
// Assume a transition animation has started running before recents animation. Then the
// activity will receive onAnimationFinished that notifies app transition finished when
// removing the recents animation of task.
activity.getTask().getAnimationSources().add(activity);
// Simulate swiping to home/recents before the transition is done.
mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
// The rotation transform should be preserved. In real case, it will be cleared by the next
// move-to-top transition.
assertTrue(activity.hasFixedRotationTransform());
}
@Test @Test
public void testWallpaperHasFixedRotationApplied() { public void testWallpaperHasFixedRotationApplied() {
mWm.setRecentsAnimationController(mController); mWm.setRecentsAnimationController(mController);

View File

@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -139,6 +140,8 @@ public class WindowTokenTests extends WindowTestsBase {
public void testFinishFixedRotationTransform() { public void testFinishFixedRotationTransform() {
final WindowToken appToken = mAppWindow.mToken; final WindowToken appToken = mAppWindow.mToken;
final WindowToken wallpaperToken = mWallpaperWindow.mToken; final WindowToken wallpaperToken = mWallpaperWindow.mToken;
final WindowToken testToken =
WindowTestUtils.createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent);
final Configuration config = new Configuration(mDisplayContent.getConfiguration()); final Configuration config = new Configuration(mDisplayContent.getConfiguration());
final int originalRotation = config.windowConfiguration.getRotation(); final int originalRotation = config.windowConfiguration.getRotation();
final int targetRotation = (originalRotation + 1) % 4; final int targetRotation = (originalRotation + 1) % 4;
@@ -151,11 +154,20 @@ public class WindowTokenTests extends WindowTestsBase {
assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation()); assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation());
assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation()); assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation());
// The display doesn't rotate, the transformation will be canceled. testToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config);
mAppWindow.mToken.finishFixedRotationTransform(); // The wallpaperToken was linked to appToken, this should make it link to testToken.
wallpaperToken.linkFixedRotationTransform(testToken);
// The window tokens should restore to the original rotation. // Assume the display doesn't rotate, the transformation will be canceled.
appToken.finishFixedRotationTransform();
// The appToken should restore to the original rotation.
assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation()); assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation());
// The wallpaperToken is linked to testToken, it should keep the target rotation.
assertNotEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation());
testToken.finishFixedRotationTransform();
// The rotation of wallpaperToken should be restored because its linked state is finished.
assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation()); assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation());
} }