Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5dcacf79 authored by Vadim Caen's avatar Vadim Caen Committed by Automerger Merge Worker
Browse files

Merge changes I24d33b94,I9db3c5d1 into rvc-dev am: ade62d56

Change-Id: I9bebe4cd5d30b553d92b7a8e9a9816e1a5a8a3fb
parents 36f4c776 ade62d56
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -85,4 +85,25 @@ interface AnimationAdapter {
    }

    void dumpDebug(ProtoOutputStream proto);

    /**
     * Gets called when the animation is about to finish and gives the client the opportunity to
     * defer finishing the animation, i.e. it keeps the leash around until the client calls
     * endDeferFinishCallback.
     * <p>
     * This has the same effect as
     * {@link com.android.server.wm.SurfaceAnimator.Animatable#shouldDeferAnimationFinish(Runnable)}
     * . The later will be evaluated first and has precedence over this method if it returns true,
     * which means that if the {@link com.android.server.wm.SurfaceAnimator.Animatable} requests to
     * defer its finish, this method won't be called so this adapter will never have access to the
     * finish callback. On the other hand, if the
     * {@link com.android.server.wm.SurfaceAnimator.Animatable}, doesn't request to defer, this
     * {@link AnimationAdapter} is responsible for ending the animation.
     *
     * @param endDeferFinishCallback The callback to call when defer finishing should be ended.
     * @return Whether the client would like to defer the animation finish.
     */
    default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
        return false;
    }
}
+14 −0
Original line number Diff line number Diff line
@@ -499,6 +499,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     */
    ActivityRecord mFixedRotationLaunchingApp;

    FixedRotationAnimationController mFixedRotationAnimationController;

    final FixedRotationTransitionListener mFixedRotationTransitionListener =
            new FixedRotationTransitionListener();

@@ -1528,6 +1530,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    private void startFixedRotationTransform(WindowToken token, int rotation) {
        if (mFixedRotationAnimationController == null) {
            mFixedRotationAnimationController = new FixedRotationAnimationController(
                    this);
        }
        mFixedRotationAnimationController.hide(rotation);
        mTmpConfiguration.unset();
        final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
        final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
@@ -1549,6 +1556,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        }
    }

    void finishFixedRotationAnimation() {
        if (mFixedRotationAnimationController != null
                && mFixedRotationAnimationController.show()) {
            mFixedRotationAnimationController = null;
        }
    }

    /**
     * Update rotation of the display.
     *
+2 −0
Original line number Diff line number Diff line
@@ -560,6 +560,7 @@ public class DisplayRotation {
        }, true /* traverseTopToBottom */);
        mSeamlessRotationCount = 0;
        mRotatingSeamlessly = false;
        mDisplayContent.finishFixedRotationAnimation();
    }

    private void prepareSeamlessRotation() {
@@ -646,6 +647,7 @@ public class DisplayRotation {
                    "Performing post-rotate rotation after seamless rotation");
            // Finish seamless rotation.
            mRotatingSeamlessly = false;
            mDisplayContent.finishFixedRotationAnimation();

            updateRotationAndSendNewConfigIfChanged();
        }
+197 −0
Original line number Diff line number Diff line
/*
 * 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.res.Configuration;
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 WindowManagerService mWmService;
    private boolean mShowRequested = true;
    private int mTargetRotation = Configuration.ORIENTATION_UNDEFINED;
    private final ArrayList<WindowState> mAnimatedWindowStates = new ArrayList<>(2);
    private final Runnable[] mDeferredFinishCallbacks;

    public FixedRotationAnimationController(DisplayContent displayContent) {
        mWmService = displayContent.mWmService;
        addAnimatedWindow(displayContent.getDisplayPolicy().getStatusBar());
        addAnimatedWindow(displayContent.getDisplayPolicy().getNavigationBar());
        mDeferredFinishCallbacks = new Runnable[mAnimatedWindowStates.size()];
    }

    private void addAnimatedWindow(WindowState windowState) {
        if (windowState != null) {
            mAnimatedWindowStates.add(windowState);
        }
    }

    /**
     * Show the previously hidden {@link WindowToken} if their surfaces have already been rotated.
     *
     * @return True if the show animation has been started, in which case the caller no longer needs
     * this {@link FixedRotationAnimationController}.
     */
    boolean show() {
        if (!mShowRequested && readyToShow()) {
            mShowRequested = true;
            for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
                WindowState windowState = mAnimatedWindowStates.get(i);
                fadeWindowToken(true, windowState.getParent(), i);
            }
            return true;
        }
        return false;
    }

    void hide(int targetRotation) {
        mTargetRotation = targetRotation;
        if (mShowRequested) {
            mShowRequested = false;
            for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
                WindowState windowState = mAnimatedWindowStates.get(i);
                fadeWindowToken(false /* show */, windowState.getParent(), i);
            }
        }
    }

    void cancel() {
        for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
            WindowState windowState = mAnimatedWindowStates.get(i);
            mShowRequested = true;
            fadeWindowToken(true /* show */, windowState.getParent(), i);
        }
    }

    private void fadeWindowToken(boolean show, WindowContainer<WindowToken> windowToken,
            int index) {
        Animation animation = AnimationUtils.loadAnimation(mWmService.mContext,
                show ? R.anim.fade_in : R.anim.fade_out);
        LocalAnimationAdapter.AnimationSpec windowAnimationSpec = createAnimationSpec(animation);

        FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter(
                windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, index);

        // We deferred the end of the animation when hiding the token, so we need to end it now that
        // it's shown again.
        SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
            if (mDeferredFinishCallbacks[index] != null) {
                mDeferredFinishCallbacks[index].run();
                mDeferredFinishCallbacks[index] = null;
            }
        } : null;
        windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
                mShowRequested, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback);
    }

    /**
     * Check if all the mAnimatedWindowState's surfaces have been rotated to the
     * mTargetRotation.
     */
    private boolean readyToShow() {
        for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
            WindowState windowState = mAnimatedWindowStates.get(i);
            if (windowState.getConfiguration().windowConfiguration.getRotation()
                    != mTargetRotation || windowState.mPendingSeamlessRotate != null) {
                return false;
            }
        }
        return true;
    }


    private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) {
        return new LocalAnimationAdapter.AnimationSpec() {

            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 int mIndex;

        FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec,
                SurfaceAnimationRunner surfaceAnimationRunner, boolean show, int index) {
            super(windowAnimationSpec, surfaceAnimationRunner);
            mShow = show;
            mIndex = index;
        }

        @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[mIndex] = endDeferFinishCallback;
                return true;
            }
            return false;
        }
    }
}
+18 −2
Original line number Diff line number Diff line
@@ -109,7 +109,10 @@ class SurfaceAnimator {
                        animationFinishCallback.onAnimationFinished(type, anim);
                    }
                };
                if (!mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)) {
                // If both the Animatable and AnimationAdapter requests to be deferred, only the
                // first one will be called.
                if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)
                        || anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) {
                    resetAndInvokeFinish.run();
                }
            }
@@ -485,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
@@ -502,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 {}
@@ -592,6 +602,12 @@ class SurfaceAnimator {
         * Gets called when the animation is about to finish and gives the client the opportunity to
         * defer finishing the animation, i.e. it keeps the leash around until the client calls
         * {@link #cancelAnimation}.
         * <p>
         * {@link AnimationAdapter} has a similar method which is called only if this method returns
         * false. This mean that if both this {@link Animatable} and the {@link AnimationAdapter}
         * request to be deferred, this method is the sole responsible to call
         * endDeferFinishCallback. On the other hand, the animation finish might still be deferred
         * if this method return false and the one from the {@link AnimationAdapter} returns true.
         *
         * @param endDeferFinishCallback The callback to call when defer finishing should be ended.
         * @return Whether the client would like to defer the animation finish.
Loading