前言
打开MainActivity,然后进入最近任务触发分屏,可以成功进入分屏模式。
本篇文章我们来具体梳理一下这个过程的源码调用流程。
一 launcher3阶段
1.1 源码
//packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/TaskView.java
public class TaskView extends FrameLayout implements Reusable {private void onClick(View view) {if (getTask() == null) {return;}if (confirmSecondSplitSelectApp()) {return;}launchTasks();...代码省略...}private boolean confirmSecondSplitSelectApp() {boolean isSelectingSecondSplitApp = getRecentsView().isSplitSelectionActive();if (isSelectingSecondSplitApp) {//调用RecentsView的confirmSplitSelect方法getRecentsView().confirmSplitSelect(this);}return isSelectingSecondSplitApp;}
}//packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java
public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,TaskVisualsChangeListener {protected SplitSelectStateController mSplitSelectStateController;public void confirmSplitSelect(TaskView taskView) {...代码省略...pendingAnimation.addEndListener(aBoolean -> {pendingAnimation.addEndListener(aBoolean ->//待动画结束,执行SplitSelectStateController的setSecondTaskId方法mSplitSelectStateController.setSecondTaskId(taskView.getTask(),aBoolean1 -> RecentsView.this.resetFromSplitSelectionState())); ...代码省略...}
}//packages/apps/Launcher3/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
public class SplitSelectStateController {public void setSecondTaskId(Task task, Consumer<Boolean> callback) {mSecondTask = task;launchTasks(mInitialTask, mSecondTask, mStagePosition, callback,false /* freezeTaskList */, DEFAULT_SPLIT_RATIO);}private final SystemUiProxy mSystemUiProxy;public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition,Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {...代码省略...mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(),taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,splitRatio, adapter); ...代码省略...}}//packages/apps/Launcher3/quickstep/src/com/android/quickstep/SystemUiProxy.java
public class SystemUiProxy implements ISystemUiProxy, NavHandle {private ISplitScreen mSplitScreen;public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,float splitRatio, RemoteAnimationAdapter adapter) {if (mSystemUiProxy != null) {try {mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,sideOptions, sidePosition, splitRatio, adapter);} catch (RemoteException e) {Log.w(TAG, "Failed call startTasksWithLegacyTransition");}}}
}
1.2 时序图
二 SystemUI阶段
2.1 源码
public class SplitScreenController implements DragAndDropPolicy.Starter,RemoteCallable<SplitScreenController> {private static class ISplitScreenImpl extends ISplitScreen.Stub {@Overridepublic void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,float splitRatio, RemoteAnimationAdapter adapter) {executeRemoteCallWithTaskPermission(mController, "startTasks",(controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition,splitRatio, adapter));}}
}class StageCoordinator implements SplitLayout.SplitLayoutHandler,RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {private final ShellTaskOrganizer mTaskOrganizer;void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,float splitRatio, RemoteAnimationAdapter adapter) {//设置分割线的可见性setDividerVisibility(false /* visible */);//初始化分屏的分割线的布局mSplitLayout.init();// Set false to avoid record new bounds with old task still on top;mShouldUpdateRecents = false;final WindowContainerTransaction wct = new WindowContainerTransaction();final WindowContainerTransaction evictWct = new WindowContainerTransaction();prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);//创建一个远程动画的回调binder对象IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {@Overridepublic void onAnimationStart(@WindowManager.TransitionOldType int transit,RemoteAnimationTarget[] apps,RemoteAnimationTarget[] wallpapers,RemoteAnimationTarget[] nonApps,final IRemoteAnimationFinishedCallback finishedCallback) {...代码省略...}@Overridepublic void onAnimationCancelled() {...代码省略...}};//创建RemoteAnimationAdapter类型的远程动画RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());if (mainOptions == null) {//构建出对应的mainOptions,及上分屏的启动optionmainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();} else {ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));mainOptions = mainActivityOptions.toBundle();}//准备好对应的sideOptions,下分屏的optionsideOptions = sideOptions != null ? sideOptions : new Bundle();setSideStagePosition(sidePosition, wct);//设置分界线比例mSplitLayout.setDivideRatio(splitRatio);if (mMainStage.isActive()) {mMainStage.moveToTop(getMainStageBounds(), wct);} else {// Build a request WCT that will launch both apps such that task 0 is on the main stage// while task 1 is on the side stage.mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);}mSideStage.moveToTop(getSideStageBounds(), wct);//准备好对应的option参数// Make sure the launch options will put tasks in the corresponding split rootsaddActivityOptions(mainOptions, mMainStage);addActivityOptions(sideOptions, mSideStage);// Add task launch requestswct.startTask(mainTaskId, mainOptions);//主分屏taskwct.startTask(sideTaskId, sideOptions);//次分屏task//最后把前面准备好的参数统一apply到SystemServer里面mTaskOrganizer.applyTransaction(wct);}
}
2.2 时序图
三 SystemServer阶段
3.1 源码
//frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java
public class ShellTaskOrganizer extends TaskOrganizer implements CompatUIController.CompatUICallback {//父类方法public void applyTransaction(@NonNull WindowContainerTransaction t) {try {if (!t.isEmpty()) {//调用ActivityTaskManagerService的getWindowOrganizerController方法得到WindowOrganizerController对象//并调用WindowOrganizerController对象的applyTransaction方法getWindowOrganizerController().applyTransaction(t);}} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}static IWindowOrganizerController getWindowOrganizerController() {return IWindowOrganizerControllerSingleton.get();}private static final Singleton<IWindowOrganizerController> IWindowOrganizerControllerSingleton =new Singleton<IWindowOrganizerController>() {@Overrideprotected IWindowOrganizerController create() {try {return ActivityTaskManager.getService().getWindowOrganizerController();} catch (RemoteException e) {return null;}}};
}public class ActivityTaskManagerService extends IActivityTaskManager.Stub {WindowOrganizerController mWindowOrganizerController;@Overridepublic IWindowOrganizerController getWindowOrganizerController() {return mWindowOrganizerController;}
}//base/services/core/java/com/android/server/wm/WindowOrganizerController.java
class WindowOrganizerController extends IWindowOrganizerController.Stub {@Overridepublic void applyTransaction(WindowContainerTransaction t) {...代码省略...applyTransaction(t, -1 /*syncId*/, null /*transition*/, caller);...代码省略...}private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,@Nullable Transition transition, @NonNull CallerInfo caller) {...代码省略...ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();//获取WindowContainerTransaction的change部分Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =t.getChanges().entrySet().iterator();while (entries.hasNext()) {//遍历每个变化的元素final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());if (wc == null || !wc.isAttached()) {Slog.e(TAG, "Attempt to operate on detached container: " + wc);continue;}// Make sure we add to the syncSet before performing// operations so we don't end up splitting effects between the WM// pending transaction and the BLASTSync transaction.if (syncId >= 0) {addToSyncSet(syncId, wc);}if (transition != null) transition.collect(wc);//注释1,这里一般就是前面说过的上屏和下屏的对应Task,调用applyWindowContainerChange方法进行对应处理int containerEffect = applyWindowContainerChange(wc, entry.getValue());effects |= containerEffect;// Lifecycle changes will trigger ensureConfig for everything.if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0&& (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {haveConfigChanges.add(wc);}}// Hierarchy changesfinal List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();final int hopSize = hops.size();if (hopSize > 0) {final boolean isInLockTaskMode = mService.isInLockTaskMode();for (int i = 0; i < hopSize; ++i) {//注释2,调用applyHierarchyOp方法,对reorder和starTask的操作进行处理effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,isInLockTaskMode, caller, t.getErrorCallbackToken(),t.getTaskFragmentOrganizer());}} ...代码省略...}private int applyWindowContainerChange(WindowContainer wc, WindowContainerTransaction.Change c) {sanitizeWindowContainer(wc);//调用applyChangesint effects = applyChanges(wc, c);if (wc instanceof DisplayArea) {effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c);} else if (wc instanceof Task) {effects |= applyTaskChanges(wc.asTask(), c);}return effects;}private int applyChanges(WindowContainer container, WindowContainerTransaction.Change change) {...代码省略...//最重要就是获取change的configration,因为bounds变化被包在了configration里面,//这里再调用container的进行通知configration的变化final Configuration c =new Configuration(container.getRequestedOverrideConfiguration());c.setTo(change.getConfiguration(), configMask, windowMask);//Task容器调用这个onRequestedOverrideConfigurationChanged,//代表根据传递过来的Configration作为自己的覆盖变化,即也就把对应的bounds设置给了Taskcontainer.onRequestedOverrideConfigurationChanged(c);...代码省略...}
}
调用applyHierarchyOp方法将task放到最上层
class WindowOrganizerController extends IWindowOrganizerController.Stub {//HIERARCHY_OP_TYPE_REORDER和HIERARCHY_OP_TYPE_REPARENT类型private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,int syncId, @Nullable Transition transition, boolean isInLockTaskMode,@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,@Nullable ITaskFragmentOrganizer organizer) {final int type = hop.getType();...代码省略...switch (type) {...代码省略...case HIERARCHY_OP_TYPE_REORDER:case HIERARCHY_OP_TYPE_REPARENT: {//首先要从hop中获取出WindowContainerfinal WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());...代码省略...//调用sanitizeAndApplyHierarchyOp进行处理effects |= sanitizeAndApplyHierarchyOp(wc, hop);break;}case HIERARCHY_OP_TYPE_LAUNCH_TASK: {...代码省略...return effects;}private int sanitizeAndApplyHierarchyOp (WindowContainer container,WindowContainerTransaction.HierarchyOp hop){//这里获取task,其实就是RootTask,分屏最顶端那个taskId为4的final Task task = container.asTask();...代码省略...//需要把task进行移动放到所有task的顶端位置task.getParent().positionChildAt(hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,task, false /* includingParents */);...代码省略...return TRANSACT_EFFECTS_LIFECYCLE;}}
调用applyHierarchyOp方法对数据进行拆解,然后调用ActivityTaskSupervisor的startActivityFromRecents方法:
class WindowOrganizerController extends IWindowOrganizerController.Stub {//HIERARCHY_OP_TYPE_REORDER和HIERARCHY_OP_TYPE_REPARENT类型private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,int syncId, @Nullable Transition transition, boolean isInLockTaskMode,@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,@Nullable ITaskFragmentOrganizer organizer) {final int type = hop.getType();...代码省略...switch (type) {...代码省略...case HIERARCHY_OP_TYPE_REORDER:case HIERARCHY_OP_TYPE_REPARENT: ...代码省略...case HIERARCHY_OP_TYPE_LAUNCH_TASK: {mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,"launchTask HierarchyOp");final Bundle launchOpts = hop.getLaunchOptions();final int taskId = launchOpts.getInt(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);final SafeActivityOptions safeOptions =SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);final Integer[] starterResult = {null};// startActivityFromRecents should not be called in lock.mService.mH.post(() -> {try {//调用ActivityTaskSupervisor的startActivityFromRecents方法starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(caller.mPid, caller.mUid, taskId, safeOptions);} catch (Throwable t) {starterResult[0] = ActivityManager.START_CANCELED;Slog.w(TAG, t);}synchronized (mGlobalLock) {mGlobalLock.notifyAll();}});while (starterResult[0] == null) {try {mGlobalLock.wait();} catch (InterruptedException ignored) {}}break;}...代码省略...return effects;}}
}
//base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
public class ActivityTaskSupervisor implements RecentTasks.Callbacks {RootWindowContainer mRootWindowContainer;final ActivityTaskManagerService mService;int startActivityFromRecents(int callingPid, int callingUid, int taskId,SafeActivityOptions options) {final Task task;final int taskCallingUid;final String callingPackage;final String callingFeatureId;final Intent intent;final int userId;final ActivityOptions activityOptions = options != null? options.getOptions(this): null;boolean moveHomeTaskForward = true;synchronized (mService.mGlobalLock) {int activityType = ACTIVITY_TYPE_UNDEFINED;if (activityOptions != null) {activityType = activityOptions.getLaunchActivityType();...代码省略...//这里主要通过taskId来获取一个Task,但是这个方法不仅仅只干了获取task的事情,//还干了把taskId对应的Task进行reparent到新上下分屏的容器Task,这样实现了层级结构树上面的挂载完成,//剩下就是一系列操作来保证Activiyt生命周期正常相关task = mRootWindowContainer.anyTaskForId(taskId,MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);...代码省略...if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)&& task.getRootActivity() != null) {//获取task的Activityfinal ActivityRecord targetActivity = task.getTopNonFinishingActivity();...代码省略...//调用mService.moveTaskToFrontLocked(null /* appThread */,null /* callingPackage */, task.mTaskId, 0, options);...代码省略...}}}}}
}
RootWindowContainer的anyTaskForId方法
class RootWindowContainer extends WindowContainer<DisplayContent>implements DisplayManager.DisplayListener {Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode,@Nullable ActivityOptions aOptions, boolean onTop) {final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTaskId, PooledLambda.__(Task.class), id);Task task = getTask(p);//遍历获取Taskp.recycle();if (task != null) {if (aOptions != null) {//注意这里aOptions不为null,而且携带了task//这里有调用了getOrCreateRootTask来获取targetRootTaskfinal Task targetRootTask =getOrCreateRootTask(null, aOptions, task, onTop);if (targetRootTask != null && task.getRootTask() != targetRootTask) {final int reparentMode = onTop? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;task.reparent(targetRootTask, onTop, reparentMode, ANIMATE, DEFER_RESUME,"anyTaskForId");}}return task;}//省略}Task getOrCreateRootTask(@Nullable ActivityRecord r,@Nullable ActivityOptions options, @Nullable Task candidateTask,@Nullable Task sourceTask, boolean onTop,@Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {// First preference goes to the launch root task set in the activity options.if (options != null) {//这里终于体现systemui传递的mainoptions作用了final Task candidateRoot = Task.fromWindowContainerToken(options.getLaunchRootTask());if (candidateRoot != null && canLaunchOnDisplay(r, candidateRoot)) {return candidateRoot;//大家看这里就直接返回了options带的task}}//省略}}
ActivityTaskManagerService的moveTaskToFrontLocked方法
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,@Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options) {//省略try {final Task task = mRootWindowContainer.anyTaskForId(taskId);//省略ActivityOptions realOptions = options != null? options.getOptions(mTaskSupervisor): null;//这方法最为关键,寻找到task而且移到最前端mTaskSupervisor.findTaskToMoveToFront(task, flags, realOptions, "moveTaskToFront",false /* forceNonResizable */);//开始启动StartingWindowfinal ActivityRecord topActivity = task.getTopNonFinishingActivity();if (topActivity != null) {// We are reshowing a task, use a starting window to hide the initial draw delay// so the transition can start earlier.topActivity.showStartingWindow(true /* taskSwitch */);}//省略}}
}
findTaskToMoveToFront方法
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {/** This doesn't just find a task, it also moves the task to front. */void findTaskToMoveToFront(Task task, int flags, ActivityOptions options, String reason,boolean forceNonResizeable) {//这里currentRootTask就是taskId =4的根taskTask currentRootTask = task.getRootTask();//省略final ActivityRecord r = task.getTopNonFinishingActivity();//这里又调用到了关键moveTaskToFront方法currentRootTask.moveTaskToFront(task, false /* noAnimation */, options,r == null ? null : r.appTimeTracker, reason);//省略}final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,AppTimeTracker timeTracker, boolean deferResume, String reason) {//省略//这里又关键调用到了顶部ActivityRecord的moveFocusableActivityToTop方法// Set focus to the top running activity of this task and move all its parents to top.top.moveFocusableActivityToTop(reason);//省略if (!deferResume) {//进行对应resume操作mRootWindowContainer.resumeFocusedTasksTopActivities();}//省略}boolean moveFocusableActivityToTop(String reason) {final Task rootTask = getRootTask();//这里调用了rootTask把当前app的task移到最前rootTask.moveToFront(reason, task);// Report top activity change to tracking services and WMif (mRootWindowContainer.getTopResumedActivity() == this) { //注意这里可能大家有疑问为啥都可以getTopResumedActivity到了,还需要设置,那是因为getTopResumedActivity可能真正ResumedActivity为null,但是会通过获取getFocusedActivity获取作为ResumedActivity//这个操作关键,把ActivityRecord开始要变成Resumed状态了,这个就不展开,前面课程视频讲解mAtmService.setResumedActivityUncheckLocked(this, reason);}return true;}@NullableActivityRecord getTopResumedActivity() {final Task focusedRootTask = getTopDisplayFocusedRootTask();//getTopResumedActivity这个时候是为null哦final ActivityRecord resumedActivity = focusedRootTask.getTopResumedActivity();if (resumedActivity != null && resumedActivity.app != null) {return resumedActivity;}// The top focused root task might not have a resumed activity yet - look on all displays in// focus order.//前面发现为null后就获取getFocusedActivityreturn getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity);}
}