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
This commit is contained in:
Riddle Hsu
2020-05-13 01:07:33 +08:00
parent 742313e4c3
commit eae6ef3ebf
6 changed files with 68 additions and 35 deletions

View File

@@ -1705,7 +1705,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
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;
}

View File

@@ -2498,7 +2498,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
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();

View File

@@ -2476,13 +2476,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// 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);

View File

@@ -235,7 +235,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
void rotateInDifferentOrientationIfNeeded(ActivityRecord activityRecord) {
int rotation = rotationForActivityInDifferentOrientation(activityRecord);
if (rotation != NO_ROTATION) {
if (rotation != ROTATION_UNDEFINED) {
startFixedRotationTransform(activityRecord, rotation);
}
}

View File

@@ -69,6 +69,7 @@ import static org.mockito.ArgumentMatchers.anyString;
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;
@@ -1439,6 +1440,32 @@ public class ActivityRecordTests extends ActivityTestsBase {
assertFalse(mActivity.hasFixedRotationTransform());
}
@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 =

View File

@@ -307,7 +307,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
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 @@ public class AppWindowTokenTests extends WindowTestsBase {
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 @@ public class AppWindowTokenTests extends WindowTestsBase {
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 @@ public class AppWindowTokenTests extends WindowTestsBase {
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 @@ public class AppWindowTokenTests extends WindowTestsBase {
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 @@ public class AppWindowTokenTests extends WindowTestsBase {
// 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