重学wms:你知道什么是AdjacentTask吗?分屏模式的判断方法

背景:

在我们做多窗口开发过程中一般有以下几种模式:

    public static final int WINDOWING_MODE_FULLSCREEN = 1;
    /** Always on-top (always visible). of other siblings in its parent container. */
    public static final int WINDOWING_MODE_PINNED = 2;
    /** Can be freely resized within its parent container. */
    // TODO: Remove once freeform is migrated to wm-shell.
    public static final int WINDOWING_MODE_FREEFORM = 5;
    /** Generic multi-window with no presentation attribution from the window manager. */
    public static final int WINDOWING_MODE_MULTI_WINDOW = 6;

明显自由窗口和pip模式可以在系统中直接通过windowingMode的值进行直接判断,这时候大家是否想过我们分屏模式应该如何判断啊?
可能很多同学会有如下回答:
直接使用windowingMode判断,看看是否为WINDOWING_MODE_MULTI_WINDOW不就行了。
但是大家注意哈,正常情况下确实一般分屏模式的两个task是mode为multi-window,但是大家注意mutilwindow却不一定为分屏模式哈,比如以前的车载桌面那个Activity嵌入显示的模式,也是multiwindow但不是分屏模式。
那么有啥好办法可以判断当前显示的Activity或者task是否为分屏呢?下面本文就带大家来剖析一下该问题。

系统如何判断分屏模式?

在系统代码中收到如下代码来判断当前显示的Task是否处于分屏模式

final boolean inSplitScreenMode  =
                defaultTaskDisplayArea.getRootTask(task -> task.isVisible()
                        && task.getTopLeafTask().getAdjacentTask() != null)
                        != null;

针对上面代码展开源码分析有如下几个过程:

1、遍历defaultTaskDisplayArea这个节点下面的所有RootTask

2、接下来开始挨个RootTask进行,判断条件
a. task是显示状态isVisible为true
b. 判断task的最顶部的叶子task
c. 判断叶子task的AdjacentTask是否不为null
如果不为null说明就是分屏模式。

上面判断代码让大家最疑惑的应该是为啥可以通过getAdjacentTask来判断是否为分屏模式呢?

源码分析adjacent相关设置

上面判断为分屏模式代码中,关键就是靠
这里的AdjacentTask属于熟悉而又陌生的方法,熟悉在于你经常见到它在framework代码中,陌生在于你可能没有本质理解它什么意思,想不到它的实际场景。
Adjacent 翻译后的中文意思就是“ 相邻;邻近的 ”,也就是mAdjacentTaskFragment本质上代表是一个邻居Task。

   /** The TaskFragment that is adjacent to this one. */
    @Nullable
    private TaskFragment mAdjacentTaskFragment;

那么这个邻居Task字面意思理解就是两个Task在一起,相邻着的意思。

那么我们关键就看看mAdjacentTaskFragment到底是在哪里进行的赋值,通过代码调试追查发现如下地方进行的设置。
在这里插入图片描述

分屏设置AdjacentTask的调用堆栈:

setAdjacentTaskFragment:447, TaskFragment (com.android.server.wm)
setAdjacentRootsHierarchyOp:2015, WindowOrganizerController (com.android.server.wm)
applyHierarchyOp:1083, WindowOrganizerController (com.android.server.wm)
applyTransaction:718, WindowOrganizerController (com.android.server.wm)
applyTransaction:579, WindowOrganizerController (com.android.server.wm)
applyTransaction:596, WindowOrganizerController (com.android.server.wm)
lambda$applySyncTransaction$0:259, WindowOrganizerController (com.android.server.wm)
accept:0, WindowOrganizerController$$ExternalSyntheticLambda1 (com.android.server.wm)
startLegacySyncOrQueue:1481, TransitionController (com.android.server.wm)
applySyncTransaction:258, WindowOrganizerController (com.android.server.wm)
onTransact:204, WindowOrganizerController (com.android.server.wm)
execTransactInternal:1505, Binder (android.os)
execTransact:1444, Binder (android.os)

明显可以看到是在systemui进程创建分屏的两个task时候会触发这个setAdjacentTaskFragment设置。
这里来详细看看setAdjacentTaskFragment方法:

    void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
        if (mAdjacentTaskFragment == taskFragment) {
            return;
        }
        resetAdjacentTaskFragment();
        if (taskFragment != null) {
            mAdjacentTaskFragment = taskFragment;
            //这里把当前task设置成参数task的AdjacentTask
            taskFragment.setAdjacentTaskFragment(this);
        }
    }

简单说就是Task1和Task2分别设置对方成为自己的AdjacentTask,形成如下图的依赖模式
在这里插入图片描述

systemui如何触发到system端setAdjacentTaskFragment

frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java

StageCoordinator的onRootTaskAppeared方法中触发的设置

在这里插入图片描述其实这里的也很,注释明显

// Make the stages adjacent to each other so they occlude what's behind them.

保证上下分屏的task与彼此相邻。

frameworks/base/core/java/android/window/WindowContainerTransaction.java

 /**
     * Sets to containers adjacent to each other. Containers below two visible adjacent roots will
     * be made invisible. This currently only applies to TaskFragment containers created by
     * organizer.
     * @param root1 the first root.
     * @param root2 the second root.
     */
    @NonNull
    public WindowContainerTransaction setAdjacentRoots(
            @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) {
        mHierarchyOps.add(HierarchyOp.createForAdjacentRoots(
                root1.asBinder(),
                root2.asBinder()));
        return this;
    }

这里主要就是createForAdjacentRoots方法,创建对一个HierarchyOp对象,然后跨进程传递system_server进行task的setAdjacentTaskFragment操作

   /** Create a hierarchy op for setting adjacent root tasks. */
        public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2) {
            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
                    .setContainer(root1)
                    .setReparentContainer(root2)
                    .build();
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值