窗口进入动画
应用端窗口绘制完成之后,调用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;
}
所以,在动画播放和结束的流程中,图层有以下变化