Android 13 平行视界 ActivityEmbedding详解

avatar
@github.com/NasdaqGodzilla

背景

Android 13推出了一个大屏幕设备显示方案:Activity嵌入(Activity Embedding)。该功能不同于分屏模式(将多个应用同时显示在屏幕上),而是类似华为平行视界将同一个应用的多个不同Activity同时显示到屏幕上。

本文结合Android 13窗口架构,介绍Activity Embedding的创建流程。

image.png

image.png

窗口模型与Activity Embedding平行视界

Actiivty Embedding的实现流程与Android 13的窗口模型紧密相关。最简单最抽象的情况下,窗口对象之间的关系如下:

image.png

简单来说,Activity所在的Task,是以DisplayArea的形式在整个层级中组织管理的。代表Activity节点的ActivityRecord作为Task的child来管理,Task则由TaskDisplayArea来管理。

用层级结构来看非常直观。下图为常规情况(未进入Activity Embedding平行视界的情况)的层级描述:

image.png

简单解释一下这个层级,该Task位于一个DisplayArea,并以Activity栈的形式管理多个Activity,Activity管理WindowState。其中“V“图标含义是”可见“。

而进入平行视界的分屏模式时,两个Activity将同时显示,而Task本身不提供这个能力,而是由TaskFragment来实现。TaskFragment插入到Task和Activity之间,分割了Task在屏幕上的显示区域,提供给平行视界的两个Activity:

image.png

进入平行视界的层级,可见Task不再管理Actiivty栈,而被TaskFragment取代。

因此,TaskFragment是实现Activity Embedding平行视界的关键。进入平行视界实际上也就是创建TaskFragment并排布位置。

平行视界的一大特征是,Configuration有专属的WindowingMode、MaxBounds不等于Bounds。

image.png

Activity Embedding的两个Activity是独立绘制的:

image.png

Activity Embedding平行视界的流程

Activity Embedding的应用层经过封装,使用相对简单,并且可以根据配置的分屏规则自动完成分屏。

其中关键的两个技术点,自动完成分屏、执行分配操作分别依靠Instrumentation.ActivityMonitor和android.window.ITaskFragmentOrganizerController这个Binder来实现。当新的Activity启动时,ActivityMonitor.onActivityStart()被回调,判断需要启动平行视界时,自动调用ITaskFragmentOrganizerController,实现自动进入分屏。

ITaskFragmentOrganizerController

进入Activity Embedding分屏的关键接口为ITaskFragmentOrganizerController.applyTransaction(),该接口在WindowManagerService中由WindowOrganizerController实现

该方法主要处理Transaction,分为两大类类:Change、HierachyOps。对于平行视界的进入流程,为HierachyOps,简称为HOPs。

通过Transaction为左右两个Activity创建平行视界

创建平行视界的流程封装到了Transaction内,作为HOPs进行处理,保存到Transaction.hops(ArrayLists)内。

创建一个平行视界,实际上分为4步走:1. 创建左边Activity的TaskFragment,设置Configuration内的Bounds属性为左边的平行视界面积大小,并添加到Task内;2. 将左边Activity添加到TaskFragment内;3. 重复第一步,只不过创建的是右边Activity的Fragment;4. 重复第2步,只是目标是右边的Activity。

对应到源码,分别为HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT、HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT、HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT、HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS。

image.png

image.png

image.png

image.png

创建的各个参数,关键点为initialBounds属性记录的Rect,它确定了TaskFragment的大小和位置,最终确定了平行视界左右两个Activity的位置和大小。

添加完成后,会按照常规方式触发窗口的relayout和绘制,将平行视界的内容显示到屏幕上。