Fixed rotation: rotate wallpaper

The wallpaper should be rotated if its target WindowState is rotated.

The fixed rotation is applied to the WallpaperWindowToken and
the offsets are computed using the overriden DisplayInfo contained in
the WindowToken.ForcedRotationState.

Test: atest WmTests:RecentsAnimationControllerTest#testWallpaperHasFixedRotationApplied
Bug: 143053092, 148000485, 147999946
Change-Id: I244b3cb81dd29995a1a9181949e4f3f973816825
This commit is contained in:
Vadim Caen
2020-01-29 12:21:41 +01:00
parent a0fa966a37
commit 2a9ccc9d2a
4 changed files with 125 additions and 2 deletions

View File

@@ -34,6 +34,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.ActivityManager.TaskSnapshot;
import android.app.WindowConfiguration;
import android.graphics.Point;
@@ -836,6 +837,19 @@ public class RecentsAnimationController implements DeathRecipient {
return task != null && isAnimatingTask(task) && !isTargetApp(windowState.mActivityRecord);
}
/**
* If the animation target ActivityRecord has a fixed rotation ({@link
* WindowToken#hasFixedRotationTransform()}, the provided wallpaper will be rotated accordingly.
*
* This avoids any screen rotation animation when animating to the Recents view.
*/
void applyFixedRotationTransformIfNeeded(@NonNull WindowToken wallpaper) {
if (mTargetActivityRecord == null) {
return;
}
wallpaper.applyFixedRotationTransform(mTargetActivityRecord);
}
@VisibleForTesting
class TaskAnimationAdapter implements AnimationAdapter {

View File

@@ -122,10 +122,37 @@ class WallpaperWindowToken extends WindowToken {
mDisplayContent.setLayoutNeeded();
}
final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
if (visible) {
final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
final RecentsAnimationController recentsAnimationController =
mWmService.getRecentsAnimationController();
if (wallpaperTarget != null
&& recentsAnimationController != null
&& recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) {
// If the Recents animation is running, and the wallpaper target is the animating
// task we want the wallpaper to be rotated in the same orientation as the
// RecentsAnimation's target (e.g the launcher)
recentsAnimationController.applyFixedRotationTransformIfNeeded(this);
} else if (wallpaperTarget != null
&& wallpaperTarget.mToken.hasFixedRotationTransform()) {
// If the wallpaper target has a fixed rotation, we want the wallpaper to follow its
// rotation
applyFixedRotationTransform(wallpaperTarget.mToken);
} else if (hasFixedRotationTransform()) {
clearFixedRotationTransform();
}
}
DisplayInfo displayInfo = getFixedRotationTransformDisplayInfo();
if (displayInfo == null) {
displayInfo = mDisplayContent.getDisplayInfo();
}
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
final WindowState wallpaper = mChildren.get(wallpaperNdx);

View File

@@ -377,6 +377,19 @@ class WindowToken extends WindowContainer<WindowState> {
onConfigurationChanged(getParent().getConfiguration());
}
/**
* Copies the {@link FixedRotationTransformState} (if any) from the other WindowToken to this
* one.
*/
void applyFixedRotationTransform(WindowToken other) {
final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState;
if (fixedRotationState != null) {
applyFixedRotationTransform(fixedRotationState.mDisplayInfo,
fixedRotationState.mDisplayFrames,
fixedRotationState.mRotatedOverrideConfiguration);
}
}
/** Clears the transformation and continue updating the orientation change of display. */
void clearFixedRotationTransform() {
if (mFixedRotationTransformState == null) {

View File

@@ -20,7 +20,9 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
@@ -67,12 +69,16 @@ import androidx.test.filters.SmallTest;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.google.common.truth.Truth;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
/**
* Build/Install/Run:
* atest WmTests:RecentsAnimationControllerTest
@@ -370,6 +376,69 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
homeAppWindow.getConfiguration().orientation);
}
@Test
public void testWallpaperHasFixedRotationApplied() {
mWm.mIsFixedRotationTransformEnabled = true;
mWm.setRecentsAnimationController(mController);
// Create a portrait home stack, a wallpaper and a landscape application displayed on top.
// Home stack
final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final ActivityRecord homeActivity =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
.setStack(homeStack)
.setCreateTask(true)
.build();
homeActivity.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final WindowState homeWindow = createWindow(null, TYPE_BASE_APPLICATION, homeActivity,
"homeWindow");
homeActivity.addWindow(homeWindow);
homeWindow.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
// Landscape application
final ActivityRecord activity = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final WindowState applicationWindow = createWindow(null, TYPE_BASE_APPLICATION, activity,
"applicationWindow");
activity.addWindow(applicationWindow);
activity.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// Wallpaper
final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
"wallpaperWindow");
// Make sure the landscape activity is on top and the display is in landscape
activity.moveFocusableActivityToTop("test");
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
spyOn(mDisplayContent.mWallpaperController);
doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
// Start the recents animation
mController
.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
mDisplayContent.mWallpaperController.adjustWallpaperWindows();
// Check preconditions
ArrayList<WallpaperWindowToken> wallpapers = new ArrayList<>(1);
mDisplayContent.forAllWallpaperWindows(wallpapers::add);
Truth.assertThat(wallpapers).hasSize(1);
Truth.assertThat(wallpapers.get(0).getTopChild()).isEqualTo(wallpaperWindow);
// Actual check
assertEquals(Configuration.ORIENTATION_PORTRAIT,
wallpapers.get(0).getConfiguration().orientation);
}
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);