Android N引入了Multi-Window, Freeform自由窗口模式是其中的一種。自由窗口模式下可以實現窗口的可以自由縮放,自由移動。
1. Freeform功能開啓
Android原生版本沒有開啓Freeform功能,ActivityManagerService中定義是否支持freeform模式,可以看到有兩種方式來開啓Freeform,一種是通過system feature定義,一種是通過setting增加開關啓動。
如果通過system feature定義,可以查看AOSP已經定義的Feature配置文件:
frameworks/native/data/etc/android.software.freeform_window_management.xml
只需要把此文件push到手機的system/etc/permissions/目錄下,開機時PMS會通過的讀取此目錄下xml配置開啓freeform這個feature.
2. Freeform模式主要功能實現
要支持Freeform自由窗口模式,主要有如下一些邏輯支持:
A)定義特有的freeform stack,所有的freeform模式的Activity會在特定的Freeform stack啓動。
B) 爲Freeform窗口添加特殊的layout, 用於控制窗口最大化,關閉以及拖動等功能。
C)爲Freeform提供一個控制窗口初始化位置和大小的類
D) 爲Freeform提供可以控制窗口移動和縮放處理的類
2.1 Freeform stack
增加了Freeform特有的stack
已經定義了freeform的stack,那要如何讓應用進入Freeform stack?
AMS提供了API支持Task在不同stack間移動, 將task移動到FREEFORM_WORKSPACE_STACK_ID,則應用進入自由窗口模式:
public void moveTaskToStack(int taskId, int stackId, boolean toTop)
2.2 Freeform窗口關閉最小化控制
爲Freeform增加了一個特殊的Layout: DecorCaptionView, 直接掛在DecorView下
framework/base/core/res/res/layout/decor_caption.xml
關閉&退出按鈕的實現在Activity類中實現,DecorCaptionView通過兩個Callback將關閉及退出的操作轉發給Activity.
具體由Activity類實現了關閉及退出的操作。
2.3 Freeform窗口默認大小及位置
Freeform窗口的默認大小及佈局由LaunchingTaskPositioner控制,啓動Activity時通過設定Default Bounds來設置窗口初始化大小及位置。
AOSP默認Freeform窗口大小爲 屏幕的1/2,位置屏幕中間位置。如果啓動了多個窗口,通過位移錯開排布。
2.4 窗口移動及縮放
窗口的移動主要由TaskPostioner處理, 開始移動時先記下初始位置,註冊Input事件監聽. 移動過程中根據Input更新窗口Bounds達到移動窗口的目標。
對於Freeform窗口的縮放,AOSP默認支持橫向/縱向/對角三種拉伸方式,窗口縮放 與窗口移動一樣由TaskPositioner處理
整個流程與remove類似。由於窗口縮放後,config發生變化,對於某些採用sw/ w/ h/resolution等定義的資源有影響,可能會觸發重新加載資源。
3. Debug技巧
通過am stack move-task命令將stack移到freeform stack.
首先可以通過am命令來查看stack及task信息
然後用am stack move-task的命令移動stack, 這樣窗口就進入了freeform自由窗口模式。
某些應用可能設置了不能resizeable, 需要使用adb shell am task resizeable來設置resizeable屬性,這樣窗口才能自由拖動和縮放。