Only use snapshot starting window for the same rotation
So the snapshot won't show half if the its has a delta of 90 degree
rotation with the actual activity. If the snapshot is not compatible
with the activity, the starting window type will be splash screen.
Bug: 155862858
Test: atest ActivityRecordTests#testIsSnapshotCompatible
Change-Id: I8d8a926d057f1d18d028fcc03bddbb17ffbbf96b
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d177c12..35cb8f9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1705,7 +1705,7 @@
boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
+ boolean allowTaskSnapshot, boolean activityCreated) {
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
if (!okToDisplay()) {
@@ -1726,7 +1726,7 @@
mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
- allowTaskSnapshot, activityCreated, fromRecents, snapshot);
+ allowTaskSnapshot, activityCreated, snapshot);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
if (isActivityTypeHome()) {
@@ -1888,12 +1888,12 @@
private final AddStartingWindow mAddStartingWindow = new AddStartingWindow();
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
+ boolean allowTaskSnapshot, boolean activityCreated,
ActivityManager.TaskSnapshot snapshot) {
if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
- if (snapshotOrientationSameAsTask(snapshot) || (snapshot != null && fromRecents)) {
+ if (isSnapshotCompatible(snapshot)) {
return STARTING_WINDOW_TYPE_SNAPSHOT;
}
if (!isActivityTypeHome()) {
@@ -1905,11 +1905,22 @@
}
}
- private boolean snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot) {
+ /**
+ * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+ * rotation must be the same).
+ */
+ @VisibleForTesting
+ boolean isSnapshotCompatible(ActivityManager.TaskSnapshot snapshot) {
if (snapshot == null) {
return false;
}
- return task.getConfiguration().orientation == snapshot.getOrientation();
+ final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this);
+ final int targetRotation = rotation != ROTATION_UNDEFINED
+ // The display may rotate according to the orientation of this activity.
+ ? rotation
+ // The activity won't change display orientation.
+ : task.getWindowConfiguration().getRotation();
+ return snapshot.getRotation() == targetRotation;
}
void removeStartingWindow() {
@@ -5664,11 +5675,6 @@
}
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
- showStartingWindow(prev, newTask, taskSwitch, false /* fromRecents */);
- }
-
- void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
- boolean fromRecents) {
if (mTaskOverlay) {
// We don't show starting window for overlay activities.
return;
@@ -5685,8 +5691,7 @@
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
- fromRecents);
+ mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal());
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 3e7e0c8..62979ff 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2498,7 +2498,7 @@
mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
- task.mTaskId, 0, options, true /* fromRecents */);
+ task.mTaskId, 0, options);
// Apply options to prevent pendingOptions be taken by client to make sure
// the override pending app transition will be applied immediately.
targetActivity.applyOptionsLocked();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f21ec6b..7e97460 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2476,13 +2476,12 @@
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
synchronized (mGlobalLock) {
moveTaskToFrontLocked(appThread, callingPackage, taskId, flags,
- SafeActivityOptions.fromBundle(bOptions), false /* fromRecents */);
+ SafeActivityOptions.fromBundle(bOptions));
}
}
void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
- @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options,
- boolean fromRecents) {
+ @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
assertPackageMatchesCallingUid(callingPackage);
@@ -2527,7 +2526,7 @@
// We are reshowing a task, use a starting window to hide the initial draw delay
// so the transition can start earlier.
topActivity.showStartingWindow(null /* prev */, false /* newTask */,
- true /* taskSwitch */, fromRecents);
+ true /* taskSwitch */);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b11502d..d0f7021 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -235,7 +235,6 @@
implements WindowManagerPolicy.DisplayContentInfo {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
- private static final int NO_ROTATION = -1;
/** The default scaling mode that scales content automatically. */
static final int FORCE_SCALING_MODE_AUTO = 0;
@@ -1409,21 +1408,24 @@
return mDisplayRotation.updateOrientation(orientation, forceUpdate);
}
- /** @return a valid rotation if the activity can use different orientation than the display. */
+ /**
+ * Returns a valid rotation if the activity can use different orientation than the display.
+ * Otherwise {@link #ROTATION_UNDEFINED}.
+ */
@Surface.Rotation
- private int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
+ int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
if (!mWmService.mIsFixedRotationTransformEnabled) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
if (r.inMultiWindowMode()
|| r.getRequestedConfigurationOrientation() == getConfiguration().orientation) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
final int currentRotation = getRotation();
final int rotation = mDisplayRotation.rotationForOrientation(r.getRequestedOrientation(),
currentRotation);
if (rotation == currentRotation) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
return rotation;
}
@@ -1458,7 +1460,7 @@
return false;
}
final int rotation = rotationForActivityInDifferentOrientation(r);
- if (rotation == NO_ROTATION) {
+ if (rotation == ROTATION_UNDEFINED) {
return false;
}
if (!r.getParent().matchParentBounds()) {
@@ -1555,7 +1557,7 @@
*/
void rotateInDifferentOrientationIfNeeded(ActivityRecord activityRecord) {
int rotation = rotationForActivityInDifferentOrientation(activityRecord);
- if (rotation != NO_ROTATION) {
+ if (rotation != ROTATION_UNDEFINED) {
startFixedRotationTransform(activityRecord, rotation);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 5bd85bd..db83eaa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -69,6 +69,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
+import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -1440,6 +1441,32 @@
}
@Test
+ public void testIsSnapshotCompatible() {
+ mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
+ final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+ .setRotation(mActivity.getWindowConfiguration().getRotation())
+ .build();
+
+ assertTrue(mActivity.isSnapshotCompatible(snapshot));
+
+ setRotatedScreenOrientationSilently(mActivity);
+
+ assertFalse(mActivity.isSnapshotCompatible(snapshot));
+ }
+
+ /**
+ * Sets orientation without notifying the parent to simulate that the display has not applied
+ * the requested orientation yet.
+ */
+ private static void setRotatedScreenOrientationSilently(ActivityRecord r) {
+ final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
+ ? SCREEN_ORIENTATION_LANDSCAPE
+ : SCREEN_ORIENTATION_PORTRAIT;
+ doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
+ r.setOrientation(rotatedOrentation);
+ }
+
+ @Test
public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
final ActivityRecord secondaryDisplayActivity =
createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 9263d8a..8f18f64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -307,7 +307,7 @@
public void testCreateRemoveStartingWindow() {
mActivity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
assertHasStartingWindow(mActivity);
mActivity.removeStartingWindow();
@@ -322,7 +322,7 @@
for (int i = 0; i < 1000; i++) {
appToken.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
appToken.removeStartingWindow();
waitUntilHandlersIdle();
assertNoStartingWindow(appToken);
@@ -335,11 +335,11 @@
final ActivityRecord activity2 = createIsolatedTestActivityRecord();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
- true, true, false, true, false, false);
+ true, true, false, true, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -355,11 +355,11 @@
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0,
activity1.appToken.asBinder(), true, true, false,
- true, false, false);
+ true, false);
});
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -371,11 +371,11 @@
final ActivityRecord activity2 = createIsolatedTestActivityRecord();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
- true, true, false, true, false, false);
+ true, true, false, true, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -413,7 +413,7 @@
// Add a starting window.
activityTop.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
// Make the top one invisible, and try transferring the starting window from the top to the