WindowManager相关容器类

窗口中容器类介绍:
本节内容较多,建议结合前面的内容一起阅读:
1、addWindow的宏观概念
2、WindowManager#addView_1
3、WindowManager#addView_2

1)、WindowContainer:

class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>{
……………………
}

WindowContainer的定义如上,可见其是一个容器,容器内的元素是自己或自己的子类(如:RootWindowContainer、DisplayContent、DisplayArea、DisplayArea.Tokens、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState),而WindowContainer类继承自ConfigurationContainer类,该类也是一个容器类,其元素为自己或自己的子类。
其中有一些属性比较重要:mParent和mChildren,分别代表父节点和子节点。其中子节点是WindowList类型的,其排列顺序是依据其在z轴上的高度排列的,尾部的节点在z轴上最高最容易被用户看到。

2)、RootWindowContainer:

class RootWindowContainer extends WindowContainer<DisplayContent>
        implements DisplayManager.DisplayListener {

WindowContainer的根容器,可通过该节点遍历到窗口树上的任意窗口。他的mChildren继承自WindowContainer,所以该List的元素为DisplayContent。
在这里插入图片描述

3)、DisplayContent:

class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {

对应显示屏幕的概念,一个屏幕对应一个DisplayContent。一般情况下都是只有一个。在同一个DisplayContent中的窗口都会显示在同一个屏幕内。

4)、WindowToken:

class WindowToken extends WindowContainer<WindowState> {

WindowToken类是WindowState的容器,WindowState之前说过,在WMS中代表了一个窗口。
在这里插入图片描述

5)、ActivityRecord:

final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {

该类继承自WindowToken,所以也是WindowState类的容器。
在这里插入图片描述

6)、WindowState:

class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
        InsetsControlTarget, InputTarget {

其实WindowState也可以作为其他WindowState的容器;
在这里插入图片描述

7)、WallpaperWindowToken:

class WallpaperWindowToken extends WindowToken {

该类同样继承自WindowToken;
对以上4)-7)进行统一分析,所有的窗口分三大类:系统窗口、应用窗口、其他窗口;其中系统窗口在最上层,应用窗口次之,而系统窗口的容器则为WindowToken,应用窗口为ActivityRecord。而App以下的窗口,父容器就为WallpaperWindowToken。

8)、DisplayArea.Tokens:

是WindowToken的父容器,同时会在其中对WindowToken进行排序;
在这里插入图片描述

public static class Tokens extends DisplayArea<WindowToken> {
private final Comparator<WindowToken> mWindowComparator =
        Comparator.comparingInt(WindowToken::getWindowLayerFromType);//这就是排序算法的核心。
}
 

排序算法触发的前提就是addChild函数,和前一节说的一样,找到addChild函数:

void addChild(WindowToken token) {
    addChild(token, mWindowComparator);
}

这里可以看到在addChild的时候,通过mWindowComparator为WindowToken确认顺序,而mWindowComparator的初始化是通过WindowToken.java中的getWindowLayerFromType方法作为比较器的。最后的方法实现在WindowManagerPolicy.java中的getWindowLayerFromTypeLw()方法。这里在addWindow的宏观概念一文中有讲到,主要就是对比了窗口的类型,如果是应用窗口则直接返回2,如果是wallpaper窗口,直接返回1(在最底层);然后再根据窗口的类型返回其排序的权重,根据权重再决定该窗口在子窗口中该插入到哪个位置。其中这里的type是在WindowToken中的一个属性:从注释看就是WindowManager类中的LayoutParams属性,这个属性会在窗口初始化时确定。

/** The type of window this token is for, as per {@link WindowManager.LayoutParams} */
final int windowType;

9)、Task:

ActivityRecord的容器,作为应用窗口的容器,ActivityRecord也是需要容器的。
在这里插入图片描述

class Task extends TaskFragment {

从定义可见Task是继承自TaskFragment的一个类。而TaskFragment则也是继承自WindowContainer的类。
class TaskFragment extends WindowContainer {
Task可以是Task的容器,也可以是ActivityRecord的容器,最形象的理解就是多任务界面的一个窗口就是一个Task。TaskFragment这个类型我了解不多,只知道和平行视界相关。平行视界中两个Activity需要同时显示,Task实现不了这个功能,所以再Task和ActivityRecord之间加入了TaskFragment。而一般情况下因为TaskFragment是Task的父类,所以大家都会通过TaskFragment创建对象,但是最终创建的还是Task类型的对象
这里的排序的话比较简单:老规矩找到addchild方法。

void addChild(WindowContainer child, int index) {
    index = getAdjustedChildPosition(child, index);
    super.addChild(child, index);

    ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);

    // A rootable task that is now being added to be the child of an organized task. Making
    // sure the root task references is keep updated.
    if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
        getDisplayArea().addRootTaskReferenceIfNeeded((Task) child);
    }

    // Make sure the list of display UID allowlists is updated
    // now that this record is in a new task.
    mRootWindowContainer.updateUIDsPresentOnDisplay();

    // Only pass minimum dimensions for pure TaskFragment. Task's minimum dimensions must be
    // passed from Task constructor.下面应该就是平行视界这类相关的操作了
    final TaskFragment childTaskFrag = child.asTaskFragment();
    if (childTaskFrag != null && childTaskFrag.asTask() == null) {
        childTaskFrag.setMinDimensions(mMinWidth, mMinHeight);

        // The starting window should keep covering its task when a pure TaskFragment is added
        // because its bounds may not fill the task.
        final ActivityRecord top = getTopMostActivity();
        if (top != null) {
            top.associateStartingWindowWithTaskIfNeeded();
        }
    }
}

这个方法比较直接,直接通过index指定了位置。虽然指定了位置,但是程序中还是要对其进行调整的。

private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) {
    final boolean canShowChild = wc.showToCurrentUser();

    final int size = mChildren.size();

    // Figure-out min/max possible position depending on if child can show for current user.
    int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0;
    int maxPosition = minPosition;
    if (size > 0) {
        maxPosition = (canShowChild) ? size - 1 : computeMaxUserPosition(size - 1);
    }

    // Factor in always-on-top children in max possible position.
    if (!wc.isAlwaysOnTop()) {
        // We want to place all non-always-on-top containers below always-on-top ones.
        while (maxPosition > minPosition) {
            if (!mChildren.get(maxPosition).isAlwaysOnTop()) break;
            --maxPosition;
        }
    }

    // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
    if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) {
        return POSITION_BOTTOM;
    } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) {
        return POSITION_TOP;
    }

    // Increase the maxPosition because children size will grow once wc is added.
    if (!hasChild(wc)) {
        ++maxPosition;
    }

    // Reset position based on minimum/maximum possible positions.
    return Math.min(Math.max(suggestedPosition, minPosition), maxPosition);
}

这里其实就是根据最大最小值和指定的值进行对比然后修正一下。

不过还有另一个形式的addChild算法:

void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) {
    Task task = child.asTask();//这里如果child是task则返回一个值,否则返回null。
    try {
        if (task != null) {
            task.setForceShowForAllUsers(showForAllUsers);
        }
        // We only want to move the parents to the parents if we are creating this task at the
        // top of its root task.
        addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/);
    } finally {
        if (task != null) {
            task.setForceShowForAllUsers(false);
        }
    }
}

这个算法参数都不同了,有三个参数,这里第一步直接判断子元素是不是task类型。如果是的话,就执行setForceShowForAllUsers该方法,但是这里也没啥,就是对mForceShowForAllUsers进行赋值,然后就是对其进行比较器为null的排序,这里就不重复讲了,比较的过程在WindowContainer.java中的protected void addChild(E child, Comparator comparator) 该方法中。

10)、TaskDisplayArea:

Task或者TaskDisplayArea的容器。继承自DisplayArea类。代表的是屏幕上一块专门用来存放app窗口的区域。其父容器是DisplayContent。

在这里插入图片描述

final class TaskDisplayArea extends DisplayArea<WindowContainer> {
这个类对其中元素排序的方法依然可以通过addChild方法去查看,
void addChild(WindowContainer child, int position) {
    if (child.asTaskDisplayArea() != null) {
        if (DEBUG_ROOT_TASK) {
            Slog.d(TAG_WM, "Set TaskDisplayArea=" + child + " on taskDisplayArea=" + this);
        }
        super.addChild(child, position);
    } else if (child.asTask() != null) {
        addChildTask(child.asTask(), position);
    } else {
        throw new IllegalArgumentException(
                "TaskDisplayArea can only add Task and TaskDisplayArea, but found "
                        + child);
    }
}

其对于两个子类的元素有着不同的排序方法。第一种就是直接调用WindowContainer.java中的addChild(E child, int index)方法,直接在指定位置添加。
第二个的话就是如果元素是task类的话其实和上面也差不多,就是通过当前已有的一些子类对指定的位置进行一些修正。

11)、DisplayArea:

该类用于将WindowContainer分组到DisplayContent下方的容器。DisplayArea是被DisplayAreaPolicy管理的,能够复写Configuration和被绑定到leash上,并且可以嵌套DisplayArea,该类有三种风格:
BELOW_TASKS:只能包含位于任务下方的BELLOW_TASK显示区域和WindowToken。
ABOVE_TASKS:只能包含位于任务上方的ABOVE_TASK显示区域和WindowToken。
ANY:可以包含任何类型的DisplayArea,以及任何类型的WindowToken或Task容器。

12)、RootDisplayArea:

DisplayArea的根节点。根据注释来看:从等级制度上是DisplayArea的根节点。同时也可以是 逻辑屏幕上DisplayContent的根节点,或者逻辑屏幕上一个群组DisplayAreaGroup的根节点。

/**
 * Root of a {@link DisplayArea} hierarchy. It can be either the {@link DisplayContent} as the root
 * of the whole logical display, or a {@link DisplayAreaGroup} as the root of a partition of the
 * logical display.
 */
class RootDisplayArea extends DisplayArea.Dimmable {

所以这里将屏幕上的窗口分为两个逻辑,一个是等级制度,一个是物理屏幕。
在这里插入图片描述

13)、DisplayAreaGroup:

继承自RootDisplayArea,可以理解为一个集群,一个DisplayArea和DisplayContent之间的一个集群。 DisplayContent是整个屏幕上DisplayArea的根节点,但是一部分DisplayArea也可以挂载在DisplayAreaGroup上 。

/** The root of a partition of the logical display. */
class DisplayAreaGroup extends RootDisplayArea {

14)、另外还有一个容器ImeContainer:

这是输入法相关的,我暂时没了解,看定义大概能知道也是一类WindowToken的容器。

private static class ImeContainer extends DisplayArea.Tokens {

综上最后得到一个关系图:其中我将一个层级的都用同一个颜色标注出来。
请添加图片描述

然后再通过类图对其中涉及到的类进行归类。
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/677355.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python编程基础2

文件对象&#xff1a; open内建函数&#xff1a;通过了初始化输入、输出&#xff08;I/O&#xff09;操作的通用接口&#xff0c;成功打开文件后会返回一个文件对象&#xff0c;否则引发错误。file_objectopen&#xff08;file_name&#xff0c;mode‘r’&#xff09;:file_nam…

一款仅200kb好看的免费引导页源码

源码介绍: 这是一款200kb左右的引导页,超级好看,用服务器或者主机均可搭建 下载压缩包解压至根目录即可&#xff0c;页面内容在index.html里修改 左边图片采用的是API接口&#xff08;不喜欢可以自行更换,在66/67行&#xff09; 引导页压缩包放在下面了,有需要的朋友可以直接下…

【热点】老黄粉碎摩尔定律被,量产Blackwell解决ChatGPT耗电难题

6月3日&#xff0c;老黄又高调向全世界秀了一把&#xff1a;已经量产的Blackwell&#xff0c;8年内将把1.8万亿参数GPT-4的训练能耗狂砍到1/350&#xff1b; 英伟达惊人的产品迭代&#xff0c;直接原地冲破摩尔定律&#xff1b;Blackwell的后三代路线图&#xff0c;也一口气被…

杂谈k8s

其实看我之前的博客&#xff0c;k8s刚有点苗头的时候我就研究过&#xff0c;然后工作的时候间接接触 也自己玩过 但是用的不多就忘记了&#xff0c;正苦于不知道写什么&#xff0c;水一篇 简化容器应用程序的部署和管理 自动化部署、自动伸缩、负载均衡、存储管理、自我修复 支…

DP-Kmaens密度峰值聚类算法

我有个问题 关于 [密度值>密度阈值] 的判定这里&#xff0c;新进来的新数据怎么确定他的密度值&#xff1f;密度阈值又是怎样确定的呢&#xff1f;

Golang | Leetcode Golang题解之第129题求根节点到叶节点数字之和

题目&#xff1a; 题解&#xff1a; type pair struct {node *TreeNodenum int }func sumNumbers(root *TreeNode) (sum int) {if root nil {return}queue : []pair{{root, root.Val}}for len(queue) > 0 {p : queue[0]queue queue[1:]left, right, num : p.node.Left, …

RPM包方式离线部署gitlab

下载安装包 要求&#xff1a;可以联网&#xff0c;系统及版本与目标服务器一致。配置gitlab yum仓库 curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash 新建包存放目录 mkdir /root/gitlab 下载gitlab及相关安装包 …

Linux之线程及线程安全详解

前言&#xff1a;在操作系统中&#xff0c;进程是资源分配的基本单位&#xff0c;那么线程是什么呢&#xff1f;线程是调度的基本单位&#xff0c;我们该怎么理解呢&#xff1f; 目录 一&#xff0c;线程概念理解 二&#xff0c;Linux里面的线程原理 三&#xff0c;为什么要…

《MySQL索引》学习笔记

《MySQL索引》学习笔记 MySQL的体系结构存储引擎简介InnoDB简介MyISAM简介 索引索引结构BTreeHash索引思考索引分类 索引语法SQL性能分析索引使用最左前缀法则 索引失效的情况范围查询索引列运算字符串不加引号模糊查询or连接的条件数据分布影响 SQL提示覆盖索引前缀索引单列索…

【MyBatisPlus】DML编程控制

【MyBatisPlus】DML编程控制 文章目录 【MyBatisPlus】DML编程控制1、id生成策略2、逻辑删除 1、id生成策略 id生成策略控制&#xff08;TableId注解&#xff09; 名称&#xff1a;TableId 类型&#xff1a;属性注解 位置&#xff1a;模型类中用于表示主键的属性定义上方 作…

机器学习中的集成学习

&#x1f4ac;内容概要 1 集成学习概述及主要研究领域 2 简单集成技术  2.1 投票法  2.2 平均法  2.3 加权平均 3 高级集成技术  3.1 Bagging  3.2 Boosting  3.3 Bagging vs Boosting 4 基于Bagging和Boosting的机器学习算法  4.1 sklearn中的Bagging算法  4.2 sklea…

AI大模型探索之路-实战篇15: Agent智能数据分析平台之整合封装Tools和Memory功能代码

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…

C++基础-vector容器

目录 零. 前言: 一.简介 二. 主要特点 三. 例子 1.创建 2.添加元素 3.访问元素 4.获取大小 5.删除元素 6.扩展 begin() end() 零. 前言: 在编程中&#xff0c;数组通常具有固定的大小&#xff0c;这在某些情况下可能会带来一些限制。 当我们事先无法确切知道需要存…

topK 问题

topK 问题 topK二、实验内容三、数据结构设计四、算法设计五、运行结果六、程序源码 topK &#xff08;1&#xff09;实验题目 topK 问题 &#xff08;2&#xff09;问题描述 从大批量数据序列中寻找最大的前 k 个数据&#xff0c;比如从 10 万个数据中&#xff0c;寻找最大的…

leetcode155 最小栈

题目 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。i…

OpenCv之简单的人脸识别项目(特征标注页面)

人脸识别 准备八、特征标注页面1.导入所需的包2.设置窗口2.1定义窗口外观和大小2.2设置窗口背景2.2.1设置背景图片2.2.2创建label控件 3.定义两个全局变量4.定义选择图片的函数4.1函数定义和全局变量声明4.2打开文件对话框并获取文件路径4.3处理图片并创建标签4.4显示图像 5.定…

Window11端口开放防火墙

&#xff08;1&#xff09;打开控制面板&#xff0c;进入【控制面板\系统和安全\Windows Defender 防火墙】 &#xff08;2&#xff09;点击左侧菜单【高级设置】&#xff0c;进入防火墙设置页面 &#xff08;3&#xff09;根据需要选择【入站规则】或者【出站规则】&#xff…

【深度好文】到底什么是质量意识?如何衡量,如何提升?

大家好&#xff0c;我是狂师&#xff01; 在软件测试中&#xff0c;质量意识是一个核心且至关重要的概念。相信大家&#xff0c;经常会听到&#xff1a;"这个家伙质量意识很强&#xff0c;某某某要提升质量意识“之类的话语。 在企业中&#xff0c;“质量意识”不仅关乎…

NoSQL实战(MongoDB搭建主从复制)

什么是复制集&#xff1f; MongoDB复制是将数据同步到多个服务器的过程&#xff1b; 复制集提供了数据的冗余备份并提高了数据的可用性&#xff0c;通常可以保证数据的安全性&#xff1b; 复制集还允许您从硬件故障和服务中断中恢复数据。 保障数据的安全性 数据高可用性 (2…

day30--mybatis(三)高级

一.Mybatis注解开发单表操作 1.1 MyBatis的常用注解 这几年来注解开发越来越流行&#xff0c;Mybatis也可以使用注解开发方式&#xff0c;这样我们就可以减少编写Mapper 映射文件了。我们先围绕一些基本的CRUD来学习&#xff0c;再学习复杂映射多表操作。 Insert&#xff1…