From 14ea8c60f5ca17087e41719988f7d83b1b9521e3 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Thu, 30 Sep 2021 17:28:35 -0700 Subject: [PATCH] Unrotate going-away apps during a launch-into-orientation transition When going from a non-launcher task to another non-launcher task that is in a different orientation, we just animate the new task opening in the new orientation (no screen rotation animation). To make this work, though, we need to unrotate all the going-away windows because they are in the old orientation. Added CounterRotator to a utility area in shell so it can be shared with other components (like Sysui shared lib). Bug: 183993924 Test: atest OpenAppColdTest Change-Id: I0263dfb8d529b6fc3dfbe3775e3e6e0b77f6ca8a --- libs/WindowManager/Shell/Android.bp | 8 ++ .../transition/DefaultTransitionHandler.java | 58 ++++++++++--- .../android/wm/shell/util/CounterRotator.java | 87 +++++++++++++++++++ packages/SystemUI/shared/Android.bp | 3 +- .../system/RemoteAnimationAdapterCompat.java | 60 ++----------- 5 files changed, 152 insertions(+), 64 deletions(-) create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 9aaef3b1f6552..3ba1a34bd432b 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -38,6 +38,14 @@ filegroup { path: "src", } +filegroup { + name: "wm_shell_util-sources", + srcs: [ + "src/com/android/wm/shell/util/**/*.java", + ], + path: "src", +} + filegroup { name: "wm_shell-aidls", srcs: [ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index b673d48f3d154..663d6477c3fef 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -41,6 +41,7 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import static android.window.TransitionInfo.FLAG_TRANSLUCENT; +import static android.window.TransitionInfo.isIndependent; import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE; import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE; @@ -70,6 +71,7 @@ import android.view.animation.Animation; import android.view.animation.Transformation; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; +import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.R; @@ -82,6 +84,7 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.util.CounterRotator; import java.util.ArrayList; @@ -269,9 +272,16 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { final ArrayList animations = new ArrayList<>(); mAnimations.put(transition, animations); + final ArrayMap counterRotators = new ArrayMap<>(); + final Runnable onAnimFinish = () -> { if (!animations.isEmpty()) return; + for (int i = 0; i < counterRotators.size(); ++i) { + counterRotators.valueAt(i).cleanUp(info.getRootLeash()); + } + counterRotators.clear(); + if (mRotationAnimation != null) { mRotationAnimation.kill(); mRotationAnimation = null; @@ -285,16 +295,44 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); - if (info.getType() == TRANSIT_CHANGE && change.getMode() == TRANSIT_CHANGE - && (change.getFlags() & FLAG_IS_DISPLAY) != 0) { - boolean isSeamless = isRotationSeamless(info, mDisplayController); - final int anim = getRotationAnimation(info); - if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) { - mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession, - mTransactionPool, startTransaction, change, info.getRootLeash()); - mRotationAnimation.startAnimation(animations, onAnimFinish, - mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor); - continue; + if (change.getMode() == TRANSIT_CHANGE && (change.getFlags() & FLAG_IS_DISPLAY) != 0) { + int rotateDelta = change.getEndRotation() - change.getStartRotation(); + int displayW = change.getEndAbsBounds().width(); + int displayH = change.getEndAbsBounds().height(); + if (info.getType() == TRANSIT_CHANGE) { + boolean isSeamless = isRotationSeamless(info, mDisplayController); + final int anim = getRotationAnimation(info); + if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) { + mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession, + mTransactionPool, startTransaction, change, info.getRootLeash()); + mRotationAnimation.startAnimation(animations, onAnimFinish, + mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor); + continue; + } + } else { + // opening/closing an app into a new orientation. Counter-rotate all + // "going-away" things since they are still in the old orientation. + for (int j = info.getChanges().size() - 1; j >= 0; --j) { + final TransitionInfo.Change innerChange = info.getChanges().get(j); + if (!Transitions.isClosingType(innerChange.getMode()) + || !isIndependent(innerChange, info) + || innerChange.getParent() == null) { + continue; + } + CounterRotator crot = counterRotators.get(innerChange.getParent()); + if (crot == null) { + crot = new CounterRotator(); + crot.setup(startTransaction, + info.getChange(innerChange.getParent()).getLeash(), + rotateDelta, displayW, displayH); + if (crot.getSurface() != null) { + int layer = info.getChanges().size() - j; + startTransaction.setLayer(crot.getSurface(), layer); + } + counterRotators.put(innerChange.getParent(), crot); + } + crot.addChild(startTransaction, innerChange.getLeash()); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java new file mode 100644 index 0000000000000..b9b671635010e --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.util; + +import android.view.SurfaceControl; + +import java.util.ArrayList; + +/** + * Utility class that takes care of counter-rotating surfaces during a transition animation. + */ +public class CounterRotator { + SurfaceControl mSurface = null; + ArrayList mRotateChildren = null; + + /** Gets the surface with the counter-rotation. */ + public SurfaceControl getSurface() { + return mSurface; + } + + /** + * Sets up this rotator. + * + * @param rotateDelta is the forward rotation change (the rotation the display is making). + * @param displayW (and H) Is the size of the rotating display. + */ + public void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta, + float displayW, float displayH) { + if (rotateDelta == 0) return; + mRotateChildren = new ArrayList<>(); + // We want to counter-rotate, so subtract from 4 + rotateDelta = 4 - (rotateDelta + 4) % 4; + mSurface = new SurfaceControl.Builder() + .setName("Transition Unrotate") + .setContainerLayer() + .setParent(parent) + .build(); + // column-major + if (rotateDelta == 1) { + t.setMatrix(mSurface, 0, 1, -1, 0); + t.setPosition(mSurface, displayW, 0); + } else if (rotateDelta == 2) { + t.setMatrix(mSurface, -1, 0, 0, -1); + t.setPosition(mSurface, displayW, displayH); + } else if (rotateDelta == 3) { + t.setMatrix(mSurface, 0, -1, 1, 0); + t.setPosition(mSurface, 0, displayH); + } + t.show(mSurface); + } + + /** + * Add a surface that needs to be counter-rotate. + */ + public void addChild(SurfaceControl.Transaction t, SurfaceControl child) { + if (mSurface == null) return; + t.reparent(child, mSurface); + mRotateChildren.add(child); + } + + /** + * Clean-up. This undoes any reparenting and effectively stops the counter-rotation. + */ + public void cleanUp(SurfaceControl rootLeash) { + if (mSurface == null) return; + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + for (int i = mRotateChildren.size() - 1; i >= 0; --i) { + t.reparent(mRotateChildren.get(i), rootLeash); + } + t.remove(mSurface); + t.apply(); + } +} diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 3a23094d67da3..4880b124fcdb1 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -43,6 +43,7 @@ android_library { "src/**/*.kt", "src/**/*.aidl", ":wm_shell-aidls", + ":wm_shell_util-sources", ], static_libs: [ @@ -50,5 +51,5 @@ android_library { "androidx.dynamicanimation_dynamicanimation", ], java_version: "1.8", - min_sdk_version: "26", + min_sdk_version: "current", } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java index 7aee721972d4e..dcc4ea1193760 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java @@ -40,7 +40,7 @@ import android.window.IRemoteTransitionFinishedCallback; import android.window.RemoteTransition; import android.window.TransitionInfo; -import java.util.ArrayList; +import com.android.wm.shell.util.CounterRotator; /** * @see RemoteAnimationAdapter @@ -109,52 +109,6 @@ public class RemoteAnimationAdapterCompat { }; } - private static class CounterRotator { - SurfaceControl mSurface = null; - ArrayList mRotateChildren = null; - - void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta, - float displayW, float displayH) { - if (rotateDelta == 0) return; - mRotateChildren = new ArrayList<>(); - // We want to counter-rotate, so subtract from 4 - rotateDelta = 4 - (rotateDelta + 4) % 4; - mSurface = new SurfaceControl.Builder() - .setName("Transition Unrotate") - .setContainerLayer() - .setParent(parent) - .build(); - // column-major - if (rotateDelta == 1) { - t.setMatrix(mSurface, 0, 1, -1, 0); - t.setPosition(mSurface, displayW, 0); - } else if (rotateDelta == 2) { - t.setMatrix(mSurface, -1, 0, 0, -1); - t.setPosition(mSurface, displayW, displayH); - } else if (rotateDelta == 3) { - t.setMatrix(mSurface, 0, -1, 1, 0); - t.setPosition(mSurface, 0, displayH); - } - t.show(mSurface); - } - - void addChild(SurfaceControl.Transaction t, SurfaceControl child) { - if (mSurface == null) return; - t.reparent(child, mSurface); - mRotateChildren.add(child); - } - - void cleanUp(SurfaceControl rootLeash) { - if (mSurface == null) return; - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - for (int i = mRotateChildren.size() - 1; i >= 0; --i) { - t.reparent(mRotateChildren.get(i), rootLeash); - } - t.remove(mSurface); - t.apply(); - } - } - private static IRemoteTransition.Stub wrapRemoteTransition( final RemoteAnimationRunnerCompat remoteAnimationAdapter) { return new IRemoteTransition.Stub() { @@ -204,14 +158,14 @@ public class RemoteAnimationAdapterCompat { if (launcherTask != null && rotateDelta != 0 && launcherTask.getParent() != null) { counterLauncher.setup(t, info.getChange(launcherTask.getParent()).getLeash(), rotateDelta, displayW, displayH); - if (counterLauncher.mSurface != null) { - t.setLayer(counterLauncher.mSurface, launcherLayer); + if (counterLauncher.getSurface() != null) { + t.setLayer(counterLauncher.getSurface(), launcherLayer); } } if (isReturnToHome) { - if (counterLauncher.mSurface != null) { - t.setLayer(counterLauncher.mSurface, info.getChanges().size() * 3); + if (counterLauncher.getSurface() != null) { + t.setLayer(counterLauncher.getSurface(), info.getChanges().size() * 3); } // Need to "boost" the closing things since that's what launcher expects. for (int i = info.getChanges().size() - 1; i >= 0; --i) { @@ -237,8 +191,8 @@ public class RemoteAnimationAdapterCompat { if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) { counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(), rotateDelta, displayW, displayH); - if (counterWallpaper.mSurface != null) { - t.setLayer(counterWallpaper.mSurface, -1); + if (counterWallpaper.getSurface() != null) { + t.setLayer(counterWallpaper.getSurface(), -1); counterWallpaper.addChild(t, leashMap.get(wallpaper.getLeash())); } }