Merge "System Bars animation for fixed rotation transform" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
148fb0e8c2
@@ -498,6 +498,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
*/
|
||||
private ActivityRecord mFixedRotationLaunchingApp;
|
||||
|
||||
private FixedRotationAnimationController mFixedRotationAnimationController;
|
||||
|
||||
final FixedRotationTransitionListener mFixedRotationTransitionListener =
|
||||
new FixedRotationTransitionListener();
|
||||
|
||||
@@ -1487,6 +1489,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
return mFixedRotationLaunchingApp;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable FixedRotationAnimationController getFixedRotationAnimationController() {
|
||||
return mFixedRotationAnimationController;
|
||||
}
|
||||
|
||||
void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r) {
|
||||
setFixedRotationLaunchingAppUnchecked(r, ROTATION_UNDEFINED);
|
||||
}
|
||||
@@ -1494,8 +1501,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) {
|
||||
if (mFixedRotationLaunchingApp == null && r != null) {
|
||||
mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation);
|
||||
if (mFixedRotationAnimationController == null) {
|
||||
mFixedRotationAnimationController = new FixedRotationAnimationController(this);
|
||||
mFixedRotationAnimationController.hide();
|
||||
}
|
||||
} else if (mFixedRotationLaunchingApp != null && r == null) {
|
||||
mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this);
|
||||
finishFixedRotationAnimationIfPossible();
|
||||
}
|
||||
mFixedRotationLaunchingApp = r;
|
||||
}
|
||||
@@ -1584,6 +1596,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
}
|
||||
|
||||
/** Re-show the previously hidden windows if all seamless rotated windows are done. */
|
||||
void finishFixedRotationAnimationIfPossible() {
|
||||
final FixedRotationAnimationController controller = mFixedRotationAnimationController;
|
||||
if (controller != null && !mDisplayRotation.hasSeamlessRotatingWindow()) {
|
||||
controller.show();
|
||||
mFixedRotationAnimationController = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update rotation of the display.
|
||||
*
|
||||
|
||||
@@ -560,6 +560,7 @@ public class DisplayRotation {
|
||||
}, true /* traverseTopToBottom */);
|
||||
mSeamlessRotationCount = 0;
|
||||
mRotatingSeamlessly = false;
|
||||
mDisplayContent.finishFixedRotationAnimationIfPossible();
|
||||
}
|
||||
|
||||
private void prepareSeamlessRotation() {
|
||||
@@ -573,6 +574,10 @@ public class DisplayRotation {
|
||||
return mRotatingSeamlessly;
|
||||
}
|
||||
|
||||
boolean hasSeamlessRotatingWindow() {
|
||||
return mSeamlessRotationCount > 0;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) {
|
||||
// Display doesn't need to be frozen because application has been started in correct
|
||||
@@ -646,6 +651,7 @@ public class DisplayRotation {
|
||||
"Performing post-rotate rotation after seamless rotation");
|
||||
// Finish seamless rotation.
|
||||
mRotatingSeamlessly = false;
|
||||
mDisplayContent.finishFixedRotationAnimationIfPossible();
|
||||
|
||||
updateRotationAndSendNewConfigIfChanged();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.server.wm;
|
||||
|
||||
import static com.android.server.wm.AnimationSpecProto.WINDOW;
|
||||
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
|
||||
import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Controller to fade out and in system ui when applying a fixed rotation transform to a window
|
||||
* token.
|
||||
*
|
||||
* The system bars will be fade out when the fixed rotation transform starts and will be fade in
|
||||
* once all surfaces have been rotated.
|
||||
*/
|
||||
public class FixedRotationAnimationController {
|
||||
|
||||
private final Context mContext;
|
||||
private final WindowState mStatusBar;
|
||||
private final WindowState mNavigationBar;
|
||||
private final ArrayList<WindowToken> mAnimatedWindowToken = new ArrayList<>(2);
|
||||
private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();
|
||||
|
||||
public FixedRotationAnimationController(DisplayContent displayContent) {
|
||||
mContext = displayContent.mWmService.mContext;
|
||||
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
|
||||
mStatusBar = displayPolicy.getStatusBar();
|
||||
// Do not animate movable navigation bar (e.g. non-gesture mode).
|
||||
mNavigationBar = !displayPolicy.navigationBarCanMove()
|
||||
? displayPolicy.getNavigationBar()
|
||||
: null;
|
||||
}
|
||||
|
||||
/** Applies show animation on the previously hidden window tokens. */
|
||||
void show() {
|
||||
for (int i = mAnimatedWindowToken.size() - 1; i >= 0; i--) {
|
||||
final WindowToken windowToken = mAnimatedWindowToken.get(i);
|
||||
fadeWindowToken(true /* show */, windowToken);
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies hide animation on the window tokens which may be seamlessly rotated later. */
|
||||
void hide() {
|
||||
if (mNavigationBar != null) {
|
||||
fadeWindowToken(false /* show */, mNavigationBar.mToken);
|
||||
}
|
||||
if (mStatusBar != null) {
|
||||
fadeWindowToken(false /* show */, mStatusBar.mToken);
|
||||
}
|
||||
}
|
||||
|
||||
private void fadeWindowToken(boolean show, WindowToken windowToken) {
|
||||
if (windowToken == null || windowToken.getParent() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Animation animation = AnimationUtils.loadAnimation(mContext,
|
||||
show ? R.anim.fade_in : R.anim.fade_out);
|
||||
final LocalAnimationAdapter.AnimationSpec windowAnimationSpec =
|
||||
createAnimationSpec(animation);
|
||||
|
||||
final FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter(
|
||||
windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken);
|
||||
|
||||
// We deferred the end of the animation when hiding the token, so we need to end it now that
|
||||
// it's shown again.
|
||||
final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
|
||||
final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken);
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
} : null;
|
||||
windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
|
||||
show /* hidden */, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback);
|
||||
mAnimatedWindowToken.add(windowToken);
|
||||
}
|
||||
|
||||
private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) {
|
||||
return new LocalAnimationAdapter.AnimationSpec() {
|
||||
|
||||
final Transformation mTransformation = new Transformation();
|
||||
|
||||
@Override
|
||||
public boolean getShowWallpaper() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDuration() {
|
||||
return animation.getDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
|
||||
long currentPlayTime) {
|
||||
mTransformation.clear();
|
||||
animation.getTransformation(currentPlayTime, mTransformation);
|
||||
t.setAlpha(leash, mTransformation.getAlpha());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.print(prefix);
|
||||
pw.println(animation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpDebugInner(ProtoOutputStream proto) {
|
||||
final long token = proto.start(WINDOW);
|
||||
proto.write(ANIMATION, animation.toString());
|
||||
proto.end(token);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class FixedRotationAnimationAdapter extends LocalAnimationAdapter {
|
||||
private final boolean mShow;
|
||||
private final WindowToken mToken;
|
||||
|
||||
FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec,
|
||||
SurfaceAnimationRunner surfaceAnimationRunner, boolean show,
|
||||
WindowToken token) {
|
||||
super(windowAnimationSpec, surfaceAnimationRunner);
|
||||
mShow = show;
|
||||
mToken = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
|
||||
// We defer the end of the hide animation to ensure the tokens stay hidden until
|
||||
// we show them again.
|
||||
if (!mShow) {
|
||||
mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -488,6 +488,12 @@ class SurfaceAnimator {
|
||||
*/
|
||||
static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
|
||||
|
||||
/**
|
||||
* Animation when a fixed rotation transform is applied to a window token.
|
||||
* @hide
|
||||
*/
|
||||
static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
|
||||
|
||||
/**
|
||||
* Bitmask to include all animation types. This is NOT an {@link AnimationType}
|
||||
* @hide
|
||||
@@ -505,7 +511,8 @@ class SurfaceAnimator {
|
||||
ANIMATION_TYPE_DIMMER,
|
||||
ANIMATION_TYPE_RECENTS,
|
||||
ANIMATION_TYPE_WINDOW_ANIMATION,
|
||||
ANIMATION_TYPE_INSETS_CONTROL
|
||||
ANIMATION_TYPE_INSETS_CONTROL,
|
||||
ANIMATION_TYPE_FIXED_TRANSFORM
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface AnimationType {}
|
||||
|
||||
@@ -57,6 +57,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
|
||||
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
|
||||
|
||||
@@ -1060,6 +1061,11 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
@Test
|
||||
public void testApplyTopFixedRotationTransform() {
|
||||
mWm.mIsFixedRotationTransformEnabled = true;
|
||||
final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
|
||||
// Only non-movable (gesture) navigation bar will be animated by fixed rotation animation.
|
||||
doReturn(false).when(displayPolicy).navigationBarCanMove();
|
||||
displayPolicy.addWindowLw(mStatusBarWindow, mStatusBarWindow.mAttrs);
|
||||
displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
|
||||
final Configuration config90 = new Configuration();
|
||||
mDisplayContent.computeScreenConfiguration(config90, ROTATION_90);
|
||||
|
||||
@@ -1080,6 +1086,12 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
|
||||
false /* forceUpdate */));
|
||||
|
||||
assertNotNull(mDisplayContent.getFixedRotationAnimationController());
|
||||
assertTrue(mStatusBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
|
||||
ANIMATION_TYPE_FIXED_TRANSFORM));
|
||||
assertTrue(mNavBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
|
||||
ANIMATION_TYPE_FIXED_TRANSFORM));
|
||||
|
||||
final Rect outFrame = new Rect();
|
||||
final Rect outInsets = new Rect();
|
||||
final Rect outStableInsets = new Rect();
|
||||
@@ -1132,6 +1144,7 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
assertFalse(app.hasFixedRotationTransform());
|
||||
assertFalse(app2.hasFixedRotationTransform());
|
||||
assertEquals(config90.orientation, mDisplayContent.getConfiguration().orientation);
|
||||
assertNull(mDisplayContent.getFixedRotationAnimationController());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1310,7 +1323,7 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
}
|
||||
|
||||
private static int getRotatedOrientation(DisplayContent dc) {
|
||||
return dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
|
||||
return dc.mBaseDisplayWidth > dc.mBaseDisplayHeight
|
||||
? SCREEN_ORIENTATION_PORTRAIT
|
||||
: SCREEN_ORIENTATION_LANDSCAPE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user