1. 基礎(chǔ)原理
1.1 ActivityRecord、TaskRecord、ActivityStack關(guān)系

一個(gè)ActivityRecord對(duì)應(yīng)著一個(gè)Activity,而一個(gè)Activity可能對(duì)應(yīng)著不同的ActivityRecord(因?yàn)锳ctivity可能被實(shí)例化多次)。一系列的ActivityRecord存在于TaskRecord(一個(gè)Task就是用戶體驗(yàn)上的一個(gè)“應(yīng)用”,它將相關(guān)的Activity組合在一起,以ArrayList存儲(chǔ)),而一系列TaskRecord存在于ActivityStack。ActivityStackSupervisor是用來管理這些ActivityStack的。
ActivityRecord對(duì)應(yīng)Activity的三種類型:
static final int APPLICATION_ACTIVITY_TYPE = 0;//普通應(yīng)用類型
static final int HOME_ACTIVITY_TYPE = 1;//桌面類型
static final int RECENTS_ACTIVITY_TYPE = 2;//最近任務(wù)類型
ActivityStack有五種靜態(tài)棧:
0 HOME_STACK_ID //Home應(yīng)用以及recents app所在的棧
1 FULLSCREEN_WORKSPACE_STACK_ID //一般應(yīng)用所在的棧
2 FREEFORM_WORKSPACE_STACK_ID //類似桌面操作系統(tǒng)
3 DOCKED_STACK_ID //分屏的應(yīng)用所在的棧
4 PINNED_STACK_ID //畫中畫棧
1.2 為什么要定義多個(gè)ActivityStack?
ActivityStack主要用于給TaskRecord的顯示類型分類。
在Android系統(tǒng)中,無論是普通的Activity窗口,還是特殊的輸入法窗口和壁紙窗口,它們都是被WindowManagerService服務(wù)組織在一個(gè)窗口堆棧中的,其中,Z軸位置較大的窗口排列在Z軸位置較小的窗口的上面。
通過ActivityStack中定義的棧類型,WMS可以方便的指定ActivityStack中各個(gè)Activity窗口顯示的z軸位置。比如ActivityStack為DOCKED_STACK_ID的一系列Activity窗口就要顯示在ActivityStack為FULLSCREEN_WORKSPACE_STACK_ID的所有Activity窗口之上。
1.3 Activity繪制
每一個(gè)Activity組件都有一個(gè)關(guān)聯(lián)的Window對(duì)象(PhoneWindow),用來描述一個(gè)應(yīng)用程序窗口。每一個(gè)應(yīng)用程序窗口內(nèi)部又包含有一個(gè)View對(duì)象(DecorView),用來描述應(yīng)用程序窗口的視圖。

控制Acivity的顯示,就是通過PhoneWindow控制顯示區(qū)域,通過DecorView控制顯示樣式和布局。
2. 原生分屏顯示功能
2.1 Recents中的任務(wù)管理

任務(wù)列表界面中的每一個(gè)任務(wù)對(duì)應(yīng)一個(gè)TaskView,TaskView通過一個(gè)對(duì)應(yīng)的Task類存儲(chǔ)Activity的包名類名等信息。
2.2 分屏操作流程

1,通過AMS將要分屏的TaskRecord放入DOCKED_STACK_ID所在的ActivityStack
2,計(jì)算分屏后窗口大?。ㄊ紫纫詫?duì)半分的形式顯示)
3,要分屏的TaskRecord中的Activity重新啟動(dòng),并在WMS中根據(jù)新窗口大小進(jìn)行繪制
4,將RecentActivity放入DOCKED_STACK_ID所在的ActivityStack并同樣根據(jù)新窗口進(jìn)行繪制,顯示在另一半邊
5,繪制分割線DividerView。拖動(dòng)分割線會(huì)重新計(jì)算窗口大小,釋放觸摸后重繪窗口
另外,分屏顯示流程中使用了EventBus進(jìn)行消息傳遞。
2.3 EventBus
SystemUI的Recents相關(guān)代碼,使用EventBus進(jìn)行消息傳遞。大致原理是首先向EventBus注冊(cè)回調(diào),當(dāng)通過EventBus傳遞消息時(shí),會(huì)遍歷注冊(cè)的回調(diào),通知所有符合的回調(diào)。
分屏主要使用了以下Event(基于android8.0源碼):
DragEndEvent消息,將一個(gè)TaskView分屏;
LaunchTaskEvent消息,在任務(wù)列表中打開應(yīng)用;
UndockingTaskEvent消息,分屏分割線的拖動(dòng)消息
3. SF的生產(chǎn)者消費(fèi)者模型

SF的Client對(duì)象創(chuàng)建了一個(gè)圖元生產(chǎn)者,并且賦值給SurfaceControl中,SurfaceControl生產(chǎn)Surface對(duì)象。
Surface通過Binder和BufferQueue通信,申請(qǐng)buffer,往這個(gè)buffer中填入想要顯示的內(nèi)容,再塞回BufferQueue,BufferQueue會(huì)通知SuefaceFlinger進(jìn)行渲染顯示。
4.開機(jī)自動(dòng)分屏的簡單實(shí)現(xiàn)
基本思想就是查找目標(biāo)Activity的TaskView和Task,使用DragEndEvent消息模擬TaskView的拖動(dòng)進(jìn)行分屏,然后通過LaunchTaskEvent消息在另一個(gè)分屏區(qū)域打開目標(biāo)應(yīng)用。還可以通過自定義Event模擬分屏分割線的拖動(dòng),實(shí)現(xiàn)分屏比例修改。

參考:
Android7.1.1上下/左右分屏的策略分析
Android8.0多窗口調(diào)研
Android 重學(xué)系列 渲染圖層-圖元緩沖隊(duì)列初始化