窗口动画流程

250 阅读2分钟

动画类型

WMS动画类型定义在 SurfaceAnimator, 下面分别分析窗口动画、Activity切换动画、转屏动画的流程。

class SurfaceAnimator {

    /**
     * The type of the animation.
     * @hide
     */
    @IntDef(flag = true, prefix = { "ANIMATION_TYPE_" }, value = {
            ANIMATION_TYPE_NONE,
            ANIMATION_TYPE_APP_TRANSITION,
            ANIMATION_TYPE_SCREEN_ROTATION,
            ANIMATION_TYPE_DIMMER,
            ANIMATION_TYPE_RECENTS,
            ANIMATION_TYPE_WINDOW_ANIMATION,
            ANIMATION_TYPE_INSETS_CONTROL,
            ANIMATION_TYPE_TOKEN_TRANSFORM,
            ANIMATION_TYPE_STARTING_REVEAL,
            ANIMATION_TYPE_PREDICT_BACK
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface AnimationType {}
    
}

窗口动画流程

所有动画都是通过创建 AnimationSpec 和 AnimationAdapter,并交给 SurfaceAnimator 去执行。

窗口动画的类型定义在 WindowManagerPolicy.

public interface WindowManagerPolicy {
    // 第一次显示
    public static final int TRANSIT_ENTER = 1;
    // 退出
    public static final int TRANSIT_EXIT = 2;
    // 显示
    public static final int TRANSIT_SHOW = 3;
    // 未使用
    public static final int TRANSIT_HIDE = 4;
    // 应用启动窗口退出
    public static final int TRANSIT_PREVIEW_DONE = 5;
}

WindowStateAnimator 类负责跟踪窗口动画,动画执行流程如下:

  1. applyAnimationLocked() 根据窗口动画类型选择并加载动画资源文件,生成 Animation 对象;
  2. 在 WindowState 的 startAnimation() 方法创建 AnimationSpec 和 AniamtionAdapter 对象;
  3. 交给 SurfaceAnimator 执行动画。
class WindowStateAnimator {

    void applyEnterAnimationLocked() {
        final int transit;
        // addWindow() 中设置 mEnterAnimationPending 为 ture, 
        // 第一次显示为入场动画(TRANSIT_ENTER),其它为 TRANSIT_SHOW
        // addWindow() 中置为 true
        if (mEnterAnimationPending) {
            mEnterAnimationPending = false;
            transit = WindowManagerPolicy.TRANSIT_ENTER;
        } else {
            transit = WindowManagerPolicy.TRANSIT_SHOW;
        }

        // Activity 动画由 ActivityRecord 控制, 壁纸的动画由 WallpaperController 控制
        if (mAttrType != TYPE_BASE_APPLICATION && !mIsWallpaper) {
            applyAnimationLocked(transit, true);
        }
        ...
    }
    
    boolean applyAnimationLocked(int transit, boolean isEntrance) {
        ...
        // 屏幕没有冻结
        if (mWin.mToken.okToAnimate()) {
            int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);
            int attr = -1;
            Animation a = null;
            if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {
                if (anim != DisplayPolicy.ANIMATION_NONE) {
                    a = AnimationUtils.loadAnimation(mContext, anim);
                }
            } else {
                switch (transit) {
                    case WindowManagerPolicy.TRANSIT_ENTER:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
                        break;
                    case WindowManagerPolicy.TRANSIT_EXIT:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
                        break;
                    case WindowManagerPolicy.TRANSIT_SHOW:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
                        break;
                    case WindowManagerPolicy.TRANSIT_HIDE:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
                        break;
                }
                if (attr >= 0) {
                    a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
                            mWin.mAttrs, attr, TRANSIT_OLD_NONE);
                }
            }
            if (a != null) {
                mWin.startAnimation(a);
                mAnimationIsEntrance = isEntrance;
            }
        } else {
            mWin.cancelAnimation();
        }

        return mWin.isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
    }
}

WindowState

class WindowState {
    void startAnimation(Animation anim) {
        ...
        final DisplayInfo displayInfo = getDisplayInfo();
        // 1. 初始化 Animation 对象,设置最大运行时长
        anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
                displayInfo.appWidth, displayInfo.appHeight);
        anim.restrictDuration(MAX_ANIMATION_DURATION);
        anim.scaleCurrentDuration(mWmService.getWindowAnimationScaleLocked());
        // 2. 创建 WindowAnimationSpec, LocalAnimationAdapter 对象
        final AnimationAdapter adapter = new LocalAnimationAdapter(
                new WindowAnimationSpec(anim, mSurfacePosition, false /* canSkipFirstFrame */,
                        0 /* windowCornerRadius */),
                mWmService.mSurfaceAnimationRunner);
        // 3. 通过 SurfaceAnimator 执行动画
        startAnimation(getPendingTransaction(), adapter);
        commitPendingTransaction();
    }
}