Android7.0多窗口实现原理(二)

    从上文可以知道当开始分屏时从SystemUI调用到ActivityStackSupervisor中的startActivityFromRecentsInner函数,当要分屏的Activity已经存在了,属于热启动分屏。

Android7.0多窗口实现原理(二)_第1张图片

在anyTaskForIdLocked函数中就直接将对应的TaskRecord对象返回。

Android7.0多窗口实现原理(二)_第2张图片

Move Stack    

由于获取到的TaskRecord并不是在分屏所属的ActivityStack,launchStackId和获得task的stack id不相同,就调用moveTaskToStackLocked函数将Task移动到分屏的stack中。

Android7.0多窗口实现原理(二)_第3张图片

在moveTaskToStackLocked函数中,首先根据taskId获取到对应的TaskRecord,如果task为空,或者task所在的stack就是分屏stack就会直接返回,如果请求stack为freeform是stack,但是系统不支持freeform stack就抛出异常。

Android7.0多窗口实现原理(二)_第4张图片

     接下来就需要将tack移动到对应到对应的stack中,之后记录新stack的id,冻结task的边界,对新的stack中的task进行重新计算尺寸。

Android7.0多窗口实现原理(二)_第5张图片

    首先分析moveTaskToStackUncheckedLocked函数将task移动到分屏的stack中。获取task顶层正在运行的Activity,将task所在的stack记录在preStack中,表示为之前的stack,判断preStack是否为焦点stack并且现在最顶层的Activity是否与之前的相同,preStack中可见的Activity是否与之前最顶端的Activity相同,并且判断之前顶层的Activity是否是最前端的Activity。

Android7.0多窗口实现原理(二)_第6张图片

    当在获取分屏stack时,我们要临时将resizeablility设置为false,不能进行resize,当获取完stack才可以resize。getStack的详细调用流程在上文https://blog.csdn.net/fu_kevin0606/article/details/81191078做过详细的分析。获取到的stack为分屏stack,stack id为3.

      获取完stack后调用WindowManagerService来移动task,在moveTaskToStack函数中根据taskId从mTaskIdToTask中获取到Task对象,然后根据stackId获取对应的TaskStack对象,之后调用Task.java的moveTaskToStack函数移动task到对应stack。

      在Task.java中判断task所属的TaskStack是否为空,如果不为空,就先将该task从TaskStack中移除,再重新添加到顶部。

Android7.0多窗口实现原理(二)_第7张图片

     在WMS中将task移动到对应的TaskStack后,需要将TaskRecord移动到分屏的ActivityStack中。由于需要将task添加的分屏stack的顶端,就调用insertTaskAtTop函数,将task插入顶端。

Android7.0多窗口实现原理(二)_第8张图片

      在将task插入最顶端时,如果task是从Home界面启动的,就获取这个task的下一个taskRecord,如果下一个task也不为空,就将这个task的返回类型传递给下一个taskRecord。

Android7.0多窗口实现原理(二)_第9张图片

      之后根据Activity的启动类型,从那个界面启动的来设置Activity的返回类型,有事我们会遇到从一个界面返回,应该返回到主界面,却返回到了其他打开过的应用中,就是该返回值设置错误。

Android7.0多窗口实现原理(二)_第10张图片

之后将task从历史列表中移除,从新计算位置,插入mTaskHistory列表。

Android7.0多窗口实现原理(二)_第11张图片

最后,如果我们移动的task之前有焦点,或者我们请求将焦点交给他,我们通过将stack移动到前面来移动焦点。

如果需将r赋值给mResumedActivity,调用moveToFront将stack移动到最前面。

Android7.0多窗口实现原理(二)_第12张图片

      将task移动到对应的stack中后,调用resizeTaskLocked函数resize task,由于此时为分屏stack,所以就使用分屏stack的边界来resize task。

在resize task时会先判断stack边界是否可用,如果可用,之后调用TaskRecord的updateOverrideConfiguration函数来更新Task的配置数据信息。

Android7.0多窗口实现原理(二)_第13张图片

       在计算config信息时调用calculateOverrideConfig函数,在该函数中获得设备的宽高,根据宽高来计算设备的方向,最后将获取的config信息返回。来判断config是否发生改变,如果改变了就将新的config信息返回,如果没有发生改变就返回null。

Android7.0多窗口实现原理(二)_第14张图片

如果此时config发生了改变overrideConfig不为null,就获取顶层的Activity,确认顶层的Activity的config信息与当前系统的config相同,如果config不相同,就将系统的config赋值给顶层Activity,然后通知应用config发生改变调用onConfigurationChanged函数。之后确保Activity在正确的config下使Activity可见。最后显示顶端的Activity。

Android7.0多窗口实现原理(二)_第15张图片

      之后调用WindowManagerService来resizeTask,根据taskId从mTaskIdToTask中取出对应的Task,调用的task的resizeLocked函数来resize task,当resize成功后,如果需要relayout,就需要调用performSurfacePlacement界面刷新函数来刷新界面。在resizeLocked函数中将bounds设置给task。

Android7.0多窗口实现原理(二)_第16张图片

    此时将task从原来的stack中移动到了分屏stack中,并且对task重新计算了size,下面重新回到 startActivityFromRecentsInner函数中。

Android7.0多窗口实现原理(二)_第17张图片

     前面主要是将另一个stack的task移动到分屏stack中,下面主要做的就是将移动到分屏stack的task移动到前台,可以被用户看到。该动作主要在moveTaskToFrontLocked函数中执行。首先根据taskId获取到对应的TaskRecord,获取当前正在运行的Activity记录在prev变量中,表现将要新的Activity要启动,该Activity变为前一个Activity。最后调用findTaskToMoveToFrontLocked函数来移动task。

Android7.0多窗口实现原理(二)_第18张图片

    在findTaskToMoveToFrontLocked函数中,根据task对象获取到栈顶的Activity,然后调用ActivityStack的moveTaskToFrontLocked函数将分屏task移动到stack的顶端。

Android7.0多窗口实现原理(二)_第19张图片

     在将task移动到stack顶端时调用insertTaskAtTop函数,将task插入顶端。此时task位于mTaskHistory列表的顶端,此时通过topRunningActivityLocked函数获得mTaskHistory顶端的task中顶端的Activity,也就是要进行分屏的Activity。将焦点设置在该Activity上面。

最后调用resumeFocusedStackTopActivityLocked来显示Activity。

你可能感兴趣的:(Android7.0多窗口实现原理(二))