Fix animation glitch with overlapping orientation changes.

Imagine the following scenario:
1. We want to begin a new app transition to an app which will change the
orientation.
2. A rotation animation from a previous rotation change is in progress.
3. Windows have finished drawing the first orientation change,
   so the display is already unfrozen.
In this case, we won't have a chance to select the new orientation which
our pending transition requires, because updateRotationUncheckedLocked
will bail due to the existing animation being in progress. This causes
the app behind to be revealed in the incorrect orientation (sometimes
creating landscape launchers) and the transition to be interrupted
halfway by the screenshot. In this case we can just defer the app
transition until the rotation animation has had a chance to complete.

Bug: 31098404
Change-Id: I1ae1041d3018d5681b46cd39c2d582861f0b014e
This commit is contained in:
Robert Carr
2016-09-20 13:36:42 -07:00
parent d031d57c9e
commit 42769fff6f
2 changed files with 30 additions and 0 deletions

View File

@@ -3859,6 +3859,19 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
// If this is true we have updated our desired orientation, but not yet
// changed the real orientation our applied our screen rotation animation.
// For example, because a previous screen rotation was in progress.
boolean rotationNeedsUpdateLocked() {
int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
mLastOrientation, rotation);
if (mRotation == rotation && mAltOrientation == altOrientation) {
return false;
}
return true;
}
@Override
public int[] setNewConfiguration(Configuration config) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,

View File

@@ -1353,8 +1353,25 @@ class WindowSurfacePlacer {
"Checking " + appsCount + " opening apps (frozen="
+ mService.mDisplayFrozen + " timeout="
+ mService.mAppTransition.isTimeout() + ")...");
final ScreenRotationAnimation screenRotationAnimation =
mService.mAnimator.getScreenRotationAnimationLocked(
Display.DEFAULT_DISPLAY);
int reason = APP_TRANSITION_TIMEOUT;
if (!mService.mAppTransition.isTimeout()) {
// Imagine the case where we are changing orientation due to an app transition, but a previous
// orientation change is still in progress. We won't process the orientation change
// for our transition because we need to wait for the rotation animation to finish.
// If we start the app transition at this point, we will interrupt it halfway with a new rotation
// animation after the old one finally finishes. It's better to defer the
// app transition.
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
mService.rotationNeedsUpdateLocked()) {
if (DEBUG_APP_TRANSITIONS) {
Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
}
return false;
}
for (int i = 0; i < appsCount; i++) {
AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,