Fixed rotation: home and recents animation

Add support for home and recents animations using the fixed
orientation transform.

When the recent animation is started, the target ActivityRecord is
rotated before being displayed.

Bug: 143053092, 146416687, 147469164
Test: atest WmTests:RecentsAnimationControllerTest
                #testRecentViewInFixedPortraitWhenTopAppInLandscape

Change-Id: I194673d621e8c0e8222306915a60f69e4de53b75
This commit is contained in:
Vadim Caen
2020-01-27 15:00:01 +01:00
parent 1ad9e57d97
commit a0fa966a37
3 changed files with 65 additions and 4 deletions

View File

@@ -16,7 +16,6 @@
package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
@@ -84,9 +83,6 @@ import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -105,12 +101,15 @@ import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER;
import static com.android.server.wm.DisplayContentProto.DPI;
import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
import static com.android.server.wm.DisplayContentProto.ID;
import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
import static com.android.server.wm.DisplayContentProto.OVERLAY_WINDOWS;
import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.ROTATION;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE;
import static com.android.server.wm.DisplayContentProto.TASKS;
import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
@@ -1552,6 +1551,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
}
/**
* If the provided {@link ActivityRecord} can be displayed in an orientation different from the
* display's, it will be rotated to match its requested orientation.
*
* @see #rotationForActivityInDifferentOrientation(ActivityRecord).
* @see WindowToken#applyFixedRotationTransform(DisplayInfo, DisplayFrames, Configuration)
*/
void rotateInDifferentOrientationIfNeeded(ActivityRecord activityRecord) {
int rotation = rotationForActivityInDifferentOrientation(activityRecord);
if (rotation != NO_ROTATION) {
startFixedRotationTransform(activityRecord, rotation);
}
}
/**
* Update rotation of the display.
*

View File

@@ -423,6 +423,11 @@ public class RecentsAnimationController implements DeathRecipient {
mService.mWindowPlacerLocked.performSurfacePlacement();
// If the target activity has a fixed orientation which is different from the current top
// activity, it will be rotated before being shown so we avoid a screen rotation
// animation when showing the Recents view.
mDisplayContent.rotateInDifferentOrientationIfNeeded(mTargetActivityRecord);
// Notify that the animation has started
if (mStatusBar != null) {
mStatusBar.onRecentsAnimationStateChanged(true /* running */);
@@ -695,6 +700,9 @@ public class RecentsAnimationController implements DeathRecipient {
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
mTargetActivityRecord.token);
}
if (mTargetActivityRecord.hasFixedRotationTransform()) {
mTargetActivityRecord.clearFixedRotationTransform();
}
}
// Notify that the animation has ended

View File

@@ -53,6 +53,8 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.app.ActivityManager.TaskSnapshot;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
@@ -330,6 +332,44 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
assertTrue(activity.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
}
@Test
public void testRecentViewInFixedPortraitWhenTopAppInLandscape() {
mWm.mIsFixedRotationTransformEnabled = true;
mWm.setRecentsAnimationController(mController);
final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final ActivityRecord homeAppWindow =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
.setStack(homeStack)
.setCreateTask(true)
.build();
final ActivityRecord appWindow = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final WindowState win0 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
appWindow.addWindow(win0);
final ActivityRecord landActivity = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
landActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, landActivity, "win1");
landActivity.addWindow(win1);
assertEquals(landActivity.getTask().getTopVisibleActivity(), landActivity);
assertEquals(landActivity.findMainWindow(), win1);
// Ensure that the display is in Landscape
landActivity.onDescendantOrientationChanged(landActivity.token, landActivity);
assertEquals(Configuration.ORIENTATION_LANDSCAPE,
mDisplayContent.getConfiguration().orientation);
mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeAppWindow);
// Check that the home app is in portrait
assertEquals(Configuration.ORIENTATION_PORTRAIT,
homeAppWindow.getConfiguration().orientation);
}
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);