Android 12系统源码_窗口动画(二)应用程序间的切换动画

avatar
作者
猴君
阅读量:0

前言

在 Android 系统中,系统主要是通过AppTransitionController和AppTransition这两个类是用于管理应用程序间切换动画的重要类。

一、简介

1、AppTransitionController

AppTransitionController 是一个系统级别的类,用于管理应用程序间切换时的动画效果。其作用包括:

  • 动画类型管理:控制不同应用切换时的动画类型,如窗口动画、应用切换动画等。
  • 动画资源管理:管理和加载与切换动画相关的资源,如动画文件、持续时间等。
  • 调度动画:决定何时开始和结束应用程序切换的动画。

2、AppTransition

AppTransition 是 AppTransitionController 的一部分,负责实际执行应用切换动画。主要功能包括:

  • 动画执行:根据 AppTransitionController 的设置,执行应用程序间的切换动画。
  • 动画参数设置:配置和管理动画的参数,例如动画类型、持续时间、插值器等。
  • 状态监控:监控动画执行的状态,以便在动画完成或被取消时进行适当的处理。

3、使用场景和重要性

这两个类在 Android 系统中的重要性体现在以下几个方面:

  • 用户体验:应用程序切换时的流畅动画可以显著提升用户体验,这些动画通过 AppTransitionController 和 AppTransition 进行管理和优化。
  • 系统一致性:Android 系统通过这些类确保应用程序切换时的动画表现一致性,使整个系统看起来更加统一。
  • 定制性:开发者可以通过这些类定制应用切换时的动画效果,以满足特定应用或设备的需求。

二、对象的创建

1、AppTransition和AppTransitionController实例对象的创建。

AppTransition和AppTransitionController实例对象都是在DisplayContent对象的构造方法中被创建的。

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>         implements WindowManagerPolicy.DisplayContentInfo {               DisplayContent(Display display, RootWindowContainer root) {         super(root.mWindowManager);                ...代码省略...         mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);         mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);         mAppTransition.registerListenerLocked(mFixedRotationTransitionListener);         mAppTransitionController = new AppTransitionController(mWmService, this);         ...代码省略...      }  } 

2、关于DisplayContent对象

我们在Android 12系统源码_窗口管理(七)DisplayContent简介这篇文章有讲过,DisplayContent 用于管理屏幕,一块DisplayContent 对象实例代表一个屏幕设备,这样有多个屏幕的设备就可以创建多个DisplayContent 对象,虽然多数设备只有一个显示屏,但它们同样可以创建多个 DisplayContent 对象,如投屏的时候,可以创建一个虚拟的DisplayContent,DisplayContent会根据窗口的显示位置将窗口进行分组,隶属于同一个DisplayContent的窗口将会显示在同一个屏幕中,每一个DisplayContent都对应一个唯一的ID,在添加窗口时可以通过指定这个ID决定其将被显示在对应的个屏幕中。DisplayContent是一个非常具有隔离性的一个概念。处于不同DisplayContent的两个窗口在布局、显示顺序以及动画处理上不会产生任何耦合,而如果我们想让不同DisplayContent的窗口切换动画不同,就可以通过定制该DisplayContent对应的AppTransition和AppTransitionController来实现。

三、AppTransition

来看下AppTransition的相关的源码。

frameworks/base/services/core/java/com/android/server/wm/AppTransition.java

public class AppTransition implements Dump {      static final int DEFAULT_APP_TRANSITION_DURATION = 336;//应用默认专场动画的执行时间          private final Context mContext;     private final WindowManagerService mService;     private final DisplayContent mDisplayContent;          private final TransitionAnimation mTransitionAnimation;//应用间的切换动画      private final int mConfigShortAnimTime;     private final Interpolator mDecelerateInterpolator;     private final Interpolator mThumbnailFadeInInterpolator;     private final Interpolator mThumbnailFadeOutInterpolator;     private final Interpolator mLinearOutSlowInInterpolator;     private final Interpolator mFastOutLinearInInterpolator;     private final Interpolator mFastOutSlowInInterpolator;          private final int mClipRevealTranslationY;      private final boolean mGridLayoutRecentsEnabled;     private final boolean mLowRamRecentsEnabled;          private final int mDefaultWindowAnimationStyleResId;          private RemoteAnimationController mRemoteAnimationController;      final Handler mHandler;          AppTransition(Context context, WindowManagerService service, DisplayContent displayContent) {         mContext = context;         mService = service;         mHandler = new Handler(service.mH.getLooper());         mDisplayContent = displayContent;         mTransitionAnimation = new TransitionAnimation(context, DEBUG_ANIM, TAG);         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,                 com.android.internal.R.interpolator.linear_out_slow_in);         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,                 com.android.internal.R.interpolator.fast_out_linear_in);         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,                 com.android.internal.R.interpolator.fast_out_slow_in);         mConfigShortAnimTime = context.getResources().getInteger(                 com.android.internal.R.integer.config_shortAnimTime);         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,                 com.android.internal.R.interpolator.decelerate_cubic);         mThumbnailFadeInInterpolator = new Interpolator() {             @Override             public float getInterpolation(float input) {                 // Linear response for first fraction, then complete after that.                 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {                     return 0f;                 }                 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /                         (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);                 return mFastOutLinearInInterpolator.getInterpolation(t);             }         };         mThumbnailFadeOutInterpolator = new Interpolator() {             @Override             public float getInterpolation(float input) {                 // Linear response for first fraction, then complete after that.                 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {                     float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;                     return mLinearOutSlowInInterpolator.getInterpolation(t);                 }                 return 1f;             }         };         mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP                 * mContext.getResources().getDisplayMetrics().density);         mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);         mLowRamRecentsEnabled = ActivityManager.isLowRamDeviceStatic();          final TypedArray windowStyle = mContext.getTheme().obtainStyledAttributes(                 com.android.internal.R.styleable.Window);         mDefaultWindowAnimationStyleResId = windowStyle.getResourceId(                 com.android.internal.R.styleable.Window_windowAnimationStyle, 0);         windowStyle.recycle();     }          /**      *      * @param lp 窗口参数      * @param transit 窗口切换动画类型      * @param enter 是否是进入      * @param frame 如果是进入动画,则是动画结束后窗口的位置,如果是退出动画,则是动画开始时窗口的位置      * @return 返回的就是最终的窗口转换动画      */     Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,             int orientation, Rect frame, Rect displayFrame, Rect insets,             @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,             boolean freeform, WindowContainer container) {          if (mNextAppTransitionOverrideRequested                 && (container.canCustomizeAppTransition() || mOverrideTaskTransition)) {             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;         }          Animation a;         if (isKeyguardGoingAwayTransitOld(transit) && enter) {             a = mTransitionAnimation.loadKeyguardExitAnimation(mNextAppTransitionFlags,                     transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);         } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {             a = null;         } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE && !enter) {             a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();         } else if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) {             a = null;         } else if (isVoiceInteraction && (transit == TRANSIT_OLD_ACTIVITY_OPEN                 || transit == TRANSIT_OLD_TASK_OPEN                 || transit == TRANSIT_OLD_TASK_TO_FRONT)) {             a = mTransitionAnimation.loadVoiceActivityOpenAnimation(enter);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,                     appTransitionOldToString(transit), enter, Debug.getCallers(3));         } else if (isVoiceInteraction && (transit == TRANSIT_OLD_ACTIVITY_CLOSE                 || transit == TRANSIT_OLD_TASK_CLOSE                 || transit == TRANSIT_OLD_TASK_TO_BACK)) {             a = mTransitionAnimation.loadVoiceActivityExitAnimation(enter);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,                     appTransitionOldToString(transit), enter, Debug.getCallers(3));         } else if (transit == TRANSIT_OLD_ACTIVITY_RELAUNCH) {             a = mTransitionAnimation.createRelaunchAnimation(frame, insets,                     mDefaultNextAppTransitionAnimationSpec != null                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s transit=%s Callers=%s", a,                     appTransitionOldToString(transit), Debug.getCallers(3));         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {             a = mTransitionAnimation.loadAppTransitionAnimation(mNextAppTransitionPackage,                     enter ? mNextAppTransitionEnter : mNextAppTransitionExit);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "                             + "isEntrance=%b Callers=%s",                     a, appTransitionOldToString(transit), enter, Debug.getCallers(3));         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {             a = mTransitionAnimation.loadAppTransitionAnimation(                     mNextAppTransitionPackage, mNextAppTransitionInPlace);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE "                             + "transit=%s Callers=%s",                     a, appTransitionOldToString(transit), Debug.getCallers(3));         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {             a = mTransitionAnimation.createClipRevealAnimationLockedCompat(                     transit, enter, frame, displayFrame,                     mDefaultNextAppTransitionAnimationSpec != null                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL "                             + "transit=%s Callers=%s",                     a, appTransitionOldToString(transit), Debug.getCallers(3));         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {             a = mTransitionAnimation.createScaleUpAnimationLockedCompat(transit, enter, frame,                     mDefaultNextAppTransitionAnimationSpec != null                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s "                             + "isEntrance=%s Callers=%s",                     a, appTransitionOldToString(transit), enter, Debug.getCallers(3));         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {             mNextAppTransitionScaleUp =                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);             final HardwareBuffer thumbnailHeader = getAppTransitionThumbnailHeader(container);             a = mTransitionAnimation.createThumbnailEnterExitAnimationLockedCompat(enter,                     mNextAppTransitionScaleUp, frame, transit, thumbnailHeader,                     mDefaultNextAppTransitionAnimationSpec != null                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "                             + "Callers=%s",                     a,  mNextAppTransitionScaleUp                             ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN",                     appTransitionOldToString(transit), enter, Debug.getCallers(3));         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {             mNextAppTransitionScaleUp =                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);             AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(                     container.hashCode());             a = mTransitionAnimation.createAspectScaledThumbnailEnterExitAnimationLocked(enter,                     mNextAppTransitionScaleUp, orientation, transit, frame, insets, surfaceInsets,                     stableInsets, freeform, spec != null ? spec.rect : null,                     mDefaultNextAppTransitionAnimationSpec != null                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "                             + "Callers=%s",                     a, mNextAppTransitionScaleUp                             ? "ANIM_THUMBNAIL_ASPECT_SCALE_UP"                         : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN",                     appTransitionOldToString(transit), enter, Debug.getCallers(3));         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {             a = mTransitionAnimation.loadCrossProfileAppEnterAnimation();             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "                             + "anim=%s transit=%s isEntrance=true Callers=%s",                     a, appTransitionOldToString(transit), Debug.getCallers(3));         } else if (isChangeTransitOld(transit)) {             // In the absence of a specific adapter, we just want to keep everything stationary.             a = new AlphaAnimation(1.f, 1.f);             a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",                     a, appTransitionOldToString(transit), enter, Debug.getCallers(3));         } else {             int animAttr = 0;             switch (transit) {                 case TRANSIT_OLD_ACTIVITY_OPEN:                 case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN:                     animAttr = enter                             ? WindowAnimation_activityOpenEnterAnimation                             : WindowAnimation_activityOpenExitAnimation;                     break;                 case TRANSIT_OLD_ACTIVITY_CLOSE:                 case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE:                     animAttr = enter                             ? WindowAnimation_activityCloseEnterAnimation                             : WindowAnimation_activityCloseExitAnimation;                     break;                 case TRANSIT_OLD_TASK_OPEN:                     animAttr = enter                             ? WindowAnimation_taskOpenEnterAnimation                             : WindowAnimation_taskOpenExitAnimation;                     break;                 case TRANSIT_OLD_TASK_CLOSE:                     animAttr = enter                             ? WindowAnimation_taskCloseEnterAnimation                             : WindowAnimation_taskCloseExitAnimation;                     break;                 case TRANSIT_OLD_TASK_TO_FRONT:                     animAttr = enter                             ? WindowAnimation_taskToFrontEnterAnimation                             : WindowAnimation_taskToFrontExitAnimation;                     break;                 case TRANSIT_OLD_TASK_TO_BACK:                     animAttr = enter                             ? WindowAnimation_taskToBackEnterAnimation                             : WindowAnimation_taskToBackExitAnimation;                     break;                 case TRANSIT_OLD_WALLPAPER_OPEN:                     animAttr = enter                             ? WindowAnimation_wallpaperOpenEnterAnimation                             : WindowAnimation_wallpaperOpenExitAnimation;                     break;                 case TRANSIT_OLD_WALLPAPER_CLOSE:                     animAttr = enter                             ? WindowAnimation_wallpaperCloseEnterAnimation                             : WindowAnimation_wallpaperCloseExitAnimation;                     break;                 case TRANSIT_OLD_WALLPAPER_INTRA_OPEN:                     animAttr = enter                             ? WindowAnimation_wallpaperIntraOpenEnterAnimation                             : WindowAnimation_wallpaperIntraOpenExitAnimation;                     break;                 case TRANSIT_OLD_WALLPAPER_INTRA_CLOSE:                     animAttr = enter                             ? WindowAnimation_wallpaperIntraCloseEnterAnimation                             : WindowAnimation_wallpaperIntraCloseExitAnimation;                     break;                 case TRANSIT_OLD_TASK_OPEN_BEHIND:                     animAttr = enter                             ? WindowAnimation_launchTaskBehindSourceAnimation                             : WindowAnimation_launchTaskBehindTargetAnimation;                     break;                 // TODO(b/189386466): Use activity transition as the fallback. Investigate if we                 //  need new TaskFragment transition.                 case TRANSIT_OLD_TASK_FRAGMENT_OPEN:                     animAttr = enter                             ? WindowAnimation_activityOpenEnterAnimation                             : WindowAnimation_activityOpenExitAnimation;                     break;                 // TODO(b/189386466): Use activity transition as the fallback. Investigate if we                 //  need new TaskFragment transition.                 case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:                     animAttr = enter                             ? WindowAnimation_activityCloseEnterAnimation                             : WindowAnimation_activityCloseExitAnimation;                     break;             }             //动画             a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,                     "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "                             + "Callers=%s",                     a, animAttr, appTransitionOldToString(transit), enter,                     Debug.getCallers(3));         }         setAppTransitionFinishedCallbackIfNeeded(a);         return a;     }          /**      *      * @param lp 窗口参数      * @param animAttr 动画资源id      * @param transit 窗口切换动画类型      * @return Animation动画      */     @Nullable     Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {         return mTransitionAnimation.loadAnimationAttr(lp, animAttr, transit);     }  } 

frameworks/base/core/java/com/android/internal/policy/TransitionAnimation.java

public class TransitionAnimation {     @Nullable     public Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {         int resId = Resources.ID_NULL;         Context context = mContext;         if (animAttr >= 0) {             AttributeCache.Entry ent = getCachedAnimations(lp);             if (ent != null) {                 context = ent.context;                 resId = ent.array.getResourceId(animAttr, 0);             }         }         resId = updateToTranslucentAnimIfNeeded(resId, transit);         if (ResourceId.isValid(resId)) {             return loadAnimationSafely(context, resId, mTag);         }         return null;     }          private static int updateToTranslucentAnimIfNeeded(int anim, @TransitionOldType int transit) {         if (transit == TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN                 && anim == R.anim.activity_open_enter) {             return R.anim.activity_translucent_open_enter;         }         if (transit == TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE                 && anim == R.anim.activity_close_exit) {             return R.anim.activity_translucent_close_exit;         }         return anim;     }  } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!