wctha_android是什么软件

wctha_android是什么软件WCT——WindowContainerTransactionWindowContainerTransaction表示一些WindowContainer上应该一次性应用的操作集合

一、定义

WCT——WindowContainerTransaction

/**
 * Represents a collection of operations on some WindowContainers that should be applied all at
 * once.
 *
 * @hide
 */
@TestApi
public final class WindowContainerTransaction implements Parcelable {
    ......
} 

WindowContainerTransaction表示一些WindowContainer上应该一次性应用的操作集合。

从使用意义上来看,WindowContainerTransaction类和Transaction类比较相似,Transaction是应用在SurfaceControl上的操作集合,WindowContainerTransaction是应用在WindowContainer上的操作集合。另外WindowContainerTransaction也实现了Parcelable,这为其在系统服务端和App端之间的传输提供了支持。

二、使用

结合分屏的一处逻辑,看下WindowContainerTransaction是如何使用的,以下是进入分屏的过程中LegacySplitScreenController#splitPrimaryTask做的事情:

 public boolean splitPrimaryTask() {
        ......
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        // Clear out current windowing mode before reparenting to split task.
        wct.setWindowingMode(topRunningTask.token, WINDOWING_MODE_UNDEFINED);
        wct.reparent(topRunningTask.token, mSplits.mPrimary.token, true /* onTop */);
        mWindowManagerProxy.applySyncTransaction(wct);
        return true;
    } 

1)、创建一个WindowContainerTransaction对象。

2)、调用WindowContainerTransaction#setWindowingMode。

3)、调用WindowContainerTransaction#reparent。

4)、调用WindowManagerProxy#applySyncTransaction发送当前WindowContainerTransaction,关于WCT的发送留在以后分析,这里重点分析第2、3点。

1 WindowContainerTransaction#setWindowingMode

 /**
     * Sets the windowing mode of the given container.
     */
    @NonNull
    public WindowContainerTransaction setWindowingMode(
            @NonNull WindowContainerToken container, int windowingMode) {
        Change chg = getOrCreateChange(container.asBinder());
        chg.mWindowingMode = windowingMode;
        return this;
    } 

内容很简单:

1)、根据传入的WindowContainerToken对象,通过WindowContainerTransaction#getOrCreateChange方法获取一个Change对象。

2)、将Change的成员变量mWindowingMode赋值为传入的windowingMode。

在分析WindowContainerTransaction#getOrCreateChange方法之前,先看下WindowContainerToken的作用:

/**
 * Interface for a window container to communicate with the window manager. This also acts as a
 * token.
 * @hide
 */
@TestApi
public final class WindowContainerToken implements Parcelable {

    private final IWindowContainerToken mRealToken;

    /** @hide */
    public WindowContainerToken(IWindowContainerToken realToken) {
        mRealToken = realToken;
    }

    private WindowContainerToken(Parcel in) {
        mRealToken = IWindowContainerToken.Stub.asInterface(in.readStrongBinder());
    }

    /** @hide */
    public IBinder asBinder() {
        return mRealToken.asBinder();
    }

	......
} 

WindowContainterToken实现了Parcelable,这为其跨进程传输提供了支持。WindowContainterToken内部有一个成员变量mRealToken,是一个IWindowContainerToken类型的token,在系统服务创建WindowContainer时候生成(目前只有DisplayArea和Task),对于WindowContainer来说是一个独特的跨进程的标识。WindowContainerToken可以看做是IBinder类型的token的封装,这个token通过WindowContainerToken#asBinder返回。

Task可以通过Task#fillTaskInfo方法将该Task对应的WindowContainerToken保存在对应的TaskInfo中,这样App进程可以先获取TaskInfo进而拿到这个token。

App端如果想通过WindowContainerTransaction的方法修改某个WindowContainer的属性,必须传入该WindowContainer对应的token,这样系统服务端在接收到这个WindowContainerTransaction的时候,才可以通过token知道需要修改哪些WindowContainer。

接着看下WindowContainerTransaction#getOrCreateChange的内容:

 private Change getOrCreateChange(IBinder token) {
        Change out = mChanges.get(token);
        if (out == null) {
            out = new Change();
            mChanges.put(token, out);
        }
        return out;
    } 

从mChanges中查找该WindowContainerToken有没有相应的Change对象,没有就创建一个,然后以键值对的方式把这个WindowContainerToken对象和为其创建的Change对象加入到mChanges中。

mChanges是一个ArrayMap类型的WindowContainerTransaction的成员变量,以IBinder类型的WindowContainerToken对象为key,以WindowContainerTransaction为该WindowContainerToken创建的Change对象为value:

private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>(); 

后续该WindowContainerTransaction发送到WM端的时候,WindowOrganizerController遍历这个WindowContainerTransaction的mChanges成员变量,对于mChanges中的每一个Change对象:

1)、从该Change中提取出WindowContainerToken,将该WindowContainerToken转化为WM端对应的WindowContainer对象。

2)、提取出Change中为该WindowContainerToken保存的WindowingMode,然后应用到第1步中转化得到的WindowContainer。

上面的第2步可以看WindowOrganizerController#applyChanges方法进一步了解一下:

 private int applyChanges(WindowContainer container, WindowContainerTransaction.Change change) {
        .......
        final int windowingMode = change.getWindowingMode();
        ......
        if (windowingMode > -1) {
            ......
            container.setWindowingMode(windowingMode);
        }
        return effects;
    } 

看到这里似乎对WindowContainerTransaction的运作方式有了一部分的了解了,App端如果想要通过WindowContainerTransaction修改WM端的WindowContainter的属性,需要这几步操作:

1)、App端首先要能够拿到这个WindowContainer对应的WindowContainerToken。

2)、创建一个WindowContainerTransaction对象,调用WindowContainerTransaction的相关方法对这个WindowContainerToken进行设置。

3)、发送WindowContainerTransaction。

2 WindowContainerTransaction#setFocusable

为了印证这个猜想,再看另外一个类似的方法WindowContainerTransaction#setFocusable。调用的地方在分屏相关逻辑处:

 public void setHomeMinimized(final boolean minimized) {
		......
        WindowContainerTransaction wct = new WindowContainerTransaction();
        final boolean minimizedChanged = mMinimized != minimized;
        // Update minimized state
        if (minimizedChanged) {
            mMinimized = minimized;
        }
        // Always set this because we could be entering split when mMinimized is already true
        wct.setFocusable(mSplits.mPrimary.token, !mMinimized);

		......
    } 

先创建一个WindowContainerTransaction,然后调用WindowContainerTransaction.setFocusable方法设置:

 /**
     * Sets whether a container or any of its children can be focusable. When {@code false}, no
     * child can be focused; however, when {@code true}, it is still possible for children to be
     * non-focusable due to WM policy.
     */
    @NonNull
    public WindowContainerTransaction setFocusable(
            @NonNull WindowContainerToken container, boolean focusable) {
        Change chg = getOrCreateChange(container.asBinder());
        chg.mFocusable = focusable;
        chg.mChangeMask |= Change.CHANGE_FOCUSABLE;
        return this;
    } 

该方法用来设置一个WindowContainer和其子WindowContainer是否可以获取焦点,同样是两步操作:

1)、根据传入的WindowContainerToken对象,通过WindowContainerTransaction#getOrCreateChange方法获取一个Change对象。

2)、将Change的成员变量mFocusable赋值为传入的focusable参数。

Change.mChange应用的地方依然是WindowOrganizerController#applyChanges:

 private int applyChanges(WindowContainer container, WindowContainerTransaction.Change change) {
        ......
        if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) {
            if (container.setFocusable(change.getFocusable())) {
                effects |= TRANSACT_EFFECTS_LIFECYCLE;
            }
        }
        ......
    } 

套路都是一样的:

1)、从该Change中提取出WindowContainerToken,将该WindowContainerToken转化为WM端对应的WindowContainer对象。

2)、提取出Change中为该WindowContainerToken保存的focusable属性,然后应用到第1步中转化得到的WindowContainer。

3 WindowContainerTransaction.Change类

 /**
     * Holds changes on a single WindowContainer including Configuration changes.
     * @hide
     */
    public static class Change implements Parcelable {
        public static final int CHANGE_FOCUSABLE = 1;
        public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1;
        public static final int CHANGE_PIP_CALLBACK = 1 << 2;
        public static final int CHANGE_HIDDEN = 1 << 3;
        public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4;
        public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5;
        private final Configuration mConfiguration = new Configuration();
        private boolean mFocusable = true;
        private boolean mHidden = false;
        private boolean mIgnoreOrientationRequest = false;
        private int mChangeMask = 0;
        private @ActivityInfo.Config int mConfigSetMask = 0;
        private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
        private Rect mPinnedBounds = null;
        private SurfaceControl.Transaction mBoundsChangeTransaction = null;
        private Rect mBoundsChangeSurfaceBounds = null;
        private int mActivityWindowingMode = -1;
        private int mWindowingMode = -1;
        ......
        public int getWindowingMode() {
            return mWindowingMode;
        }
        public int getActivityWindowingMode() {
            return mActivityWindowingMode;
        }
        public Configuration getConfiguration() {
            return mConfiguration;
        }
        /** Gets the requested focusable state */
        public boolean getFocusable() {
            if ((mChangeMask & CHANGE_FOCUSABLE) == 0) {
                throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first");
            }
            return mFocusable;
        }
        /** Gets the requested hidden state */
        public boolean getHidden() {
            if ((mChangeMask & CHANGE_HIDDEN) == 0) {
                throw new RuntimeException("Hidden not set. check CHANGE_HIDDEN first");
            }
            return mHidden;
        }
        /** Gets the requested state of whether to ignore orientation request. */
        public boolean getIgnoreOrientationRequest() {
            if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) == 0) {
                throw new RuntimeException("IgnoreOrientationRequest not set. "
                        + "Check CHANGE_IGNORE_ORIENTATION_REQUEST first");
            }
            return mIgnoreOrientationRequest;
        }
        public int getChangeMask() {
            return mChangeMask;
        }
        @ActivityInfo.Config
        public int getConfigSetMask() {
            return mConfigSetMask;
        }
        @WindowConfiguration.WindowConfig
        public int getWindowSetMask() {
            return mWindowSetMask;
        }
        /**
         * Returns the bounds to be used for scheduling the enter pip callback
         * or null if no callback is to be scheduled.
         */
        public Rect getEnterPipBounds() {
            return mPinnedBounds;
        }
        public SurfaceControl.Transaction getBoundsChangeTransaction() {
            return mBoundsChangeTransaction;
        }
        public Rect getBoundsChangeSurfaceBounds() {
            return mBoundsChangeSurfaceBounds; 
        }
        ......
    } 

持有对单一WindowContainer的包括Configuration的修改。

通过对WindowContainerTransaction#setWindowingMode和WindowContainerTransaction#setFocusable这两部分的分析,可以看到不管是改变WindowContainer的windowingMode,或是focusable属性,都需要:

1)、创建一个WindowContainerTransaction对象,调用WindowContainerTransaction提供的方法对WindowContainerToken进行设置,实际上就是将客户端对WindowContainer期望的一些修改先保存到WindowContainerTransaction为WindowContainerToken创建的Change对象的相关成员变量中。

2)、发送创建的WindowContainerTransaction到WM端,WM端获取到WindowContainerTransaction.Change相关成员变量的值,然后应用到WindowContainer上。

那么也就是说,WindowContainerTransaction.Change有多少成员变量,WindowContainerTransaction就可以向客户端提供多少可以改变WindowContainer的方法接口。

看下WindowContainerTransaction.Change的成员变量都有哪些:

 private final Configuration mConfiguration = new Configuration();
        private boolean mFocusable = true;
        private boolean mHidden = false;
        private boolean mIgnoreOrientationRequest = false;
        ......
        private Rect mPinnedBounds = null;
        private SurfaceControl.Transaction mBoundsChangeTransaction = null;
        private Rect mBoundsChangeSurfaceBounds = null;
        private int mActivityWindowingMode = -1;
        private int mWindowingMode = -1; 

重点看一下成员变量mConfiguration,毕竟Configuration中包含了很多的配置属性,但是WindowContainerTransaction并不支持对Configuration中所有的属性进行修改,主要是screenSize、windowingMode和bounds等。

目前来看设计WindowContainerTransaction是为多窗口功能服务的,因此WindowContainerTransaction.Change提供的这些方法已经满足需要了。之前都是SystemUI直接跨Binder调用系统服务的一些resizeStack之类的方法去修改分屏Task的bounds。有了WindowContainerTransaction.Chang之后,就可以把系统服务向客户端提供的对WindowContainer的所有修改方法统一组织起来,方便管理以及后续扩展新内容。

4 WindowContainerTransaction#reparent

我们上面只分析了LegacySplitScreenController#splitPrimaryTask中的一个方法WindowContainerTransaction#setWindowingMode,还有一个方法WindowContainerTransaction#reparent没有分析。

 /**
     * Reparents a container into another one. The effect of a {@code null} parent can vary. For
     * example, reparenting a stack to {@code null} will reparent it to its display.
     *
     * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
     *              the bottom.
     */
    @NonNull
    public WindowContainerTransaction reparent(@NonNull WindowContainerToken child,
            @Nullable WindowContainerToken parent, boolean onTop) {
        mHierarchyOps.add(HierarchyOp.createForReparent(child.asBinder(),
                parent == null ? null : parent.asBinder(),
                onTop));
        return this;
    } 

该方法的作用是将一个WindowContainer重新reparent到另外一个WindowContainer,最终结果受到参数parent的影响,如果parent为null,那么将参数child子WindowContainer容器reparent到它对应的display上。

看下createForReparent方法:

 public static HierarchyOp createForReparent(
                @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
            return new HierarchyOp(HIERARCHY_OP_TYPE_REPARENT,
                    container, reparent, null, null, toTop, null);
        } 

再看下mHierarchyOps:

 // Flat list because re-order operations are order-dependent
    private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>(); 

因此这个方法的内容是:

1)、根据传入的IBinder类型container和reparent创建一个HierarchyOp对象。

2)、将这个HierarchyOp对象添加到WindowContainerTransaction的成员变量mHierarchyOps中。

后续这个WindowContainerTransaction发送到系统服务端的时候,由WindowOrganizerController负责将以上两个IBinder类型的token转化为WindowContainer对象,然后进行reparent操作。

对比一下WindowContainerTransaction.Change的相关内容:

1)、WindowContainerTransaction创建的Change对象是和WindowContainerToken内部的token对象一一对应的,创建的时候会判断WindowContainerTransaction的mChanges中是否已经有了一个与token对应的Change对象,对应的是

2)、HierarchyOp对象在每次需要进行reparent的时候就会创建一次,对应的是一次层次结构上的操作。

5 WindowContainerTransaction.HierarchyOp类

在做出进一步的总结前,还是需要看下WindowContainerTransaction.HierarchyOp类的作用。

 private HierarchyOp(int type, @Nullable IBinder container, @Nullable IBinder reparent,
                int[] windowingModes, int[] activityTypes, boolean toTop,
                @Nullable Bundle launchOptions) {
            mType = type;
            mContainer = container;
            mReparent = reparent;
            mWindowingModes = windowingModes != null ?
                    Arrays.copyOf(windowingModes, windowingModes.length) : null;
            mActivityTypes = activityTypes != null ?
                    Arrays.copyOf(activityTypes, activityTypes.length) : null;
            mToTop = toTop;
            mLaunchOptions = launchOptions;
        } 

创建HierarchyOp对象的时候会对其成员变量进行赋值,比较重要的是其中三个成员变量:

 // Container we are performing the operation on.
        private final IBinder mContainer;
        // If this is same as mContainer, then only change position, don't reparent.
        private final IBinder mReparent;
        // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
        private final boolean mToTop; 

mContainer是子WindowContainer对应的token,mReparent是父WindowContainer对应的token,mToTop表示reparent操作后是否需要将子WindowContainer移动到父WindowContainer的top。

这样来看,WindowContainerTransaction.HierarchyOp的作用逻辑和WindowContainerTransaction.Change类似。WindowContainerTransaction.HierarchyOp将App端设置的一次WindowContainer层级调整操作中的子WindowContainer对应的token和父WindowContainer对应的token保存起来,后续WindowContainerTransaction发送到服务端后,服务端读取HierarchyOp中token并转化为对应的WindowContainer对象,再完成此次WindowContainer层级调整。

根据mReparent的值,会有几种不同的情况:

1)、mReparent不为空,且不等于mContainer,这个是最普遍的reparent的操作,将子WindowContainer移入父WindowContainer中。

2)、mReparent不为空,且等于mContainer,那么此次操作不是reparent,而是reorder,根据mToTop的值调整mContainer在当前父容器中的位置。

3)、mReparent为空,那么将mContainer移入当前display中。

具体的代码情况在WCT的应用一文中详细分析。

三、总结

WindowContainerTransaction向客户端提供了远程修改系统服务中的WindowContainer的能力,类似于Transaction修改SurfaceControl,直白点说就是,由于客户端无法直接修改WindowContainer,所以客户端需要先告诉WindowContainerTransaction我想修改哪些WindowContainer的哪些内容,WindowContainerTransaction把这些期望的修改保存起来,后续客户端把这个WindowContainerTransaction发送到服务端,服务端读取WindowContainerTransaction中的设置后由服务端帮助客户端完成修改。

一般流程是:

1)、客户端创建一个WindowContainerTransaction对象。

2)、调用WindowContainerTransaction的相关方法,这一步需要将期望修改的WindowContainer对应的WindowContaienrToken对象作为参数传入。

3)、通过WindowOrganizer将WindowContainerTransaction发送到服务端,最终服务端读取WindowContainerTransaction中保存的参数完成相应操作。

WindowContainerTransaction支持以下两类修改:

1)、修改WindowContainer的属性,包括WindowingMode和Configuration之类,这类修改保存在WindowContainerTransaction.Change类中。

2)、修改WindowContainer的层级,既可以将一个子容器从当前父容器移入另外一个新的父容器中,也可以仅仅调整子容器在当前父容器中的位置,这类修改保存在WindowContainerTransaction.HierarchyOp类中。

——————————

欢迎大家一键三连支持,若需要更多资料,可直接点击文末CSDN官方认证微信卡片免费领取【保证100%免费】,也可在评论区扣1或私信↓↓↓
wctha_android是什么软件

今天的文章wctha_android是什么软件分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/87172.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注