WindowContainerTransaction类详解(一)
1、WindowContainerTransaction是什么:
windowContainerTransaction类的对象是用来存储对windowContainer的修改的一个集合,windowContainer。因为应用侧是无法直接操作windowContainer的,如果应用侧需要修改windowContainer的话,需要通过系统侧对windowContainer进行修改,这就涉及了信息的跨进程传输了。所以首先,WindowContainerTransaction类应该是一个磕跨进程传输的类。看到定义:
public final class WindowContainerTransaction implements Parcelable
也证实了这个猜测,其实现了Parcelable接口。然后就是另一个问题,应用通过系统侧修改WindowContainer的话,必定会告诉他修改窗口的什么属性,然后进去这个类找找代码:
* Sets whether a container or its children should be hidden. When {@code false}, the existing* visibility of the container applies, but when {@code true} the container will be forced* to be hidden.*/
@NonNull
public WindowContainerTransaction setHidden(@NonNull WindowContainerToken container, boolean hidden) {Change chg = getOrCreateChange(container.asBinder());chg.mHidden = hidden;chg.mChangeMask |= Change.CHANGE_HIDDEN;return this;
}
这里可以看到一个设置窗口及其子窗口是否被隐藏的接口,暂时不详细叙述这个方法的实现。这里可以看到修改这个hidden属性是通过一个Change类的对象实现的,Change类是WindowContainerTransaction的内部类,也是实现了Parcelable接口的。而且WindowContainerTransaction类内部也维护了一个包含Change类的Map:
private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
所以可以大概知道,对窗口的修改应该是通过Change类的对象去描述的。
所以目前可以得知WindowContainerTransaction类的作用,他的对象就是应用侧需要对窗口进行的修改的集合。而这个修改,则是通过Change类的对象描述的。
这里通过一个例子来展示下WindowContainerTransaction类的使用(例子引用自博客https://blog.csdn.net/ukynho/article/details/126747771):
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;
}
由上述示例可见这个WindowContainerTransaction类的使用过程为:1.创建一个WindowContainerTransaction对象;2.通过该对象设置你需要修改的属性;3.提交步骤2设置的修改。
2、如何通过WindowContainerTransaction修改窗口属性:
前面已经讲到了WindowContainerTransaction中的setHidden方法,那就继续分析这个方法:
public WindowContainerTransaction setHidden(@NonNull WindowContainerToken container, boolean hidden) {Change chg = getOrCreateChange(container.asBinder());chg.mHidden = hidden;chg.mChangeMask |= Change.CHANGE_HIDDEN;return this;
}
1)、看参数列表:
参数列表第一个是一个WindowContainerToken对象,看一下定义,这个类是什么含义:
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();}…………………………………
}
从代码上看,这个类也是实现了Parcelable,然后主要是包装了一个IWindowContainerToken类型的对象。因为系统侧的WMS里要管理所有的WindowContainer,那么WMS中该如何区分每一个WindowContainer呢?那就得用唯一的身份标识,即这个IWindowContainerToken,通过这个Token,WMS可以区分不同的WindowContainer,可以简单理解成,我们每个人其实在国家的户籍管理的制度里,就是用一个身份证号进行辨识的,在人口管理的系统中,我们是以身份证号进行区分的,所以身份证号就是这个Token。而WMS也可以通过WindowContainerToken的asBinder()方法访问到对应WindowContainer的方法。
而我们怎么获取到这个WindowContainerToken方法呢?从示例代码中可见:
wct.setWindowingMode(topRunningTask.token, WINDOWING_MODE_UNDEFINED);
可以通过TaskInfo类的token属性获取。看到TaskInfo类的token属性,正是WindowContainerToken类型的对象。那问题又来了,我们的这个token属性是在什么时候进行的赋值操作的呢?
这里得找到Task.java中的fillTaskInfo()方法了,这里可见info.token的赋值:
void fillTaskInfo(TaskInfo info, boolean stripExtras, @Nullable TaskDisplayArea tda) {
………………………………………………………………info.token = mRemoteToken.toWindowContainerToken();
………………………………………………………………}
这里再提一个小小的疑问:mRemoteToken又是什么?看到Task类中没有定义,于是找到其父类中,最后在WindowContainer类中发现如下定义:
首先他实现了一个aidl接口的Stub类,所以其实RemoteToken就是一个binder的server端的抽象类Stub的子类的实现 。他包含了对WindowContainer的引用和WindowContainerToken。
static class RemoteToken extends IWindowContainerToken.Stub {final WeakReference<WindowContainer> mWeakRef;private WindowContainerToken mWindowContainerToken;RemoteToken(WindowContainer container) {mWeakRef = new WeakReference<>(container);}@NullableWindowContainer getContainer() {return mWeakRef.get();}static RemoteToken fromBinder(IBinder binder) {return (RemoteToken) binder;}WindowContainerToken toWindowContainerToken() {if (mWindowContainerToken == null) {mWindowContainerToken = new WindowContainerToken(this);}return mWindowContainerToken;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder(128);sb.append("RemoteToken{");sb.append(Integer.toHexString(System.identityHashCode(this)));sb.append(' ');sb.append(mWeakRef.get());sb.append('}');return sb.toString();}
}
而且在WindowContainerToken中的mRealToken其实就是IWindowContainerToken的对象,也就是说,mRealToken其实就是一个RemoteToken类型的对象,他才是能够通过弱引用真正的指向WindowContainer,同时还包含WindowContainerToken属性。这里再多说一个点,就是WindowContainerToken,只有Task和DisplayArea才会有。
然后第二个参数就是需要设置的属性了,就不再多说;
2)、setHidden方法的实现:
public WindowContainerTransaction setHidden(@NonNull WindowContainerToken container, boolean hidden) {Change chg = getOrCreateChange(container.asBinder());chg.mHidden = hidden;chg.mChangeMask |= Change.CHANGE_HIDDEN;return this;
}
该方法第一步,定义一个Change对象chg,定义后通过getOrCreateChange方法对chg进行赋值。继续查看该方法的实现。
private Change getOrCreateChange(IBinder token) {Change out = mChanges.get(token);if (out == null) {out = new Change();mChanges.put(token, out);}return out;
}
定义一个Change类型的对象out,然后在mChanges中去get一个Change,看下mChanges的定义发现,这是一个ArrayMap。Key是IBinder(这个IBinder的对象就是一个WindowContainerToken的对象,对应唯一的WindowContainer),value是Change。
private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
那就知道了,肯定有有地方会把这个键值对IBinder和Change组成的键值对放进mChanges中。这里如果是刚初始化的WindowContainerTransaction对象,mChanges肯定是空的,所以out == null,则会将token和out放进mChanges,并返回out。注意这里out只是一个默认的Change()方法构造出来的对象。
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;public static final int CHANGE_FORCE_NO_PIP = 1 << 6;public static final int CHANGE_FORCE_TRANSLUCENT = 1 << 7;public static final int CHANGE_DRAG_RESIZING = 1 << 8;private final Configuration mConfiguration = new Configuration();private boolean mFocusable = true;private boolean mHidden = false;private boolean mIgnoreOrientationRequest = false;private boolean mForceTranslucent = false;private boolean mDragResizing = 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 Change() {}
…………………………………………………………………………………………………
}
所以Out的属性都是默认值,接下来就是对这个Change进行赋值了,我们看的是setHidden方法,所以需要修改Hidden相关的属性。首先是修改chg.mHidden属性,然后修改chg.mChangeMask。
mHidden属性就可以简单的认为是否需要隐藏,下面的mChangeMask就是一个标志位,通过这个属性能得知提交的WindowContainerTransaction进行了哪些属性的修改。
通过Change的初始值可知,mChangeMask = 0;是int类型。CHANGE_HIDDEN = 1<<3; 通过将二者进行异或运算,就能将标志着HIDDEN属性变化的第三位设置为1.
于是,在系统侧应用WindowContainerTransaction的时候,可以看到,这里就会通过mChangeMask属性与标志位的结果进行判断后,再对修改进行应用。
private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {int effects = applyChanges(tr, c, null /* errorCallbackToken */);final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {if (tr.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, c.getHidden())) {effects = TRANSACT_EFFECTS_LIFECYCLE;}}if ((c.getChangeMask()& WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT) != 0) {tr.setForceTranslucent(c.getForceTranslucent());effects = TRANSACT_EFFECTS_LIFECYCLE;}
…………………………………………………………………………………………
}
3)reparent方法的实现:
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;
}
这里不是通过Change保存reparent操作,而是通过mHierarchyOps来保存修改的。看下定义,mHierarchyOps 是一个ArrayList类型的对象。里面存储的是HierarchyOp类型的变量。
private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
然后再看到HierarchyOp的构造方法,这里container就是需要重新设置parent的WindowContainer,然后reparent就是新的parent,toTop代表reparent操作后是否需要将子WindowContainer移动到父
WindowContainer的Top。
public static HierarchyOp createForReparent(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT).setContainer(container).setReparentContainer(reparent).setToTop(toTop).build();
}
相关文章:
WindowContainerTransaction类详解(一)
1、WindowContainerTransaction是什么: windowContainerTransaction类的对象是用来存储对windowContainer的修改的一个集合,windowContainer。因为应用侧是无法直接操作windowContainer的,如果应用侧需要修改windowContainer的话,…...
安装NFS扩展
#添加helm源 helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner #创建个namespace(可选,主要是为了查看资源方便) kubectl create ns nfs-sc-default #使用helm安装(10.1.129.86为NFS地址,/home/data/nfs…...
计算机网络——运输层(进程之间的通信、运输层端口,UDP与TCP、TCP详解)
运输层协议概述 进程之间的通信 运输层向它上面的应用层提供通信服务。 当网络边缘部分的两台主机使用网络核心部分的功能进行端到端的通信时,都要使用协议栈中的运输层;而网络核心部分中的路由器在转发分组时只用到下三层的功能。 Q1:我们…...
代码随想录算法训练营第一天 | 二分查找
文章目录 Leetcode704 二分查找二分法的使用前提:区间选择其他注意事项 Leetcode27 移除元素解题思路:优化思路 Leetcode704 二分查找 链接:https://leetcode.cn/problems/binary-search/ 代码随想录: https://programmercarl.com/ 时间复杂度: O(logN) 空间复杂度:…...
python相关知识
1、注释 共有三种:#、 、””” ””” 2、数据类型 整数、浮点、字符串、布尔、列表、元组、集合、字典 num1 666、num2 3.14、t1 True、t2 False、 列表:list [1,2,3,4] 元组:tuple (11,aaa,ddd,3) 字典:dict {li…...
Visual Studio 2022 LNK2001无法解析的外部符号 _wcscat_s 问题记录
ANSI C程序中,用到了wcsrchr、wcsncpy_s、wcscat_s、wcscpy_s等几个字符串函数,但是编译时提示: 错误 LNK2001 无法解析的外部符号 _wcscat_s 查了挺多帖子,没有解决。 https://bbs.csdn.net/topics/250012844 解决VS编译…...
Java高并发处理机制
高并发处理的思路: 扩容:水平扩容、垂直扩容缓存:将基础的数据放入缓存进行处理使用SpringCloud的注册中心,分服务注册到同一个注册中心,服务器检测使用Spring的熔断操作,检测服务器的心跳那个正常随机跳转…...
7 数据存储单位,整型、浮点型、字符型、布尔型数据类型,sizeof 运算符
目录 1 数据类型的分类 2 数据存储单位 2.1 位 2.2 字节 2.3 其余单位 3 整数类型 3.1 基本介绍 3.2 整型的类型 3.2.1 整数类型多样性的原因 3.2.2 整型类型之间的相对大小关系 3.3 整型注意事项 3.4 字面量后缀 3.5 格式占位符 3.6 案例:声明并输出…...
导游职业资格考试真题题库
导游职业资格考试真题题库 80.重庆有"雾都"之称。壁山区的()全年雾日多204天,堪称"世界之最"。 A.枇杷山 B.雾灵山 C.云雾山 D.四姑娘山 答案:C 81.我国最具热带海洋气候特色的地方为()。 A.广西壮族…...
【Rust】使用开源项目搭建瓦片地图服务
本文通过获取在线和离线地图数据,使用开源Rust项目搭建瓦片地图服务,并使用DevExpress的MapControl控件使用自建地图服务 获取地图数据 获取地图数据有很多种方式,这里分别用在线和离线地图数据举例说明 在线下载瓦片地图 打开在线瓦片地…...
【面试宝典】mysql常见面试题总结(上)
一、MySQL 中有哪几种锁? MySQL中的锁机制是数据库并发控制的重要组成部分,它用于管理多个用户对数据库资源的访问,确保数据的一致性和完整性。MySQL中的锁可以根据不同的分类标准进行分类,以下是一些常见的分类方式及对应的锁类…...
第1章 初识C语言
第1章 初识C语言 1.1 C语言概述 1.1.1 C语言的发展历史 C语言的原型为ALGOL 60语言(也称A语言)。 1963年 剑桥大学将ALGOL 60语言发展成为GPL语言。 1967年 剑桥大学的Matin Richards简化GPL,产生了BGPL语言。 1970年 美国贝尔实验室的Ken…...
【考研数学】定积分应用——旋转体体积的计算(一文以蔽之)
目录 一、如何计算旋转体体积?思考一个小例子 二、旋转体体积的二重积分表达式 三、用真题,小试牛刀 定积分的应用中,有一类题是求解旋转体的体积问题。 相较于记忆体积计算公式,有一种通法求解体积更不容易出错:二重…...
PHP移动端商城分销全平台全端同步使用
📱【掌中购物新纪元:探索移动端购物商城系统的无限魅力】🛍️ 🚀 随时随地,购物自由新体验 在这个快节奏的时代,移动端购物商城系统彻底颠覆了传统购物方式,让消费者享受到了前所未有的便捷与…...
TLE8386-2EL:汽车级DC-DC转换器中文资料书
描述 TLE8386-2EL是一款具有内置保护功能的低端感应升压控制器。该器件的主要功能是将输入电压升高(升压)到更大的输出电压。开关频率可从100kHz调整至700kHz,并可与外部时钟源同步。 TLE8386-2EL的独特功能可将关断电流消耗降至 <2μA。该…...
EasyRecovery17中文mac苹果电脑版数据恢复软件 永久免费破解版下载
🎉 数据丢失不再是噩梦!EasyRecovery17中文版来拯救你的硬盘啦! 各位小伙伴们,有没有遇到过重要文件一不小心就消失无踪的尴尬情况?别担心,今天就给大家种草一款神奇的工具——EasyRecovery17中文版&#x…...
Ubuntu 22.04 安装 VirtualBox7
Ubuntu默认库为VirtualBox-6版本 # 安装 VirtualBox-6 sudo apt update sudo apt install virtualbox# 卸载 VirtualBox-6 sudo apt remove --purge --auto-remove virtualbox virtualbox-6.1 1. 安装 VirtualBox-7 # 导入软件包密钥 curl https://www.virtualbox.org/downl…...
NPM使用教程:从入门到精通
NPM使用教程:从入门到精通,掌握Node.js包管理神器 引言 随着Node.js的流行,JavaScript已经成为服务器端开发的主力军。NPM(Node Package Manager)作为Node.js的官方包管理工具,为开发者提供了一个庞大的代…...
模电实验3 - 单电源集成运放交流耦合放大器
实验目标 学习集成运放的单电源使用。掌握交流耦合单电源集成运放放大器的测试方法。了解交流耦合单电源集成运放放大器的特点。 实验器材 ADALM2000 1kΩ 电阻 (1/4 W) x 1 10 kΩ 电阻 (1/4 W) x 1 100kΩ 电阻 (1/4 W) x 3 0.1μF电容 x 1 1μF电容 …...
海对外经贸大学学报
《上海对外经贸大学学报》创刊于1994年,原名为《世界贸易组织动态与研究》(上海对外贸易学院学报),随原上海对外贸易学院更名为上海对外经贸大学,自2014年起更为现名,现为综合性社科类双月刊,为中文社会科学引文检索&a…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
