Android窗口动画体系

779 阅读3分钟

窗口动画:LocalAnimationAdapter RemoteAnimationAdapter

本地动画 LocalAnimationAdapter:基本的activity切换动画

远程动画 RemoteAnimationAdapter:桌面点击启动app,app退出到桌面

LocalAnimationAdapter窗口动画时序图

image.png

note right of RootWindowContainer:mAppTransitionState的四种状态:
1. APP_STATE_IDLE = 0 初始值,prepareAppTransition设置transit时会设置state;
2. APP_STATE_READY = 1 executeAppTransition时设置成ready状态;
3. APP_STATE_RUNNING = 2;
4. APP_STATE_TIMEOUT 在prepareAppTransition时,发送一个5s的runnable,如果5s动画还没有执行设置动画超时
note right of AppTransitionController:* 
1. transitionGoodToGo 判断是否可以进行动画;
2. adjustWallpaperWindowsForAppTransitionIfNeeded 调整WallpaperTarget;
3. getTransitCompatType  根据appTransition中的mNextAppTransitionRequests值、translucent、closing(opening)AppHasWallpaper计算出transit;
4. overrideWithRemoteAnimationIfSet 是否执行的是remoteAnimation,创建RemoteAnimationController;
5. applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp, voiceInteraction); 分别对openingApps和closingApps获取getAnimationTargets--->applyAnimations遍历所有的openingWcs/closingWcs执行wc.applyAnimation;
6. handleChangingApps 对changingApps执行wc.applyAnimation;
7. appTransition.goodToGo(transit, topOpeningApp)执行远程动画--->RemoteAnimationController.goodToGo;
8. handleNonAppWindowsInTransition 处理非窗口动画,比如keyguard_going_away;
9. mDisplayContent.computeImeTarget(true ); 更新输入法窗口

<5> wc.applyAnimation-->applyAnimationUnchecked 获取当前windowcontainer的动画适配器getAnimationAdapter

protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
        @TransitionOldType int transit, boolean isVoiceInteraction,
        @Nullable ArrayList<WindowContainer> sources) {
        final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
                transit, enter, isVoiceInteraction);

根据transit和enter找到动画xml资源activity_open_enter.xml,通过loadAnimation把xml资源转成Animation对象,创建一个WindowAnimationSpec对象,并把Animation对象作为构造方法的第一个参数传给了WindowAnimationSpec

Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
        @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction) {
    final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
    
    WindowAnimationSpec spec = new WindowAnimationSpec(
        a, mTmpPoint, mTmpRect,
        getDisplayContent().mAppTransition.canSkipFirstFrame(),
        appRootTaskClipMode,
        true /* isAppAnimation */,
        windowCornerRadius);

    AnimationAdapter adapter = new LocalAnimationAdapter(spec,
        getSurfaceAnimationRunner());

mSurfaceAnimator.startAnimation()执行动画,进行动画的surfacecontrol创建一个parent的surfacecontrol类型的mLeash对象,通过操控mLeash对象来实现窗口的大小、位置、透明度等动画属性的改变。最终是在SurfaceAnimationRunner.startAnimationLocked实现动画

通过mChoreographer切换到SurfaceAnimationThread线程来执行,然后创建了ValueAnimator属性动画对象,交由ValueAnimator属性动画对象的addUpdateListener方法来实现逐帧控制动画mLeash对象(surfacecontrol类型)的变化,具体的update方法的实现是在WindowAnimatonSpec类的apply方法里面。
private void startAnimationLocked(RunningAnimation a) {
    final ValueAnimator anim = mAnimatorFactory.makeAnimator();

    // Animation length is already expected to be scaled.
    anim.overrideDurationScale(1.0f);
    anim.setDuration(a.mAnimSpec.getDuration());
    anim.addUpdateListener(animation -> {
        synchronized (mCancelLock) {
            if (!a.mCancelled) {
                final long duration = anim.getDuration();
                long currentPlayTime = anim.getCurrentPlayTime();
                if (currentPlayTime > duration) {
                    currentPlayTime = duration;
                }
                applyTransformation(a, mFrameTransaction, currentPlayTime);
            }
        }

        // Transaction will be applied in the commit phase.
        scheduleApplyTransaction();
    });

    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            synchronized (mCancelLock) {
                if (!a.mCancelled) {
                    // TODO: change this back to use show instead of alpha when b/138459974 is
                    // fixed.
                    mFrameTransaction.setAlpha(a.mLeash, 1);
                }
            }
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            synchronized (mLock) {
                mRunningAnimations.remove(a.mLeash);
                synchronized (mCancelLock) {
                    if (!a.mCancelled) {

                        // Post on other thread that we can push final state without jank.
                        mAnimationThreadHandler.post(a.mFinishCallback);
                    }
                }
            }
        }
    });
    a.mAnim = anim;
    mRunningAnimations.put(a.mLeash, a);

    anim.start();
    if (a.mAnimSpec.canSkipFirstFrame()) {
        // If we can skip the first frame, we start one frame later.
        anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
    }

    // Immediately start the animation by manually applying an animation frame. Otherwise, the
    // start time would only be set in the next frame, leading to a delay.
    anim.doAnimationFrame(mChoreographer.getFrameTime());
}

前面介绍到appTransition.goodToGo(transit, topOpeningApp)执行远程动画--->RemoteAnimationController.goodToGo

image.png

App侧会继承IRemoteAnimationRunner.Stub实现 onAnimationStart方法通过ValueAnimator实现具体的动画

`public` `class` `MainActivity ``extends` `Activity {`

 

`    ``private` `Button mButton;`

`    ``private` `Handler mHandler;`

 

`    ``private` `RemoteAnimationAdapter mRemoteAnimationAdapter;`

 

 

`    ``@Override`

`    ``protected` `void` `onCreate(``@Nullable` `Bundle savedInstanceState) {`

`        ``super``.onCreate(savedInstanceState);`

`        ``setContentView(R.layout.activity_main);`

 

`        ``mButton = findViewById(R.id.anim);`

`        ``mButton.setOnClickListener(``new` `View.OnClickListener() {`

`            ``@Override`

`            ``public` `void` `onClick(View view) {`

`                ``ActivityOptions options = ActivityOptions.makeRemoteAnimation(mRemoteAnimationAdapter);`

`                ``Intent intent = ``new` `Intent(MainActivity.``this``, SecondActivity.``class``);`

`                ``startActivity(intent, options.toBundle());`

`            ``}`

`        ``});`

 

`        ``mRemoteAnimationAdapter = getAnimationAdapter();`

`        ``//这个是为了返回动画也交给remoteanimation`

`        ``registerRemoteAnimations();`

 

`        ``mHandler = ``new` `Handler(getMainLooper());`

`    ``}`

 

 

`    ``private` `void` `registerRemoteAnimations() {`

`        ``RemoteAnimationDefinition definition = ``new` `RemoteAnimationDefinition();`

`        ``//Demo从第二个页面返回第一个页面是TRANSIT_OLD_ACTIVITY_CLOSE类型的动画,所以这里第一个参数是TRANSIT_OLD_ACTIVITY_CLOSE;如果返回桌面应该是TRANSIT_OLD_WALLPAPER_CLOSE`

`        ``definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE,`

`                ``ACTIVITY_TYPE_STANDARD, mRemoteAnimationAdapter);`

`        ``registerRemoteAnimations(definition);`

`    ``}`

 

`    ``private` `RemoteAnimationAdapter getAnimationAdapter() {`

`        ``AnimationRunner animationRunner = ``new` `AnimationRunner();`

`        ``return` `new` `RemoteAnimationAdapter(animationRunner, ``400``/*duration 动画时长*/``, ``200``/*statusBarTransitionDelay*/``);`

`    ``}`

 

`    ``class` `AnimationRunner ``extends` `IRemoteAnimationRunner.Stub {`

`        ``private` `final` `SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier;`

 

`        ``public` `AnimationRunner() {`

`            ``mSyncRtTransactionApplier = ``new` `SyncRtSurfaceTransactionApplier(mButton);`

`        ``}`

 

`        ``@Override`

`        ``public` `void` `onAnimationStart(``int` `transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) ``throws` `RemoteException {`

`            ``Slog.e(``"suiyue-test"``, ``"apps = "` `+ apps + ``" wallpapers = "` `+ wallpapers);`

`            ``mHandler.post(``new` `Runnable() {`

`                ``@Override`

`                ``public` `void` `run() {`

`                    ``for` `(RemoteAnimationTarget target : apps) {`

`                        ``//target.leash就是需要做动画的animation-leash`

`                        ``//apps一般是2个 一个mode是OPENING,一个mode是CLOSING,但不排除异常情况,所以要有容错处理`

`                        ``//拿到了leash跟mode就可以尽情做你想要的动画,这里只是简单的做了个打开应用的alpha动画`

`                        ``Slog.e(``"suiyue-test"``, ``"leash = "` `+ target.leash + ``" mode = "` `+ target.mode);`

`                        ``if` `(target.mode == RemoteAnimationTarget.MODE_OPENING) {`

`                            ``ValueAnimator anim = ValueAnimator.ofFloat(``0``, ``1``);`

`                            ``anim.setDuration(``400``);`

`                            ``anim.setInterpolator(``new` `LinearInterpolator());`

`                            ``anim.addUpdateListener(``new` `ValueAnimator.AnimatorUpdateListener() {`

`                                ``@Override`

`                                ``public` `void` `onAnimationUpdate(ValueAnimator animation) {`

`                                    ``SurfaceParams params = ``new` `SurfaceParams.Builder(target.leash)`

`                                            ``.withAlpha((``float``) animation.getAnimatedValue())`

`                                            ``.withVisibility(``true``)`

`                                            ``.build();`

`                                    ``mSyncRtTransactionApplier.scheduleApply(params);`

`                                ``}`

`                            ``});`

`                            ``anim.addListener(``new` `Animator.AnimatorListener() {`

`                                ``@Override`

`                                ``public` `void` `onAnimationStart(Animator animation) {`

 

`                                ``}`

 

`                                ``@Override`

`                                ``public` `void` `onAnimationEnd(Animator animation) {`

`                                    ``//这个是动画结束给系统的回调,一定要调用,不然就系统就要等动画10s超时`

`                                    ``invokeCallback(finishedCallback);`

`                                ``}`

 

`                                ``@Override`

`                                ``public` `void` `onAnimationCancel(Animator animation) {`

 

`                                ``}`

 

`                                ``@Override`

`                                ``public` `void` `onAnimationRepeat(Animator animation) {`

 

`                                ``}`

`                            ``});`

`                            ``anim.start();`

`                        ``}`

`                    ``}`

`                ``}`

`            ``});`

`        ``}`

 

`        ``@Override`

`        ``public` `void` `onAnimationCancelled() ``throws` `RemoteException {`

 

`        ``}`

 

`        ``private` `void` `invokeCallback(IRemoteAnimationFinishedCallback callback) {`

`            ``try` `{`

`                ``callback.onAnimationFinished();`

`            ``} ``catch` `(RemoteException e) {`

`                ``e.printStackTrace();`

`            ``}`

`        ``}`

`    ``}`

`}`