通过Theme设置的动画
支持的动画属性
在AndroidManifest.xml中通过设置style的形式指定动画资源,比如有:activityOpenEnterAnimation
framework中定义动画的属性文件为:base/core/res/res/values/attrs.xml 其中 <declare-styleable name="WindowAnimation">
默认动画
对应的默认动画资源文件:base/core/res/res/values/styles.xml 其中 <style name="Animation.Activity">, 完整定义:
<!-- Standard animations for a full-screen window or activity. -->
<style name="Animation.Activity">
<item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
<item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
<item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
<item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
<item name="dreamActivityCloseExitAnimation">@anim/dream_activity_close_exit</item>
<item name="dreamActivityOpenEnterAnimation">@anim/dream_activity_open_enter</item>
<item name="dreamActivityOpenExitAnimation">@anim/dream_activity_open_exit</item>
<item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
<item name="taskOpenExitAnimation">@anim/task_open_exit</item>
<item name="launchTaskBehindTargetAnimation">@anim/launch_task_behind_target</item>
<item name="launchTaskBehindSourceAnimation">@anim/launch_task_behind_source</item>
<item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
<item name="taskCloseExitAnimation">@anim/task_close_exit</item>
<item name="taskToFrontEnterAnimation">@anim/task_open_enter</item>
<item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
<item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
<item name="taskToBackExitAnimation">@anim/task_close_exit</item>
<item name="wallpaperOpenEnterAnimation">@anim/wallpaper_open_enter</item>
<item name="wallpaperOpenExitAnimation">@anim/wallpaper_open_exit</item>
<item name="wallpaperCloseEnterAnimation">@anim/wallpaper_close_enter</item>
<item name="wallpaperCloseExitAnimation">@anim/wallpaper_close_exit</item>
<item name="wallpaperIntraOpenEnterAnimation">@anim/wallpaper_intra_open_enter</item>
<item name="wallpaperIntraOpenExitAnimation">@anim/wallpaper_intra_open_exit</item>
<item name="wallpaperIntraCloseEnterAnimation">@anim/wallpaper_intra_close_enter</item>
<item name="wallpaperIntraCloseExitAnimation">@anim/wallpaper_intra_close_exit</item>
<item name="fragmentOpenEnterAnimation">@animator/fragment_open_enter</item>
<item name="fragmentOpenExitAnimation">@animator/fragment_open_exit</item>
<item name="fragmentCloseEnterAnimation">@animator/fragment_close_enter</item>
<item name="fragmentCloseExitAnimation">@animator/fragment_close_exit</item>
<item name="fragmentFadeEnterAnimation">@animator/fragment_fade_enter</item>
<item name="fragmentFadeExitAnimation">@animator/fragment_fade_exit</item>
</style>
每种动画类型都定义了默认的动画资源
Overlay
厂商一般都会通过定义overlay apk来覆盖默认的动画资源
动画资源的加载
只有activity动画没有被override或者禁用的时候,framework才会加载app自定义的动画,动画的加载位于 base/services/core/java/com/android/server/wm/AppTransition.java 的loadAnimation函数
加载条件
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) {
//1
final boolean canCustomizeAppTransition = container.canCustomizeAppTransition();
if (mNextAppTransitionOverrideRequested) {
if (canCustomizeAppTransition || mOverrideTaskTransition) {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
}
}
//2
if(...) {
...
} else {
//3
int animAttr = mapOpenCloseTransitTypes(transit, enter);
//4
a = animAttr == 0 ? null : (canCustomizeAppTransition
? loadAnimationAttr(lp, animAttr, transit)
: mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit));
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
+ " canCustomizeAppTransition=%b Callers=%s",
a, animAttr, appTransitionOldToString(transit), enter,
canCustomizeAppTransition, Debug.getCallers(3));
}canCustomizeAppTransition
关注点1:是否允许加载自定义动画
WindowContainer继承关系
WindowContainer定义为false
ActivityRecord定义为true
TaskFragment 条件为
@Override
boolean canCustomizeAppTransition() {
return isEmbedded() && matchParentBounds();
}当一个Activity作为任务栈的根Activity时, 在loadAnimation时发现传入的WindowContainer是Task, 根据上面的继承关系源自于TaskFragment.
全屏的Activity matchParentBounds() 总是为true, 接下来跟踪下 isEmbedded(), 也就是isEmbedded变量的来源
private Task(...) {
super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */);
}从源码发现在Task创建的时候传入false
结论:只要是任务栈里边的根Activity,在加载动画资源的时候不允许加载自定义动画
关注点2:这里会对一些override动画类型做判断,或者锁屏,语音窗口的特殊动画
关注点4:此处会检测canCustomizeAppTransition,如果不允许自定义动画,就会加载系统定义的默认动画
资源映射
mapOpenCloseTransitTypes
关注点3:假设关注点2的条件都不满足,这个时候准备加载Activity自定义动画,通过mapOpenCloseTransitTypes函数映射取出对应的动画类型,也就是AndroidManifest.xml中定义的 动画类型,如activityOpenEnterAnimation
private static int mapOpenCloseTransitTypes(int transit, boolean enter) {
int animAttr = 0;
switch (transit) {
case TRANSIT_OLD_ACTIVITY_OPEN:
case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN:
animAttr = enter
? WindowAnimation_activityOpenEnterAnimation
: WindowAnimation_activityOpenExitAnimation;
break;
...
}可能我们会好奇transit是怎么来的,这里再稍微深入分析一点
transit: 当前窗口的正在执行的动画类型根据loadAnimation调用栈,transit来源于base/services/core/java/com/android/server/wm/AppTransitionController.java
void handleAppTransitionReady() {
...
//Get old transit type based on the current transit requests.
@TransitionOldType final int transit = getTransitCompatType(
mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps,
mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers,
mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
...
try {
applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
animLp, voiceInteraction);
...
}getTransitCompatType: 根据当前窗口的app的请求获取不同的动画类型
本文只关注动画资源加载的逻辑,就不再深入研究不同的窗口动画类型之间的切换了
流程图
总结下是如何加载到自定义资源的
对于当前的窗口是否允许自定义动画流程图如下:
activity自定义资源解析
实现资源解析的类是 base/core/java/com/android/internal/policy/TransitionAnimation.java
/** Load animation by attribute Id from specific LayoutParams */
@Nullable
public Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
int resId = Resources.ID_NULL;
Context context = mContext;
if (animAttr >= 0) {
//1
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)) {
//2
return loadAnimationSafely(context, resId, mTag);
}
return null;
}总的来说:动画资源是通过读取WindowManager的LayoutParams.windowAnimations而来
关注点1:获取resId的时候,会判断一次window_type
private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
if (lp != null && lp.windowAnimations != 0) {
String packageName = lp.packageName != null ? lp.packageName : DEFAULT_PACKAGE;
int resId = getAnimationStyleResId(lp);
if ((resId & 0xFF000000) == 0x01000000) {
packageName = DEFAULT_PACKAGE;
}
return AttributeCache.instance().get(packageName, resId,
com.android.internal.R.styleable.WindowAnimation);
}
return null;
}如果窗口类型为 TYPE_APPLICATION_STARTING , 同样使用默认动画资源
public int getAnimationStyleResId(@NonNull LayoutParams lp) {
int resId = lp.windowAnimations;
if (lp.type == LayoutParams.TYPE_APPLICATION_STARTING) {
resId = mDefaultWindowAnimationStyleResId;
}
return resId;
}最后通过传入packageContext和resId获取Activity的动画资源
context: 如果是系统动画,那么就是默认的context, 如果是自定义动画资源,这个context在创建entry的时候创建,源码如下:
context = mContext.createPackageContextAsUser(packageName, 0,
new UserHandle(userId));关注点2:最后加载资源的类是 base/core/java/android/view/animation/AnimationUtils.java , 完成从xml到Animation的转换
通过ActivityOptions添加的动画
概述
传入自定义动画
val activityOptions = ActivityOptions.makeCustomAnimation(context, R.anim.slide_in, 0).setLaunchDisplayId(windowContext.displayId)
context.startActivityAsUser(intent, activityOptions.toBundle(), UserHandle.of(windowContext.userProfile.userId))Options内部将动画类型置为ANIM_CUSTOM , 可以理解为自定义动画
public static ActivityOptions makeCustomAnimation(Context context,
int enterResId, int exitResId, int backgroundColor, Handler handler,
OnAnimationStartedListener listener) {
ActivityOptions opts = new ActivityOptions();
opts.mPackageName = context.getPackageName();
opts.mAnimationType = ANIM_CUSTOM;
opts.mCustomEnterResId = enterResId;
opts.mCustomExitResId = exitResId;
opts.mCustomBackgroundColor = backgroundColor;
opts.setOnAnimationStartedListener(handler, listener);
return opts;
}所有的动画类型
其中ANIM_REMOTE_ANIMATION是一个远程动画,Launcher启动app时,app图表放大到全屏的过度动画就是这个类型, ActivityOptions多个静态方法对应了多种动画类型
/** @hide */
public static final int ANIM_UNDEFINED = -1;
/** @hide */
public static final int ANIM_NONE = 0;
/** @hide */
public static final int ANIM_CUSTOM = 1;
/** @hide */
public static final int ANIM_SCALE_UP = 2;
/** @hide */
public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
/** @hide */
public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
/** @hide */
public static final int ANIM_SCENE_TRANSITION = 5;
/** @hide */
public static final int ANIM_DEFAULT = 6;
/** @hide */
public static final int ANIM_LAUNCH_TASK_BEHIND = 7;
/** @hide */
public static final int ANIM_THUMBNAIL_ASPECT_SCALE_UP = 8;
/** @hide */
public static final int ANIM_THUMBNAIL_ASPECT_SCALE_DOWN = 9;
/** @hide */
public static final int ANIM_CUSTOM_IN_PLACE = 10;
/** @hide */
public static final int ANIM_CLIP_REVEAL = 11;
/** @hide */
public static final int ANIM_OPEN_CROSS_PROFILE_APPS = 12;
/** @hide */
public static final int ANIM_REMOTE_ANIMATION = 13;
/** @hide */
public static final int ANIM_FROM_STYLE = 14;窗口切换动画资源最终会由base/services/core/java/com/android/server/wm/AppTransition.java 类来处理
当Activity生命周期走到 onResume时,在ActivityRecord会触发以下逻辑
在AppTransition#overridePendingAppTransition中会保存自定动画的res id和app包名, 后边loadAnimation函数在加载资源的时候会使用
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
@ColorInt int backgroundColor, IRemoteCallback startedCallback,
IRemoteCallback endedCallback, boolean overrideTaskTransaction) {
if (canOverridePendingAppTransition()) {
clear();
mNextAppTransitionOverrideRequested = true;
mNextAppTransitionPackage = packageName;
mNextAppTransitionEnter = enterAnim;
mNextAppTransitionExit = exitAnim;
mNextAppTransitionBackgroundColor = backgroundColor;
postAnimationCallback();
mNextAppTransitionCallback = startedCallback;
mAnimationFinishedCallback = endedCallback;
mOverrideTaskTransition = overrideTaskTransaction;
}
}在自定义动画的时候这里发现一个条件: canOverridePendingAppTransition
private boolean canOverridePendingAppTransition() {
// Remote animations always take precedence
return isTransitionSet() && mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
}这个函数大意是,transitionSet不为空,前提是prepareAppTransition函数被调用,开始有一个prepare流程,另外一个条件就是动画类型非远程类型,有了远程动画之后就不会执行自定义动画
options参数
在启动Activity的时候可以传入option参数来指定进入和退出动画资源,自定义动画通常会这样:
ActivityOptions.makeCustomAnimation(context, anim_enter, anim_exit )根据applyOptionsAnimation的调用栈,我们可以发现 ActivityRecord对这个option做了缓存和解析
void applyOptionsAnimation() {
if (mPendingRemoteAnimation != null) {
//1
mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(
mPendingRemoteAnimation);
mTransitionController.setStatusBarTransitionDelay(
mPendingRemoteAnimation.getStatusBarTransitionDelay());
} else {
if (mPendingOptions == null
|| mPendingOptions.getAnimationType() == ANIM_SCENE_TRANSITION) {
// Scene transition will run on the client side.
return;
}
//2
applyOptionsAnimation(mPendingOptions, intent);
}
clearOptionsAnimationForSiblings();
}关注点1:这是系统应用定义的远程动画,具有非常高的优先级,如果是通过makeRemoteAnimation函数传入的动画则会生效
关注点2:传入我们设置的pendingOptions,也就是 ActivityOptions
/**
* Apply override app transition base on options & animation type.
*/
private void applyOptionsAnimation(ActivityOptions pendingOptions, Intent intent) {
//3
final int animationType = pendingOptions.getAnimationType();
final DisplayContent displayContent = getDisplayContent();
AnimationOptions options = null;
IRemoteCallback startCallback = null;
IRemoteCallback finishCallback = null;
switch (animationType) {
//4
case ANIM_CUSTOM:
displayContent.mAppTransition.overridePendingAppTransition(
pendingOptions.getPackageName(),
pendingOptions.getCustomEnterResId(),
pendingOptions.getCustomExitResId(),
pendingOptions.getCustomBackgroundColor(),
pendingOptions.getAnimationStartedListener(),
pendingOptions.getAnimationFinishedListener(),
pendingOptions.getOverrideTaskTransition());
options = AnimationOptions.makeCustomAnimOptions(pendingOptions.getPackageName(),
pendingOptions.getCustomEnterResId(), pendingOptions.getCustomExitResId(),
pendingOptions.getCustomBackgroundColor(),
pendingOptions.getOverrideTaskTransition());
startCallback = pendingOptions.getAnimationStartedListener();
finishCallback = pendingOptions.getAnimationFinishedListener();
break;
case ANIM_CLIP_REVEAL:关注点3:动画类型,上面的options就会生成一个类型为ANIM_CUSTOM的options,当然还有其他缩放平移动画属于系统默认的,由其他case处理
关注点4:overridePendingAppTransition, 直接进入AppTransition类处理
overridePendingAppTransition
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
@ColorInt int backgroundColor, IRemoteCallback startedCallback,
IRemoteCallback endedCallback, boolean overrideTaskTransaction) {
if (canOverridePendingAppTransition()) {
clear();
mNextAppTransitionOverrideRequested = true;
mNextAppTransitionPackage = packageName;
mNextAppTransitionEnter = enterAnim;
mNextAppTransitionExit = exitAnim;
mNextAppTransitionBackgroundColor = backgroundColor;
postAnimationCallback();
mNextAppTransitionCallback = startedCallback;
mAnimationFinishedCallback = endedCallback;
mOverrideTaskTransition = overrideTaskTransaction;
}
}AppTranstion会将进入,进出动画缓存起来,mNextAppTransitionOverrideRequested,mOverrideTaskTransition: 在loadAnimation时候作为override动画的判断条件
options动画的加载
继续关注 loadAnimation函数
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) {
//条件1
if (mNextAppTransitionOverrideRequested) {
//条件2
if (canCustomizeAppTransition || mOverrideTaskTransition) {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
} else {
ProtoLog.e(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: "
+ " override requested, but it is prohibited by policy.");
}
}
if(...)
//条件3
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = getNextAppRequestedAnimation(enter);
}
....条件1:首先判断 mNextAppTransitionOverrideRequested 在上面的overridePendingAppTransition已经设置为true
条件2: mOverrideTaskTransition, 只有通过 makeCustomTaskAnimation 创建的动画才是true, 此函数需要系统权限,普通应用调用的makeCustomAnimation是不满足这个条件的
条件3:假设满足1,2两个条件,则会通过getNextAppRequestedAnimation加载传入的自定义动画资源,此函数会传入缓存的动画资源等。
Animation getNextAppRequestedAnimation(boolean enter) {
final Animation a = mTransitionAnimation.loadAppTransitionAnimation(
mNextAppTransitionPackage,
enter ? mNextAppTransitionEnter : mNextAppTransitionExit);
...
return a;
}调用栈
此动画加载和自定义动画加载一样,都是在窗口焦点发生切换的时候触发
通过overridePendingTransition添加的动画
override默认动画
这个函数只有在Activity内部启动另一个Activity才能调用,属于Activity内部方法
public void overridePendingTransition(int enterAnim, int exitAnim, int backgroundColor) {
ActivityClient.getInstance().overridePendingTransition(mToken, getPackageName(), enterAnim,
exitAnim, backgroundColor);
}进入了ActivityClient类,最终交给ActivityClientController处理,函数如下:
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim, @ColorInt int backgroundColor) {
...
r.mDisplayContent.mAppTransition.overridePendingAppTransition(
packageName, enterAnim, exitAnim, backgroundColor, null, null,
r.mOverrideTaskTransition);
...
}
}
}内部也调用了Apptransition类overridePendingAppTransition函数,接下來的处理逻辑就和ActivityOptions一样了,只不过时机不一样,ActivityOptions先缓存到ActivityRecord,等Activity焦点变换的时候再调用AppTransition处理,而这里直接就传递给AppTransition处理了
load自定义动画
和ActivityOptions动画一样的逻辑
通过registerRemoteAnimations添加的动画
override默认动画
先看入口函数
public void registerRemoteAnimations(RemoteAnimationDefinition definition) {
ActivityClient.getInstance().registerRemoteAnimations(mToken, definition);
}先进入ActivityClientController函数,最后传递给ActivityRecord
public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
...
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
if (r != null) {
r.registerRemoteAnimations(definition);
}
...
}
void registerRemoteAnimations(RemoteAnimationDefinition definition) {
mRemoteAnimationDefinition = definition;
}和ActivityOptions一样,先缓存,当Activity焦点变化时,再加载动画
load Remote动画
当页面切换时,触发handleAppTransitionReady函数,和最开始的自定义动画的调用栈一样
void handleAppTransitionReady() {
...
// Check if there is any override
//条件1
if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
// Unfreeze the windows that were previously frozen for TaskFragment animation.
unfreezeEmbeddedChangingWindows();
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
}
...
条件1:检测远程动画,如果有,会更新AppTransition的远程动画变量,函数如下
private void overrideWithRemoteAnimationIfSet(@Nullable ActivityRecord animLpActivity,
@TransitionOldType int transit, ArraySet<Integer> activityTypes) {
RemoteAnimationAdapter adapter = null;
if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) {
// The crash transition has higher priority than any involved remote animations.
} else if (AppTransition.isKeyguardGoingAwayTransitOld(transit)) {
adapter = mRemoteAnimationDefinition != null
? mRemoteAnimationDefinition.getAdapter(transit, activityTypes)
: null;
//条件2
} else if (mDisplayContent.mAppTransition.getRemoteAnimationController() == null) {
//3
adapter = getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
}
if (adapter != null) {
//4
mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
}
}条件2:如果AppTransition没有远程动画,则会获取Activity的远程动画
关注点3:这里返回的就是ActivityRecord缓存remote动画
emoteAnimationAdapter getRemoteAnimationOverride(@Nullable WindowContainer container,
@TransitionOldType int transit, ArraySet<Integer> activityTypes) {
if (container != null) {
final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition();
}
关注点4:进入AppTransition的overridePendingAppTransitionRemote函数
void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter,
boolean sync, boolean isActivityEmbedding) {
ProtoLog.i(WM_DEBUG_APP_TRANSITIONS, "Override pending remote transitionSet=%b adapter=%s",
isTransitionSet(), remoteAnimationAdapter);
if (isTransitionSet() && !mNextAppTransitionIsSync) {
// ActivityEmbedding animation will run by the app process for which we want to respect
// the app override for whether or not to show background color.
clear(!isActivityEmbedding /* clearAppOverride */);
mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
mRemoteAnimationController = new RemoteAnimationController(mService, mDisplayContent,
remoteAnimationAdapter, mHandler, isActivityEmbedding);
mNextAppTransitionIsSync = sync;
}
}设置了mRemoteAnimationController变量
最后做动画的时候会有优先使用Remote动画
int goodToGo(@TransitionOldType int transit, ActivityRecord topOpeningApp) {
mNextAppTransitionFlags = 0;
if (mRemoteAnimationController != null) {
mRemoteAnimationController.goodToGo(transit);
}
...当我们设置了远程动画之后,其他动画都会失效,禁止override
private boolean canOverridePendingAppTransition() {
// Remote animations always take precedence
return isTransitionSet() && mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
}Launcher在启动应用的时候有一个全局过度动画,就是设置的这个动画
FLAG_ACTIVITY_NO_ANIMATION禁用动画
flag设置
startActivity的时候加入flag Intent.FLAG_ACTIVITY_NO_ANIMATION, 禁用窗口动画
void startActivityLocked(ActivityRecord r, @Nullable Task topTask, boolean newTask,
boolean isTaskSwitch, ActivityOptions options, @Nullable ActivityRecord sourceRecord) {
...
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
dc.prepareAppTransition(TRANSIT_NONE);
mTaskSupervisor.mNoAnimActivities.add(r);
}
startActivity的时候 调用prepareAppTransition(TRANSIT_NONE),设置为无动画状态
在loadAnimation的时候会对transit做一次转换,得到animAttr=0
private static int mapOpenCloseTransitTypes(int transit, boolean enter) {
int animAttr = 0;
switch (transit) {
...
}
return animAttrloadAnimation会返回null,则不会执行动画效果
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) {
...
int animAttr = mapOpenCloseTransitTypes(transit, enter);
a = animAttr == 0 ? null
return animAttr;
}加载默认动画资源
在AppTransition#loadAnimation中
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) {
...
a = animAttr == 0 ? null : (canCustomizeAppTransition
? loadAnimationAttr(lp, animAttr, transit)
//1
: mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit));
return animAttr;
}关注点1:loadDefaultAnimationAttr
public Animation loadDefaultAnimationAttr(int animAttr, @TransitionOldType int transit) {
return loadAnimationAttr(DEFAULT_PACKAGE, mDefaultWindowAnimationStyleResId, animAttr,
false /* translucent */, transit);
}默认的包名和attr定义如下:
private static final String DEFAULT_PACKAGE = "android";
mDefaultWindowAnimationStyleResId = windowStyle.getResourceId(
com.android.internal.R.styleable.Window_windowAnimationStyle, 0);ActivityOptions
调用栈
applyOptionsAnimation调用栈
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.ActivityRecord.applyOptionsAnimation(ActivityRecord.java:4878)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1375)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5050)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:4980)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:5031)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.ActivityRecord.makeActiveIfNeeded(ActivityRecord.java:6034)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer.lambda$resumeFocusedTasksTopActivities$19(RootWindowContainer.java:2538)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer$$ExternalSyntheticLambda16.accept(Unknown Source:13)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.Task.forAllRootTasks(Task.java:3182)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2108)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2108)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2108)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2108)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2108)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2108)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2101)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2519)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2497)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2492)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.Task.moveTaskToBackInner(Task.java:5758)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.Task.moveTaskToBack(Task.java:5734)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.ActivityClientController.moveActivityTaskToBack(ActivityClientController.java:325)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:668)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:127)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at android.os.Binder.execTransactInternal(Binder.java:1280)
01-07 11:23:46.485 18087 19833 W APP_ANIMATION_DEBUG: at android.os.Binder.execTransact(Binder.java:1244)
applyOptionsAnimation 会调用AppTransition#overridePendingAppTransition,设置对应的动画类型,最后在loadAnimation的时候 根据不同的动画类型加载不同的动画资源
loadAnimation调用栈
11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.AppTransition.loadAnimation(AppTransition.java:781)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.loadAnimation(WindowContainer.java:3284)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.getAnimationAdapter(WindowContainer.java:3111)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.applyAnimationUnchecked(WindowContainer.java:3156)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.Task.applyAnimationUnchecked(Task.java:3371)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowContainer.applyAnimation(WindowContainer.java:3000)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:918)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:1121)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:302)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:987)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:850)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:793)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at android.os.Handler.handleCallback(Handler.java:942)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at android.os.Handler.dispatchMessage(Handler.java:99)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at android.os.Looper.loopOnce(Looper.java:201)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at android.os.Looper.loop(Looper.java:288)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at android.os.HandlerThread.run(HandlerThread.java:67)
01-07 11:23:46.546 18087 18155 W APP_ANIMATION_DEBUG: at com.android.server.ServiceThread.run(ServiceThread.java:44)
loadAnimation在窗口切换的时候由AppTransitionController触发