Android11 窗口动画

窗口进入动画

应用端窗口绘制完成之后,调用finshDraw告知WMS,WMS这边最后就会调用WindowSurfacePlacer的performSurfacePlacement方法,最终调用到 WindowStateAnimator的commitFinishDrawingLocked方法

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
	boolean commitFinishDrawingLocked() {
       
       //省略
        mDrawState = READY_TO_SHOW;//READY_TO_SHOW状态
        boolean result = false;
        final ActivityRecord activity = mWin.mActivityRecord;
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
            result = mWin.performShowLocked();
        }
        return result;
    }

对于系统窗口,直接调用WindowState的performShowLocked 方法

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
boolean performShowLocked() {
	//省略
	mWinAnimator.applyEnterAnimationLocked();//动画
	mWinAnimator.mDrawState = HAS_DRAWN;//HAS_DRAWN状态
	//省略
}

applyEnterAnimationLocked

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
void applyEnterAnimationLocked() {
      	//省略
        final int transit;
        if (mEnterAnimationPending) {
            mEnterAnimationPending = false;
            transit = WindowManagerPolicy.TRANSIT_ENTER;//走这个分支
        } else {
            transit = WindowManagerPolicy.TRANSIT_SHOW;
        }

        // We don't apply animation for application main window here since this window type
        // should be controlled by AppWindowToken in general.
        if (mAttrType != TYPE_BASE_APPLICATION) {
            applyAnimationLocked(transit, true);//动画
        }
	//省略
    }

最后调用applyAnimationLocked去播放动画。

窗口退出动画

应用端remove,导致WMS的removeWindow被调用

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
 void removeWindow(Session session, IWindow client) {
        synchronized (mGlobalLock) {
            WindowState win = windowForClientLocked(session, client, false);
            if (win != null) {
                win.removeIfPossible();
                return;
            }

            // Remove embedded window map if the token belongs to an embedded window
            mEmbeddedWindowController.remove(client);
        }
    }

removeIfPossible

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
@Override
    void removeIfPossible() {
        super.removeIfPossible();
        removeIfPossible(false /*keepVisibleDeadWindow*/);
        immediatelyNotifyBlastSync();
    }

private void removeIfPossible(boolean keepVisibleDeadWindow) {
	//省略
if (wasVisible) {
	final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;//transit 为TRANSIT_EXIT 

	// Try starting an animation.
	if (mWinAnimator.applyAnimationLocked(transit, false)) {
		mAnimatingExit = true;
		//省略
	}
}
//省略

和窗口进入动画一样,也是调用WindowStateAnimator的applyAnimationLocked去处理动画相关的工作,只是传入的参数不一致。窗口进入时,transit为TRANSIT_ENTER,退出时,transit为TRANSIT_EXIT

applyAnimationLocked

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
boolean applyAnimationLocked(int transit, boolean isEntrance) {
	//省略
	if (mWin.mToken.okToAnimate()) {
		int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);//对于系统窗口,返回0
		Animation a = null;
		if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {
           //省略    
    	} 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_NONE);//加载动画
                }
		}
		if (a != null) {
                if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#startAnimation");
                mWin.startAnimation(a);//开始动画
                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                mAnimationIsEntrance = isEntrance;
		}
		//省略
}

首先根据不同的transit去加载不同的XML文件并创建对应的Animation 对象,然后调用WindowState的startAnimation 开始动画

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void startAnimation(Animation anim) {
		//省略

        final DisplayInfo displayInfo = getDisplayInfo();
        anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
                displayInfo.appWidth, displayInfo.appHeight);
        anim.restrictDuration(MAX_ANIMATION_DURATION);
        anim.scaleCurrentDuration(mWmService.getWindowAnimationScaleLocked());
        final AnimationAdapter adapter = new LocalAnimationAdapter(
                new WindowAnimationSpec(anim, mSurfacePosition, false /* canSkipFirstFrame */,
                        0 /* windowCornerRadius */),
                mWmService.mSurfaceAnimationRunner);//创建LocalAnimationAdapter
        startAnimation(getPendingTransaction(), adapter);
        commitPendingTransaction();
    }

首先创建LocalAnimationAdapter对象,LocalAnimationAdapter对象中的mSpec成员是WindowAnimationSpec对象,WindowAnimationSpec对象中的mAnimation成员是上一步创建的Animation 对象。LocalAnimationAdapter对象中的mAnimator指向的是WMS中的mSurfaceAnimationRunner。创建好LocalAnimationAdapter对象后,继续调用startAnimation处理

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
 private void startAnimation(Transaction t, AnimationAdapter adapter) {
        startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION);
 }

调用父类WindowContainer的startAnimation方法

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type,
            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
            
        // TODO: This should use isVisible() but because isVisible has a really weird meaning at
        // the moment this doesn't work for all animatable window containers.
        mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
                mSurfaceFreezer);
    }

    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type) {
        startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
    }

SurfaceAnimator.startAnimation

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type,
            @Nullable OnAnimationFinishedCallback animationFinishedCallback,
            @Nullable SurfaceFreezer freezer) {
        cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
        mAnimation = anim;//mAnimation 就为之前创建的LocalAnimationAdapter对象
        mAnimationType = type;
        mAnimationFinishedCallback = animationFinishedCallback;
        final SurfaceControl surface = mAnimatable.getSurfaceControl();//mAnimatable为窗口的WindowState
        mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
        if (mLeash == null) {
            mLeash = createAnimationLeash(mAnimatable, surface, t, type,
                    mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
                    0 /* y */, hidden, mService.mTransactionFactory);//创建leash图层
            mAnimatable.onAnimationLeashCreated(t, mLeash);
        }
        mAnimatable.onLeashAnimationStarting(t, mLeash);
      
        mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);//继续处理
    }

首先创建leash图层,然后调用LocalAnimationAdapter的startAnimation继续处理,注意传入的mInnerAnimationFinishedCallback参数,后续动画完成后会回调里面的方法。高版本的动画都是基于leash图层来做的

createAnimationLeash

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java
static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
            Transaction t, @AnimationType int type, int width, int height, int x, int y,
            boolean hidden, Supplier<Transaction> transactionFactory) {
        if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
        final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
                .setParent(animatable.getAnimationLeashParent())//将leash图层挂载到WindowState父亲的图层下
                .setName(surface + " - animation-leash")
                // TODO(b/151665759) Defer reparent calls
                // We want the leash to be visible immediately because the transaction which shows
                // the leash may be deferred but the reparent will not. This will cause the leashed
                // surface to be invisible until the deferred transaction is applied. If this
                // doesn't work, you will can see the 2/3 button nav bar flicker during seamless
                // rotation.
                .setHidden(hidden)
                .setEffectLayer()
                .setCallsite("SurfaceAnimator.createAnimationLeash");
        final SurfaceControl leash = builder.build();
        t.setWindowCrop(leash, width, height);
        t.setPosition(leash, x, y);
        t.show(leash);
        t.setAlpha(leash, hidden ? 0 : 1);

        t.reparent(surface, leash);//将windowState的图层挂载在leash下
        return leash;
    }

注意这这只是对surface图层的关系进行操作,WMS这边的层级树是没有改变的。此时,图层的关系如下:

LocalAnimationAdapter.startAnimation

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
	@Override
    public void startAnimation(SurfaceControl animationLeash, Transaction t,
            @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
        mAnimator.startAnimation(mSpec, animationLeash, t,
                () -> finishCallback.onAnimationFinished(type, this));//前面说过,mAnimator为SurfaceAnimationRunner对象,mSpec为WindowAnimationSpec对象
    }

SurfaceAnimationRunner.startAnimation

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
            Runnable finishCallback) {
        synchronized (mLock) {
            final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
                    finishCallback);//创建RunningAnimation对象
            mPendingAnimations.put(animationLeash, runningAnim);//放入map中,注意map中也放入了leash图层
            if (!mAnimationStartDeferred) {
                mChoreographer.postFrameCallback(this::startAnimations);//请求vsync
            }
			//省略
        }
    }

又创建了一个RunningAnimation对象,RunningAnimation中的mAnimSpec为WindowAnimationSpec对象,这个WindowAnimationSpec对象中是有之前创建的Animation 对象的。然后将RunningAnimation对象保存到mPendingAnimations Map中。然后请求vsync信号。当vsync信号来了的时候,调用startAnimations方法

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
private void startAnimations(long frameTimeNanos) {
        synchronized (mLock) {
            startPendingAnimationsLocked();
        }
        mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
}

@GuardedBy("mLock")
    private void startPendingAnimationsLocked() {
        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {//遍历mPendingAnimations
            startAnimationLocked(mPendingAnimations.valueAt(i));
        }
        mPendingAnimations.clear();
    }

startAnimationLocked就是去执行动画的播放了。

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@GuardedBy("mLock")
    private void startAnimationLocked(RunningAnimation a) {
        final ValueAnimator anim = mAnimatorFactory.makeAnimator();//创建ValueAnimator 

        // 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();//请求下一个vsync信号
        });
	
	//省略

applyTransformation

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
        a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
    }

WindowAnimationSpec.apply

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@Override
    public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
        final TmpValues tmp = mThreadLocalTmps.get();
        tmp.transformation.clear();
        mAnimation.getTransformation(currentPlayTime, tmp.transformation);
        tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
        t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
        t.setAlpha(leash, tmp.transformation.getAlpha());

        boolean cropSet = false;
        if (mStackClipMode == STACK_CLIP_NONE) {
            if (tmp.transformation.hasClipRect()) {
                t.setWindowCrop(leash, tmp.transformation.getClipRect());
                cropSet = true;
            }
        } else {
            mTmpRect.set(mStackBounds);
            if (tmp.transformation.hasClipRect()) {
                mTmpRect.intersect(tmp.transformation.getClipRect());
            }
            t.setWindowCrop(leash, mTmpRect);
            cropSet = true;
        }

        // We can only apply rounded corner if a crop is set, as otherwise the value is meaningless,
        // since it doesn't have anything it's relative to.
        if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
            t.setCornerRadius(leash, mWindowCornerRadius);
        }
    }

可以看出播放动画就是对leash图层进行操作。

以一张图来总结下窗口动画的播放流程

leash图层的移除

在播放动画时,创建了leash图层,动画结束后需要移除该图层。

在上面SurfaceAnimationRunner的startAnimationLocked方法中,除了有动画更新的回调,当动画结束时也是有回调的

c 复制代码
private void startAnimationLocked(RunningAnimation a) {
	//省略
	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);
                        }
                    }
                }
            }
        });
	//省略
}

动画结束时,post了一个Runnable,了解了前面动画的播放流程的话,就知道这个Runnable是 SurfaceAnimator的 mInnerAnimationFinishedCallback,mInnerAnimationFinishedCallback的定义如下

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java
SurfaceAnimator(Animatable animatable,
            @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback,
            WindowManagerService service) {
       //省略
        mInnerAnimationFinishedCallback = getFinishedCallback(staticAnimationFinishedCallback);
}

private OnAnimationFinishedCallback getFinishedCallback(
            @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback) {
        return (type, anim) -> {
            synchronized (mService.mGlobalLock) {
                final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
                if (target != null) {
                    target.mInnerAnimationFinishedCallback.onAnimationFinished(type, anim);
                    return;
                }

                if (anim != mAnimation) {
                    return;
                }
                final Runnable resetAndInvokeFinish = () -> {
                    // We need to check again if the animation has been replaced with a new
                    // animation because the animatable may defer to finish.
                    if (anim != mAnimation) {
                        return;
                    }
                    final OnAnimationFinishedCallback animationFinishCallback =
                            mAnimationFinishedCallback;
                    reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);//移除leash
                   //省略
                };
                // 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();//执行上面的Runnable 
                }
            }
        };
    }

可以看出,动画结束时,调用reset去移除leash图层

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java
private void reset(Transaction t, boolean destroyLeash) {
        mService.mAnimationTransferMap.remove(mAnimation);
        mAnimation = null;
        mAnimationFinishedCallback = null;
        mAnimationType = ANIMATION_TYPE_NONE;
        if (mLeash == null) {
            return;
        }
        SurfaceControl leash = mLeash;
        mLeash = null;
        final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
        if (scheduleAnim) {
            mService.scheduleAnimationLocked();
        }
    }

removeLeash

c 复制代码
//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java
static boolean removeLeash(Transaction t, Animatable animatable, @NonNull SurfaceControl leash,
            boolean destroy) {
        boolean scheduleAnim = false;
        final SurfaceControl surface = animatable.getSurfaceControl();//得到windowstate的图层
        final SurfaceControl parent = animatable.getParentSurfaceControl();//windowstate对应父节点的图层

        // If the surface was destroyed or the leash is invalid, we don't care to reparent it back.
        // Note that we also set this variable to true even if the parent isn't valid anymore, in
        // order to ensure onAnimationLeashLost still gets called in this case.
        final boolean reparent = surface != null;
        if (reparent) {
            if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent: " + parent);
            // We shouldn't really need these isValid checks but we do
            // b/130364451
            if (surface.isValid() && parent != null && parent.isValid()) {
                t.reparent(surface, parent);//将windowstate的图层重新挂载到父节点的图层下
                scheduleAnim = true;
            }
        }
        if (destroy) {
            t.remove(leash);//移除leash图层
            scheduleAnim = true;
        }

        if (reparent) {
            // Make sure to inform the animatable after the surface was reparented (or reparent
            // wasn't possible, but we still need to invoke the callback)
            animatable.onAnimationLeashLost(t);
            scheduleAnim = true;
        }
        return scheduleAnim;
    }

所以,在动画播放和结束的流程中,图层有以下变化

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui