WMS 动画初探

1,555 阅读8分钟

Android 动画原理

Android 动画过程中:在某一个时间点,调用 getTransformation()

根据 mStartTime 和 mDuration , 计算出当前的进度。

再根据 mInterpolator 计算出转换的进度,然后计算出属性的当前值,保存在 matrix 中。

再调用 Matrix.getValues 将属性值取出,运用在动画目标上。

Animation 和 Transfrom

Animtaion

在给定了初始状态

SurfaceAnimator.java

41  /**
42   * A class that can run animations on objects that have a set of child surfaces. We do this by
43   * reparenting all child surfaces of an object onto a new surface, called the "Leash". The Leash
44   * gets attached in the surface hierarchy where the the children were attached to. We then hand off
45   * the Leash to the component handling the animation, which is specified by the
46   * {@link AnimationAdapter}. When the animation is done animating, our callback to finish the
47   * animation will be invoked, at which we reparent the children back to the original parent.
48   */
49  class SurfaceAnimator {

该类可以针对那种存在多个child surface 的对象进行动画,在执行动画的过程中会创建一个没有 Buffer 的 Surface -- "Leash" , 将所有 child surface 绑定到 leash 上,leash 同时也会绑定到原先这些 child surface 绑定的位置。

然后我们将 leash 给到 AnimationAdaoter 去执行动画,执行动画结束后会将所有 child surface 重新绑定到原先的父节点上。

startAnimation@SurfaceAnimator.java

122      /**
123       * Starts an animation.
124       *
125       * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
126       *             component responsible for running the animation. It runs the animation with
127       *             {@link AnimationAdapter#startAnimation} once the hierarchy with
128       *             the Leash has been set up.
129       * @param hidden Whether the container holding the child surfaces is currently visible or not.
130       *               This is important as it will start with the leash hidden or visible before
131       *               handing it to the component that is responsible to run the animation.
132       * @param animationFinishedCallback The callback being triggered when the animation finishes.
133       */
134      void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
135              @AnimationType int type,
136              @Nullable OnAnimationFinishedCallback animationFinishedCallback,
137              @Nullable SurfaceFreezer freezer) {
138          cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
139          mAnimation = anim;
140          mAnimationType = type;
141          mAnimationFinishedCallback = animationFinishedCallback;
    // step1. 先获取当前需要执行动画的对象的 surface 
142          final SurfaceControl surface = mAnimatable.getSurfaceControl();
143          if (surface == null) {
144              Slog.w(TAG, "Unable to start animation, surface is null or no children.");
145              cancelAnimation();
146              return;
147          }
    // step2.根据 freezer 来构建一个 Leash 
148          mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
149          if (mLeash == null) {
150              mLeash = createAnimationLeash(mAnimatable, surface, t, type,
151                      mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
152                      0 /* y */, hidden, mService.mTransactionFactory);
153              mAnimatable.onAnimationLeashCreated(t, mLeash);
154          }
155          mAnimatable.onLeashAnimationStarting(t, mLeash);
156          if (mAnimationStartDelayed) {
157              if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
158              return;
159          }
160          if (mAnimation != null) {
     // step3.将 Leash 传给 AnimationAdapter , 启动动画
161              mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
162          }
163      }
164  

这里的 startAnimation 的第一个参数是 Transaction ,所以一定是在 打开一次 transaction 的情况下开始启动动画的。

step1. 这个 getSurfaceControl 是 Animatable 这个 Interface 中的一个接口,所有能够执行动画的对象都需要实现这个 interface 。

599          /**
600           * @return The surface of the object to be animated.
601           *         This SurfaceControl must be valid if non-null.
602           */
603          @Nullable SurfaceControl getSurfaceControl();

step2. 创建 Leash (leash 就是狗绳的意思,就是有用这个leash 拴住这些 child surface 来跑动画,在SF中这些 layer 的层次结构不会出现异常)

386      static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
387              Transaction t, @AnimationType int type, int width, int height, int x, int y,
388              boolean hidden, Supplier<Transaction> transactionFactory) {
389          if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
             // step2.1 通过 makeAnimationLeash 构造这个 Surface 
390          final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
391                  .setParent(animatable.getAnimationLeashParent())
392                  .setName(surface + " - animation-leash of " + animationTypeToString(type))
393                  // TODO(b/151665759) Defer reparent calls
394                  // We want the leash to be visible immediately because the transaction which shows
395                  // the leash may be deferred but the reparent will not. This will cause the leashed
396                  // surface to be invisible until the deferred transaction is applied. If this
397                  // doesn't work, you will can see the 2/3 button nav bar flicker during seamless
398                  // rotation.
399                  .setHidden(hidden)
400                  .setEffectLayer()
401                  .setCallsite("SurfaceAnimator.createAnimationLeash");
402          final SurfaceControl leash = builder.build();
             // step2.2 设置 transaction 相关参数,show 和 reparent 
             // show : 这次 transaction 中显示 leash
             // reparent: 将leash reparent 到当前 Surface 的父节点上
403          t.setWindowCrop(leash, width, height);
404          t.setPosition(leash, x, y);
405          t.show(leash);
406          t.setAlpha(leash, hidden ? 0 : 1);
407  
408          t.reparent(surface, leash);
409          return leash;
410      }

step2.1 创建 leash

在 WindowContaoner.java 中,递归调用到根节点到 DisplayContent 中

2543      @Override
2544      public Builder makeAnimationLeash() {
2545          return makeSurface().setContainerLayer();
2546      }

2195      SurfaceControl.Builder makeSurface() {
2196          final WindowContainer p = getParent();
2197          return p.makeChildSurface(this);
2198      }

2200      /**
2201       * @param child The WindowContainer this child surface is for, or null if the Surface
2202       *              is not assosciated with a WindowContainer (e.g. a surface used for Dimming).
2203       */
2204      SurfaceControl.Builder makeChildSurface(WindowContainer child) {
2205          final WindowContainer p = getParent();
2206          // Give the parent a chance to set properties. In hierarchy v1 we rely
2207          // on this to set full-screen dimensions on all our Surface-less Layers.
2208          return p.makeChildSurface(child)
2209                  .setParent(mSurfaceControl);
2210      }

在DisplayContent 中

4828      @Override
4829      SurfaceControl.Builder makeChildSurface(WindowContainer child) {
4830          SurfaceSession s = child != null ? child.getSession() : getSession();
          // 通过 wms 来创建实际的 SurfaceControl , 然后层层返回,最终这个 Surface 绑定到最早调用启动动画的对象上
4831          final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(s).setContainerLayer();
4832          if (child == null) {
4833              return b;
4834          }
4835  
4836          return b.setName(child.getName())
4837                  .setParent(mSurfaceControl);
4838      }
4839  

Step2. 使用 AnimationAdapter 启动动画

// frameworks/base/services/core/java/com/android/server/wm/AnimationAdapter.java
43      /**
44       * Requests to start the animation.
45       *
46       * @param animationLeash The surface to run the animation on. See {@link SurfaceAnimator} for an
47       *                       overview of the mechanism. This surface needs to be released by the
48       *                       component running the animation after {@code finishCallback} has been
49       *                       invoked, or after the animation was cancelled.
50       * @param t The Transaction to apply the initial frame of the animation.
51       * @param type The type of the animation.
52       * @param finishCallback The callback to be invoked when the animation has finished.
53       */
54      void startAnimation(SurfaceControl animationLeash, Transaction t, @AnimationType int type,
55              OnAnimationFinishedCallback finishCallback);

LocalAnimationAdapter 就是对 AnimationAdapter 的实现:

// frameworks/base/services/core/java/com/android/server/wm/LocalAnimationAdapter.java 
32  /**
33   * Animation that can be executed without holding the window manager lock. See
34   * {@link SurfaceAnimationRunner}.
35   */
36  class LocalAnimationAdapter implements AnimationAdapter {
    ...
        
52      @Override
53      public void startAnimation(SurfaceControl animationLeash, Transaction t,
54              @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
55          mAnimator.startAnimation(mSpec, animationLeash, t,
56                  () -> finishCallback.onAnimationFinished(type, this));
57      }

这里用于执行动画的 mAnimator 的类型是 SurfaceAnimationRunner ,在构造 AnimationAdapter 的时候会传入 SurfaceAnimationRuner,这个类会去执行动画。

  
42      LocalAnimationAdapter(AnimationSpec spec, SurfaceAnimationRunner animator) {
43          mSpec = spec;
44          mAnimator = animator;
45      }

每一个 WC 对应一个 SA , 当一个 WC 需要执行一个特定动画的时候,只需要传入一个 AD 来指定特定的动画即可,而动画执行的线程都是在 AD 的构造中创建。

SurfaceAnimationRunner

//frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java 
134      void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
135              Runnable finishCallback) {
136          synchronized (mLock) {
    // step1. 使用spec,leash,动画结束后的回调构造一个RunningAnimation,这个类相当于一个动画的记录
137              final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
138                      finishCallback);
139              mPendingAnimations.put(animationLeash, runningAnim);
    // step2. 往编舞者上抛一个回调
140              if (!mAnimationStartDeferred) {
141                  mChoreographer.postFrameCallback(this::startAnimations);
142              }
143  
144              // Some animations (e.g. move animations) require the initial transform to be applied
145              // immediately.
146              applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
147          }
148      }

从这个来看这个 Runner 是可以复用的,构造一个然后将多个 RunningAnimation 放在上面运行,因为 Runner 中维护了一个列表可以存储多个 Animation.

往编舞者上面抛的回调是 startAnimations

170      @GuardedBy("mLock")
171      private void startPendingAnimationsLocked() {
172          for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
173              startAnimationLocked(mPendingAnimations.valueAt(i));
174          }
175          mPendingAnimations.clear();
176      }
177  

从上面可以看出,将pending的动画全部拿出来执行,然后清空掉 pending 的列表

178      @GuardedBy("mLock")
179      private void startAnimationLocked(RunningAnimation a) {
             // step1. 创建一个 valueanimator
180          final ValueAnimator anim = mAnimatorFactory.makeAnimator();
181          // step2. 根据AnimationSpec 设置这个 VA 的属性以及注册回调函数
182          // Animation length is already expected to be scaled.
183          anim.overrideDurationScale(1.0f);
184          anim.setDuration(a.mAnimSpec.getDuration());
185          anim.addUpdateListener(animation -> {  // 这个是动画更新的回调
186              synchronized (mCancelLock) {
187                  if (!a.mCancelled) {
188                      final long duration = anim.getDuration();
189                      long currentPlayTime = anim.getCurrentPlayTime();
190                      if (currentPlayTime > duration) {
191                          currentPlayTime = duration;
192                      }
193                      applyTransformation(a, mFrameTransaction, currentPlayTime);
194                  }
195              }
196  
197              // Transaction will be applied in the commit phase.
198              scheduleApplyTransaction(); // 在下一次Vsync 信号到来的时候使前面的修改生效
199          });
200  
201          anim.addListener(new AnimatorListenerAdapter() {
202              @Override
203              public void onAnimationStart(Animator animation) {
204                  synchronized (mCancelLock) {
205                      if (!a.mCancelled) {
206                          // TODO: change this back to use show instead of alpha when b/138459974 is
207                          // fixed.
208                          mFrameTransaction.setAlpha(a.mLeash, 1); // 动画开始的时候显示Leash这个Surface
209                      }
210                  }
211              }
212  
213              @Override
214              public void onAnimationEnd(Animator animation) {
215                  synchronized (mLock) {
216                      mRunningAnimations.remove(a.mLeash);
217                      synchronized (mCancelLock) {
218                          if (!a.mCancelled) {
219  
220                              // Post on other thread that we can push final state without jank.
221                              mAnimationThreadHandler.post(a.mFinishCallback);
222                          }
223                      }
224                  }
225              }
226          });
227          a.mAnim = anim;
             // step3. 加入到正在运行的动画 map 中
228          mRunningAnimations.put(a.mLeash, a);
229          // step4. 调用VA的start,动画的执行是依赖于VA本身的执行框架(ValueAnimation)
230          anim.start();
231          if (a.mAnimSpec.canSkipFirstFrame()) {
232              // If we can skip the first frame, we start one frame later.
233              anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
234          }
235  
236          // Immediately start the animation by manually applying an animation frame. Otherwise, the
237          // start time would only be set in the next frame, leading to a delay.
238          anim.doAnimationFrame(mChoreographer.getFrameTime());
239      }

step1. 这里创建的是一个 ValueAnimator 来 执行动画

step2. 设置 ValueAnimator 的回调函数

step3. 将该动画加到一个正在运行的 animation map 中

step4. 调用 start 开始动画