Android U WindowManagerService 屏幕旋转动画(2)

1,878 阅读9分钟

activity relaunch 会让 Activity 生命周期重新走到 RESUMED,并触发 app 再次绘制。当 WindowManagerService 收到 app 绘制完成时,检测到可以开始执行动画,于是收集 Transition 数据,如下

{
    id=13 
    t=CHANGE 
    f=0x0 
    // track id
    trk=0 
    r=[0@Point(0, 0)] 
    
    // TransitionInfo#mChanges
    c=[
        {
            WCT{RemoteToken{4220415 Task{d77d5e9 #26 type=standard A=10206:com.awesome.helloworld}}} 
            m=CHANGE 
            f=NONE 
            p=WCT{RemoteToken{fec6a3d DefaultTaskDisplayArea@10996965}} 
            leash=Surface(name=Task=26)/@0xe4347ff 
            sb=Rect(0, 0 - 1280, 1840) 
            eb=Rect(0, 0 - 1840, 1280) 
            d=0 
            r=0->1:0
        },

        {
            WCT{RemoteToken{fec6a3d DefaultTaskDisplayArea@10996965}} 
            m=CHANGE 
            f=NONE 
            p=WCT{RemoteToken{3f0e1d2 Display{#0 state=ON size=1840x1280 ROTATION_90}}} 
            leash=Surface(name=DefaultTaskDisplayArea)/@0x46effc9 
            sb=Rect(0, 0 - 1280, 1840) 
            eb=Rect(0, 0 - 1840, 1280) 
            d=0 
            r=0->1:-1
        },

        {
            WCT{RemoteToken{3f0e1d2 Display{#0 state=ON size=1840x1280 ROTATION_90}}} 
            m=CHANGE 
            f=IS_DISPLAY 
            leash=Surface(name=WindowedMagnification:0:31)/@0x5399049 
            sb=Rect(0, 0 - 1280, 1840) 
            eb=Rect(0, 0 - 1840, 1280) 
            d=0 
            // 0->1 代表90°旋转
            r=0->1:-1 
            // 截图层 surface
            snapshot=Surface(name=RotationLayer)/@0x48338b1
        }
    ]
}

Wm-Shell 执行动画

有了 Transition 数据后,就发送给 Wm-Shell 来执行动画

// Transitions.java

// 参数 t 是 start transaction
void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
        @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
            transitionToken, info);
    
    // 获取 Transition 数据
    final int activeIdx = findByToken(mPendingTransitions, transitionToken);
    final ActiveTransition active = mPendingTransitions.remove(activeIdx);
    active.mInfo = info;
    active.mStartT = t;
    active.mFinishT = finishT;
    
    if (!mReadyDuringSync.isEmpty()) {
        // ...
    } else {
        // 分发 transition
        dispatchReady(active);
    }
}


boolean dispatchReady(ActiveTransition active) {
    final TransitionInfo info = active.mInfo;

    // ...

    // 获取/创建 Track
    final Track track = getOrCreateTrack(info.getTrack());
    // active 保存到 Track 的 ready queue
    track.mReadyTransitions.add(active);
    
    // ...
    
    // 1. 动画状态初始化
    setupStartState(active.mInfo, active.mStartT, active.mFinishT);
    
    // ...

    // 2. 执行 track ready queue 中的动画
    processReadyQueue(track);
    return true;
}

1.动画状态初始化

// Transitions.java

    /**
     * Sets up visibility/alpha/transforms to resemble the starting state of an animation.
     */
    private static void setupStartState(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
        // ...
        
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            
            final TransitionInfo.Change change = info.getChanges().get(i);
            // ...
            final SurfaceControl leash = change.getLeash();
            final int mode = info.getChanges().get(i).getMode();

            // ...

            // 只有 DisplayContent 能独立做动画,因为它没有 parent surface
            // Don't move anything that isn't independent within its parents
            if (!TransitionInfo.isIndependent(change, info)) {
                if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
                    // 对 leash 执行操作
                    // t 是 start transaction
                    t.show(leash);
                    t.setMatrix(leash, 1, 0, 0, 1);
                    t.setAlpha(leash, 1.f);
                    t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
                }
                continue;
            }

            // ...
        }
    }

目前,只有 DisplayContent 能独立做动画,这里也只是做了一些基本的操作,没啥用。

2.执行 track ready queue 中的动画

// Transitions.java

    void processReadyQueue(Track track) {
        // ...

        final ActiveTransition ready = track.mReadyTransitions.get(0);
        if (track.mActiveTransition == null) {
            track.mReadyTransitions.remove(0);
            track.mActiveTransition = ready;

            // ...

            // 执行 transition
            playTransition(ready);
            
            // ...
            return;
        }

        // ...
    }


    private void playTransition(@NonNull ActiveTransition active) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Playing animation for %s", active);
        
        // ...

        // 1.初始化动画层级
        setupAnimHierarchy(active.mInfo, active.mStartT, active.mFinishT);

        // ...

        // 2. 分发 Transition
        active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
                active.mFinishT, (wct, cb) -> onFinish(active, wct, cb), active.mHandler);
    }

1.初始化动画层级

// Transitions.java

    /**
     * Reparents all participants into a shared parent and orders them based on: the global transit
     * type, their transit mode, and their destination z-order.
     */
    // 参数 t 是 start transaction
    // finishT 是 finish transaction
    private static void setupAnimHierarchy(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
        
        // TRANSIT_CHANGE
        final int type = info.getType();
        // false
        final boolean isOpening = isOpeningType(type);
        // false
        final boolean isClosing = isClosingType(type);

        // 1. start transaction 中 show Transition Root leash
        for (int i = 0; i < info.getRootCount(); ++i) {
            t.show(info.getRoot(i).getLeash());
        }
        
        final int numChanges = info.getChanges().size();

        // Put animating stuff above this line and put static stuff below it.
        final int zSplitLine = numChanges + 1;

        // changes should be ordered top-to-bottom in z
        for (int i = numChanges - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            final SurfaceControl leash = change.getLeash();
            final int mode = change.getMode();

            // 不能独立于 parent 做动画的,不执行layer初始化
            // 目前只有 DisplayContent 能单独做动画,因为它没有 parent surface
            if (!TransitionInfo.isIndependent(change, info)) {
                continue;
            }

            boolean hasParent = change.getParent() != null;
            final int rootIdx = TransitionUtil.rootIndexFor(change, info);
            // 2. start transaction 中,DisplayContent leash reparent 到 Transition Root lesh
            // 并更新 position
            if (!hasParent) {
                t.reparent(leash, info.getRoot(rootIdx).getLeash());
                t.setPosition(leash,
                        change.getStartAbsBounds().left - info.getRoot(rootIdx).getOffset().x,
                        change.getStartAbsBounds().top - info.getRoot(rootIdx).getOffset().y);
            }

            final int layer;
            // Put all the OPEN/SHOW on top
            if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
                // ...
            } else if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
                // ...
            } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
                // ...
            } else { // CHANGE or other
                if (isClosing || TransitionUtil.isOrderOnly(change)) {
                    // ...
                } else {
                    // Put above CLOSE mode.
                    layer = zSplitLine + numChanges - i;
                }
            }
            // 3. start transction 中设置 DisplayContent leash 的 layer
            t.setLayer(leash, layer);
        }
    }

对于屏幕旋转动画来说,由于 DisplayContent 是 root surface,因此 DisplayContent leash 直接 reparent 到 Transition Root leash,并更新 position 和 layer。

而 TaskDisplayArea 和 Task,是不能独立于 parent 做动画的,而 DisplayContent 就是他们的根 parent。因此,只要操作 DisplayContent leash,即可完成屏幕旋转动画。

2.分发Transition

分发 Transition 就是找一个合适的 TransitionHandler 来执行动画,旋转动画由 DefaultTransitionHandler 执行

// DefaultTransitionHandler.java

    public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                "start default transition animation, info = %s", info);
        
        // ...

        // 不同的目标,可能执行不同的动画
        // animations 用来保存所有需要执行的动画
        final ArrayList<Animator> animations = new ArrayList<>();
        mAnimations.put(transition, animations);

        // 任意一个动画执行完成的回调
        final Runnable onAnimFinish = () -> {
            
            // 所有动画都执行完毕,才能执行 Transition finished
            if (!animations.isEmpty()) return;

            mAnimations.remove(transition);
            
            // 4. transition finished
            // 回调到 Transition#onFinish(),注意,参数都是为 null
            finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
        };

        // ...

        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            
            // ...

            final boolean isTask = change.getTaskInfo() != null;
            final int mode = change.getMode();
            boolean isSeamlessDisplayChange = false;

            // 处理 DisplayContent 旋转
            if (mode == TRANSIT_CHANGE && change.hasFlags(FLAG_IS_DISPLAY)) {
                if (info.getType() == TRANSIT_CHANGE) {
                    // 最终解析为 ROTATION_ANIMATION_ROTATE
                    final int anim = getRotationAnimationHint(change, info, mDisplayController);
                    // false
                    isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS;
                    if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
                        // 为 DisplayContent 创建旋转动画,并收集到 animations
                        startRotationAnimation(startTransaction, change, info, anim, animations,
                                onAnimFinish);
                        
                        isDisplayRotationAnimationStarted = true;
                        continue;
                    }
                } else {
                    // ...
                }
            }

            // ...

            // 不能独立于 parent 做动画的,就不单独为他们创建动画
            // Don't animate anything that isn't independent.
            if (!TransitionInfo.isIndependent(change, info)) continue;

            // ...
        }

        // ...

        // 2. apply start transaction
        startTransaction.apply();

        // 3. 在动画线程中执行所有收集来的动画
        mAnimExecutor.execute(() -> {
            for (int i = 0; i < animations.size(); ++i) {
                animations.get(i).start();
            }
        });

        // ...

        // run finish now in-case there are no animations
        // 立即执行一次动画完成的回调,防止当前没有动画
        onAnimFinish.run();
        return true;
    }
创建屏幕旋转动画
// DefaultTransitionHandler.java

    private void startRotationAnimation(SurfaceControl.Transaction startTransaction,
            TransitionInfo.Change change, TransitionInfo info, int animHint,
            ArrayList<Animator> animations, Runnable onAnimFinish) {
        final int rootIdx = TransitionUtil.rootIndexFor(change, info);

        // 1.创建 ScreenRotationAnimation
        final ScreenRotationAnimation anim = new ScreenRotationAnimation(mContext, mSurfaceSession,
                mTransactionPool, startTransaction, change, info.getRoot(rootIdx).getLeash(),
                animHint);
        
        // The rotation animation may consist of 3 animations: fade-out screenshot, fade-in real
        // content, and background color. The item of "animGroup" will be removed if the sub
        // animation is finished. Then if the list becomes empty, the rotation animation is done.
        final ArrayList<Animator> animGroup = new ArrayList<>(3);
        final ArrayList<Animator> animGroupStore = new ArrayList<>(3);

        final Runnable finishCallback = () -> {
            if (!animGroup.isEmpty()) return;
            anim.kill();
            animations.removeAll(animGroupStore);
            // 所有动画执行完毕,执行 transition finished
            onAnimFinish.run();
        };

        // 2.ScreenRotationAnimation 构建动画
        anim.buildAnimation(animGroup, finishCallback, mTransitionAnimationScaleSetting,
                mMainExecutor);

        // animGroup、animGroupStore、animations 保存的动画都是一样的
        for (int i = animGroup.size() - 1; i >= 0; i--) {
            final Animator animator = animGroup.get(i);
            animGroupStore.add(animator);
            animations.add(animator);
        }
    }
创建 ScreenRotationAnimation
// ScreenRotationAnimation.java

    // t 是 start transaction
    // animHint 动画类型是 ROTATION_ANIMATION_ROTATE
    ScreenRotationAnimation(Context context, SurfaceSession session, TransactionPool pool,
            Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash, int animHint) {
        mContext = context;
        mTransactionPool = pool;
        mAnimHint = animHint;

        // change 属于 DisplayContent
        mSurfaceControl = change.getLeash();
        mStartWidth = change.getStartAbsBounds().width();
        mStartHeight = change.getStartAbsBounds().height();
        mEndWidth = change.getEndAbsBounds().width();
        mEndHeight = change.getEndAbsBounds().height();
        mStartRotation = change.getStartRotation();
        mEndRotation = change.getEndRotation();

        // 1. 创建并显示 screenshot leash
        mAnimLeash = new SurfaceControl.Builder(session)
                // 挂载到 transition root leash 下
                .setParent(rootLeash)
                .setEffectLayer()
                .setCallsite("ShellRotationAnimation")
                .setName("Animation leash of screenshot rotation")
                .build();

        try {
            if (change.getSnapshot() != null) {
                mScreenshotLayer = change.getSnapshot();
                // 把 screenshot surface 挂载到 screenshot leash 下
                t.reparent(mScreenshotLayer, mAnimLeash);
                mStartLuma = change.getSnapshotLuma();
            } else {
                // ...
            }
            // SCREEN_FREEZE_LAYER_BASE 为 10000 * 200 + 10000
            t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
            t.show(mAnimLeash);
            // Crop the real content in case it contains a larger child layer, e.g. wallpaper.
            t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));

            // 动画方式为 ROTATION_ANIMATION_CROSSFADE 和 ROTATION_ANIMATION_JUMPCUT 才是自定义动画
            if (!isCustomRotate()) {
                // 2. 创建并显示 back color surface
                mBackColorSurface = new SurfaceControl.Builder(session)
                        // 挂在 Transition Root leash 下
                        .setParent(rootLeash)
                        .setColorLayer()
                        .setOpaque(true)
                        .setCallsite("ShellRotationAnimation")
                        .setName("BackColorSurface")
                        .build();
                // layer 为 -1
                t.setLayer(mBackColorSurface, -1);
                t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
                // start transaction show
                t.show(mBackColorSurface);
            }

        } catch (Surface.OutOfResourcesException e) {
            Slog.w(TAG, "Unable to allocate freeze surface", e);
        }

        // 3. screenshot surface 是竖屏大小,现在要显示在横屏坐标系下,需要对其设置 matrix
        setScreenshotTransform(t);

        // 4. apply start transaction
        t.apply();
    }

最后的 apply start transaction 操作,它会如下效果

  1. 坐标系切换到横屏。
  2. 最上层显示的是 screenshot surface。 虽然它是竖屏大小,但是由于设置了 matrix,因此它能完整显示在横屏坐标系下,看起来它像一个横屏大小的 surface。
  3. 最底层显示的 back color surface。
ScreenRotationAnimation 构建动画
// ScreenRotationAnimation.java

    boolean buildAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, float animationScale,
            @NonNull ShellExecutor mainExecutor) {
        if (mScreenshotLayer == null) {
            return false;
        }

        // 自定义旋转动画只有两种 ROTATION_ANIMATION_CROSSFADE 和 ROTATION_ANIMATION_JUMPCUT
        final boolean customRotate = isCustomRotate();
        if (customRotate) {
            // ...
        } else {
            // Figure out how the screen has moved from the original rotation.
            int delta = deltaRotation(mEndRotation, mStartRotation);
            switch (delta) { /* Counter-Clockwise Rotations */
                // ...

                case Surface.ROTATION_270:
                    // 获取动画资源
                    mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                            R.anim.screen_rotate_minus_90_exit);
                    mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                            R.anim.screen_rotate_minus_90_enter);
                    break;
            }
        }

        // 初始化退场动画,这是为 screenshot leash 准备的
        mRotateExitAnimation.initialize(mEndWidth, mEndHeight, mStartWidth, mStartHeight);
        mRotateExitAnimation.restrictDuration(MAX_ANIMATION_DURATION);
        mRotateExitAnimation.scaleCurrentDuration(animationScale);
        
        // 初始化入场动画,这是为 DisplayContent leash 准备的
        mRotateEnterAnimation.initialize(mEndWidth, mEndHeight, mStartWidth, mStartHeight);
        mRotateEnterAnimation.restrictDuration(MAX_ANIMATION_DURATION);
        mRotateEnterAnimation.scaleCurrentDuration(animationScale);

        if (customRotate) {
            // ...
        } else {
            // 1. 为 DisplayContent surface 创建动画
            startDisplayRotation(animations, finishCallback, mainExecutor);
            // 2. 为 screenshot surface 创建动画
            startScreenshotRotationAnimation(animations, finishCallback, mainExecutor);
        }

        return true;
    }


    private void startDisplayRotation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
        buildSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback,
                mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
                null /* clipRect */);
    }

    private void startScreenshotRotationAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
        buildSurfaceAnimation(animations, mRotateExitAnimation, mAnimLeash, finishCallback,
                mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
                null /* clipRect */);
    }


    static void buildSurfaceAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Animation anim, @NonNull SurfaceControl leash,
            @NonNull Runnable finishCallback, @NonNull TransactionPool pool,
            @NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
            @Nullable Rect clipRect) {

        final SurfaceControl.Transaction transaction = pool.acquire();

        // 构建动画
        final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
        final Transformation transformation = new Transformation();
        final float[] matrix = new float[9];
        // Animation length is already expected to be scaled.
        va.overrideDurationScale(1.0f);
        va.setDuration(anim.computeDurationHint());

        // 监听动画的每一帧
        final ValueAnimator.AnimatorUpdateListener updateListener = animation -> {
            final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
            // 对 surface 进行操作
            applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
                    position, cornerRadius, clipRect);
        };
        va.addUpdateListener(updateListener);

        // 动画完成时的回调
        final Runnable finisher = () -> {
            applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
                    position, cornerRadius, clipRect);

            pool.release(transaction);
            mainExecutor.execute(() -> {
                animations.remove(va);
                // 执行回调
                // 由 DefaultTransitionHanlder 的 finishCallback 实现
                finishCallback.run();
            });
        };

        va.addListener(new AnimatorListenerAdapter() {
            private boolean mFinished = false;

            @Override
            public void onAnimationEnd(Animator animation) {
                onFinish();
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                onFinish();
            }

            private void onFinish() {
                if (mFinished) return;
                mFinished = true;
                // 动画完成,执行回调
                finisher.run();
                va.removeUpdateListener(updateListener);
            }
        });

        // 保存动画
        animations.add(va);
    }

所谓的动画,其实指的就是 ValueAnimator,通过它的每一帧更新时机,来操作 surface(DisplayContent leash 或者 screenshot leash)

// DefaultTransitionHandler.java

    private static void applyTransformation(long time, SurfaceControl.Transaction t,
            SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix,
            Point position, float cornerRadius, @Nullable Rect immutableClipRect) {
        
        // 从动画中获取获取这一帧的 Transformation
        tmpTransformation.clear();
        anim.getTransformation(time, tmpTransformation);

        // ...

        // 对 surface 进行操作
        t.setMatrix(leash, tmpTransformation.getMatrix(), matrix);
        t.setAlpha(leash, tmpTransformation.getAlpha());

        // ...

        // transactihon 中设置 Vsync id
        t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());

        // apply transaction
        t.apply();
    }
Transition finished

当所有动画都结束时,最终回调 Transitions#onFinish()

// Transitions.java

    // 参数都是 null
    private void onFinish(ActiveTransition active,
            @Nullable WindowContainerTransaction wct,
            @Nullable WindowContainerTransactionCallback wctCB) {

        final Track track = mTracks.get(active.getTrack());
        track.mActiveTransition = null;

        // ...

        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition animation finished "
                + "(aborted=%b), notifying core %s", active.mAborted, active);
        
        // 1. 清理 start transaction
        if (active.mStartT != null) {
            // Applied by now, so clear immediately to remove any references. Do not set to null
            // yet, though, since nullness is used later to disambiguate malformed transitions.
            active.mStartT.clear();
        }
        
        // 2. apply finish transaction
        SurfaceControl.Transaction fullFinish = active.mFinishT;
        // ...
        if (fullFinish != null) {
            fullFinish.apply();
        }

        releaseSurfaces(active.mInfo);

        // 3. 通知 WM-Core finish transition
        // 参数 wct 和 wctCB 都是 null
        mOrganizer.finishTransition(active.mToken, wct, wctCB);

        // ...
    }

Wm-Core finish transition

Wm-Core 收到 finish transition,最终会执行 Transition#finishTransition()

// Transition.java

    void finishTransition() {
        if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER) && mIsPlayerEnabled) {
            asyncTraceEnd(System.identityHashCode(this));
        }

        // 记录 finish transition 的日志
        mLogger.mFinishTimeNs = SystemClock.elapsedRealtimeNanos();
        mController.mLoggerHandler.post(mLogger::logOnFinish);
        mController.mTransitionTracer.logFinishedTransition(this);


        // 1.清理 ST,FT, CT
        if (mStartTransaction != null) mStartTransaction.close();
        if (mFinishTransaction != null) mFinishTransaction.close();
        mStartTransaction = mFinishTransaction = null;
        if (mCleanupTransaction != null) {
            mCleanupTransaction.apply();
            mCleanupTransaction = null;
        }


        // 标记正在 finishing 的 transition
        mController.mFinishingTransition = this;

        if (mTransientHideTasks != null && !mTransientHideTasks.isEmpty()) {
            // ...
        }

        boolean hasParticipatedDisplay = false;
        boolean hasVisibleTransientLaunch = false;
        boolean enterAutoPip = false;
        boolean committedSomeInvisible = false;
        // Commit all going-invisible containers
        for (int i = 0; i < mParticipants.size(); ++i) {
            final WindowContainer<?> participant = mParticipants.valueAt(i);

            // ...

            // 旋转动画有 DisplayContent 参与
            if (participant.asDisplayContent() != null) {
                hasParticipatedDisplay = true;
                continue;
            }

            // ...

        // ...

        for (int i = 0; i < mTargetDisplays.size(); ++i) {
            final DisplayContent dc = mTargetDisplays.get(i);
            final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
            // 2.通知 AsyncRotationController 动画完成了
            if (asyncRotationController != null && containsChangeFor(dc, mTargets)) {
                asyncRotationController.onTransitionFinished();
            }

            // ...
        }
       
        // ...

        // 3.Transition 状态切换到 STATE_FINISHED
        mState = STATE_FINISHED;

        // 4. 执行推迟的旋转动画
        if (hasParticipatedDisplay && !mController.useShellTransitionsRotation()) {
            mController.mAtm.mWindowManager.updateRotation(false /* alwaysSendConfiguration */,
                    false /* forceRelayout */);
        }
        
        // ...

        // finishing transition 已经处理完成
        mController.mFinishingTransition = null;
    }

finish transition 的流程,对于案例分析的屏幕旋转动画来说,没什么太大价值,我这里展示一些关键点,只是为了做点记录。