From 0165c9e7f3c62d80ae289129424cc6d1d3eee9ab Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 2 Aug 2022 23:12:33 -0600 Subject: [PATCH] Support shell rotation transition on general window container This eliminate the limitation of rotation animation that it could only have one instance for display. Now the rotation animations can be tracked by them self so there could have multiple instances run at the same time, such as for multiple display or individual child window container. The first usage is: (also see commit d16620e) The fixed rotation transform of activity is canceled so display doesn't have rotation change but the activity has. Then only the activity needs to animate. Bug: 223397858 Test: adb shell setprop persist.wm.debug.shell_transit 1; reboot Enable auto rotation. Launch an app without fixed orientation from portrait launcher while device is in landscape. Before the launch animation is done, rotate the device to portrait (there is no display orientation change). The launched app should rotate from landscape to portrait without flickering. Change-Id: Ic47960e812f07365965df4ab2913e2003289a315 --- .../transition/DefaultTransitionHandler.java | 47 ++++++++++++++----- .../transition/ScreenRotationAnimation.java | 2 +- .../wm/shell/transition/Transitions.java | 2 +- .../com/android/server/wm/WindowState.java | 14 ++++-- .../com/android/server/wm/WindowToken.java | 7 +++ 5 files changed, 53 insertions(+), 19 deletions(-) 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 0bec54399dd84..ed3d64abd5718 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 @@ -152,8 +152,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { private final int mCurrentUserId; - private ScreenRotationAnimation mRotationAnimation; - private Drawable mEnterpriseThumbnailDrawable; private BroadcastReceiver mEnterpriseResourceUpdatedReceiver = new BroadcastReceiver() { @@ -332,12 +330,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { final Runnable onAnimFinish = () -> { if (!animations.isEmpty()) return; - - if (mRotationAnimation != null) { - mRotationAnimation.kill(); - mRotationAnimation = null; - } - mAnimations.remove(transition); finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */); }; @@ -357,11 +349,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { isSeamlessDisplayChange = isRotationSeamless(info, mDisplayController); final int anim = getRotationAnimation(info); if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) { - mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession, - mTransactionPool, startTransaction, change, info.getRootLeash(), - anim); - mRotationAnimation.startAnimation(animations, onAnimFinish, - mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor); + startRotationAnimation(startTransaction, change, info, anim, animations, + onAnimFinish); continue; } } else { @@ -405,6 +394,13 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { startTransaction.setWindowCrop(change.getLeash(), change.getEndAbsBounds().width(), change.getEndAbsBounds().height()); } + // Rotation change of independent non display window container. + if (change.getParent() == null + && change.getStartRotation() != change.getEndRotation()) { + startRotationAnimation(startTransaction, change, info, + ROTATION_ANIMATION_ROTATE, animations, onAnimFinish); + continue; + } } // Don't animate anything that isn't independent. @@ -535,6 +531,31 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } + private void startRotationAnimation(SurfaceControl.Transaction startTransaction, + TransitionInfo.Change change, TransitionInfo info, int animHint, + ArrayList animations, Runnable onAnimFinish) { + final ScreenRotationAnimation anim = new ScreenRotationAnimation(mContext, mSurfaceSession, + mTransactionPool, startTransaction, change, info.getRootLeash(), animHint); + // The rotation animation may consist of 3 animations: fade-out screenshot, fade-in real + // content, and background color. The item of "animGroup" will be removed if the sub + // animation is finished. Then if the list becomes empty, the rotation animation is done. + final ArrayList animGroup = new ArrayList<>(3); + final ArrayList animGroupStore = new ArrayList<>(3); + final Runnable finishCallback = () -> { + if (!animGroup.isEmpty()) return; + anim.kill(); + animations.removeAll(animGroupStore); + onAnimFinish.run(); + }; + anim.startAnimation(animGroup, finishCallback, mTransitionAnimationScaleSetting, + mMainExecutor, mAnimExecutor); + for (int i = animGroup.size() - 1; i >= 0; i--) { + final Animator animator = animGroup.get(i); + animGroupStore.add(animator); + animations.add(animator); + } + } + private void edgeExtendWindow(TransitionInfo.Change change, Animation a, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java index 1005ef1705f0f..a843b2a0ac39f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java @@ -84,7 +84,7 @@ class ScreenRotationAnimation { private final Context mContext; private final TransactionPool mTransactionPool; private final float[] mTmpFloats = new float[9]; - /** The leash of display. */ + /** The leash of the changing window container. */ private final SurfaceControl mSurfaceControl; private final Rect mStartBounds = new Rect(); private final Rect mEndBounds = new Rect(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 881b7a1699f6b..0bb6335463e78 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -358,7 +358,7 @@ public class Transitions implements RemoteCallable { // Put all the OPEN/SHOW on top if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) { // Wallpaper is always at the bottom. - layer = 0; + layer = -zSplitLine; } else if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { if (isOpening) { // put on top diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 86e14c2faa040..86fa3560a69e5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2453,8 +2453,7 @@ class WindowState extends WindowContainer implements WindowManagerP dc.setImeLayeringTarget(null); dc.computeImeTarget(true /* updateImeTarget */); } - if (dc.getImeInputTarget() == this - && (mActivityRecord == null || !mActivityRecord.isRelaunching())) { + if (dc.getImeInputTarget() == this && !inRelaunchingActivity()) { dc.updateImeInputAndControlTarget(null); } @@ -2581,7 +2580,10 @@ class WindowState extends WindowContainer implements WindowManagerP // usually unnoticeable (e.g. covered by rotation animation) and the animation // bounds could be inconsistent, such as depending on when the window applies // its draw transaction with new rotation. - final boolean allowExitAnimation = !getDisplayContent().inTransition(); + final boolean allowExitAnimation = !getDisplayContent().inTransition() + // There will be a new window so the exit animation may not be visible or + // look weird if its orientation is changed. + && !inRelaunchingActivity(); if (wasVisible) { final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE; @@ -3871,7 +3873,7 @@ class WindowState extends WindowContainer implements WindowManagerP // If the activity is scheduled to relaunch, skip sending the resized to ViewRootImpl now // since it will be destroyed anyway. This also prevents the client from receiving // windowing mode change before it is destroyed. - if (mActivityRecord != null && mActivityRecord.isRelaunching()) { + if (inRelaunchingActivity()) { return; } // If this is an activity or wallpaper and is invisible or going invisible, don't report @@ -3957,6 +3959,10 @@ class WindowState extends WindowContainer implements WindowManagerP Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + boolean inRelaunchingActivity() { + return mActivityRecord != null && mActivityRecord.isRelaunching(); + } + boolean isClientLocal() { return mClient instanceof IWindow.Stub; } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index bbb21f8122c57..72e7e65ae43a3 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -46,6 +46,7 @@ import android.view.DisplayInfo; import android.view.InsetsState; import android.view.Surface; import android.view.SurfaceControl; +import android.view.WindowManager; import android.view.WindowManager.LayoutParams.WindowType; import android.window.WindowContext; @@ -558,6 +559,12 @@ class WindowToken extends WindowContainer { // The window may be detached or detaching. return; } + if (mTransitionController.isShellTransitionsEnabled() + && asActivityRecord() != null && isVisible()) { + // Trigger an activity level rotation transition. + mTransitionController.requestTransitionIfNeeded(WindowManager.TRANSIT_CHANGE, this); + mTransitionController.setReady(this); + } final int originalRotation = getWindowConfiguration().getRotation(); onConfigurationChanged(parent.getConfiguration()); onCancelFixedRotationTransform(originalRotation);