AndroidS对TransitionOldType的重构

1,061 阅读3分钟

Google关键提交

Replace old app transition type to new transition type (1/N)

Replace old app transition type to new transition type (2/N)

Replace old app transition type to new transition type (3/N)

从提交说明可以看出这次重构主要做了三件事:

  1. 将旧的TransitionType注更为TransitionOldType
  2. 增加AppTransitionController#getTransitCompatType方法用于确定apptransition类型
  3. 移除了大量old transition逻辑

原来的TransitionType注解变更为TransitionOldType

  • core/java/android/view/WindowManager.java
  • packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java

3fcc9ce0f7831252bdf2d9f0a21f1bc0.png

重新定义了新的TransitionType

0d89ef01f250736f803c3f26498ce1fd.png

TransitionType参数全部变更为TransitionOldType

core/java/android/view/RemoteAnimationDefinition.java
core/java/android/window/TransitionInfo.java
libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
services/core/java/com/android/server/wm/AccessibilityController.java
services/core/java/com/android/server/wm/AppTransitionController.java
...

修改了prepareAppTransition的调用逻辑

   // services/core/java/com/android/server/wm/AppTransition.java
   private final ArrayList<Integer> mNextAppTransitionRequests = new ArrayList<>();
   
    boolean prepareAppTransition(@TransitionType int transit, @TransitionFlags int flags) {
        if (mService.mAtmService.getTransitionController().getTransitionPlayer() != null) {
            return false;
        }
        mNextAppTransitionRequests.add(transit);
        mNextAppTransitionFlags |= flags;
        updateBooster();
        removeAppTransitionTimeoutCallbacks();
        mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable,
                APP_TRANSITION_TIMEOUT_MS);
        return prepare();
    }
  

对比AndroidR源码,不再使用之前的mNextAppTransition变量直接指定下一次的transition类型,

而是替换为将transition类型添加到mNextAppTransitionRequests列表

增加getTransitCompatType方法确定transit类型

// services/core/java/com/android/server/wm/AppTransitionController.java
    void handleAppTransitionReady() {
        final @TransitionOldType int transit = getTransitCompatType(
          mDisplayContent.mAppTransition,
          mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
          mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
          mDisplayContent.mSkipAppTransitionAnimation);
    }

    int goodToGo(@TransitionOldType int transit, ActivityRecord topOpeningApp) {
        mNextAppTransitionFlags = 0;
        mNextAppTransitionRequests.clear();
      ...
    }

在handleAppTransitionReady中使用getTransitCompatType方法获取将要执行的transit类型;

在goodToGo方法即app transition将要执行前清除mNextAppTransitionRequests列表。

    // services/core/java/com/android/server/wm/AppTransitionController.java
    /**
     * Get old transit type based on the current transit requests.
     *
     * @param appTransition {@link AppTransition} for managing app transition state.
     * @param openingApps {@link ActivityRecord}s which are becoming visible.
     * @param closingApps {@link ActivityRecord}s which are becoming invisible.
     * @param wallpaperTarget If non-null, this is the currently visible window that is associated
     *                        with the wallpaper.
     * @param oldWallpaper The currently visible window that is associated with the wallpaper in
     *                     case we are transitioning from an activity with a wallpaper to one
     *                     without. Otherwise null.
     */
    static @TransitionOldType int getTransitCompatType(AppTransition appTransition,
            ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
            @Nullable WindowState wallpaperTarget, @Nullable WindowState oldWallpaper,
            boolean skipAppTransitionAnimation) {

        // 1.确定openning app和closing app中是否有能作为wallpapertarget的
        final boolean openingAppHasWallpaper = canBeWallpaperTarget(openingApps)
                && wallpaperTarget != null;
        final boolean closingAppHasWallpaper = canBeWallpaperTarget(closingApps)
                && wallpaperTarget != null;

        // 2. 锁屏动画享有最高优先级
        switch (appTransition.getKeyguardTransition()) {
            case TRANSIT_KEYGUARD_GOING_AWAY:
                return openingAppHasWallpaper ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
                        : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
            case TRANSIT_KEYGUARD_OCCLUDE:
                // When there is a closing app, the keyguard has already been occluded by an
                // activity, and another activity has started on top of that activity, so normal
                // app transition animation should be used.
                return closingApps.isEmpty() ? TRANSIT_OLD_KEYGUARD_OCCLUDE
                        : TRANSIT_OLD_ACTIVITY_OPEN;
            case TRANSIT_KEYGUARD_UNOCCLUDE:
                return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
        }

        // 3. 如果dc设置了mSkipAppTransitionAnimation,将跳过动画
        if (skipAppTransitionAnimation) {
            return WindowManager.TRANSIT_OLD_UNSET;
        }
        final @TransitionFlags int flags = appTransition.getTransitFlags();
        final @TransitionType int firstTransit = appTransition.getFirstAppTransition();

        // 4. 处理几种特殊场景
        if (appTransition.containsTransitRequest(TRANSIT_CHANGE)) {
            return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
        }
        if ((flags & TRANSIT_FLAG_APP_CRASHED) != 0) {
            return TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
        }
        if (firstTransit == TRANSIT_NONE) {
            return TRANSIT_OLD_NONE;
        }

        // 5. 在某些场景下我们open/close新的activity或task
        // 但实际上,只有在现有activity之上的一个半透明活动才是打开/关闭
        // 这种情况下,对半透明的app使用特殊动画
        if (isNormalTransit(firstTransit)) {
            boolean allOpeningVisible = true;
            boolean allTranslucentOpeningApps = !openingApps.isEmpty();
            for (int i = openingApps.size() - 1; i >= 0; i--) {
                final ActivityRecord activity = openingApps.valueAt(i);
                if (!activity.isVisible()) {
                    allOpeningVisible = false;
                    if (activity.fillsParent()) {
                        allTranslucentOpeningApps = false;
                    }
                }
            }
            boolean allTranslucentClosingApps = !closingApps.isEmpty();
            for (int i = closingApps.size() - 1; i >= 0; i--) {
                if (closingApps.valueAt(i).fillsParent()) {
                    allTranslucentClosingApps = false;
                    break;
                }
            }

            if (allTranslucentClosingApps && allOpeningVisible) {
                return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
            }
            if (allTranslucentOpeningApps && closingApps.isEmpty()) {
                return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN;
            }
        }
        // 6.对WallPaperTarget场景做处理
        final ActivityRecord topOpeningApp = getTopApp(openingApps,
                false /* ignoreHidden */);
        final ActivityRecord topClosingApp = getTopApp(closingApps,
                true /* ignoreHidden */);

        if (closingAppHasWallpaper && openingAppHasWallpaper) {
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
            switch (firstTransit) {
                case TRANSIT_OPEN:
                case TRANSIT_TO_FRONT:
                    return TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
                case TRANSIT_CLOSE:
                case TRANSIT_TO_BACK:
                    return TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
            }
        } else if (oldWallpaper != null && !openingApps.isEmpty()
                && !openingApps.contains(oldWallpaper.mActivityRecord)
                && closingApps.contains(oldWallpaper.mActivityRecord)
                && topClosingApp == oldWallpaper.mActivityRecord) {
            // We are transitioning from an activity with a wallpaper to one without.
            return TRANSIT_OLD_WALLPAPER_CLOSE;
        } else if (wallpaperTarget != null && wallpaperTarget.isVisible()做
                && openingApps.contains(wallpaperTarget.mActivityRecord)
                && topOpeningApp == wallpaperTarget.mActivityRecord
                /* && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE */) {
            // We are transitioning from an activity without
            // a wallpaper to now showing the wallpaper
            return TRANSIT_OLD_WALLPAPER_OPEN;
        }
        
        // 7.处理一般场景,决定使用TASK动画还是ACTIVITY动画
        final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
                openingApps, closingApps, true /* visible */);
        final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
                openingApps, closingApps, false /* visible */);
        final boolean isActivityOpening = !openingWcs.isEmpty()
                && openingWcs.valueAt(0).asActivityRecord() != null;
        final boolean isActivityClosing = !closingWcs.isEmpty()
                && closingWcs.valueAt(0).asActivityRecord() != null;
        final boolean isTaskOpening = !openingWcs.isEmpty() && !isActivityOpening;
        final boolean isTaskClosing = !closingWcs.isEmpty() && !isActivityClosing;

        if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && isTaskOpening) {
            return TRANSIT_OLD_TASK_TO_FRONT;
        }
        if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && isTaskClosing) {
            return TRANSIT_OLD_TASK_TO_BACK;
        }
        if (appTransition.containsTransitRequest(TRANSIT_OPEN)) {
            if (isTaskOpening) {
                return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0
                        ? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN;
            }
            if (isActivityOpening) {
                return TRANSIT_OLD_ACTIVITY_OPEN;
            }
        }
        if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) {
            if (isTaskClosing) {
                return TRANSIT_OLD_TASK_CLOSE;
            }
            if (isActivityClosing) {
                for (int i = closingApps.size() - 1; i >= 0; i--) {
                    if (closingApps.valueAt(i).visibleIgnoringKeyguard) {
                        return TRANSIT_OLD_ACTIVITY_CLOSE;
                    }
                }
                // Skip close activity transition since no closing app can be visible
                return WindowManager.TRANSIT_OLD_UNSET;
            }
        }
        if (appTransition.containsTransitRequest(TRANSIT_RELAUNCH)
                && !openingWcs.isEmpty() && !openingApps.isEmpty()) {
            return TRANSIT_OLD_ACTIVITY_RELAUNCH;
        }
        return TRANSIT_OLD_NONE;
    }

getTransitCompatType将会扫描在prepare阶段设置的transit列表(mNextAppTransitionRequests), 最终决定app tranisition的类型,可以看到最终确定的transit都还是TransitionOldType类型的 - -!

总结getTransitionCompatType主要做了以下工作:

  1. 确定openning app和closing app中是否有能作为WallpaperTarget的, WallpaperTarget是指想要让壁纸显示在其背后的窗口。
  2. 锁屏动画享有最高优先级,如果transition请求列表中包含锁屏动画类型,将直接返回keyguard transition,这其中包括锁屏解锁(keyguardGoingAway)动画、锁屏被覆盖(occlude)、取消覆盖(unocclude)动画
  3. 如果没有锁屏动画并且dc设置了mSkipAppTransitionAnimation,将跳过动画。 跳过动画的场景是:假设没有设置锁屏,启动了一个activity后灭屏再亮屏,不需要app transition
  4. 处理几种特殊的flag或transition请求
  5. 处理半透明activity场景
  6. 处理WallPaperTarget场景
  7. 处理一般场景,决定使用TASK动画还是ACTIVITY动画

AndroidS AppTransition启动流程图

378f8cd1e2499c4c84bdee4008a3233e.png