窗口进入动画
应用端窗口绘制完成之后,调用finshDraw告知WMS,WMS这边最后就会调用WindowSurfacePlacer的performSurfacePlacement方法,最终调用到 WindowStateAnimator的commitFinishDrawingLocked方法
//frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.javaboolean 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 方法
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
boolean performShowLocked() {//省略mWinAnimator.applyEnterAnimationLocked();//动画mWinAnimator.mDrawState = HAS_DRAWN;//HAS_DRAWN状态//省略
}
applyEnterAnimationLocked
//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被调用
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javavoid 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 windowmEmbeddedWindowController.remove(client);}}
removeIfPossible
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
@Overridevoid 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
//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);//对于系统窗口,返回0Animation 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 开始动画
//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);//创建LocalAnimationAdapterstartAnimation(getPendingTransaction(), adapter);commitPendingTransaction();}
首先创建LocalAnimationAdapter对象,LocalAnimationAdapter对象中的mSpec成员是WindowAnimationSpec对象,WindowAnimationSpec对象中的mAnimation成员是上一步创建的Animation 对象。LocalAnimationAdapter对象中的mAnimator指向的是WMS中的mSurfaceAnimationRunner。创建好LocalAnimationAdapter对象后,继续调用startAnimation处理
//frameworks/base/services/core/java/com/android/server/wm/WindowState.javaprivate void startAnimation(Transaction t, AnimationAdapter adapter) {startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION);}
调用父类WindowContainer的startAnimation方法
//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
//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为窗口的WindowStatemLeash = 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
//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
//frameworks/base/services/core/java/com/android/server/wm/LocalAnimationAdapter.java@Overridepublic 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
//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方法
//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--) {//遍历mPendingAnimationsstartAnimationLocked(mPendingAnimations.valueAt(i));}mPendingAnimations.clear();}
startAnimationLocked就是去执行动画的播放了。
//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
//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
//frameworks/base/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@Overridepublic 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方法中,除了有动画更新的回调,当动画结束时也是有回调的
private void startAnimationLocked(RunningAnimation a) {//省略anim.addListener(new AnimatorListenerAdapter() {@Overridepublic 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);}}}@Overridepublic 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的定义如下
//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图层
//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
//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/130364451if (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;}
所以,在动画播放和结束的流程中,图层有以下变化