Android N引入了Multi-Window, 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.
要支持Freeform自由窗口模式,主要有如下一些逻辑支持:
A)定义特有的freeform stack,所有的freeform模式的Activity会在特定的Freeform stack启动。
B) 为Freeform窗口添加特殊的layout, 用于控制窗口最大化,关闭以及拖动等功能。
C)为Freeform提供一个控制窗口初始化位置和大小的类
D) 为Freeform提供可以控制窗口移动和缩放处理的类
增加了Freeform特有的stack
已经定义了freeform的stack,那要如何让应用进入Freeform stack?
AMS提供了API支持Task在不同stack间移动, 将task移动到FREEFORM_WORKSPACE_STACK_ID,则应用进入自由窗口模式:
public void moveTaskToStack(int taskId, int stackId, boolean toTop)
为Freeform增加了一个特殊的Layout: DecorCaptionView, 直接挂在DecorView下
framework/base/core/res/res/layout/decor_caption.xml
关闭&退出按钮的实现在Activity类中实现,DecorCaptionView通过两个Callback将关闭及退出的操作转发给Activity.
具体由Activity类实现了关闭及退出的操作。
Freeform窗口的默认大小及布局由LaunchingTaskPositioner控制,启动Activity时通过设定Default Bounds来设置窗口初始化大小及位置。
AOSP默认Freeform窗口大小为 屏幕的1/2,位置屏幕中间位置。如果启动了多个窗口,通过位移错开排布。
窗口的移动主要由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属性,这样窗口才能自由拖动和缩放。