1. 基礎原理
1.1 ActivityRecord、TaskRecord、ActivityStack關系
一個ActivityRecord對應著一個Activity,而一個Activity可能對應著不同的ActivityRecord(因為Activity可能被實例化多次)。一系列的ActivityRecord存在于TaskRecord(一個Task就是用戶體驗上的一個“應用”,它將相關的Activity組合在一起,以ArrayList存儲),而一系列TaskRecord存在于ActivityStack。ActivityStackSupervisor是用來管理這些ActivityStack的。
ActivityRecord對應Activity的三種類型:
static final int APPLICATION_ACTIVITY_TYPE = 0;//普通應用類型
static final int HOME_ACTIVITY_TYPE = 1;//桌面類型
static final int RECENTS_ACTIVITY_TYPE = 2;//最近任務類型
ActivityStack有五種靜態棧:
0 HOME_STACK_ID //Home應用以及recents app所在的棧
1 FULLSCREEN_WORKSPACE_STACK_ID //一般應用所在的棧
2 FREEFORM_WORKSPACE_STACK_ID //類似桌面操作系統
3 DOCKED_STACK_ID //分屏的應用所在的棧
4 PINNED_STACK_ID //畫中畫棧
1.2 為什么要定義多個ActivityStack?
ActivityStack主要用于給TaskRecord的顯示類型分類。
在Android系統中,無論是普通的Activity窗口,還是特殊的輸入法窗口和壁紙窗口,它們都是被WindowManagerService服務組織在一個窗口堆棧中的,其中,Z軸位置較大的窗口排列在Z軸位置較小的窗口的上面。
通過ActivityStack中定義的棧類型,WMS可以方便的指定ActivityStack中各個Activity窗口顯示的z軸位置。比如ActivityStack為DOCKED_STACK_ID的一系列Activity窗口就要顯示在ActivityStack為FULLSCREEN_WORKSPACE_STACK_ID的所有Activity窗口之上。
1.3 Activity繪制
每一個Activity組件都有一個關聯的Window對象(PhoneWindow),用來描述一個應用程序窗口。每一個應用程序窗口內部又包含有一個View對象(DecorView),用來描述應用程序窗口的視圖。
控制Acivity的顯示,就是通過PhoneWindow控制顯示區域,通過DecorView控制顯示樣式和布局。
2. 原生分屏顯示功能
2.1 Recents中的任務管理
任務列表界面中的每一個任務對應一個TaskView,TaskView通過一個對應的Task類存儲Activity的包名類名等信息。
2.2 分屏操作流程
1,通過AMS將要分屏的TaskRecord放入DOCKED_STACK_ID所在的ActivityStack
2,計算分屏后窗口大小(首先以對半分的形式顯示)
3,要分屏的TaskRecord中的Activity重新啟動,并在WMS中根據新窗口大小進行繪制
4,將RecentActivity放入DOCKED_STACK_ID所在的ActivityStack并同樣根據新窗口進行繪制,顯示在另一半邊
5,繪制分割線DividerView。拖動分割線會重新計算窗口大小,釋放觸摸后重繪窗口
另外,分屏顯示流程中使用了EventBus進行消息傳遞。
2.3 EventBus
SystemUI的Recents相關代碼,使用EventBus進行消息傳遞。大致原理是首先向EventBus注冊回調,當通過EventBus傳遞消息時,會遍歷注冊的回調,通知所有符合的回調。
分屏主要使用了以下Event(基于android8.0源碼):
DragEndEvent消息,將一個TaskView分屏;
LaunchTaskEvent消息,在任務列表中打開應用;
UndockingTaskEvent消息,分屏分割線的拖動消息
3. SF的生產者消費者模型
SF的Client對象創建了一個圖元生產者,并且賦值給SurfaceControl中,SurfaceControl生產Surface對象。
Surface通過Binder和BufferQueue通信,申請buffer,往這個buffer中填入想要顯示的內容,再塞回BufferQueue,BufferQueue會通知SuefaceFlinger進行渲染顯示。
4.開機自動分屏的簡單實現
基本思想就是查找目標Activity的TaskView和Task,使用DragEndEvent消息模擬TaskView的拖動進行分屏,然后通過LaunchTaskEvent消息在另一個分屏區域打開目標應用。還可以通過自定義Event模擬分屏分割線的拖動,實現分屏比例修改。
參考:
Android7.1.1上下/左右分屏的策略分析
Android8.0多窗口調研
Android 重學系列 渲染圖層-圖元緩沖隊列初始化