Merge changes Idb4f9a92,I8d8a926d,I8e30e87e into rvc-dev am: fc48f7e52a

Change-Id: If89aff43cf12c9e5071195f910db374cbac68f3a
This commit is contained in:
Riddle Hsu
2020-05-14 14:30:14 +00:00
committed by Automerger Merge Worker
9 changed files with 173 additions and 57 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() {
@@ -5662,11 +5673,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;
@@ -5683,8 +5689,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;
@@ -1394,36 +1393,40 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final WindowContainer orientationSource = getLastOrientationSource();
final ActivityRecord r =
orientationSource != null ? orientationSource.asActivityRecord() : null;
if (r != null && r.getTask() != null
&& orientation != r.getTask().mLastReportedRequestedOrientation) {
if (r != null) {
final Task task = r.getTask();
task.mLastReportedRequestedOrientation = orientation;
mAtmService.getTaskChangeNotificationController()
.notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
}
// Currently there is no use case from non-activity.
if (r != null && handleTopActivityLaunchingInDifferentOrientation(r)) {
// Display orientation should be deferred until the top fixed rotation is finished.
return false;
if (task != null && orientation != task.mLastReportedRequestedOrientation) {
task.mLastReportedRequestedOrientation = orientation;
mAtmService.getTaskChangeNotificationController()
.notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
}
// Currently there is no use case from non-activity.
if (handleTopActivityLaunchingInDifferentOrientation(r, true /* checkOpening */)) {
// Display orientation should be deferred until the top fixed rotation is finished.
return false;
}
}
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;
}
@@ -1433,9 +1436,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* is launching until the launch animation is done to avoid showing the previous activity
* inadvertently in a wrong orientation.
*
* @param r The launching activity which may change display orientation.
* @param checkOpening Whether to check if the activity is animating by transition. Set to
* {@code true} if the caller is not sure whether the activity is launching.
* @return {@code true} if the fixed rotation is started.
*/
private boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r) {
boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
boolean checkOpening) {
if (!mWmService.mIsFixedRotationTransformEnabled) {
return false;
}
@@ -1446,19 +1453,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// It has been set and not yet finished.
return true;
}
if (!mAppTransition.isTransitionSet()) {
// Apply normal rotation animation in case of the activity set different requested
// orientation without activity switch.
return false;
}
if (!mOpeningApps.contains(r)
// Without screen rotation, the rotation behavior of non-top visible activities is
// undefined. So the fixed rotated activity needs to cover the screen.
&& r.findMainWindow() != mDisplayPolicy.getTopFullscreenOpaqueWindow()) {
if (checkOpening) {
if (!mAppTransition.isTransitionSet() && !mOpeningApps.contains(r)) {
// Apply normal rotation animation in case of the activity set different requested
// orientation without activity switch.
return false;
}
} else if (r != topRunningActivity()) {
// If the transition has not started yet, the activity must be the top.
return false;
}
final int rotation = rotationForActivityInDifferentOrientation(r);
if (rotation == NO_ROTATION) {
if (rotation == ROTATION_UNDEFINED) {
return false;
}
if (!r.getParent().matchParentBounds()) {
@@ -1511,6 +1517,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
sendNewConfiguration();
return;
}
if (mDisplayRotation.isWaitingForRemoteRotation()) {
// There is pending rotation change to apply.
return;
}
// The orientation of display is not changed.
clearFixedRotationLaunchingApp();
}
@@ -1551,7 +1561,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

@@ -297,6 +297,13 @@ class TaskSnapshotController {
Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
return false;
}
if (activity.hasFixedRotationTransform()) {
if (DEBUG_SCREENSHOT) {
Slog.i(TAG_WM, "Skip taking screenshot. App has fixed rotation " + activity);
}
// The activity is in a temporal state that it has different rotation than the task.
return false;
}
builder.setIsRealSnapshot(true);
builder.setId(System.currentTimeMillis());

View File

@@ -195,6 +195,16 @@ class TaskSnapshotSurface implements StartingSurface {
+ activity);
return null;
}
if (topFullscreenActivity.getWindowConfiguration().getRotation()
!= snapshot.getRotation()) {
// The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
// that the activity will be updated to the same rotation as the snapshot. Since
// the transition is not started yet, fixed rotation transform needs to be applied
// earlier to make the snapshot show in a rotated container.
activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
topFullscreenActivity, false /* checkOpening */);
}
sysUiVis = topFullscreenOpaqueWindow.getSystemUiVisibility();
WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
windowFlags = attrs.flags;

View File

@@ -35,6 +35,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -69,6 +70,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;
@@ -82,14 +84,18 @@ import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
import android.view.DisplayInfo;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
import android.view.IWindowSession;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import androidx.test.filters.MediumTest;
@@ -1404,6 +1410,10 @@ public class ActivityRecordTests extends ActivityTestsBase {
assertTrue(displayRotation.isRotatingSeamlessly());
// The launching rotated app should not be cleared when waiting for remote rotation.
display.continueUpdateOrientationForDiffOrienLaunchingApp();
assertNotNull(display.mFixedRotationLaunchingApp);
// Simulate the rotation has been updated to previous one, e.g. sensor updates before the
// remote rotation is completed.
doReturn(originalRotation).when(displayRotation).rotationForOrientation(
@@ -1435,6 +1445,73 @@ 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));
}
@Test
public void testFixedRotationSnapshotStartingWindow() {
mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
// TaskSnapshotSurface requires a fullscreen opaque window.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
mActivity.addWindow(w);
// Assume the activity is launching in different rotation, and there was an available
// snapshot accepted by {@link Activity#isSnapshotCompatible}.
final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
.setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
.build();
setRotatedScreenOrientationSilently(mActivity);
final IWindowSession session = WindowManagerGlobal.getWindowSession();
spyOn(session);
try {
// Return error to skip unnecessary operation.
doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
any() /* window */, anyInt() /* seq */, any() /* attrs */,
anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
any() /* outContentInsets */, any() /* outStableInsets */,
any() /* outDisplayCutout */, any() /* outInputChannel */,
any() /* outInsetsState */, any() /* outActiveControls */);
TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
} catch (RemoteException ignored) {
} finally {
reset(session);
}
// Because the rotation of snapshot and the corresponding top activity are different, fixed
// rotation should be applied when creating snapshot surface if the display rotation may be
// changed according to the activity orientation.
assertTrue(mActivity.hasFixedRotationTransform());
assertEquals(mActivity, mActivity.mDisplayContent.mFixedRotationLaunchingApp);
}
/**
* 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

View File

@@ -192,10 +192,18 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
final ActivityManager.TaskSnapshot.Builder builder =
new ActivityManager.TaskSnapshot.Builder();
mWm.mTaskSnapshotController.prepareTaskSnapshot(mAppWindow.mActivityRecord.getTask(),
PixelFormat.UNKNOWN, builder);
boolean success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
assertTrue(success);
// The pixel format should be selected automatically.
assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat());
// Snapshot should not be taken while the rotation of activity and task are different.
doReturn(true).when(mAppWindow.mActivityRecord).hasFixedRotationTransform();
success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
assertFalse(success);
}
}