Android T 窗口动画(本地动画)显示流程其一——整体流程介绍

1,494 阅读3分钟

如何创建一个窗口动画?我们通过先从APP创建一个窗口,以这个窗口的创建过程的窗口动画为例 请添加图片描述

这个demo就是点击BUTTON显示窗口,点击CLOSE WINDOW关闭窗口,下面简述关键代码

//定义WindowManager和LayoutParams
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;

//取得系统窗体
mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
//窗体的布局样式
mLayoutParams = new WindowManager.LayoutParams();
//窗口设置动画
mLayoutParams.windowAnimations = R.style.MyWindow;
//设置窗口名字
mLayoutParams.setTitle("test-window");

在res/values/styles.xml目录下添加styles

<style name="MyWindow">
    <item name="android:windowEnterAnimation">@anim/enter</item>
    <item name="android:windowExitAnimation">@anim/exit</item>
</style>

android:windowEnterAnimationandroid:windowExitAnimation属性指定进入和退出时的转场动画。

创建res/anim/enter.xml和res/anim/exit.xml

enter.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha android:fromAlpha="0"
        android:toAlpha="1.0"
        android:duration="1000"/>
</set>

设置透明度从0到1 exit.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha android:fromAlpha="1.0"
        android:toAlpha="0"
        android:duration="1000"/>
</set>

设置透明度从1到0 这两个xml都只是简单的做了一个透明度变化,实现了一个淡入淡出的效果 注:该demo可见附件,或者窗口相关的演示demo

分析思路

我们如何知道上面的demo所涉及的动画在我们framework侧的哪个部分?

图层

根据上面的demo我们从winscope上看看在图层上是怎么显示的 在这里插入图片描述 我们点击BUTTON后添加窗口,从图层中可以看到WindowToken和我们创建的窗口test-window中间添加了一个动画Surface(name=2257b8c test-window)/@0x825faea - animation-leash of window_animation#529。同时我们也能看到test-window的color : r:-1.000 g:-1.000 b:-1.000 a:0.193603515625,其中a:0.193603515625表示透明度,透明度从0逐渐到1就是从透明到显示的过程。 在这里插入图片描述 透明度为1时动画退出,窗口完全显示;窗口的移除流程同理,唯一不同的就是透明度从1到0,透明度为0时动画移除,窗口完全退出。 其过程我们简化如下图所示: 在这里插入图片描述

上图就是一次完整动画图层显示过程,也就是说动画的显示过程就是为其添加或移除的窗口和这个该窗口的父窗口之前添加一个层级(leash)用于显示动画;动画播放完成后,再移除这个层级(leash)。 注:Surface(name=2257b8c test-window)/@0x825faea - animation-leash of window_animation#529中的window_animation表示动画的类型是窗口动画。还有一种动画类型是insets_animation(一般是输入法、状态栏、导航栏等涉及),流程上大体也相同,这里我们不讨论

代码

添加动画

从上面的例子来看,不论是窗口显示还是隐藏,都会有类似于Surface(name=2257b8c test-window)/@0x825faea - animation-leash of window_animation#529的动画,那么我们就可以通过这点切入查找相应的代码,dump信息在代码中基本都有迹可循,搜索animation-leash 在这里插入图片描述 找到对应代码位置frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java 在这里插入图片描述 我们可以在createAnimationLeash方法中添加堆栈来查看其调用流程 Slog.i("WindowManager:","createAnimationLeash type = " + animationTypeToString(type) , new Exception()); 也可以使用走读代码的方式追踪

移除动画

既然有createAnimationLeash,那么就会有类似removeAnimationLeash\removeLeash\removeAnimation相关方法,我们逐个排查 在这里插入图片描述找到removeLeash方法,同样在frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java中 在这里插入图片描述

我们可以在removeLeash方法中添加堆栈来查看其调用流程 Slog.i("WindowManager:","removeLeash leash = " + leash , new Exception()); 同样也可以使用走读代码的方式追踪

堆栈

动画添加

简易图: 在这里插入图片描述 先来看看Demo中点击Button显示窗口和点击CLOSE_WINDOW退出窗口的动画的显示流程

1.点击Button添加窗口的动画流程

WindowManager: createAnimationLeash type = window_animation
WindowManager: java.lang.Exception
WindowManager: 	at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:458)
WindowManager: 	at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:184)
WindowManager: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2757)
WindowManager: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2764)
WindowManager: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2770)
WindowManager: 	at com.android.server.wm.WindowState.startAnimation(WindowState.java:5305)
WindowManager: 	at com.android.server.wm.WindowState.startAnimation(WindowState.java:5281)
WindowManager: 	at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:655)
WindowManager: 	at com.android.server.wm.WindowStateAnimator.applyEnterAnimationLocked(WindowStateAnimator.java:583)
WindowManager: 	at com.android.server.wm.WindowState.performShowLocked(WindowState.java:4648)
WindowManager: 	at com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked(WindowStateAnimator.java:276)
WindowManager: 	at com.android.server.wm.DisplayContent.lambda$new$8$com-android-server-wm-DisplayContent(DisplayContent.java:987)
WindowManager: 	at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda14.accept(Unknown Source:4)
WindowManager: 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2629)
WindowManager: 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2619)
WindowManager: 	at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4904)
WindowManager: 	at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4748)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1616)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1616)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1616)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1616)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1616)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1616)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1616)
WindowManager: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1633)
WindowManager: 	at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:4666)
WindowManager: 	at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:1021)
WindowManager: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:824)
WindowManager: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:784)
WindowManager: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: 	at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: 	at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: 	at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: 	at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: 	at android.os.Looper.loop(Looper.java:288)
WindowManager: 	at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: 	at com.android.server.ServiceThread.run(ServiceThread.java:44)

2.点击CLOSE_WINDOW移除窗口的动画流程

WindowManager: createAnimationLeash type = window_animation
WindowManager: java.lang.Exception
WindowManager: 	at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:458)
WindowManager: 	at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:184)
WindowManager: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2757)
WindowManager: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2764)
WindowManager: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2770)
WindowManager: 	at com.android.server.wm.WindowState.startAnimation(WindowState.java:5305)
WindowManager: 	at com.android.server.wm.WindowState.startAnimation(WindowState.java:5281)
WindowManager: 	at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:655)
WindowManager: 	at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2600)
WindowManager: 	at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2498)
WindowManager: 	at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2033)
WindowManager: 	at com.android.server.wm.Session.remove(Session.java:223)
WindowManager: 	at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:684)
WindowManager: 	at com.android.server.wm.Session.onTransact(Session.java:175)
WindowManager: 	at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: 	at android.os.Binder.execTransact(Binder.java:1244)

3.添加窗口和移除窗口的动画显示流程差异 从上述堆栈中我们可以发现,无论是窗口的添加还是移除,其动画都会调用WindowStateAnimator.applyAnimationLockedSurfaceAnimator.createAnimationLeash创建动画 添加窗口走WindowState.performShowLocked流程调用到WindowStateAnimator.applyAnimationLocked 移除窗口走WindowState.removeIfPossible流程调用到WindowStateAnimator.applyAnimationLocked

特别的,添加窗口时,如果没有动画需要创建则会直接给一个空的动画资源加载;但是在移除窗口时,如果没有动画需要创建则不会走到WindowStateAnimator.applyAnimationLocked,而是直接走到WindowState.removeImmediately移除窗口

动画移除

简易图: 在这里插入图片描述 动画播放完成,去掉leash图层

WindowManager: removeLeash leash = Surface(name=2257b8c test-window)/@0x825faea
WindowManager: java.lang.Exception
WindowManager: 	at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:417)
WindowManager: 	at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:410)
WindowManager: 	at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0$com-android-server-wm-SurfaceAnimator(SurfaceAnimator.java:131)
WindowManager: 	at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: 	at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1$com-android-server-wm-SurfaceAnimator(SurfaceAnimator.java:141)
WindowManager: 	at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: 	at com.android.server.wm.LocalAnimationAdapter.lambda$startAnimation$0$com-android-server-wm-LocalAnimationAdapter(LocalAnimationAdapter.java:67)
WindowManager: 	at com.android.server.wm.LocalAnimationAdapter$$ExternalSyntheticLambda0.run(Unknown Source:6)
WindowManager: 	at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: 	at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: 	at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: 	at android.os.Looper.loop(Looper.java:288)
WindowManager: 	at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: 	at com.android.server.ServiceThread.run(ServiceThread.java:44)

动画添加流程

# Android T 窗口动画(本地动画)显示流程其二——添加流程

动画移除流程

# Android T 窗口动画(本地动画)显示流程其三——移除流程