赞
踩
窗口进入动画
应用端窗口绘制完成之后,调用finshDraw告知WMS,WMS这边最后就会调用WindowSurfacePlacer的performSurfacePlacement方法,最终调用到 WindowStateAnimator的commitFinishDrawingLocked方法
//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 方法
//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.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
//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
//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 开始动画
//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处理
//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方法
//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为窗口的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
//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
@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
//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--) {//遍历mPendingAnimations startAnimationLocked(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 @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方法中,除了有动画更新的回调,当动画结束时也是有回调的
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的定义如下
//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/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; }
所以,在动画播放和结束的流程中,图层有以下变化
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。