android P/Q/R/S 9/10/11/12多任務(wù)手勢動畫OtherActivityInputConsumer情況
hi,粉絲朋友們:
????在手機屏幕屏占比越來越大的時候,用戶對手機的屏幕交互體驗也在提升,把原來的導(dǎo)航鍵3個按鈕的交互方式,在android P產(chǎn)生了一個巨大的變化,增加了全面屏上導(dǎo)航手勢的方式,后面版本也是在P的基礎(chǔ)進行一些細微修改。

???? 導(dǎo)航手勢給人的用戶體驗也確實很不錯,但是他的整套代碼實現(xiàn)也是相當(dāng)復(fù)雜的,今天我們對導(dǎo)航手勢的OtherActivityInputConsumer情況來進行分析。
1、首先OtherActivityInputConsumer指的是什么情況呢? 這里我們字面意思就可以知道它大概是指的是目前在其他Activity,要通過手勢返回到Launcher,這樣一個場景。例如以下幾幅圖:

這個時候處于聯(lián)系人界面

通過手勢滑動到Launcher
直觀剖析涉及幾個過程: 1、聯(lián)系人界面在手指滑動過程中實際還依然是一個Activity的窗口,因為滑動過程中Activity窗口是可以更新變化的,加上可以看events日志:
11-29?03:58:57.046?25180?25180?I?am_on_restart_called:?[0,com.android.launcher3.lineage.LineageLauncher,handleWindowVisibility]
11-29?03:58:57.084?25180?25180?I?am_on_start_called:?[0,com.android.launcher3.lineage.LineageLauncher,handleWindowVisibility]
手在滑動過程中這里只看到有桌面Activity onStart,沒有onResume,聯(lián)系人應(yīng)用也并沒有onPasue
11-29?03:59:15.709??2522??6076?I?am_focused_stack:?[0,0,0,31,RecentsAnimation.onAnimationFinished()]
11-29?03:59:15.712?31776?31776?I?am_on_top_resumed_lost_called:?[0,com.android.contacts.activities.PeopleActivity,topStateChangedWhenResumed]
11-29?03:59:15.714??2522??6076?I?am_pause_activity:?[0,106262359,com.android.contacts/.activities.PeopleActivity,userLeaving=false]
11-29?03:59:15.726??2522??6076?I?am_set_resumed_activity:?[0,com.android.launcher3/.lineage.LineageLauncher,resumeTopActivityInnerLocked]
11-29?03:59:15.730??2522??6076?I?am_add_to_stopping:?[0,106262359,com.android.contacts/.activities.PeopleActivity,makeInvisible]
11-29?03:59:15.734??2522??6076?I?am_resume_activity:?[0,239824215,471,com.android.launcher3/.lineage.LineageLauncher]
11-29?03:59:15.743?25180?25180?I?am_on_resume_called:?[0,com.android.launcher3.lineage.LineageLauncher,RESUME_ACTIVITY]
11-29?03:59:15.771?31776?31776?I?am_on_paused_called:?[0,com.android.contacts.activities.PeopleActivity,performPause]
這里就滑到多任務(wù)界面后松手,這里可以看出這個時候Launcher才真正onResume,聯(lián)系人應(yīng)用onPasue 2、從第一部分的分析場景看出,這個時候居然是聯(lián)系人界面顯示著還是Resume同時,桌面Activity的RecentView也同時顯示,這種場景其實對于大部分同學(xué)來說都是沒有見過的。因為平時都是要么顯示是Launcher的Activity,要么是聯(lián)系人Activity的界面,這個一下顯示兩個Activity界面情況還真的。。沒見過 下面來想想,該怎么如果我們要處理這種兩個Activity同時顯示情況,適合由誰來主導(dǎo)這種協(xié)調(diào)的顯示過程呢? 哈哈,這其實很好想到設(shè)計者一定會放到Launcher來負責(zé)協(xié)調(diào)兩個Activity的同時顯示界面,其實這也就是桌面多了一個文件夾quickstep原因,這部分代碼還依賴Systemui部分。
重點介紹OtherActivityInputConsumer情況下的多任務(wù)卡片的手勢運行步驟: 路徑:quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
??private?void?initInputMonitor()?{
???????//省略部分
????????try?{
????????????mInputMonitorCompat?=?InputMonitorCompat.fromBundle(mISystemUiProxy
????????????????????.monitorGestureInput("swipe-up",?mDefaultDisplayId),?KEY_EXTRA_INPUT_MONITOR);
????????????mInputEventReceiver?=?mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
????????????????????mMainChoreographer,?this::onInputEvent);//這里調(diào)用InputMonitor注冊了全局觸摸事件監(jiān)聽,有觸摸事件來了后會觸發(fā)onInputEvent方法
?????????????//省略部分
????}
????//接受全局觸摸的onInputEvent
??private?void?onInputEvent(InputEvent?ev)?{
???????//省略部分
????????if?(event.getAction()?==?ACTION_DOWN)?{
????????????mLogId?=?TOUCH_INTERACTION_LOG.generateAndSetLogId();
????????????sSwipeSharedState.setLogTraceId(mLogId);
????????????if?(mSwipeTouchRegion.contains(event.getX(),?event.getY()))?{
????????????????boolean?useSharedState?=?mConsumer.useSharedSwipeState();
????????????????mConsumer.onConsumerAboutToBeSwitched();
????????????????mConsumer?=?newConsumer(useSharedState,?event);//這里在其他Activity滑動時候mConsumer其實就是我們今天主角OtherActivityInputConsumer
????????????????TOUCH_INTERACTION_LOG.addLog("setInputConsumer",?mConsumer.getType());
????????????????mUncheckedConsumer?=?mConsumer;
????????????}?else?if?(mIsUserUnlocked?&&?mMode?==?Mode.NO_BUTTON
????????????????????&&?canTriggerAssistantAction(event))?{
?????????????//省略部分
????????????}
????????}
????????TOUCH_INTERACTION_LOG.addLog("onMotionEvent",?event.getActionMasked());
????????mUncheckedConsumer.onMotionEvent(event);//這里會調(diào)用對應(yīng)Consumer的onMotionEvent方法
????}
好的上面已介紹出了OtherActivityInputConsumer的onMotionEvent,因為本身整個手勢動作都是觸摸引發(fā),所以接下來觸摸相關(guān),這里因為細節(jié)代碼實在太多,很多地方只能省略,梳理出大概過程,大家知道個輪廓,然后順著輪廓去自己詳細分析。 //quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
?
????public?void?onMotionEvent(MotionEvent?ev)?{
???????//省略部分
????????switch?(ev.getActionMasked())?{
????????????case?ACTION_DOWN:?{
???????????????//省略部分
????????????????if?(!mIsDeferredDownTarget)?{
????????????????????startTouchTrackingForWindowAnimation(ev.getEventTime(),?false);
????????????????}
?????????????????//省略部分
????????????????break;
????????????}
????????????//省略部分
????????????case?ACTION_MOVE:?{
????????????????//省略部分
????????????????if?(mInteractionHandler?!=?null)?{
????????????????????if?(mPassedWindowMoveSlop)?{
????????????????????????//?根據(jù)得出的觸摸滑動距離,調(diào)用對應(yīng)的updateDisplacement方法來更新滑動界面RecentView和聯(lián)系人窗口位置
????????????????????????mInteractionHandler.updateDisplacement(displacement?-?mStartDisplacement);
????????????????????}
????????????????????if?(mMode?==?Mode.NO_BUTTON)?{
????????????????????????mMotionPauseDetector.setDisallowPause(upDist?<?mMotionPauseMinDisplacement
????????????????????????????????||?isLikelyToStartNewTask);
????????????????????????mMotionPauseDetector.addPosition(displacement,?ev.getEventTime());
????????????????????????mInteractionHandler.setIsLikelyToStartNewTask(isLikelyToStartNewTask);
????????????????????}
????????????????}
????????????????break;
????????????}
????????????case?ACTION_CANCEL:
????????????case?ACTION_UP:?{
????????????????finishTouchTracking(ev);
????????????????break;
????????????}
????????}
????}
這里主要兩個方法: 1、startTouchTrackingForWindowAnimation方法 //quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
?private?void?startTouchTrackingForWindowAnimation(
????????????long?touchTimeMs,?boolean?isLikelyToStartNewTask)?{
??????//省略部分
????????if?(listenerSet?!=?null)?{
????????????listenerSet.addListener(handler);
????????????mSwipeSharedState.applyActiveRecentsAnimationState(handler);
????????????notifyGestureStarted();
????????}?else?{
?????????//構(gòu)造出RecentsAnimationListenerSet對象
????????????RecentsAnimationListenerSet?newListenerSet?=
????????????????????mSwipeSharedState.newRecentsAnimationListenerSet();
????????????newListenerSet.addListener(handler);
????????????Intent?intent?=?handler.getLaunchIntent();
????????????intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID,?mLogId);
?????????????//通過startRecentsActivityAsync來調(diào)用把newListenerSet傳遞到startRecentsActivityAsync
????????????startRecentsActivityAsync(intent,?newListenerSet);
????????}
????}
這里主要是構(gòu)造RecentsAnimationListenerSet對象然后傳遞到startRecentsActivityAsync
quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
?public?static?void?startRecentsActivityAsync(Intent?intent,?RecentsAnimationListener?listener)?{
?????//這里調(diào)用是ActivityManagerWrapper的startRecentsActivity方法
????????UI_HELPER_EXECUTOR.execute(()?->?ActivityManagerWrapper.getInstance()
????????????????.startRecentsActivity(intent,?null,?listener,?null,?null));
????}
//frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
???/**
?????*?Starts?the?recents?activity.?The?caller?should?manage?the?thread?on?which?this?is?called.
?????*/
????public?void?startRecentsActivity(Intent?intent,?final?AssistDataReceiver?assistDataReceiver,
????????????final?RecentsAnimationListener?animationHandler,?final?Consumer<Boolean>?resultCallback,
????????????Handler?resultCallbackHandler)?{
????????try?{
???????//省略部分
????????????IRecentsAnimationRunner?runner?=?null;
????????????if?(animationHandler?!=?null)?{
?????????????//這里構(gòu)造出了一個binder的服務(wù)端,他是準備讓systemserver調(diào)用的
????????????????runner?=?new?IRecentsAnimationRunner.Stub()?{
????????????????????
????????????????????public?void?onAnimationStart(IRecentsAnimationController?controller,
????????????????????????????RemoteAnimationTarget[]?apps,?Rect?homeContentInsets,
????????????????????????????Rect?minimizedHomeBounds)?{
????????????????????????final?RecentsAnimationControllerCompat?controllerCompat?=
????????????????????????????????new?RecentsAnimationControllerCompat(controller);
????????????????????????final?RemoteAnimationTargetCompat[]?appsCompat?=
????????????????????????????????RemoteAnimationTargetCompat.wrap(apps);
????????????????????????????????//這里會調(diào)用到上一個步驟的RecentsAnimationListenerSet
????????????????????????animationHandler.onAnimationStart(controllerCompat,?appsCompat,
????????????????????????????????homeContentInsets,?minimizedHomeBounds);
????????????????????}
????????????????????
????????????????????public?void?onAnimationCanceled(boolean?deferredWithScreenshot)?{
????????????????????????animationHandler.onAnimationCanceled(
????????????????????????????????deferredWithScreenshot???new?ThumbnailData()?:?null);
????????????????????}
????????????????};
????????????}
????????????//這里跨進程調(diào)用到了ActivityTaskManagerService到了systemserver端
????????????ActivityTaskManager.getService().startRecentsActivity(intent,?receiver,?runner);
??????????//省略部分
這時候代碼就運行到了systemserver的 ActivityTaskManagerService: base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public?void?startRecentsActivity(Intent?intent,??IAssistDataReceiver?unused,
?????????IRecentsAnimationRunner?recentsAnimationRunner)?{
//省略部分
????try?{
????????synchronized?(mGlobalLock)?{
????????????final?ComponentName?recentsComponent?=?mRecentTasks.getRecentsComponent();
????????????final?int?recentsUid?=?mRecentTasks.getRecentsComponentUid();
????????????final?WindowProcessController?caller?=?getProcessController(callingPid,?callingUid);
????????????//?Start?a?new?recents?animation
????????????//構(gòu)造出對應(yīng)的RecentsAnimation動畫
????????????final?RecentsAnimation?anim?=?new?RecentsAnimation(this,?mStackSupervisor,
????????????????????getActivityStartController(),?mWindowManager,?intent,?recentsComponent,
????????????????????recentsUid,?caller);
????????????if?(recentsAnimationRunner?==?null)?{
????????????????anim.preloadRecentsActivity();
????????????}?else?{
????????????//調(diào)用RecentsAnimation的startRecentsActivity方法
????????????????anim.startRecentsActivity(recentsAnimationRunner);
????????????}
????????}
????}?finally?{
????????Binder.restoreCallingIdentity(origId);
????}
}
這里調(diào)用到了RecentsAnimation的startRecentsActivity base/services/core/java/com/android/server/wm/RecentsAnimation.java
void?startRecentsActivity(IRecentsAnimationRunner?recentsAnimationRunner)?{
???????//省略部分
????????ActivityStack?targetStack?=?mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
????????????????mTargetActivityType);//獲取目標棧,這里是Home,就是Launcher
????????ActivityRecord?targetActivity?=?getTargetActivity(targetStack);
????????final?boolean?hasExistingActivity?=?targetActivity?!=?null;
????????if?(hasExistingActivity)?{
????????????final?ActivityDisplay?display?=?targetActivity.getDisplay();
????????????mRestoreTargetBehindStack?=?display.getStackAbove(targetStack);
???????????//省略部分
????????}
??????????//省略部分
????????try?{
????????????if?(hasExistingActivity)?{
????????????????//?Move?the?recents?activity?into?place?for?the?animation?if?it?is?not?top?most
????????????????//把桌面Launcher的棧stack移到聯(lián)系人這個當(dāng)前顯示棧的后一位,緊跟著
????????????????mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
?????????????//省略部分
????????????}?else?{
??????????//省略部分
????????????}
??????????//省略部分
????????????mWindowManager.cancelRecentsAnimationSynchronously(REORDER_MOVE_TO_ORIGINAL_POSITION,
????????????????????"startRecentsActivity");
????????????????????//初始化多任務(wù)動畫相關(guān)
????????????mWindowManager.initializeRecentsAnimation(mTargetActivityType,?recentsAnimationRunner,
????????????????????this,?mDefaultDisplay.mDisplayId,
????????????????????mStackSupervisor.mRecentTasks.getRecentTaskIds());
//這里需要調(diào)用保證Launcher是處于Visible的狀態(tài),因為之前一直在后臺當(dāng)然是非visible狀態(tài)
????????????mService.mRootActivityContainer.ensureActivitiesVisible(null,?0,?PRESERVE_WINDOWS);
????????????//省略部分
????????}?catch?(Exception?e)?{
????????????Slog.e(TAG,?"Failed?to?start?recents?activity",?e);
????????????throw?e;
????????}?finally?{
????????????mWindowManager.continueSurfaceLayout();
????????????Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
????????}
????}
這里主要介紹一下initializeRecentsAnimation這個關(guān)鍵方法: base/services/core/java/com/android/server/wm/WindowManagerService.java
????public?void?initializeRecentsAnimation(int?targetActivityType,
????????????IRecentsAnimationRunner?recentsAnimationRunner,
????????????RecentsAnimationController.RecentsAnimationCallbacks?callbacks,?int?displayId,
????????????SparseBooleanArray?recentTaskIds)?{
????????synchronized?(mGlobalLock)?{
????????//這里構(gòu)造出RecentsAnimationController對象
????????????mRecentsAnimationController?=?new?RecentsAnimationController(this,
????????????????????recentsAnimationRunner,?callbacks,?displayId);
????????????mRoot.getDisplayContent(displayId).mAppTransition.updateBooster();
????????????//調(diào)用了RecentsAnimationController的initialize方法
????????????mRecentsAnimationController.initialize(targetActivityType,?recentTaskIds);
????????}
????}
這里的調(diào)用了RecentsAnimationController的initialize base/services/core/java/com/android/server/wm/RecentsAnimationController.java
?public?void?initialize(int?targetActivityType,?SparseBooleanArray?recentTaskIds)?{
????????mTargetActivityType?=?targetActivityType;
????????mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
????????//?Make?leashes?for?each?of?the?visible/target?tasks?and?add?it?to?the?recents?animation?to
????????//?be?started
????????//獲取當(dāng)前顯示的Task
????????final?ArrayList<Task>?visibleTasks?=?mDisplayContent.getVisibleTasks();
????????????????//獲取目標Stack
????????final?TaskStack?targetStack?=?mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
????????????????targetActivityType);
????????if?(targetStack?!=?null)?{
????????????for?(int?i?=?targetStack.getChildCount()?-?1;?i?>=?0;?i--)?{
????????????????final?Task?t?=?targetStack.getChildAt(i);
????????????????if?(!visibleTasks.contains(t))?{
????????????????????visibleTasks.add(t);//把對應(yīng)Stack的task加入到visibleTasks
????????????????}
????????????}
????????}
????????final?int?taskCount?=?visibleTasks.size();
????????for?(int?i?=?0;?i?<?taskCount;?i++)?{
????????????final?Task?task?=?visibleTasks.get(i);
????????????final?WindowConfiguration?config?=?task.getWindowConfiguration();
????????????if?(config.tasksAreFloating()
????????????????????||?config.getWindowingMode()?==?WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)?{
????????????????continue;
????????????}
????????????//把對應(yīng)visibleTasks一個個加入Animation中
????????????addAnimation(task,?!recentTaskIds.get(task.mTaskId));
????????}
????????//省略部分
????????//調(diào)用
????????mService.mWindowPlacerLocked.performSurfacePlacement();
????????//?Notify?that?the?animation?has?started
????????if?(mStatusBar?!=?null)?{
????????????mStatusBar.onRecentsAnimationStateChanged(true?/*?running?*/);
????????}
????}
這里主要來看看addAnimation和performSurfacePlacement: base/services/core/java/com/android/server/wm/RecentsAnimationController.java
AnimationAdapter?addAnimation(Task?task,?boolean?isRecentTaskInvisible)?{
????if?(DEBUG_RECENTS_ANIMATIONS)?Slog.d(TAG,?"addAnimation("?+?task.getName()?+?")");
????//基于Task構(gòu)造出對應(yīng)的TaskAnimationAdapter
????final?TaskAnimationAdapter?taskAdapter?=?new?TaskAnimationAdapter(task,
????????????isRecentTaskInvisible);
????//這里直接調(diào)用了task的startAnimation
????task.startAnimation(task.getPendingTransaction(),?taskAdapter,?false?/*?hidden?*/);
????task.commitPendingTransaction();
????//taskAdapter添加到了mPendingAnimations
????mPendingAnimations.add(taskAdapter);
????return?taskAdapter;
}
這里主要就是TaskAnimationAdapter構(gòu)造以后,task調(diào)用了startAnimation base/services/core/java/com/android/server/wm/WindowContainer.java
????void?startAnimation(Transaction?t,?AnimationAdapter?anim,?boolean?hidden)?{
????????if?(DEBUG_ANIM)?Slog.v(TAG,?"Starting?animation?on?"?+?this?+?":?"?+?anim);
????????//?TODO:?This?should?use?isVisible()?but?because?isVisible?has?a?really?weird?meaning?at
????????//?the?moment?this?doesn't?work?for?all?animatable?window?containers.
????????mSurfaceAnimator.startAnimation(t,?anim,?hidden);
????}
然后調(diào)用到了SurfaceAnimator的startAnimation,這里才是關(guān)鍵: base/services/core/java/com/android/server/wm/SurfaceAnimator.java
void?startAnimation(Transaction?t,?AnimationAdapter?anim,?boolean?hidden)?{
????cancelAnimation(t,?true?/*?restarting?*/,?true?/*?forwardCancel?*/);
????mAnimation?=?anim;
????final?SurfaceControl?surface?=?mAnimatable.getSurfaceControl();
????if?(surface?==?null)?{
????????Slog.w(TAG,?"Unable?to?start?animation,?surface?is?null?or?no?children.");
????????cancelAnimation();
????????return;
????}
????//根據(jù)AnimationAdapter創(chuàng)建出了對應(yīng)的mLeash牽引
????mLeash?=?createAnimationLeash(surface,?t,
????????????mAnimatable.getSurfaceWidth(),?mAnimatable.getSurfaceHeight(),?hidden);
????mAnimatable.onAnimationLeashCreated(t,?mLeash);
????if?(mAnimationStartDelayed)?{
????????if?(DEBUG_ANIM)?Slog.i(TAG,?"Animation?start?delayed");
????????return;
????}
????mAnimation.startAnimation(mLeash,?t,?mInnerAnimationFinishedCallback);
}
創(chuàng)建出來了mLeash動畫Surface,然后把mLeash設(shè)置回了AnimationAdapter
創(chuàng)建牽引過程:
??private?SurfaceControl?createAnimationLeash(SurfaceControl?surface,?Transaction?t,?int?width,
????????????int?height,?boolean?hidden)?{
????????if?(DEBUG_ANIM)?Slog.i(TAG,?"Reparenting?to?leash");
????????final?SurfaceControl.Builder?builder?=?mAnimatable.makeAnimationLeash()
????????????????.setParent(mAnimatable.getAnimationLeashParent())
????????????????.setName(surface?+?"?-?animation-leash");
????????final?SurfaceControl?leash?=?builder.build();
????????t.setWindowCrop(leash,?width,?height);
????????t.show(leash);
????????//?TODO:?change?this?back?to?use?show?instead?of?alpha?when?b/138459974?is?fixed.
????????t.setAlpha(leash,?hidden???0?:?1);
????????t.reparent(surface,?leash);
????????return?leash;
????}
那么接下來分析 mService.mWindowPlacerLocked.performSurfacePlacement()方法: 他最后一路調(diào)用會調(diào)用到base/services/core/java/com/android/server/wm/RootWindowContainer.java:
?//?"Something?has?changed!??Let's?make?it?correct?now."
????//?TODO:?Super?crazy?long?method?that?should?be?broken?down...
????void?performSurfacePlacementNoTrace(boolean?recoveringMemory)?{
???????//省略非本次重點討論部分
????????//?Defer?starting?the?recents?animation?until?the?wallpaper?has?drawn
????????final?RecentsAnimationController?recentsAnimationController?=
????????????????mWmService.getRecentsAnimationController();
????????if?(recentsAnimationController?!=?null)?{
????????????recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
????????}
?//省略非本次重點討論部分
????}
????//這里會調(diào)用到RecentsAnimationController的checkAnimationReady:
?void?checkAnimationReady(WallpaperController?wallpaperController)?{
????????if?(mPendingStart)?{
????????????final?boolean?wallpaperReady?=?!isTargetOverWallpaper()
????????????????????||?(wallpaperController.getWallpaperTarget()?!=?null
????????????????????????????&&?wallpaperController.wallpaperTransitionReady());
????????????if?(wallpaperReady)?{
????????????????//調(diào)用了RecentsAnimationController的startAnimation
????????????????mService.getRecentsAnimationController().startAnimation();
????????????}
????????}
????}
這里來看RecentsAnimationController的startAnimation: base/services/core/java/com/android/server/wm/RecentsAnimationController.java
?void?startAnimation()?{
?????//省略非本次重點討論部分
????????try?{
????????????final?ArrayList<RemoteAnimationTarget>?appAnimations?=?new?ArrayList<>();
????????????for?(int?i?=?mPendingAnimations.size()?-?1;?i?>=?0;?i--)?{
????????????????final?TaskAnimationAdapter?taskAdapter?=?mPendingAnimations.get(i);
????????????????//taskAdapter創(chuàng)建出對應(yīng)的RemoteAnimationTarget
????????????????final?RemoteAnimationTarget?target?=?taskAdapter.createRemoteAnimationApp();
????????????????if?(target?!=?null)?{
????????????????????appAnimations.add(target);
????????????????}?else?{
????????????????????removeAnimation(taskAdapter);
????????????????}
????????????}
//省略非本次重點討論部分
//這里調(diào)用了mRunner的onAnimationStart,這個mRunner就是在桌面端的binder服務(wù)端對象,這里把appTargets傳遞給了Launcher端,其實就是mPendingAnimations中的taskAdapter調(diào)用createRemoteAnimationApp()創(chuàng)建出來的
????????????mRunner.onAnimationStart(mController,?appTargets,?contentInsets,?minimizedHomeBounds);
????????????if?(DEBUG_RECENTS_ANIMATIONS)?{
????????????????Slog.d(TAG,?"startAnimation():?Notify?animation?start:");
????????????????for?(int?i?=?0;?i?<?mPendingAnimations.size();?i++)?{
????????????????????final?Task?task?=?mPendingAnimations.get(i).mTask;
????????????????????Slog.d(TAG,?"\t"?+?task.mTaskId);
????????????????}
????????????}
????????}?catch?(RemoteException?e)?{
????????????Slog.e(TAG,?"Failed?to?start?recents?animation",?e);
????????}
????????final?SparseIntArray?reasons?=?new?SparseIntArray();
????????reasons.put(WINDOWING_MODE_FULLSCREEN,?APP_TRANSITION_RECENTS_ANIM);
????????mService.mAtmInternal.notifyAppTransitionStarting(reasons,?SystemClock.uptimeMillis());
????}
//這里對createRemoteAnimationApp進行解釋
?????RemoteAnimationTarget?createRemoteAnimationApp()?{
?????????//省略部分
?????????//這里主要mTaskId,mCapturedLeash(Leash的SurfaceControl,這個屬于非常重要的,后面Launcher手勢動畫客戶端就是靠它來控制畫面縮放移動)
????????????mTarget?=?new?RemoteAnimationTarget(mTask.mTaskId,?mode,?mCapturedLeash,
????????????????????!topApp.fillsParent(),?mainWindow.mWinAnimator.mLastClipRect,
????????????????????insets,?mTask.getPrefixOrderIndex(),?mPosition,?mBounds,
????????????????????mTask.getWindowConfiguration(),?mIsRecentTaskInvisible,?null,?null);
????????????return?mTarget;
????????}
相關(guān)干貨課程了解請直接加馬哥微信:
