Android 16系统源码_窗口动画(二)窗口显示动画源码调用流程
前言
在Android 16系统源码_窗口动画(一)窗口过渡动画层级图分析这篇文章我们有分析过,系统触发窗口显示动画的过程中,会创建一个leash图层,本篇文章我们将会结合源码具体来分析下该图层的创建流程。
一 创建Leash图层的代码源头
1.1 查找创建leash图层的代码源头
触发窗口显示动画时候的SurfaceFlinger图层信息如下所示。
在叶子节点下回多了一个含有animation-leash关键字的Surface图层,我们直接在源码中查找animation-leash of 关键字,可以定位到SurfaceAnimator这个类的394行。
/base/services/core/java/com/android/server/wm/SurfaceAnimator.java:394: .setName(surface + " - animation-leash of " + animationTypeToString(type))class SurfaceAnimator {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()).setName(surface + " - animation-leash of " + animationTypeToString(type)).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);return leash;}
}
二 创建leash图层的源码流程
2.1 createAnimationLeash方法调用流程
2.1.1 堆栈信息
通过断点调试可以得到SurfaceAnimator的createAnimationLeash方法的调用堆栈信息。
2.1.2 createAnimationLeash方法源码调用流程
结合以上方法调用栈,在系统源码中进行定位可以得到以下调用流程
//frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
class WindowSurfacePlacer {void requestTraversal() {...代码省略...mService.mAnimationHandler.post(mPerformSurfacePlacement);}private class Traverser implements Runnable {@Overridepublic void run() {synchronized (mService.mGlobalLock) {//调用performSurfacePlacement方法performSurfacePlacement();}}}final void performSurfacePlacement() {performSurfacePlacement(false /* force */);}final void performSurfacePlacement(boolean force) {...代码省略...performSurfacePlacementLoop();...代码省略...}private final WindowManagerService mService;private void performSurfacePlacementLoop() {...代码省略... mService.mRoot.performSurfacePlacement();...代码省略... }}
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {// The root of the device window hierarchy.RootWindowContainer mRoot;
}
//frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
class RootWindowContainer extends WindowContainer<DisplayContent>implements DisplayManager.DisplayListener {void performSurfacePlacement() {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");try {performSurfacePlacementNoTrace();} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}}void performSurfacePlacementNoTrace() {...代码省略... //调用applySurfaceChangesTransactionapplySurfaceChangesTransaction();...代码省略... }protected final WindowList<E> mChildren = new WindowList<E>();private void applySurfaceChangesTransaction() {...代码省略... final int count = mChildren.size();for (int j = 0; j < count; ++j) {final DisplayContent dc = mChildren.get(j);dc.applySurfaceChangesTransaction();}...代码省略... }
}
//frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {void applySurfaceChangesTransaction() {...代码省略...forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);...代码省略... }//关键回调,触发WindowState的commitFinishDrawingLocked方法private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> { ...代码省略...// Take care of the window being ready to display.final boolean committed = w.mWinAnimator.commitFinishDrawingLocked();...代码省略... }}
//frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
class WindowStateAnimator {// This must be called while inside a transaction.boolean commitFinishDrawingLocked() {if (DEBUG_STARTING_WINDOW_VERBOSE &&mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="+ drawStateToString());}if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {return false;}if (DEBUG_ANIM) {Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);}mDrawState = READY_TO_SHOW;boolean result = false;final ActivityRecord activity = mWin.mActivityRecord;if (activity == null || activity.canShowWindows()|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {//调用WindowState的performShowLocked方法result = mWin.performShowLocked();}return result;}
}//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,InsetsControlTarget, InputTarget {boolean performShowLocked() {...代码省略... mWinAnimator.applyEnterAnimationLocked();...代码省略... }
}class WindowStateAnimator {void applyEnterAnimationLocked() {// If we are the new part of a window replacement transition and we have requested// not to animate, we instead want to make it seamless, so we don't want to apply// an enter transition.if (mWin.mSkipEnterAnimationForSeamlessReplacement) {return;}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 ActivityRecord in general. Wallpaper is also excluded because// WallpaperController should handle it.if (mAttrType != TYPE_BASE_APPLICATION && !mIsWallpaper) {applyAnimationLocked(transit, true);}if (mService.mAccessibilityController.hasCallbacks()) {mService.mAccessibilityController.onWindowTransition(mWin, transit);}}boolean applyAnimationLocked(int transit, boolean isEntrance) {if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {// If we are trying to apply an animation, but already running// an animation of the same type, then just leave that one alone.return true;}if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {mWin.getDisplayContent().adjustForImeIfNeeded();if (isEntrance) {mWin.setDisplayLayoutNeeded();mService.mWindowPlacerLocked.requestTraversal();}}if (mWin.mControllableInsetProvider != null) {// All our animations should be driven by the insets control target.return false;}// Only apply an animation if the display isn't frozen. If it is// frozen, there is no reason to animate and it can cause strange// artifacts when we unfreeze the display if some different animation// is running.if (mWin.mToken.okToAnimate()) {int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);int attr = -1;Animation a = null;if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {if (anim != DisplayPolicy.ANIMATION_NONE) {Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#loadAnimation");a = AnimationUtils.loadAnimation(mContext, anim);Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);}} 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.mDisplayContent.mTransitionAnimation.loadAnimationAttr(mWin.mAttrs, attr, TRANSIT_OLD_NONE);}}if (ProtoLog.isEnabled(WM_DEBUG_ANIM, LogLevel.VERBOSE)) {//关键日志打印ProtoLog.v(WM_DEBUG_ANIM, "applyAnimation: win=%s"+ " anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",this, anim, attr, a, transit, mAttrType, isEntrance, Debug.getCallers(20));}if (a != null) {Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#startAnimation");//调动WindowState的startAnimation方法,开启动画mWin.startAnimation(a);Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);mAnimationIsEntrance = isEntrance;}} else {mWin.cancelAnimation();}return mWin.isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);}
}class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,InsetsControlTarget, InputTarget {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 Point position = new Point();transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,position);//创建本地动画对象LocalAnimationAdapterfinal AnimationAdapter adapter = new LocalAnimationAdapter(new WindowAnimationSpec(anim, position, false /* canSkipFirstFrame */,0 /* windowCornerRadius */),mWmService.mSurfaceAnimationRunner);final Transaction t = mActivityRecord != null? getSyncTransaction() : getPendingTransaction();startAnimation(t, adapter);commitPendingTransaction();}private void startAnimation(Transaction t, AnimationAdapter adapter) {//继续调用父类的startAnimation方法startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION);}
}
//frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,@AnimationType int type) {startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);}void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,@AnimationType int type,@Nullable OnAnimationFinishedCallback animationFinishedCallback) {startAnimation(t, anim, hidden, type, animationFinishedCallback,null /* adapterAnimationCancelledCallback */, null /* snapshotAnim */);}void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,@AnimationType int type,@Nullable OnAnimationFinishedCallback animationFinishedCallback,@Nullable Runnable animationCancelledCallback,@Nullable AnimationAdapter snapshotAnim) {ProtoLog.v(WM_DEBUG_ANIM, "Starting animation on %s: type=%d, anim=%s",this, type, anim);// 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.//调用SurfaceAnimator的startAnimation方法mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,animationCancelledCallback, snapshotAnim);}
}
class SurfaceAnimator {void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,@AnimationType int type,@Nullable OnAnimationFinishedCallback animationFinishedCallback,@Nullable Runnable animationCancelledCallback,@Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {...代码省略...final SurfaceControl surface = mAnimatable.getSurfaceControl();if (surface == null) {Slog.w(TAG, "Unable to start animation, surface is null or no children.");cancelAnimation();return;}if (mLeash == null) {mLeash = createAnimationLeash(mAnimatable, surface, t, type,mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,0 /* y */, hidden, mService.mTransactionFactory);mAnimatable.onAnimationLeashCreated(t, mLeash);}...代码省略... }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) {ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to leash for %s", animatable);final SurfaceControl.Builder builder = animatable.makeAnimationLeash().setParent(animatable.getAnimationLeashParent())//设置leash动画图层的父类为当前窗口的父类.setName(surface + " - animation-leash of " + animationTypeToString(type))// 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);//指定窗口的父类为leash动画图层return leash;}
}
以上代码需要重点关注以下几点
- 在WindowStateAnimator的loadAnimationAttr方法中,会判断使用哪种窗口动画以及进行窗口动画资源的加载。
- 在WindowState的startAnimation方法中,会创建LocalAnimationAdapter本地动画实例对象。
- 在SurfaceAnimator的createAnimationLeash方法中,会创建leash动画图层,并将该图层的父类设置为当前窗口的父类,将当前窗口的父类设置为leash动画图层。