一、转场动画
android5.0之前使用overridePendingTransition,之后使用ActivityOptions和ActivityOptionsCompat可以实现新风格的转场动画。ActivityOptionsCompat是ActivityOptions的兼容包。
1.如何使用
ActivityOptions activityOptions = getActivityOptions(...);
Bundle optsBundle = activityLaunchOptions.toBundle();
context.startActivity(intent, optsBundle);
2.ActivityOptions
(1) makeCustomAnimation(Context context, int enterResId, int exitResId)
用户自定义动画,指定进入和退出动画,api16开始支持
参数说明:
enterResId:Activity进入动画资源id
exitResId:Activity退出动画资源id
(2) makeClipRevealAnimation (View source, int startX, int startY, int width, int height)
从一个view的剪切区域放大然后打开新的Activity,Api23开始支持
参数说明:
startX,startY:区域起点,利用source作为原点
width,height:区域宽高
(3) makeScaleUpAnimation(View source, int startX, int startY, int width, int height)
放大一个view,然后显示新的Activity
参数说明:
view:放大的view
startX,startY:从哪里开始缩放,以source为原点
width,height:新的activity从多大开始放大,如果是0,0则表示从最小开始。
(4) makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY)
放大一张图片,然后打开activity
参数说明
source:参考原点
thumbnail:要放大的图片
startX,startY:从哪里开始放大,以source为坐标原点
(5) makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)
共享元素动画
(6) makeRemoteAnimation(RemoteAnimationAdapterCompat remoteAnimationAdapter)
应用启动和关闭自定义动画,主要Launcher和多任务使用,如:Launcher启动应用时候,先用图标做放大动销,之后用RemoteAnimation应用窗口放大动画。该方法无法直接使用,需要使用systemUi打包的 sysui_shared.jar
二、RemoteAnimation
本文已Android9.0的Launcher3为例进行讲解(可从google源码中进行下载),高版本的原理一样的。
1.使用依赖
方法无法直接使用,依赖sysui_shared.jar,该jar由SystemUI源码make进行构建,android9及以下版本可以由 google提供的Launcher 源码的中获取,见quickstep的libs下
2.Launcher3有关RemoteAnimation源码介绍
Launcher3源码中RemoteAnimation、多任务、手势相关代码都在quickstep目录下,RemoteAnimation见LauncherAppTransitionManagerImpl.java 类
public LauncherAppTransitionManagerImpl(Context context) {
mLauncher = Launcher.getLauncher(context);
mDragLayer = mLauncher.getDragLayer();
mDragLayerAlpha = mDragLayer.getAlphaProperty(ALPHA_INDEX_TRANSITIONS);
mHandler = new Handler(Looper.getMainLooper());
...
// 注册应用关闭监听做动画
registerRemoteAnimations();
}
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
// 权限判断
if (hasControlRemoteAppTransitionPermission()) {
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler,
true /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
AnimationResult result) {
// 应用打开回调到这,可执行图标和窗口动画q
......
}
};
// 应用打开和fwk进行交互
return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
runner, duration, statusBarTransitionDelay));
}
return super.getActivityLaunchOptions(launcher, v);
}
public static ActivityOptions makeRemoteAnimation(RemoteAnimationAdapterCompat remoteAnimationAdapter) {
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped());
}
其核心是RemoteAnimationAdapterCompat类
public class RemoteAnimationAdapterCompat {
private final RemoteAnimationAdapter mWrapped;
public RemoteAnimationAdapterCompat(RemoteAnimationRunnerCompat runner, long duration, long statusBarTransitionDelay) {
this.mWrapped = new RemoteAnimationAdapter(wrapRemoteAnimationRunner(runner), duration, statusBarTransitionDelay);
}
RemoteAnimationAdapter getWrapped() {
return this.mWrapped;
}
private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner(final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
return new IRemoteAnimationRunner.Stub() {
public void onAnimationStart(RemoteAnimationTarget[] apps, final IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
// 开开始的回调
RemoteAnimationTargetCompat[] appsCompat = RemoteAnimationTargetCompat.wrap(apps);
Runnable animationFinishedCallback = new Runnable() {
public void run() {
try {
// 该方法结束,动画才会结束,其打开或关闭才会进行走生命周期
finishedCallback.onAnimationFinished();
} catch (RemoteException var2) {
Log.e("ActivityOptionsCompat", "Failed to call app controlled animation finished callback", var2);
}
}
};
remoteAnimationAdapter.onAnimationStart(appsCompat, animationFinishedCallback);
}
public void onAnimationCancelled() throws RemoteException {
remoteAnimationAdapter.onAnimationCancelled();
}
};
}
}
其中可以看出IRemoteAnimationRunner是一个aidl 与 系统底层进交互。IRemoteAnimationRunner.Stub会回调onAnimationStart和onAnimationCancelled,onAnimationStar方法中有2个参数
- RemoteAnimationTarget[]
所有打开或关闭应用的窗口位置、taskId、SurfaceControl、mode等信息 - IRemoteAnimationFinishedCallback
该方法执行onAnimationFinished()后代表着整个动画执行完成,下一个应用才会继续走正常的生命周期,否则可卡住直到系统超时。
onAnimationStart和onAnimationCancelled最终回调给RemoteAnimationRunnerCompat接口
RemoteAnimationRunnerCompat 是一个接口,实现类 LauncherAnimationRunner
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
private final Handler mHandler;
private final boolean mStartAtFrontOfQueue;
private AnimationResult mAnimationResult;
public LauncherAnimationRunner(Handler handler, boolean startAtFrontOfQueue) {
mHandler = handler;
// 是否执行到Handler队列的最前面
mStartAtFrontOfQueue = startAtFrontOfQueue;
}
@BinderThread
@Override
public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) {
// RemoteAnimationRunnerCompat回调到这,
Runnable r = () -> {
finishExistingAnimation();
mAnimationResult = new AnimationResult(runnable);
onCreateAnimation(targetCompats, mAnimationResult);
};
if (mStartAtFrontOfQueue) {
// 插入队列的最前面,Handler第一个执行
postAtFrontOfQueueAsynchronously(mHandler, r);
} else {
// 异步消息,有消息屏障时优先执行
postAsyncCallback(mHandler, r);
}
}
// 动画执行
@UiThread
public abstract void onCreateAnimation(
RemoteAnimationTargetCompat[] targetCompats, AnimationResult result);
@UiThread
private void finishExistingAnimation() {
if (mAnimationResult != null) {
mAnimationResult.finish();
mAnimationResult = null;
}
}
/**
* Called by the system
*/
@BinderThread
@Override
public void onAnimationCancelled() {
postAsyncCallback(mHandler, this::finishExistingAnimation);
}
public static final class AnimationResult {
private final Runnable mFinishRunnable;
private AnimatorSet mAnimator;
private boolean mFinished = false;
private boolean mInitialized = false;
private AnimationResult(Runnable finishRunnable) {
mFinishRunnable = finishRunnable;
}
@UiThread
private void finish() {
if (!mFinished) {
mFinishRunnable.run();
mFinished = true;
}
}
@UiThread
public void setAnimation(AnimatorSet animation) {
if (mInitialized) {
throw new IllegalStateException("Animation already initialized");
}
mInitialized = true;
mAnimator = animation;
if (mAnimator == null) {
finish();
} else if (mFinished) {
mAnimator.start();
mAnimator.end();
} else {
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
finish();
}
});
mAnimator.start();
mAnimator.setCurrentPlayTime(SINGLE_FRAME_MS);
}
}
}
}
3.Launcher3中应用打开动画
入口在getActivityLaunchOptions方法中的 runner
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler,
true) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
AnimationResult result) {
AnimatorSet anim = new AnimatorSet();
// 判断是否launcher进行关闭(应用打开launcher关闭)
boolean launcherClosing =launcherIsATargetWithMode(targetCompats, MODE_CLOSING);
if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) {
// 非多任务即launcher
mLauncher.getStateManager().setCurrentAnimation(anim);
// 获取目标应用的窗口位置
Rect windowTargetBounds = getWindowTargetBounds(targetCompats);
// 执行Launcher界面上的应用图标缩放动画
playIconAnimators(anim, v, windowTargetBounds);
if (launcherClosing) {
// 获取Launcher自己(workspace、AllAppsContainerView)需要执行的动画
Pair<AnimatorSet, Runnable> launcherContentAnimator =
getLauncherContentAnimator(true /* isAppOpening */);
anim.play(launcherContentAnimator.first);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
launcherContentAnimator.second.run();
}
});
}
// 同时执行应用的窗口动画
anim.play(getOpeningWindowAnimators(v, targetCompats, windowTargetBounds));
}
if (launcherClosing) {
anim.addListener(mForceInvisibleListener);
}
// 设置动画可执行
result.setAnimation(anim);
}
};
由上可见,应用打开时有三个动画:图标icon动画、应用窗口动画、Launcher动画。
3.1 应用的Icon动画
private void playIconAnimators(AnimatorSet appOpenAnimator, View v, Rect windowTargetBounds) {
final boolean isBubbleTextView = v instanceof BubbleTextView;
// 创建一个空view
mFloatingView = new View(mLauncher);
if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
// 获取点击Icon的bitmap 设置给背景
mFloatingView.setBackground(
DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag()));
}
Rect rect = new Rect();
final boolean fromDeepShortcutView = v.getParent() instanceof DeepShortcutView;
if (fromDeepShortcutView) {
// 深度快捷方式视图的图标绘制在单独的视图中
DeepShortcutView view = (DeepShortcutView) v.getParent();
mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), rect);
} else {
// 获取点击的Icon 在屏幕上的位置
mDragLayer.getDescendantRectRelativeToSelf(v, rect);
}
int viewLocationLeft = rect.left;
int viewLocationTop = rect.top;
// 初始缩放比例
float startScale = 1f;
if (isBubbleTextView && !fromDeepShortcutView) {
BubbleTextView btv = (BubbleTextView) v;
btv.getIconBounds(rect);
Drawable dr = btv.getIcon();
if (dr instanceof FastBitmapDrawable) {
startScale = ((FastBitmapDrawable) dr).getAnimatedScale();
}
} else {
rect.set(0, 0, rect.width(), rect.height());
}
viewLocationLeft += rect.left;
viewLocationTop += rect.top;
//mIsRtl 是否是从右向左绘制
int viewLocationStart = mIsRtl
? windowTargetBounds.width() - rect.right
: viewLocationLeft;
// 设置FloatingView在屏幕上的位置
LayoutParams lp = new LayoutParams(rect.width(), rect.height());
lp.ignoreInsets = true;
lp.setMarginStart(viewLocationStart);
lp.topMargin = viewLocationTop;
mFloatingView.setLayoutParams(lp);
mFloatingView.setLeft(viewLocationLeft);
mFloatingView.setTop(viewLocationTop);
mFloatingView.setRight(viewLocationLeft + rect.width());
mFloatingView.setBottom(viewLocationTop + rect.height());
// FloatingView添加到Launcher的根布局上
((ViewGroup) mDragLayer.getParent()).addView(mFloatingView);
// 点击的应用Icon 进行隐藏
v.setVisibility(View.INVISIBLE);
int[] dragLayerBounds = new int[2];
mDragLayer.getLocationOnScreen(dragLayerBounds);
//在屏幕坐标中,将应用程序图标动画化到窗口边界的中心。
float centerX = windowTargetBounds.centerX() - dragLayerBounds[0];
float centerY = windowTargetBounds.centerY() - dragLayerBounds[1];
float xPosition = mIsRtl
? windowTargetBounds.width() - lp.getMarginStart() - rect.width()
: lp.getMarginStart();
float dX = centerX - xPosition - (lp.width / 2);
float dY = centerY - lp.topMargin - (lp.height / 2);
ObjectAnimator x = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_X, 0f, dX);
ObjectAnimator y = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_Y, 0f, dY);
//对位于屏幕下半部分或/相对靠近中心
boolean useUpwardAnimation = lp.topMargin > centerY
|| Math.abs(dY) < mLauncher.getDeviceProfile().cellHeightPx;
if (useUpwardAnimation) {
x.setDuration(APP_LAUNCH_CURVED_DURATION);
y.setDuration(APP_LAUNCH_DURATION);
} else {
x.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_DURATION));
y.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_CURVED_DURATION));
}
x.setInterpolator(AGGRESSIVE_EASE);
y.setInterpolator(AGGRESSIVE_EASE);
// 动画设置x.y
appOpenAnimator.play(x);
appOpenAnimator.play(y);
// 缩放应用程序图标以占据整个屏幕,做缩放动画
float maxScaleX = windowTargetBounds.width() / (float) rect.width();
float maxScaleY = windowTargetBounds.height() / (float) rect.height();
float scale = Math.max(maxScaleX, maxScaleY);
ObjectAnimator scaleAnim = ObjectAnimator
.ofFloat(mFloatingView, SCALE_PROPERTY, startScale, scale);
scaleAnim.setDuration(APP_LAUNCH_DURATION)
.setInterpolator(Interpolators.EXAGGERATED_EASE);
appOpenAnimator.play(scaleAnim);
// 应用Icon 淡出动画
ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f);
if (useUpwardAnimation) {
alpha.setStartDelay(APP_LAUNCH_ALPHA_START_DELAY);
alpha.setDuration(APP_LAUNCH_ALPHA_DURATION);
} else {
alpha.setStartDelay((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR
* APP_LAUNCH_ALPHA_START_DELAY));
alpha.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_ALPHA_DURATION));
}
alpha.setInterpolator(LINEAR);
appOpenAnimator.play(alpha);
appOpenAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//动画结束,删除FloatingView,显示原有的应用Icon
v.setVisibility(View.VISIBLE);
((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
}
});
}
总结:可以看出先对应用Icon进行隐藏,添加了一个假的View在Launcher根布局相应的位置,对假的View做移动、缩放、透明动画,动画结束后,删除假的View,显示真正的应用Icon
3.2 应用的窗口动画
private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
Rect windowTargetBounds) {
// 获取应用Icon在屏幕上的位置
Rect bounds = new Rect();
if (v.getParent() instanceof DeepShortcutView) {
DeepShortcutView view = (DeepShortcutView) v.getParent();
mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), bounds);
} else if (v instanceof BubbleTextView) {
((BubbleTextView) v).getIconBounds(bounds);
} else {
mDragLayer.getDescendantRectRelativeToSelf(v, bounds);
}
// 用于获取假的icon 的位置信息
int[] floatingViewBounds = new int[2];
// 用于窗口动画位置信息
Rect crop = new Rect();
// 用于做窗口平移缩放等动画
Matrix matrix = new Matrix();
// 获取打开应用的RemoteAnimationTarget
RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(targets,
MODE_OPENING);
// 获取关闭应用的RemoteAnimationTarget
RemoteAnimationTargetSet closingTargets = new RemoteAnimationTargetSet(targets,
MODE_CLOSING);
// 窗口动画的真正执行类
SyncRtSurfaceTransactionApplier surfaceApplier = new SyncRtSurfaceTransactionApplier(
mFloatingView);
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setDuration(APP_LAUNCH_DURATION);
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
// 透明动画参数类封装
FloatProp mAlpha = new FloatProp(0f, 1f, 0, 60, LINEAR);
@Override
public void onUpdate(float percent) {
final float easePercent = AGGRESSIVE_EASE.getInterpolation(percent);
// 计算 icon的宽、高
float iconWidth = bounds.width() * mFloatingView.getScaleX();
float iconHeight = bounds.height() * mFloatingView.getScaleY();
// 计算缩放的比例
float scaleX = iconWidth / windowTargetBounds.width();
float scaleY = iconHeight / windowTargetBounds.height();
float scale = Math.min(1f, Math.min(scaleX, scaleY));
// 计算该缩放比例下的窗口宽、高
int windowWidth = windowTargetBounds.width();
int windowHeight = windowTargetBounds.height();
float scaledWindowWidth = windowWidth * scale;
float scaledWindowHeight = windowHeight * scale;
// 偏移
float offsetX = (scaledWindowWidth - iconWidth) / 2;
float offsetY = (scaledWindowHeight - iconHeight) / 2;
mFloatingView.getLocationOnScreen(floatingViewBounds);
// 窗口平移 x、y
float transX0 = floatingViewBounds[0] - offsetX;
float transY0 = floatingViewBounds[1] - offsetY;
// 制作窗口裁剪的动画,使其以正方形开始,然后显示水平方向
float cropHeight = windowHeight * easePercent + windowWidth * (1 - easePercent);
float initialTop = (windowHeight - windowWidth) / 2f;
crop.left = 0;
crop.top = (int) (initialTop * (1 - easePercent));
crop.right = windowWidth;
crop.bottom = (int) (crop.top + cropHeight);
SurfaceParams[] params = new SurfaceParams[targets.length];
for (int i = targets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = targets[i];
Rect targetCrop;
float alpha;
if (target.mode == MODE_OPENING) {
// 打开状态的应用做缩放、平移、透明动画
matrix.setScale(scale, scale);
matrix.postTranslate(transX0, transY0);
targetCrop = crop;
alpha = mAlpha.value;
} else {
// 关闭状态的应用 动画
matrix.setTranslate(target.position.x, target.position.y);
alpha = 1f;
targetCrop = target.sourceContainerBounds;
}
params[i] = new SurfaceParams(target.leash, alpha, matrix, targetCrop,
RemoteAnimationProvider.getLayer(target, MODE_OPENING));
}
//交由surfaceApplier进行真正的执行
surfaceApplier.scheduleApply(params);
}
});
return appAnimator;
}
其动画主要是窗口从图标位置缩放到全屏同时伴随移动、透明等动画,动画参数先封装成
SurfaceParams,都交给SyncRtSurfaceTransactionApplier真正执行。
public class SyncRtSurfaceTransactionApplier {
//Surface
private final Surface mTargetSurface;
//ViewRootImpl
private final ViewRootImpl mTargetViewRootImpl;
private final float[] mTmpFloat9 = new float[9];
public SyncRtSurfaceTransactionApplier(View targetView) {
this.mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
this.mTargetSurface = this.mTargetViewRootImpl != null ? this.mTargetViewRootImpl.mSurface : null;
}
public void scheduleApply(SurfaceParams... params) {
if (this.mTargetViewRootImpl != null) {
this.mTargetViewRootImpl.registerRtFrameCallback((frame) -> {
if (this.mTargetSurface != null && this.mTargetSurface.isValid()) {
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
for(int i = params.length - 1; i >= 0; --i) {
SurfaceParams surfaceParams = params[i];
SurfaceControl surface = surfaceParams.surface;
t.deferTransactionUntilSurface(surface, this.mTargetSurface, frame);
applyParams(t, surfaceParams, this.mTmpFloat9);
}
t.setEarlyWakeup();
// 动画参数解析后最终交给SurfaceControl进行执行
t.apply();
}
});
this.mTargetViewRootImpl.getView().invalidate();
}
}
public static void applyParams(TransactionCompat t, SurfaceParams params) {
applyParams(t.mTransaction, params, t.mTmpValues);
}
private static void applyParams(SurfaceControl.Transaction t, SurfaceParams params, float[] tmpFloat9) {
// 给SurfaceControl设置相关属性
t.setMatrix(params.surface, params.matrix, tmpFloat9);
t.setWindowCrop(params.surface, params.windowCrop);
t.setAlpha(params.surface, params.alpha);
t.setLayer(params.surface, params.layer);
t.show(params.surface);
}
public static class SurfaceParams {
final SurfaceControl surface;
final float alpha;
final Matrix matrix;
final Rect windowCrop;
final int layer;
public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix, Rect windowCrop, int layer) {
this.surface = surface.mSurfaceControl;
this.alpha = alpha;
this.matrix = new Matrix(matrix);
this.windowCrop = new Rect(windowCrop);
this.layer = layer;
}
}
}
动画最终交给SurfaceControl.Transaction类执行
4.Launcher3中应用关闭动画
private void registerRemoteAnimations() {
// 需要先注册该方法,监听应用的关闭
if (hasControlRemoteAppTransitionPermission()) {
RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
}
}
private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
return new LauncherAnimationRunner(mHandler, false /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
AnimationResult result) {
if (!mLauncher.hasBeenResumed()) {
//Launcher还没有onResume, post一个Runable在Handler队列尾部最后执行
mLauncher.setOnResumeCallback(() ->
postAsyncCallback(mHandler, () ->
onCreateAnimation(targetCompats, result)));
return;
}
...
if (anim == null) {
anim = new AnimatorSet();
// 执行窗口关闭动画,其原理同打开
anim.play(getClosingWindowAnimators(targetCompats));
if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)
|| mLauncher.isForceInvisible()) {
mLauncher.getStateManager().setCurrentAnimation(anim);
// 执行Launcher自己的页面动画(主要是workspace)
createLauncherResumeAnimation(anim);
}
}
mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
result.setAnimation(anim);
}
};
}
5.结尾
ActivityOptionsCompat.makeRemoteAnimation(...) 构建成ActivityOptions在应用startActivty传入,后应用打开会回调RemoteAnimationRunnerCompat的onCreateAnimation方法,其中会执行应用图标、窗口、Launcher页面动画;关闭需要同ActivityCompat(mLauncher).registerRemoteAnimations(definition)进行注册,后续动画回调执行同打开。应用图标动画,执行的是添加的floatView,原有图标隐藏,动画结束后删除foatView,显示原图标;窗口动画,把各种平移、缩放、透明等参数进行封装最终交给SurfaceControl.Transaction继续提交执行。