• Android T 远程动画显示流程其三——桌面侧动画启动流程(更新中)


    前言

    接着前文分析Android T 远程动画显示流程其二
    我们通过IRemoteAnimationRunner跨进程通信从系统进程来到了桌面进程,这里是真正动画播放的逻辑。
    之后又通过IRemoteAnimationFinishedCallback跨进程通信回到系统进程,处理动画结束时的逻辑。

    进入桌面进程启动动画

    跨进程通信,实现IRemoteAnimationRunner

    代码路径:frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java

    public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner.Stub {
    
        public abstract void onAnimationStart(@WindowManager.TransitionOldType int transit,
                RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
                RemoteAnimationTarget[] nonApps, Runnable finishedCallback);
    
        @Override
        public final void onAnimationStart(@TransitionOldType int transit,
                RemoteAnimationTarget[] apps,
                RemoteAnimationTarget[] wallpapers,
                RemoteAnimationTarget[] nonApps,
                final IRemoteAnimationFinishedCallback finishedCallback) {
            //调用自身抽象方法onAnimationStart
            onAnimationStart(transit, apps, wallpapers,
                    nonApps, () -> {
                        try {
                            finishedCallback.onAnimationFinished();
                        } catch (RemoteException e) {
                            Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
                                    + " finished callback", e);
                        }
                    });
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这里传递的参数都是前面RemoteAnimationController.goodToGo方法中获取的值。
    transit的值是TRANSIT_OLD_WALLPAPER_CLOSE(12);
    app指的是桌面和应用的RemoteAnimationTarget;
    wallpapers壁纸的RemoteAnimationTarget;
    nonApp非APP类型的RemoteAnimationTarget;
    finishedCallback是FinishedCallback对象,这里传递的是调用了其onAnimationFinished()方法。

    这方方法调用了自身抽象方法调用自身抽象方法onAnimationStart,onAnimationStart方法真正的实现在LauncherAnimationRunner类中

    @TargetApi(Build.VERSION_CODES.P)
    public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat {
        ......
        @BinderThread
        public void onAnimationStart(
                int transit,
                RemoteAnimationTarget[] appTargets,
                RemoteAnimationTarget[] wallpaperTargets,
                RemoteAnimationTarget[] nonAppTargets,
                Runnable runnable) {
            Runnable r = () -> {
                //退出动画的流程,此时mAnimationResult为空,尚未进入该流程
                finishExistingAnimation();
                //创建AnimationResult,传递了两个runnable
                //() -> mAnimationResult = null,把AnimationResult对象置空
                //runnable,就是前面传递的IRemoteAnimationFinishedCallback.onAnimationFinished
                mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);
                //传递从系统侧调用过来的参数创建动画
                getFactory().onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
                        mAnimationResult);
            };
            //根据mStartAtFrontOfQueue的值,执行线程 r
            if (mStartAtFrontOfQueue) {
                //将Runnable插入到消息队列的前面,以确保它尽快被执行
                postAtFrontOfQueueAsynchronously(mHandler, r);
            } else {
                //将Runnable异步地插入到消息队列中,它将在队列中的其他消息之后执行。
                postAsyncCallback(mHandler, r);
            }
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 退出动画的流程
      finishExistingAnimation();

          @UiThread
          private void finishExistingAnimation() {
              if (mAnimationResult != null) {
                  mAnimationResult.finish();
                  mAnimationResult = null;
              }
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      根据mAnimationResult是否为空执行finish方法,主要就是执行mASyncFinishRunnable,后续会在动画退出流程中细讲finish方法。

    • 创建AnimationResult
      mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);

          public static final class AnimationResult {
              ......
              private AnimationResult(Runnable syncFinishRunnable, Runnable asyncFinishRunnable) {
                  mSyncFinishRunnable = syncFinishRunnable;
                  mASyncFinishRunnable = asyncFinishRunnable;
              }
              ......
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      AnimationResult主要用来返回当前动画播放结果,以便后续执行动画播放完成时的回调(mASyncFinishRunnable)。
      () -> mAnimationResult = null,一个把AnimationResult对象置空的Runnable,保存到mSyncFinishRunnable中;
      runnable,就是前面传递的IRemoteAnimationFinishedCallback.onAnimationFinished,保存到mASyncFinishRunnable中。

    • 传递从系统侧创建的参数创建动画

      getFactory().onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
                          mAnimationResult);
      
      • 1
      • 2

      传递了从系统侧创建的参数,并传递了mAnimationResult对象。这里调用的是RemoteAnimationFactory接口中的onCreateAnimation方法。

          /**
           * Used with LauncherAnimationRunner as an interface for the runner to call back to the
           * implementation.
           */
          @FunctionalInterface
          public interface RemoteAnimationFactory {
      
              /**
               * Called on the UI thread when the animation targets are received. The implementation must
               * call {@link AnimationResult#setAnimation} with the target animation to be run.
               */
              void onCreateAnimation(int transit,
                      RemoteAnimationTarget[] appTargets,
                      RemoteAnimationTarget[] wallpaperTargets,
                      RemoteAnimationTarget[] nonAppTargets,
                      LauncherAnimationRunner.AnimationResult result);
              ......
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      在最开始Launcher.startActivitySafely流程中,QuickstepTransitionManager.getActivityLaunchOptions方法中创建了AppLaunchAnimationRunner对象,并作为RemoteAnimationFactory对象传递到了。

              mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
              RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(
                      mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);
      
      • 1
      • 2
      • 3

      因此我们这里RemoteAnimationFactory的实现,就是在QuickstepTransitionManager.AppLaunchAnimationRunner中。

    传递从系统侧创建的参数创建动画

    代码路径:packages/apps/Launcher3/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java

        private class AppLaunchAnimationRunner implements RemoteAnimationFactory {
    
            private final View mV;
            private final RunnableList mOnEndCallback;
    
            AppLaunchAnimationRunner(View v, RunnableList onEndCallback) {
                mV = v;
                mOnEndCallback = onEndCallback;
            }
    
            @Override
            public void onCreateAnimation(int transit,
                    RemoteAnimationTarget[] appTargets,
                    RemoteAnimationTarget[] wallpaperTargets,
                    RemoteAnimationTarget[] nonAppTargets,
                    LauncherAnimationRunner.AnimationResult result) {
                //创建AnimatorSet
                AnimatorSet anim = new AnimatorSet();
                //判断桌面的是否已经不在前台
                boolean launcherClosing =
                        launcherIsATargetWithMode(appTargets, MODE_CLOSING);
    
                //检查是否从桌面小部件启动应用
                final boolean launchingFromWidget = mV instanceof LauncherAppWidgetHostView;
                //检查是否从最近应用列表启动应用
                final boolean launchingFromRecents = isLaunchingFromRecents(mV, appTargets);
                //决定是否跳过动画的第一帧
                final boolean skipFirstFrame;
                if (launchingFromWidget) {//从桌面小部件启动应用的动画
                    composeWidgetLaunchAnimator(anim, (LauncherAppWidgetHostView) mV, appTargets,
                            wallpaperTargets, nonAppTargets, launcherClosing);
                    addCujInstrumentation(
                            anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_WIDGET);
                    skipFirstFrame = true;
                } else if (launchingFromRecents) {//从最近任务启动应用的动画
                    composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                            launcherClosing);
                    addCujInstrumentation(
                            anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS);
                    skipFirstFrame = true;
                } else {//点击桌面图标启动应用的动画
                    composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                            launcherClosing);
                    addCujInstrumentation(anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_ICON);
                    skipFirstFrame = false;
                }
    
                //桌面不在前台给动画添加一个监听器
                if (launcherClosing) {
                    anim.addListener(mForceInvisibleListener);
                }
                //设置动画和回调
                result.setAnimation(anim, mLauncher, mOnEndCallback::executeAllAndDestroy,
                        skipFirstFrame);
            }
    
            @Override
            public void onAnimationCancelled() {
                mOnEndCallback.executeAllAndDestroy();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    这里我们主要关注点击桌面图标启动应用的动画逻辑

    点击桌面图标启动应用的动画

    composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                            launcherClosing);
    
    • 1
    • 2

    anim一个AnimatorSet对象;
    mV这里指的是启动的应用图标,比如com.android.launcher3.BubbleTextView{bace738 VFED..CL. ........ 582,525-859,945 #7f09016a app:id/icon}
    appTargets指的是桌面和应用的RemoteAnimationTarget;
    wallpaperTargets壁纸的RemoteAnimationTarget;
    nonAppTargets非APP类型的RemoteAnimationTarget;
    launcherClosing此时桌面的是否已经不在前台,因此值为true

        /**
         * Compose the animations for a launch from the app icon.
         *
         * @param anim            the animation to add to
         * @param v               the launching view with the icon
         * @param appTargets      the list of opening/closing apps
         * @param launcherClosing true if launcher is closing
         */
        private void composeIconLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
                @NonNull RemoteAnimationTarget[] appTargets,
                @NonNull RemoteAnimationTarget[] wallpaperTargets,
                @NonNull RemoteAnimationTarget[] nonAppTargets,
                boolean launcherClosing) {
            // Set the state animation first so that any state listeners are called
            // before our internal listeners.
            //setCurrentAnimation(anim)取消任何正在运行的动画,设置新的动画
            //即将动画设置为当前状态动画
            mLauncher.getStateManager().setCurrentAnimation(anim);
    
            // Note: the targetBounds are relative to the launcher
            int startDelay = getSingleFrameMs(mLauncher);
            //设置动画参数
            Animator windowAnimator = getOpeningWindowAnimators(
                    v, appTargets, wallpaperTargets, nonAppTargets, launcherClosing);
            //设置动画启动延时
            windowAnimator.setStartDelay(startDelay);
            //设置windowAnimator给AnimatorSet对象
            anim.play(windowAnimator);
            //如果桌面已经不在最顶层显示
            if (launcherClosing) {
                // Delay animation by a frame to avoid jank.
                //将动画延迟一帧以避免抖动
                //创建一个launcherAnimator动画和endListener线程
                Pair<AnimatorSet, Runnable> launcherContentAnimator =
                        getLauncherContentAnimator(true /* isAppOpening */, startDelay, false);
                //把launcherAnimator动画放到AnimatorSet
                anim.play(launcherContentAnimator.first);
                anim.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        //运行endListener线程
                        launcherContentAnimator.second.run();
                    }
                });
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    之前最为关键的就是getOpeningWindowAnimators方法

    Animator windowAnimator = getOpeningWindowAnimators(
                    v, appTargets, wallpaperTargets, nonAppTargets, launcherClosing);
    
    • 1
    • 2

    这个方法是动画真正的设置部分

    设置动画相关参数、监听等

        /**
         * @return Animator that controls the window of the opening targets from app icons.
         */
        private Animator getOpeningWindowAnimators(View v,
                RemoteAnimationTarget[] appTargets,
                RemoteAnimationTarget[] wallpaperTargets,
                RemoteAnimationTarget[] nonAppTargets,
                boolean launcherClosing) {
            //获取应用方向
            int rotationChange = getRotationChange(appTargets);
            //获取启动应用的窗口边界
            Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange);
            //检查appTargets中所有应用目标是否半透明
            //areAllTargetsTranslucent方法返回的的是,
            //mode值为MODE_OPENING(正在打开的应用)的RemoteAnimationTarget的isTranslucent的值
            boolean appTargetsAreTranslucent = areAllTargetsTranslucent(appTargets);
    
            RectF launcherIconBounds = new RectF();
            //获取一个浮动图标视图
            FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
                    !appTargetsAreTranslucent, launcherIconBounds, true /* isOpening */);
            Rect crop = new Rect();
            Matrix matrix = new Matrix();
    
            //创建mMode为MODE_OPENING的RemoteAnimationTargets对象
            //把app、壁纸和非app类型的RemoteAnimationTarget对象保存到RemoteAnimationTargets中
            RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
                    wallpaperTargets, nonAppTargets, MODE_OPENING);
            //创建SurfaceTransactionApplier对象
            SurfaceTransactionApplier surfaceApplier =
                    new SurfaceTransactionApplier(floatingView);
            //为了确保动画完成时,释放相关资源
            openingTargets.addReleaseCheck(surfaceApplier);
            //获取导航栏的RemoteAnimationTarget对象
            RemoteAnimationTarget navBarTarget = openingTargets.getNavBarRemoteAnimationTarget();
    
            //DragLayer是一个ViewGroup,协调处理它的子view拖动的容器
            //getLocationOnScreen获取DragLayer在屏幕上的绝对位置
            int[] dragLayerBounds = new int[2];
            mDragLayer.getLocationOnScreen(dragLayerBounds);
    
            //检查是否支持冷启动窗口Splash Screen
            final boolean hasSplashScreen;
            if (supportsSSplashScreen()) {
                int taskId = openingTargets.getFirstAppTargetTaskId();
                Pair<Integer, Integer> defaultParams = Pair.create(STARTING_WINDOW_TYPE_NONE, 0);
                Pair<Integer, Integer> taskParams =
                        mTaskStartParams.getOrDefault(taskId, defaultParams);
                mTaskStartParams.remove(taskId);
                hasSplashScreen = taskParams.first == STARTING_WINDOW_TYPE_SPLASH_SCREEN;
            } else {
                hasSplashScreen = false;
            }
    
            //创建AnimOpenProperties对象,设置应用启动时的动画属性
            AnimOpenProperties prop = new AnimOpenProperties(mLauncher.getResources(), mDeviceProfile,
                    windowTargetBounds, launcherIconBounds, v, dragLayerBounds[0], dragLayerBounds[1],
                    hasSplashScreen, floatingView.isDifferentFromAppIcon());
            //计算裁剪区域的边界
            int left = prop.cropCenterXStart - prop.cropWidthStart / 2;
            int top = prop.cropCenterYStart - prop.cropHeightStart / 2;
            int right = left + prop.cropWidthStart;
            int bottom = top + prop.cropHeightStart;
            // Set the crop here so we can calculate the corner radius below.
            crop.set(left, top, right, bottom);
    
            //创建临时矩形和点对象
            RectF floatingIconBounds = new RectF();
            RectF tmpRectF = new RectF();
            Point tmpPos = new Point();
    
            //设置动画的一些参数和监听
            AnimatorSet animatorSet = new AnimatorSet();
            ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
            appAnimator.setDuration(APP_LAUNCH_DURATION);
            //设置动画的插值器为LINEAR。插值器决定了动画的速度曲线。LINEAR意味着动画将匀速进行
            appAnimator.setInterpolator(LINEAR);
            //为appAnimator添加一个动画监听器floatingView。
            //当动画开始、结束、取消或重复时,floatingView上的相应方法将被调用。
            appAnimator.addListener(floatingView);
            appAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                //监听动开始
                public void onAnimationStart(Animator animation) {
                    //获取LauncherTaskbarUIController的实例
                    LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
                    //检查是否应该调用shouldShowEdu()
                    if (taskbarController != null && taskbarController.shouldShowEdu()) {
                        // LAUNCHER_TASKBAR_EDUCATION_SHOWING is set to true here, when the education
                        // flow is about to start, to avoid a race condition with other components
                        // that would show something else to the user as soon as the app is opened.
                        //将LAUNCHER_TASKBAR_EDUCATION_SHOWING设置为true,以避免与其他组件发生竞争
                        Settings.Secure.putInt(mLauncher.getContentResolver(),
                                LAUNCHER_TASKBAR_EDUCATION_SHOWING, 1);
                    }
                }
    
                @Override
                //监听动结束
                public void onAnimationEnd(Animator animation) {
                    if (v instanceof BubbleTextView) {
                        //我们这里v是BubbleTextView类型
                        //设置控件v保持按下的状态为false
                        ((BubbleTextView) v).setStayPressed(false);
                    }
                    //获取LauncherTaskbarUIController的实例
                    LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
                    if (taskbarController != null) {
                        //调用shouldShowEdu()
                        taskbarController.showEdu();
                    }
                    //释放所有类型的RemoteAnimationTarget对象
                    //包含壁纸、app和非app类型的RemoteAnimationTarget对象
                    openingTargets.release();
                }
            });
            
            //initialWindowRadius用于设置动画开始时的窗口圆角半径
            //supportsRoundedCornersOnWindows(mLauncher.getResources()判断桌面是否支持窗口圆角
            final float initialWindowRadius = supportsRoundedCornersOnWindows(mLauncher.getResources())
                    ? Math.max(crop.width(), crop.height()) / 2f
                    : 0f;
            //finalWindowRadius用于设置动画结束时的窗口圆角半径
            //mDeviceProfile.isMultiWindowMode检查是否处于多窗口模式
            //getWindowCornerRadius(mLauncher)获取桌面窗口的圆角半径
            final float finalWindowRadius = mDeviceProfile.isMultiWindowMode
                    ? 0 : getWindowCornerRadius(mLauncher);
            //inalShadowRadius用于设置动画结束时的阴影半径
            //appTargetsAreTranslucent表示应用目标是否半透明
            //mMaxShadowRadius最大阴影半径值
            final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
            
            MultiValueUpdateListener listener = new MultiValueUpdateListener() {
                //mDx:这个属性表示在动画过程中,X轴上的位移变化。
                //它从0开始,到prop.dX结束,动画时长为APP_LAUNCH_DURATION,使用mOpeningXInterpolator作为插值器。
                FloatProp mDx = new FloatProp(0, prop.dX, 0, APP_LAUNCH_DURATION,
                        mOpeningXInterpolator);
                //这个属性表示在动画过程中,Y轴上的位移变化。
                //它从0开始,到prop.dY结束,动画时长为APP_LAUNCH_DURATION,使用mOpeningInterpolator作为插值器。
                FloatProp mDy = new FloatProp(0, prop.dY, 0, APP_LAUNCH_DURATION,
                        mOpeningInterpolator);
                
                //mIconScaleToFitScreen:这个属性表示应用图标在屏幕上的缩放变化。
                //它从prop.initialAppIconScale开始,到prop.finalAppIconScale结束,
                //动画时长为APP_LAUNCH_DURATION,使用mOpeningInterpolator作为插值器。
                FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale,
                        prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, mOpeningInterpolator);
                //mIconAlpha:这个属性表示应用图标的透明度变化。
                //它从prop.iconAlphaStart开始,到0结束,
                //动画的开始延迟为APP_LAUNCH_ALPHA_START_DELAY,时长为APP_LAUNCH_ALPHA_DURATION,
                //使用线性插值器(LINEAR)。
                FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f,
                        APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, LINEAR);
    
                //mWindowRadius:这个属性表示窗口圆角的半径变化。
                //它从initialWindowRadius开始,到finalWindowRadius结束,动画时长为APP_LAUNCH_DURATION,
                //使用mOpeningInterpolator作为插值器。
                FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
                        APP_LAUNCH_DURATION, mOpeningInterpolator);
                //mShadowRadius:这个属性表示阴影的半径变化。
                //它从0开始,到finalShadowRadius结束,动画时长为APP_LAUNCH_DURATION,
                //使用mOpeningInterpolator作为插值器。
                FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0,
                        APP_LAUNCH_DURATION, mOpeningInterpolator);
     
                //mCropRectCenterX、mCropRectCenterY、mCropRectWidth、mCropRectHeight
                //这些属性分别表示裁剪矩形的中心X坐标、中心Y坐标、宽度和高度的变化。
                //它们都有各自的起始值和结束值,动画时长为APP_LAUNCH_DURATION,使用mOpeningInterpolator作为插值器。
                FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
                        0, APP_LAUNCH_DURATION, mOpeningInterpolator);
                FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd,
                        0, APP_LAUNCH_DURATION, mOpeningInterpolator);
                FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0,
                        APP_LAUNCH_DURATION, mOpeningInterpolator);
                FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
                        APP_LAUNCH_DURATION, mOpeningInterpolator);
    
                //这个属性表示导航栏的淡出效果。
                //它从1开始,到0结束,动画时长为ANIMATION_NAV_FADE_OUT_DURATION,
                //使用NAV_FADE_OUT_INTERPOLATOR作为插值器。
                FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
                        NAV_FADE_OUT_INTERPOLATOR);
                //mNavFadeIn:这个属性表示导航栏的淡入效果。它从0开始,到1结束,
                //动画的开始延迟为ANIMATION_DELAY_NAV_FADE_IN,时长为ANIMATION_NAV_FADE_IN_DURATION,
                //使用NAV_FADE_IN_INTERPOLATOR作为插值器。
                FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
                        ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
                 
    			//动画的更新
                @Override
                public void onUpdate(float percent, boolean initOnly) {
                    // Calculate the size of the scaled icon.
    				//计算缩放图标的大小
                    float iconWidth = launcherIconBounds.width() * mIconScaleToFitScreen.value;
                    float iconHeight = launcherIconBounds.height() * mIconScaleToFitScreen.value;
    
                    int left = (int) (mCropRectCenterX.value - mCropRectWidth.value / 2);
                    int top = (int) (mCropRectCenterY.value - mCropRectHeight.value / 2);
                    int right = (int) (left + mCropRectWidth.value);
                    int bottom = (int) (top + mCropRectHeight.value);
                    crop.set(left, top, right, bottom);
    
                    final int windowCropWidth = crop.width();
                    final int windowCropHeight = crop.height();
                    if (rotationChange != 0) {
                        Utilities.rotateBounds(crop, mDeviceProfile.widthPx,
                                mDeviceProfile.heightPx, rotationChange);
                    }
    
                    // Scale the size of the icon to match the size of the window crop.
    				//缩放图标的大小以匹配窗口裁剪的大小。
                    float scaleX = iconWidth / windowCropWidth;
                    float scaleY = iconHeight / windowCropHeight;
                    float scale = Math.min(1f, Math.max(scaleX, scaleY));
    
                    float scaledCropWidth = windowCropWidth * scale;
                    float scaledCropHeight = windowCropHeight * scale;
                    float offsetX = (scaledCropWidth - iconWidth) / 2;
                    float offsetY = (scaledCropHeight - iconHeight) / 2;
    
                    // Calculate the window position to match the icon position.
    				//计算窗口位置以匹配图标位置。
                    tmpRectF.set(launcherIconBounds);
                    tmpRectF.offset(dragLayerBounds[0], dragLayerBounds[1]);
                    tmpRectF.offset(mDx.value, mDy.value);
                    Utilities.scaleRectFAboutCenter(tmpRectF, mIconScaleToFitScreen.value);
                    float windowTransX0 = tmpRectF.left - offsetX - crop.left * scale;
                    float windowTransY0 = tmpRectF.top - offsetY - crop.top * scale;
    
                    // Calculate the icon position.
    				//计算图标位置
                    floatingIconBounds.set(launcherIconBounds);
                    floatingIconBounds.offset(mDx.value, mDy.value);
                    Utilities.scaleRectFAboutCenter(floatingIconBounds, mIconScaleToFitScreen.value);
                    floatingIconBounds.left -= offsetX;
                    floatingIconBounds.top -= offsetY;
                    floatingIconBounds.right += offsetX;
                    floatingIconBounds.bottom += offsetY;
    
                    if (initOnly) {
                        // For the init pass, we want full alpha since the window is not yet ready.
                        //使用floatingView.update方法更新浮动视图的属性,包括透明度、边界、半径等。  
                        floatingView.update(1f, 255, floatingIconBounds, percent, 0f,
                                mWindowRadius.value * scale, true /* isOpening */);
                        return;
                    }
    
                    SurfaceTransaction transaction = new SurfaceTransaction();
                    
                    //遍历桌面和启动应用的RemoteAnimationTarget,获取其leash,分别做处理
                    for (int i = appTargets.length - 1; i >= 0; i--) {
                        RemoteAnimationTarget target = appTargets[i];
                        SurfaceProperties builder = transaction.forSurface(target.leash);
    
                        if (target.mode == MODE_OPENING) {
                        /**
                         * 如果目标模式是MODE_OPENING(打开模式),代码会设置一个矩阵(matrix)来进行缩放和平移操作。
                         * 根据rotationChange的值(可能是表示屏幕旋转的变量),代码会决定如何平移窗口。  
                         * 然后,使用floatingView.update方法更新浮动视图的属性,包括透明度、边界、半径等。  
                         * 接着,通过builder.setMatrix等方法设置窗口的矩阵、裁剪区域、透明度、圆角半径和阴影半径。
                         */
                            matrix.setScale(scale, scale);
                            if (rotationChange == 1) {
                                matrix.postTranslate(windowTransY0,
                                        mDeviceProfile.widthPx - (windowTransX0 + scaledCropWidth));
                            } else if (rotationChange == 2) {
                                matrix.postTranslate(
                                        mDeviceProfile.widthPx - (windowTransX0 + scaledCropWidth),
                                        mDeviceProfile.heightPx - (windowTransY0 + scaledCropHeight));
                            } else if (rotationChange == 3) {
                                matrix.postTranslate(
                                        mDeviceProfile.heightPx - (windowTransY0 + scaledCropHeight),
                                        windowTransX0);
                            } else {
                                matrix.postTranslate(windowTransX0, windowTransY0);
                            }
    
                            floatingView.update(mIconAlpha.value, 255, floatingIconBounds, percent, 0f,
                                    mWindowRadius.value * scale, true /* isOpening */);
                            builder.setMatrix(matrix)
                                    .setWindowCrop(crop)
                                    .setAlpha(1f - mIconAlpha.value)
                                    .setCornerRadius(mWindowRadius.value)
                                    .setShadowRadius(mShadowRadius.value);
                        } else if (target.mode == MODE_CLOSING) {
                        /**
                         * 如果目标模式是MODE_CLOSING(关闭模式),代码会处理关闭动画。
                         * 首先,根据目标的本地边界或位置设置临时位置(tmpPos)。
                         * 然后,根据rotationChange的值,可能需要对裁剪区域(crop)和临时位置进行旋转调整。
                         * 最后,设置窗口的矩阵和裁剪区域,并将透明度设置为1(完全不透明)。
                         */
                            if (target.localBounds != null) {
                                tmpPos.set(target.localBounds.left, target.localBounds.top);
                            } else {
                                tmpPos.set(target.position.x, target.position.y);
                            }
                            final Rect crop = new Rect(target.screenSpaceBounds);
                            crop.offsetTo(0, 0);
    
                            if ((rotationChange % 2) == 1) {
                                int tmp = crop.right;
                                crop.right = crop.bottom;
                                crop.bottom = tmp;
                                tmp = tmpPos.x;
                                tmpPos.x = tmpPos.y;
                                tmpPos.y = tmp;
                            }
                            matrix.setTranslate(tmpPos.x, tmpPos.y);
                            builder.setMatrix(matrix)
                                    .setWindowCrop(crop)
                                    .setAlpha(1f);
                        }
                    }
    
                    /**
                     * 如果navBarTarget不为空(即存在导航栏目标),代码会为其设置动画和视图属性。 
                     * 根据`mNavFadeIn.value`的值,决定是淡入还是淡出导航栏。如果淡入值大于起始值,则应用淡入动画;
                     */
                    if (navBarTarget != null) {
                        SurfaceProperties navBuilder =
                                transaction.forSurface(navBarTarget.leash);
                        if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
                            matrix.setScale(scale, scale);
                            matrix.postTranslate(windowTransX0, windowTransY0);
                            navBuilder.setMatrix(matrix)
                                    .setWindowCrop(crop)
                                    .setAlpha(mNavFadeIn.value);
                        } else {
                            navBuilder.setAlpha(mNavFadeOut.value);
                        }
                    }
                    surfaceApplier.scheduleApply(transaction);
                }
            };
            appAnimator.addUpdateListener(listener);
            // Since we added a start delay, call update here to init the FloatingIconView properly.
            //调用MultiValueUpdateListener.update更新动画显示
            listener.onUpdate(0, true /* initOnly */);
    
            // If app targets are translucent, do not animate the background as it causes a visible
            // flicker when it resets itself at the end of its animation.
            //appTargetsAreTranslucent,启动的应用为半透明
            //或 !launcherClosing,桌面在最顶层
            if (appTargetsAreTranslucent || !launcherClosing) {
                //仅设置appAnimator给animatorSet
                animatorSet.play(appAnimator);
            } else {
                //设置appAnimator和getBackgroundAnimator() (背景动画)
                //用于并行播放
                animatorSet.playTogether(appAnimator, getBackgroundAnimator());
            }
            return animatorSet;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353

    设置一些动画相关参数和监听,通过MultiValueUpdateListener.update方法更新动画显示。

    调用setAnimation设置动画和回调

    回到QuickstepTransitionManager.AppLaunchAnimationRunner.onCreateAnimation方法中,继续看到setAnimation方法:

    result.setAnimation(anim, mLauncher, mOnEndCallback::executeAllAndDestroy,
                        skipFirstFrame);
    
    • 1
    • 2

    前面的在getOpeningWindowAnimators方法中设置的动画,通过anim播放

    动画的启动与结束

    代码路径:packages/apps/Launcher3/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java

            /**
             * Sets the animation to play for this app launch
             * @param skipFirstFrame Iff true, we skip the first frame of the animation.
             *                       We set to false when skipping first frame causes jank.
             */
            @UiThread
            public void setAnimation(AnimatorSet animation, Context context,
                    @Nullable Runnable onCompleteCallback, boolean skipFirstFrame) {
                if (mInitialized) {
                    throw new IllegalStateException("Animation already initialized");
                }
                mInitialized = true;
                mAnimator = animation;
                mOnCompleteCallback = onCompleteCallback;
                //如果动画为空,直接调用finish方法,走结束动画流程
                if (mAnimator == null) {
                    finish();
                } else if (mFinished) {//mFinished为true,表示动画播放结束
                    // Animation callback was already finished, skip the animation.
                    //调用mAnimator.start()和mAnimator.end()来跳过动画
                    mAnimator.start();
                    mAnimator.end();
                    if (mOnCompleteCallback != null) {
                        mOnCompleteCallback.run();
                    }
                } else {
                    // Start the animation
                    //添加动画监听
                    mAnimator.addListener(new AnimatorListenerAdapter() {
                        @Override
                        //动画结束时的监听,调用finish()方法
                        public void onAnimationEnd(Animator animation) {
                            finish();
                        }
                    });
                    //开始播放动画
                    mAnimator.start();
                    
                    //如果skipFirstFrame为true
                    if (skipFirstFrame) {
                        // Because t=0 has the app icon in its original spot, we can skip the
                        // first frame and have the same movement one frame earlier.
                        //调用mAnimator.setCurrentPlayTime()来设置动画的当前播放时间,
                        //该时间为动画总时长与getSingleFrameMs(context)的较小值。
                        //这可以使得应用图标从原始位置开始的移动提前一帧,
                        //因为t=0时应用图标位于其原始位置。
                        mAnimator.setCurrentPlayTime(
                                Math.min(getSingleFrameMs(context), mAnimator.getTotalDuration()));
                    }
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    这个方法主要是通过mAnimator.start();启动动画的播放。当动画播放结束时,使用finish();方法进入动画结束播放流程。

    动画播放结束

    动画播放结束时,调用finish方法进入结束动画流程

    代码路径:packages/apps/Launcher3/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java

        public static final class AnimationResult {
            ......
            @UiThread
            private void finish() {
                if (!mFinished) {
                    //运行的是 () -> mAnimationResult = null
                    //即把AnimationResult对象置空
                    mSyncFinishRunnable.run();
                    UI_HELPER_EXECUTOR.execute(() -> {
                        //运行的是IRemoteAnimationFinishedCallback.onAnimationFinished
                        mASyncFinishRunnable.run();
                        if (mOnCompleteCallback != null) {
                            MAIN_EXECUTOR.execute(mOnCompleteCallback);
                        }
                    });
                    //mFinished标志位置为true,表示动画播放完成。
                    mFinished = true;
                }
            }
            ......
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    前面跨进程通信时,对AnimationResult构造方法进行了初始化

    private AnimationResult(Runnable syncFinishRunnable, Runnable asyncFinishRunnable) {
                mSyncFinishRunnable = syncFinishRunnable;
                mASyncFinishRunnable = asyncFinishRunnable;
            }
    
    • 1
    • 2
    • 3
    • 4

    并且onAnimationStart方法中给创建了AnimationResult对象,传递了两个runnable。
    mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);
    这里传递的runnable就是跨进程通信传递过来的动画完成时回调。

    mSyncFinishRunnable表示的就是() -> mAnimationResult = null,置空AnimationResult对象;
    mASyncFinishRunnable表示的就是IRemoteAnimationFinishedCallback.onAnimationFinished方法,即跨进程调用结束动画流程。

    跨进程通信进入动画结束流程

    代码路径:frameworks/base/core/java/android/view/IRemoteAnimationFinishedCallback.aidl

    /**
     * Interface to be invoked by the controlling process when a remote animation has finished.
     *
     * @see IRemoteAnimationRunner
     * {@hide}
     */
    oneway interface IRemoteAnimationFinishedCallback {
        @UnsupportedAppUsage
        void onAnimationFinished();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    IRemoteAnimationFinishedCallback的实现在RemoteAnimationController.FinishedCallback类中

    进入系统进程结束动画

    跨进程通信,实现IRemoteAnimationFinishedCallback

    代码路径:frameworks/base/services/core/java/com/android/server/wm/RemoteAnimationController.java

        private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub {
    
            RemoteAnimationController mOuter;
    
            FinishedCallback(RemoteAnimationController outer) {
                mOuter = outer;
            }
    
            @Override
            public void onAnimationFinished() throws RemoteException {
                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-onAnimationFinished(): mOuter=%s", mOuter);
                final long token = Binder.clearCallingIdentity();
                try {
                    if (mOuter != null) {
                        mOuter.onAnimationFinished();
    
                        // In case the client holds on to the finish callback, make sure we don't leak
                        // RemoteAnimationController which in turn would leak the runner on the client.
                        mOuter = null;
                    }
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
            }
    
            /**
             * Marks this callback as not be used anymore by releasing the reference to the outer class
             * to prevent memory leak.
             */
            void release() {
                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-release(): mOuter=%s", mOuter);
                mOuter = null;
            }
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    这段代码的关键就是调用mOuter.onAnimationFinished();

    onAnimationFinished方法的实现

    private void onAnimationFinished() {
            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationFinished(): mPendingAnimations=%d",
                    mPendingAnimations.size());
            //移除超时回调
            mHandler.removeCallbacks(mTimeoutRunnable);
            synchronized (mService.mGlobalLock) {
                //解除绑定IRemoteAnimationRunner
                unlinkToDeathOfRunner();
                //释放绑定的IRemoteAnimationFinishedCallback
                releaseFinishedCallback();
                //开启事务
                mService.openSurfaceTransaction();
                try {
                    ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
                            "onAnimationFinished(): Notify animation finished:");
                    //app类型动画结束时回调
                    //调用桌面和启动应用的动画结束时回调
                    for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
                        final RemoteAnimationRecord adapters = mPendingAnimations.get(i);
                        if (adapters.mAdapter != null) {
                            adapters.mAdapter.mCapturedFinishCallback
                                    .onAnimationFinished(adapters.mAdapter.mAnimationType,
                                            adapters.mAdapter);
                        }
                        if (adapters.mThumbnailAdapter != null) {
                            adapters.mThumbnailAdapter.mCapturedFinishCallback
                                    .onAnimationFinished(adapters.mThumbnailAdapter.mAnimationType,
                                            adapters.mThumbnailAdapter);
                        }
                        mPendingAnimations.remove(i);
                        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s",
                                adapters.mWindowContainer);
                    }
    
                    //壁纸类型动画结束时回调
                    for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
                        final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i);
                        adapter.getLeashFinishedCallback().onAnimationFinished(
                                adapter.getLastAnimationType(), adapter);
                        mPendingWallpaperAnimations.remove(i);
                        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken());
                    }
    
                    //非App类型动画结束时回调
                    for (int i = mPendingNonAppAnimations.size() - 1; i >= 0; i--) {
                        final NonAppWindowAnimationAdapter adapter = mPendingNonAppAnimations.get(i);
                        adapter.getLeashFinishedCallback().onAnimationFinished(
                                adapter.getLastAnimationType(), adapter);
                        mPendingNonAppAnimations.remove(i);
                        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tnonApp=%s",
                                adapter.getWindowContainer());
                    }
                } catch (Exception e) {
                    Slog.e(TAG, "Failed to finish remote animation", e);
                    throw e;
                } finally {
                    mService.closeSurfaceTransaction("RemoteAnimationController#finished");
                }
                // Reset input for all activities when the remote animation is finished.
                final Consumer<ActivityRecord> updateActivities =
                        activity -> activity.setDropInputForAnimation(false);
                mDisplayContent.forAllActivities(updateActivities);
            }
            setRunningRemoteAnimation(false);
            ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    我们这里主要关注的是App类型的动画结束流程,这里通过循环,把桌面和启动的应用动画结束时流程逐个调用。这个循环是反向遍历,因此先走的是桌面动画结束时的回调。

    adapters.mAdapter.mCapturedFinishCallback
    		  .onAnimationFinished(adapters.mAdapter.mAnimationType,
    		          adapters.mAdapter);
    
    • 1
    • 2
    • 3

    mCapturedFinishCallback是RemoteAnimationAdapterWrapper对象,它其实就是SurfaceAnimator.getFinishedCallback方法。

    在创建动画leash的流程中,SurfaceAnimator.startAnimation方法中有调用mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);,这里把mInnerAnimationFinishedCallback赋值给了RemoteAnimationAdapterWrapper的mCapturedFinishCallbackmInnerAnimationFinishedCallback在SurfaceAnimator的构造方法初始化的值是getFinishedCallback(staticAnimationFinishedCallback),即动画完成时的回调mCapturedFinishCallback对应的就是getFinishedCallback(staticAnimationFinishedCallback)。

    所以这里mCapturedFinishCallback.onAnimationFinished调用的,实际是调用就是SurfaceAnimator.getFinishedCallback中匿名的(type, anim) -> {......}

    回调处理动画完成的逻辑

    这里的流程与本地动画流程相似
    代码路径:frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java

        private OnAnimationFinishedCallback getFinishedCallback(
                @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback) {
            return (type, anim) -> {
                synchronized (mService.mGlobalLock) {
                    //移除AnimationAdapter对应的SurfaceAnimator,并将这个SurfaceAnimator返回给target
                    //mAnimationTransferMap属于启动窗口的动画场景,这里我们不涉及
                    final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
                    if (target != null) {
                        //递归调用onAnimationFinished(type, anim),即return (type, anim) -> {......}
                        //直到所有的SurfaceAnimator移除完
                        target.mInnerAnimationFinishedCallback.onAnimationFinished(type, anim);
                        return;
                    }
    
                    //检查动画是否已被新动画替换,如果当前动画 (anim) 不等于之前存储的动画 (mAnimation),则不执行后续操作
                    if (anim != mAnimation) {
                        return;
                    }
                    //定义一个名为 resetAndInvokeFinish 的 Runnable
                    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;
                        }
                        //mSurfaceAnimationFinishedCallback是在WindowContainer.startAnimation中赋值的
                        //其传递值为null,最终SurfaceAnimator.startAnimation赋值给mSurfaceAnimationFinishedCallback
                        final OnAnimationFinishedCallback animationFinishCallback =
                                mSurfaceAnimationFinishedCallback;
                        //重置与动画相关的状态
                        reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */);
                        //WindowContainer构造方法中给SurfaceAnimator构造方法传递了staticAnimationFinishedCallback
                        if (staticAnimationFinishedCallback != null) {
                            //当一个Surface上的动画结束或取消且不重新启动时,这个回调将被执行。
                            //这是一个静态回调,它对通过这个 SurfaceAnimator 启动的所有动画都有效。
                            //回调WindowContainer.onAnimationFinished方法
                            staticAnimationFinishedCallback.onAnimationFinished(type, anim);
                        }
                        //mSurfaceAnimationFinishedCallback的值为null,因此animationFinishCallback的值为null
                        if (animationFinishCallback != null) {
                            //当一个Surface上的动画结束或取消且不重新启动时,这个回调将被执行。
                            //这个回调是每个动画(即每个 AnimationAdapter)特有的。
                            //如果在WindowContainer.startAnimation方法中有赋值,
                            //则回调WindowContainer.onAnimationFinished方法
                            animationFinishCallback.onAnimationFinished(type, anim);
                        }
                    };
                    // If both the Animatable and AnimationAdapter requests to be deferred, only the
                    // first one will be called.
                    //如果 mAnimatable 或动画本身请求延迟动画完成,并且它们都没有被延迟,
                    //那么直接执行 resetAndInvokeFinish.run()。否则,延迟执行。
                    if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)
                            || anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) {
                        resetAndInvokeFinish.run();
                    }
                    //设置动画完成标志,将 mAnimationFinished 设置为 true
                    mAnimationFinished = true;
                }
            };
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    这个方法主要做了这几件事:

    1. 通过递归的方式移除所有AnimationAdapter对应的SurfaceAnimator
      其中的mAnimationTransferMap在启动窗口流程中,ActivityRecord.addStartingWindow中有调用transferStartingWindow方法,逐步调用到SurfaceAnimator.transferAnimation中进行添加mService.mAnimationTransferMap.put(mAnimation, this);,这里我们不涉及,因此target的值为null
    2. 使用shouldDeferAnimationFinish方法(默认返回false)用来判断是否需要延迟完成动画
    3. 执行resetAndInvokeFinish.run(),调用reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */);重置动画相关状态
    4. 最后调用回调通过staticAnimationFinishedCallback.onAnimationFinished(type, anim);,调用WindowContainer.onAnimationFinished方法处理和响应动画完成的逻辑

    重置动画相关状态并移除leash

    reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */);
    代码路径:frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java

        private void reset(Transaction t, boolean destroyLeash) {
            //移除AnimationAdapter对应的SurfaceAnimator
            mService.mAnimationTransferMap.remove(mAnimation);
            mAnimation = null;
            mSurfaceAnimationFinishedCallback = null;
            //动画类型置为空
            mAnimationType = ANIMATION_TYPE_NONE;
            //屏幕冻结时的快照
            final SurfaceFreezer.Snapshot snapshot = mSnapshot;
            mSnapshot = null;
            if (snapshot != null) {
                // Reset the mSnapshot reference before calling the callback to prevent circular reset.
                //如果有屏幕冻结时的快照,取消该动画。
                //最终会调用到SurfaceAnimationRunner.onAnimationCancelled
                snapshot.cancelAnimation(t, !destroyLeash);
            }
            if (mLeash == null) {
                return;
            }
            //使用leash存储动画图层mLeash
            SurfaceControl leash = mLeash;
            //把动画图层置为空
            mLeash = null;
            //移除leash
            final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
            //将mAnimationFinished设置为false
            mAnimationFinished = false;
            if (scheduleAnim) {
                //leash成功移除后,在WMS中会通过WindowAnimator调度动画,协调各个窗口
                mService.scheduleAnimationLocked();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    移除leash

    调用removeLeash方法移除leash
    final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
    传递的mAnimatable表示当前窗口,leash就是动画图层,destroyLeash在前面getFinishedCallback流程中传递的值为true

        static boolean removeLeash(Transaction t, Animatable animatable, @NonNull SurfaceControl leash,
                                   boolean destroy) {
            /* log add start*/
            Slog.i("WindowManager:","removeLeash leash = " + leash , new Exception());
            /* log add end*/
            //scheduleAnim一个标志位,初始值为false
            //为true时,走前面reset方法中的mService.scheduleAnimationLocked()流程
            boolean scheduleAnim = false;
            //获取当前窗口的SurfaceControl
            final SurfaceControl surface = animatable.getSurfaceControl();
            //获取当前窗口的父窗口的SurfaceControl
            final SurfaceControl parent = animatable.getParentSurfaceControl();
            //获取动画图层
            final SurfaceControl curAnimationLeash = animatable.getAnimationLeash();
            // 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.
            // If the animation leash is set, and it is different from the removing leash, it means the
            // surface now has a new animation surface. We don't want to reparent for that.
            //1.surface不为空
            //2.curAnimationLeash不为空,且curAnimationLeash等于leash
            //因此reparent值为true
            final boolean reparent = surface != null && (curAnimationLeash == null
                    || curAnimationLeash.equals(leash));
            if (reparent) {
                ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to original parent: %s for %s",
                        parent, animatable);
                // We shouldn't really need these isValid checks but we do
                // b/130364451
                //判断当前窗口的surface是否有效,以及该窗口的父窗口的图层不为空且有效
                if (surface.isValid() && parent != null && parent.isValid()) {
                    //把当前窗口图层和其父窗口的图层重新建立父子关系
                    t.reparent(surface, parent);
                    //scheduleAnim置为true
                    scheduleAnim = true;
                }
            }
            //destroy传递过来值为true
            if (destroy) {
                //移除图层
                t.remove(leash);
                //scheduleAnim置为true
                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)
                //1.移除和leash相关联的窗口和surface(这个只在前面requiresEdgeExtension为true时逻辑中有涉及)
                //2.调整surface
                animatable.onAnimationLeashLost(t);
                //scheduleAnim置为true
                scheduleAnim = true;
            }
            return scheduleAnim;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 获取当前窗口的图层
      final SurfaceControl surface = animatable.getSurfaceControl();
      代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

          /**
           * @return The SurfaceControl for this container.
           *         The SurfaceControl must be valid if non-null.
           */
          @Override
          public SurfaceControl getSurfaceControl() {
              return mSurfaceControl;
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      直接返回一个SurfaceControl。

    • 获取当前窗口父窗口的图层
      代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

          /*
           * @return The SurfaceControl parent for this containers SurfaceControl.
           *         The SurfaceControl must be valid if non-null.
           */
          @Override
          public SurfaceControl getParentSurfaceControl() {
              final WindowContainer parent = getParent();
              if (parent == null) {
                  return null;
              }
              return parent.getSurfaceControl();
          }
          
         @Override
         final protected WindowContainer getParent() {
             return mParent;
         }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      先获取当前窗口的父窗口,在获取父窗口的SurfaceControl。

    • 获取动画图层
      代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

      @Override
          public SurfaceControl getAnimationLeash() {
              return mAnimationLeash;
          }
      
      • 1
      • 2
      • 3
      • 4

      mAnimationLeash是前面SurfaceAnimator的startAnimation方法中的mAnimatable.onAnimationLeashCreated(t, mLeash);,把mLeash赋值给了mAnimationLeash,因此这个方法获取的是动画图层。

    • 当前窗口图层和其父窗口的图层重新建立父子关系
      t.reparent(surface, parent);
      桌面的SurfaceControl重新认DefaultTaskDsiplayArea的SurfaceControl为父。
      代码路径:frameworks/base/core/java/android/view/SurfaceControl.java

              /**
               * Re-parents a given layer to a new parent. Children inherit transform (position, scaling)
               * crop, visibility, and Z-ordering from their parents, as if the children were pixels within the
               * parent Surface.
               *
               * @param sc The SurfaceControl to reparent
               * @param newParent The new parent for the given control.
               * @return This Transaction
               */
              @NonNull
              public Transaction reparent(@NonNull SurfaceControl sc,
                      @Nullable SurfaceControl newParent) {
                  //检查传入的SurfaceControl对象是否满足某些预设条件
                  checkPreconditions(sc);
                  long otherObject = 0;
                  if (newParent != null) {
                  	//检查新父对象是否被释放。如果已经被释放,那么它会抛出异常。
                      newParent.checkNotReleased();
                      //新父对象不为null且未被释放,那么将新父对象的Native对象赋值给otherObject。
                      otherObject = newParent.mNativeObject;
                  }
                  //传入了三个参数:1.当前对象的Native对象 2.被重新设置父对象的SurfaceControl的Native对象 3.新父对象的Native对象。
                  //用于实现重新设置父对象的具体操作。
                  nativeReparent(mNativeObject, sc.mNativeObject, otherObject);
                  //把被重新设置父对象的SurfaceControl和新父对象存储到mReparentedSurfaces这个map中。
                  mReparentedSurfaces.put(sc, newParent);
                  return this;
              }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28

      前面说过reparent方法中通过mReparentedSurfaces这个ArrayMap临时存储父子关系,key值存储SurfaceControl对象,value为其父SurfaceControl对象(当前窗口的父窗口的SurfaceControl,即DefaultTaskDsiplayArea的SurfaceControl)
      此时leash还没有被释放,DefaultTaskDsiplayArea的SurfaceControl有两个儿子SurfaceControl,(以桌面为例)关系如下图所示:
      在这里插入图片描述

      此时leash逐渐发现不对劲,但是假装不知道
      假如我们后面不执行移除leash图层的操作,那么这个图层一直会保持这个状态挂在DefaultTaskDsiplayArea上和桌面Task共享父亲。

    • 移除动画图层
      t.remove(leash);

              /**
               * Equivalent to reparent with a null parent, in that it removes
               * the SurfaceControl from the scene, but it also releases
               * the local resources (by calling {@link SurfaceControl#release})
               * after this method returns, {@link SurfaceControl#isValid} will return
               * false for the argument.
               *
               * @param sc The surface to remove and release.
               * @return This transaction
               * @hide
               */
              @NonNull
              public Transaction remove(@NonNull SurfaceControl sc) {
                  reparent(sc, null);
                  sc.release();
                  return this;
              }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      同样调用了reparent方法,先把需要remove的图层的父图层置空,然后释放。
      过程如下所示:
      在这里插入图片描述
      leash:原来我才是多余的那个,悠悠苍天,何薄于我!

    • 移除和leash相关联的窗口和surface并调整surface
      animatable.onAnimationLeashLost(t);
      代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

          @Override
          public void onAnimationLeashLost(Transaction t) {
              mLastLayer = -1;
              //调用mWmService中的mSurfaceAnimationRunner对象的onAnimationLeashLost方法
              //用于移除和leash相关联的窗口,这个只在前面requiresEdgeExtension为true时逻辑中有涉及
              mWmService.mSurfaceAnimationRunner.onAnimationLeashLost(mAnimationLeash, t);
              //mAnimationLeash置为空
              mAnimationLeash = null;
              mNeedsZBoost = false;
              //调整其所有child的z-order
              reassignLayer(t);
              //更新Surface位置
              updateSurfacePosition(t);
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      其中mWmService.mSurfaceAnimationRunner.onAnimationLeashLost(mAnimationLeash, t);mAnimationLeash前面说过就是动画图层。这个只在前面SurfaceAnimationRunner的startAnimation方法中requiresEdgeExtensiontrue时逻辑中有涉及,其为true时才会操作mEdgeExtensions这个ArrayList,这里不讨论。

    协调动画显示

    在SurfaceAnimator.reset()方法最后调用了mService.scheduleAnimationLocked();
    代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

        void scheduleAnimationLocked() {
            mAnimator.scheduleAnimation();
        }
    
        void scheduleAnimation() {
            if (!mAnimationFrameCallbackScheduled) {
                //mAnimationFrameCallbackScheduled 设置为 true,表示动画帧回调已经安排
                mAnimationFrameCallbackScheduled = true;
                //每一帧被绘制时,回调mAnimationFrameCallback
                mChoreographer.postFrameCallback(mAnimationFrameCallback);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这个方法的主要作用是确保动画帧回调被正确地安排,以便在每一帧绘制时执行,可以确保动画在每一帧都被调用,从而平滑地更新和显示动画。

    处理和响应动画完成的逻辑

    回到SurfaceAnimator.getFinishedCallback中匿名的onAnimationFinished方法中有调用staticAnimationFinishedCallback.onAnimationFinished(type, anim);处理和响应动画完成的逻辑。

    这里的staticAnimationFinishedCallback也是在SurfaceAnimator构造方法中初始化的

      SurfaceAnimator(Animatable animatable,
               @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback,
               WindowManagerService service) {
           mAnimatable = animatable;
           mService = service;
           mStaticAnimationFinishedCallback = staticAnimationFinishedCallback;
           mInnerAnimationFinishedCallback = getFinishedCallback(staticAnimationFinishedCallback);
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在WindowContainer构造方法中初始化mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);,因此staticAnimationFinishedCallback.onAnimationFinished对应的就是WindowContainer.onAnimationFinished方法

    代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

        /**
         * Called when an animation has finished running.
         */
    		protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
    		       //主要用于 清空 mSurfaceAnimationSources 列表
    		       doAnimationFinished(type, anim);
    		       //WindowManagerService中实现onAnimationFinished()
    		       //用于唤醒所有等待mGlobalLock对象的线程,确保多个线程能够正确地执行任务
    		       mWmService.onAnimationFinished();
    		       //将 mNeedsZBoost 设置为 false,表示不再需要Z轴增强
    		       mNeedsZBoost = false;
    		   }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这个里面又调用了另一个doAnimationFinished(type, anim);

    		private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
    	        for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) {
    	            //mSurfaceAnimationSources中每个容器,做对应的onAnimationFinished
    	            mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);
    	        }
    	        //清除动画源列表
    	        mSurfaceAnimationSources.clear();
    	        if (mDisplayContent != null) {
    		        //调用DisplayContent的onWindowAnimationFinished方法
    		        //从当前源码上看,主要是针对输入法相关做了一些操作
    	            mDisplayContent.onWindowAnimationFinished(this, type);
    	        }
    	    }
    
    		
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    WindowContainer.cancelAnimation方法中调用的doAnimationFinished也是这个方法。

    我们这里mSurfaceAnimationSources是保存的是需要做动画的ActivityRecord,即桌面ActivityRecord和启动应用的ActivityRecord。
    mSurfaceAnimationSources的值是在前面系统侧动画启动流程中WindowContainer.applyAnimationUnchecked方法中添加的。
    mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);调用了不同容器onAnimationFinished方法,在ActivityRecord和WindowState中都重写了这个方法。我们这里是远程动画,主要调用的就是ActivityRecord中重写的onAnimationFinished方法。

    代码路径:frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java

        @Override
        protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
            super.onAnimationFinished(type, anim);
    
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
            //更新标志位
            mTransit = TRANSIT_OLD_UNSET;
            mTransitFlags = 0;
           
            //更新应用的布局变化
            setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
                    "ActivityRecord");
    
            //清除缩略图
            clearThumbnail();
            //更新应用的可见性状态
            setClientVisible(isVisible() || mVisibleRequested);
    
            getDisplayContent().computeImeTargetIfNeeded(this);
    
            ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s"
                    + ": reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
                    this, reportedVisible, okToDisplay(), okToAnimate(),
                    isStartingWindowDisplayed());
    
            // clean up thumbnail window
            if (mThumbnail != null) {
                mThumbnail.destroy();
                mThumbnail = null;
            }
    
            // WindowState.onExitAnimationDone might modify the children list, so make a copy and then
            // traverse the copy.
            //通知子窗口动画结束
            final ArrayList<WindowState> children = new ArrayList<>(mChildren);
            children.forEach(WindowState::onExitAnimationDone);
            // The starting window could transfer to another activity after app transition started, in
            // that case the latest top activity might not receive exit animation done callback if the
            // starting window didn't applied exit animation success. Notify animation finish to the
            // starting window if needed.
            //通知启动窗口动画结束
            if (task != null && startingMoved) {
                final WindowState transferredStarting = task.getWindow(w ->
                        w.mAttrs.type == TYPE_APPLICATION_STARTING);
                if (transferredStarting != null && transferredStarting.mAnimatingExit
                        && !transferredStarting.isSelfAnimating(0 /* flags */,
                        ANIMATION_TYPE_WINDOW_ANIMATION)) {
                    transferredStarting.onExitAnimationDone();
                }
            }
            //通知应用过渡动画结束
            getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
            //协调动画显示
            scheduleAnimation();
    
            // Schedule to handle the stopping and finishing activities which the animation is done
            // because the activities which were animating have not been stopped yet.
            // 如果需要,调度处理停止和结束活动的任务。这是必要的,因为正在动画的活动可能还没有被停止。
            mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    协调动画显示

    和前面在SurfaceAnimator.reset()方法最后调用了mService.scheduleAnimationLocked();相似,
    这里我们调用的scheduleAnimation();
    代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

        /**
         * Trigger a call to prepareSurfaces from the animation thread, such that pending transactions
         * will be applied.
         */
        void scheduleAnimation() {
            mWmService.scheduleAnimationLocked();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

        void scheduleAnimationLocked() {
            mAnimator.scheduleAnimation();
        }
    
    
    • 1
    • 2
    • 3
    • 4

    最终调用到了WindowAnimator.scheduleAnimation()
    代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowAnimator.java

        void scheduleAnimation() {
            if (!mAnimationFrameCallbackScheduled) {
                //mAnimationFrameCallbackScheduled 设置为 true,表示动画帧回调已经安排
                mAnimationFrameCallbackScheduled = true;
                //每一帧被绘制时,回调mAnimationFrameCallback
                mChoreographer.postFrameCallback(mAnimationFrameCallback);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这个方法的主要作用是确保动画帧回调被正确地安排,以便在每一帧绘制时执行,可以确保动画在每一帧都被调用,从而平滑地更新和显示动画。

  • 相关阅读:
    C语言被创造出来的基础是什么?它的主要结构是什么?
    深度学习入门——基于TensorFlow的鸢尾花分类实现(TensorFlow_GPU版本安装、实现)
    技术知识点汇总-20220720
    B043-JavascriptDOM&Ajax
    pico学习进程记录已经开发项目
    2345安全卫士卸载不了怎么办?
    Docker——Windows版本Docker安装
    【Go语言】(一)环境搭建与了解VScode工具
    迅为RK3568开发板ubuntu图形界面开机免密自登录
    要做CMMI认证?什么是CMMI资质认证?
  • 原文地址:https://blog.csdn.net/yimelancholy/article/details/136317809