Merge "System Bars animation for fixed rotation transform" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-05-27 06:19:51 +00:00
committed by Android (Google) Code Review
5 changed files with 215 additions and 2 deletions

View File

@@ -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.
*

View File

@@ -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();
}

View File

@@ -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;
}
}
}

View File

@@ -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 {}

View File

@@ -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;
}