Notify client to clear intermediate rotated adjustments
For example: launch a landscape activity while device is portrait, and then launch another portrait activity before previous transition is done. If the landscape activity is destroyed before sending the fixed rotation adjustment for restoration, the adjustment is always retained by client side app. That causes the Display objects associated with application Resources to always return rotation from the adjustment. This change notifies client to clear the rotated adjustments if the the display won't be rotated by the next top activity before the transition is done, so the app can get the correct rotation in time. The transform will be cleared at the end of transition animation so the closing animation won't jump cut with rotation change. E.g. launch an activity in different orientation and press home or back key before the launch animation is finished. Also simply a bit for the path of clearing fixed rotation state to avoid sending duplicated adjustments. Bug: 161519202 Bug: 168263090 Bug: 177390830 Test: DisplayContentTests#testClearIntermediateFixedRotationAdjustments Change-Id: Ica074604df3e74eabbdef931531abe51855103e5 Merged-In: Ica074604df3e74eabbdef931531abe51855103e5
This commit is contained in:
@@ -1513,6 +1513,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
final int rotation = rotationForActivityInDifferentOrientation(r);
|
||||
if (rotation == ROTATION_UNDEFINED) {
|
||||
// The display rotation won't be changed by current top activity. The client side
|
||||
// adjustments of previous rotated activity should be cleared earlier. Otherwise if
|
||||
// the current top is in the same process, it may get the rotated state. The transform
|
||||
// will be cleared later with transition callback to ensure smooth animation.
|
||||
if (hasTopFixedRotationLaunchingApp()) {
|
||||
mFixedRotationLaunchingApp.notifyFixedRotationTransform(false /* enabled */);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!r.getParent().matchParentBounds()) {
|
||||
|
||||
@@ -622,11 +622,6 @@ class WindowToken extends WindowContainer<WindowState> {
|
||||
state.mIsTransforming = false;
|
||||
if (applyDisplayRotation != null) {
|
||||
applyDisplayRotation.run();
|
||||
} else {
|
||||
// The display will not rotate to the rotation of this container, let's cancel them.
|
||||
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
|
||||
state.mAssociatedTokens.get(i).cancelFixedRotationTransform();
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
@@ -634,11 +629,15 @@ class WindowToken extends WindowContainer<WindowState> {
|
||||
final WindowToken token = state.mAssociatedTokens.get(i);
|
||||
token.mFixedRotationTransformState = null;
|
||||
token.notifyFixedRotationTransform(false /* enabled */);
|
||||
if (applyDisplayRotation == null) {
|
||||
// Notify cancellation because the display does not change rotation.
|
||||
token.cancelFixedRotationTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Notifies application side to enable or disable the rotation adjustment of display info. */
|
||||
private void notifyFixedRotationTransform(boolean enabled) {
|
||||
void notifyFixedRotationTransform(boolean enabled) {
|
||||
FixedRotationAdjustments adjustments = null;
|
||||
// A token may contain windows of the same processes or different processes. The list is
|
||||
// used to avoid sending the same adjustments to a process multiple times.
|
||||
@@ -682,7 +681,6 @@ class WindowToken extends WindowContainer<WindowState> {
|
||||
// The window may be detached or detaching.
|
||||
return;
|
||||
}
|
||||
notifyFixedRotationTransform(false /* enabled */);
|
||||
final int originalRotation = getWindowConfiguration().getRotation();
|
||||
onConfigurationChanged(parent.getConfiguration());
|
||||
onCancelFixedRotationTransform(originalRotation);
|
||||
|
||||
@@ -88,6 +88,7 @@ import static org.mockito.Mockito.doCallRealMethod;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.app.servertransaction.FixedRotationAdjustmentsItem;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
@@ -1345,6 +1346,36 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
assertFalse(recentsActivity.hasFixedRotationTransform());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearIntermediateFixedRotationAdjustments() throws RemoteException {
|
||||
final ActivityRecord activity = new ActivityTestsBase.StackBuilder(mWm.mRoot)
|
||||
.setDisplay(mDisplayContent).build().getTopMostActivity();
|
||||
mDisplayContent.setFixedRotationLaunchingApp(activity,
|
||||
(mDisplayContent.getRotation() + 1) % 4);
|
||||
// Create a window so FixedRotationAdjustmentsItem can be sent.
|
||||
createWindow(null, TYPE_APPLICATION_STARTING, activity, "AppWin");
|
||||
final ActivityRecord activity2 = new ActivityTestsBase.StackBuilder(mWm.mRoot)
|
||||
.setDisplay(mDisplayContent).build().getTopMostActivity();
|
||||
activity2.setVisible(false);
|
||||
clearInvocations(mWm.mAtmService.getLifecycleManager());
|
||||
// The first activity has applied fixed rotation but the second activity becomes the top
|
||||
// before the transition is done and it has the same rotation as display, so the dispatched
|
||||
// rotation adjustment of first activity must be cleared.
|
||||
mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(activity2,
|
||||
false /* checkOpening */);
|
||||
|
||||
final ArgumentCaptor<FixedRotationAdjustmentsItem> adjustmentsCaptor =
|
||||
ArgumentCaptor.forClass(FixedRotationAdjustmentsItem.class);
|
||||
verify(mWm.mAtmService.getLifecycleManager(), atLeastOnce()).scheduleTransaction(
|
||||
eq(activity.app.getThread()), adjustmentsCaptor.capture());
|
||||
// The transformation is kept for animation in real case.
|
||||
assertTrue(activity.hasFixedRotationTransform());
|
||||
final FixedRotationAdjustmentsItem clearAdjustments = FixedRotationAdjustmentsItem.obtain(
|
||||
activity.token, null /* fixedRotationAdjustments */);
|
||||
// The captor may match other items. The first one must be the item to clear adjustments.
|
||||
assertEquals(clearAdjustments, adjustmentsCaptor.getAllValues().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteRotation() {
|
||||
DisplayContent dc = createNewDisplay();
|
||||
|
||||
Reference in New Issue
Block a user