Android SystemUI——CarSystemBar添加到窗口(十)
上一篇文章我们看到了车载状态栏 CarSystemBar 视图的创建流程,这里我们继续分析将车载状态栏添加到 Windows 窗口中。
一、添加状态栏到窗口
前面我们已经分析了构建视图对象容器和构建视图对象内容,接下来我们继续分析 attachNavBarWindows() 方法将视图对象添加到 Window 中。
1、CarSystemBar
源码位置:/packages/apps/Car/SystemUI/src/com/android/systemui/car/systembar/CarSystemBar.java
attachNavBarWindows
private final SystemBarConfigs mSystemBarConfigs;private void attachNavBarWindows() {mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide);
}
attachNavBarWindows() 会调用 SystemBarConfigs 的 getSystemBarSidesByZOrder() 方法获取到当前存在的所有 SystemBar 所对应的 Side。
2、SystemBarConfigs
源码位置:/packages/apps/Car/SystemUI/src/com/android/systemui/car/systembar/SystemBarConfigs.java
private final List<@SystemBarSide Integer> mSystemBarSidesByZOrder = new ArrayList<>();protected List<Integer> getSystemBarSidesByZOrder() {return mSystemBarSidesByZOrder;
}
可以看到这里返回一个 List<@SystemBarSide Integer> 类型的数组,下面看一下 mSystemBarSidesByZOrder 数据的赋值。
sortSystemBarSidesByZOrder
private final Map<@SystemBarSide Integer, SystemBarConfig> mSystemBarConfigMap = new ArrayMap<>();private void sortSystemBarSidesByZOrder() {// 获取SystemBarConfig列表List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {@Overridepublic int compare(SystemBarConfig o1, SystemBarConfig o2) {// 进行大小比较return o1.getZOrder() - o2.getZOrder();}});// 存储排序后SystemBar的Side数值。systemBarsByZOrder.forEach(systemBarConfig -> {mSystemBarSidesByZOrder.add(systemBarConfig.getSide());});
}
这里首先对 SystemBarConfig 列表根据序号对 SystemBar 进行排序,并将排序后 SystemBar 的 Side 数值保存到 mSystemBarSidesByZOrder 数组中。而该函数是在 SystemBarConfigs 构造函数中进行调用,并且在调用之前还要填充 mSystemBarConfigMap 数据。
SystemBarConfigs
@Inject
public SystemBarConfigs(@Main Resources resources) {mResources = resources;// 初始化数据populateMaps();// 读取SystemBar所对应的SystemBarConfig的配置信息readConfigs();……// 使用SystemBarConfig的ZOrder属性对SystemBarConfig的Size进行排序sortSystemBarSidesByZOrder();
}
readConfigs
private void readConfigs() {mTopNavBarEnabled = mResources.getBoolean(R.bool.config_enableTopSystemBar);mBottomNavBarEnabled = mResources.getBoolean(R.bool.config_enableBottomSystemBar);mLeftNavBarEnabled = mResources.getBoolean(R.bool.config_enableLeftSystemBar);mRightNavBarEnabled = mResources.getBoolean(R.bool.config_enableRightSystemBar);// 顶部栏可用if (mTopNavBarEnabled) {SystemBarConfig topBarConfig =new SystemBarConfigBuilder().setSide(TOP)// 顶部栏高度.setGirth(mResources.getDimensionPixelSize(R.dimen.car_top_system_bar_height))// 系统栏类型.setBarType(mResources.getInteger(R.integer.config_topSystemBarType))// 系统栏Z轴序列.setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder)).setHideForKeyboard(mResources.getBoolean(R.bool.config_hideTopSystemBarForKeyboard)).build();mSystemBarConfigMap.put(TOP, topBarConfig);}// 底部栏可用if (mBottomNavBarEnabled) {SystemBarConfig bottomBarConfig =new SystemBarConfigBuilder().setSide(BOTTOM).setGirth(mResources.getDimensionPixelSize(R.dimen.car_bottom_system_bar_height)).setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType)).setZOrder(mResources.getInteger(R.integer.config_bottomSystemBarZOrder)).setHideForKeyboard(mResources.getBoolean(R.bool.config_hideBottomSystemBarForKeyboard)).build();mSystemBarConfigMap.put(BOTTOM, bottomBarConfig);}// 左侧栏不可用if (mLeftNavBarEnabled) {SystemBarConfig leftBarConfig =new SystemBarConfigBuilder().setSide(LEFT).setGirth(mResources.getDimensionPixelSize(R.dimen.car_left_system_bar_width)).setBarType(mResources.getInteger(R.integer.config_leftSystemBarType)).setZOrder(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).setHideForKeyboard(mResources.getBoolean(R.bool.config_hideLeftSystemBarForKeyboard)).build();mSystemBarConfigMap.put(LEFT, leftBarConfig);}// 右侧栏不可用if (mRightNavBarEnabled) {SystemBarConfig rightBarConfig =new SystemBarConfigBuilder().setSide(RIGHT).setGirth(mResources.getDimensionPixelSize(R.dimen.car_right_system_bar_width)).setBarType(mResources.getInteger(R.integer.config_rightSystemBarType)).setZOrder(mResources.getInteger(R.integer.config_rightSystemBarZOrder)).setHideForKeyboard(mResources.getBoolean(R.bool.config_hideRightSystemBarForKeyboard)).build();mSystemBarConfigMap.put(RIGHT, rightBarConfig);}
}
这里首先获取状态了的可用状态,从 config.xml 文件中获取对应数据。
<!-- 配置应该显示哪些系统条 -->
<bool name="config_enableTopSystemBar">true</bool>
<bool name="config_enableLeftSystemBar">false</bool>
<bool name="config_enableRightSystemBar">false</bool>
<bool name="config_enableBottomSystemBar">true</bool>
可以看到,这里配置了状态栏的显示状态,所以修改进度条的显示位置可以通过修改该数据实现。 同样其他相关的配置信息也都可以在对应的配置文件中找到。
3、添加状态栏
我们知道 attachNavBarWindows() 方法最终会循环 mSystemBarSidesByZOrder 集合的内容,用该集合的子项作为参数,依次调用 attachNavBarBySide() 方法。
attachNavBarBySide
private void attachNavBarBySide(int side) {switch (side) {case SystemBarConfigs.TOP:// 如果顶部栏视图容器不为空,将顶部栏视图容器添加到Window中if (mTopSystemBarWindow != null) {mWindowManager.addView(mTopSystemBarWindow,mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.TOP));}break;case SystemBarConfigs.BOTTOM:if (mBottomSystemBarWindow != null && !mBottomNavBarVisible) {mBottomNavBarVisible = true;mWindowManager.addView(mBottomSystemBarWindow,mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.BOTTOM));}break;case SystemBarConfigs.LEFT:if (mLeftSystemBarWindow != null) {mWindowManager.addView(mLeftSystemBarWindow,mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.LEFT));}break;case SystemBarConfigs.RIGHT:if (mRightSystemBarWindow != null) {mWindowManager.addView(mRightSystemBarWindow,mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.RIGHT));}break;default:return;}
}
该方法就是根据对应的 type 判断当前视图容器的具体类型,到底是顶部栏、底部栏、左侧栏还是右侧栏,根据类型配合类型相对应的参数将该视图容器添加到 WindowManager 中。
二、状态栏配置
状态栏配置类 SystemBarConfig 为 SystemBarConfigs 的内部类。
1、SystemBarConfig
// 系统条将开始出现在HUN的顶部的z轴顺序
private static final int HUN_ZORDER = 10;private static final int[] BAR_TYPE_MAP = {InsetsState.ITYPE_STATUS_BAR, // 状态栏对应的系统装饰窗口类型InsetsState.ITYPE_NAVIGATION_BAR, // 导航栏对应的系统装饰窗口类型InsetsState.ITYPE_CLIMATE_BAR, // 左侧栏对应的系统装饰窗口类型InsetsState.ITYPE_EXTRA_NAVIGATION_BAR // 右侧栏对应的系统装饰窗口类型private static final class SystemBarConfig {private final int mSide;private final int mBarType;private final int mGirth;private final int mZOrder;private final boolean mHideForKeyboard;private int[] mPaddings = new int[]{0, 0, 0, 0};private SystemBarConfig(@SystemBarSide int side, int barType, int girth, int zOrder,boolean hideForKeyboard) {mSide = side;mBarType = barType;mGirth = girth;mZOrder = zOrder;mHideForKeyboard = hideForKeyboard;}private int getSide() {return mSide;}private int getBarType() {return mBarType;}private int getGirth() {return mGirth;}private int getZOrder() {return mZOrder;}private boolean getHideForKeyboard() {return mHideForKeyboard;}private int[] getPaddings() {return mPaddings;}private WindowManager.LayoutParams getLayoutParams() {WindowManager.LayoutParams lp = new WindowManager.LayoutParams(isHorizontalBar(mSide) ? ViewGroup.LayoutParams.MATCH_PARENT : mGirth,isHorizontalBar(mSide) ? mGirth : ViewGroup.LayoutParams.MATCH_PARENT,mapZOrderToBarType(mZOrder),WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,PixelFormat.TRANSLUCENT); // 设置窗口半透明(全透明:TRANSPARENT)lp.setTitle(BAR_TITLE_MAP.get(mSide));//顶部栏为new int[]{InsetsState.ITYPE_STATUS_BAR, InsetsState.ITYPE_TOP_MANDATORY_GESTURES}//底部栏为new int[]{InsetsState.ITYPE_NAVIGATION_BAR, InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES}//providesInsetsTypes这个字段很重要,只有设置对这个字段,系统才会认定该窗口是对应的装饰窗口lp.providesInsetsTypes = new int[]{BAR_TYPE_MAP[mBarType], BAR_GESTURE_MAP.get(mSide)};lp.setFitInsetsTypes(0);lp.windowAnimations = 0;lp.gravity = BAR_GRAVITY_MAP.get(mSide);return lp;}private int mapZOrderToBarType(int zOrder) {// 顶部栏窗口类型为TYPE_STATUS_BAR_ADDITIONAL,底部栏TYPE_NAVIGATION_BAR_PANELreturn zOrder >= HUN_ZORDER ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;}private void setPaddingBySide(@SystemBarSide int side, int padding) {mPaddings[side] = padding;}
}
这里主要用来配置状态栏类型及对应的视图内容,其中状态栏位置和标题等信息是在上面的 populateMaps() 方法中赋值。
populateMaps
public static final int TOP = 0;
public static final int BOTTOM = 1;
public static final int LEFT = 2;
public static final int RIGHT = 3;private static void populateMaps() {// 将系统栏位置与Gravity值关联BAR_GRAVITY_MAP.put(TOP, Gravity.TOP);BAR_GRAVITY_MAP.put(BOTTOM, Gravity.BOTTOM);BAR_GRAVITY_MAP.put(LEFT, Gravity.LEFT);BAR_GRAVITY_MAP.put(RIGHT, Gravity.RIGHT);// 将系统栏位置与标题字符串关联BAR_TITLE_MAP.put(TOP, "TopCarSystemBar");BAR_TITLE_MAP.put(BOTTOM, "BottomCarSystemBar");BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar");BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar");// 将系统栏位置与手势类型关联BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_MANDATORY_GESTURES);BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES);BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_MANDATORY_GESTURES);BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_MANDATORY_GESTURES);
}
2、SystemBarConfigBuilder
private static final class SystemBarConfigBuilder {private int mSide;private int mBarType;private int mGirth;private int mZOrder;private boolean mHideForKeyboard;private SystemBarConfigBuilder setSide(@SystemBarSide int side) {mSide = side;return this;}private SystemBarConfigBuilder setBarType(int type) {mBarType = type;return this;}private SystemBarConfigBuilder setGirth(int girth) {mGirth = girth;return this;}private SystemBarConfigBuilder setZOrder(int zOrder) {mZOrder = zOrder;return this;}private SystemBarConfigBuilder setHideForKeyboard(boolean hide) {mHideForKeyboard = hide;return this;}private SystemBarConfig build() {return new SystemBarConfig(mSide, mBarType, mGirth, mZOrder, mHideForKeyboard);}
}
SystemBarConfigBuilder 同样是 SystemBarConfigs 的内部类,它实现了构建者模式(Builder Pattern),用于简化 SystemBarConfig 对象的创建。
相关文章:
Android SystemUI——CarSystemBar添加到窗口(十)
上一篇文章我们看到了车载状态栏 CarSystemBar 视图的创建流程,这里我们继续分析将车载状态栏添加到 Windows 窗口中。 一、添加状态栏到窗口 前面我们已经分析了构建视图对象容器和构建视图对象内容,接下来我们继续分析 attachNavBarWindows() 方法将视…...
《重生到现代之从零开始的C++生活》—— 类和对象1
类 我嘞个豆,类可是太重要了,简直是重中之重 class为定义类的关键字,stack为类的名字,{}为类的主题 class stack {void add (int a,int b){return ab;}//类的方法,成员函数int _c;int _d;//类的属性,成…...
《FMambaIR:一种基于混合状态空间模型和频域的方法用于图像恢复》学习笔记
paper:(PDF) FMambaIR: A Hybrid State Space Model and Frequency Domain for Image Restoration 目录 摘要 一、引言 二、相关工作 1、图像恢复 2、频率学习 3、状态空间模型(SSM) 三、框架 1、基本知识 2、整体框架 3、F-Mamba…...
每日十题八股-2025年1月18日
1.服务器处理并发请求有哪几种方式? 2.讲一下io多路复用 3.select、poll、epoll 的区别是什么? 4.epoll 的 边缘触发和水平触发有什么区别? 5.redis,nginx,netty 是依赖什么做的这么高性能? 6.零拷贝是什么…...
海康威视摄像头RTSP使用nginx推流到服务器直播教程
思路: 之前2020年在本科的时候,由于项目的需求需要将海康威视的摄像头使用推流服务器到网页进行直播。这里将自己半个月琢磨出来的步骤给大家发一些。切勿转载!!!! 使用网络摄像头中的rtsp协议---------通…...
搭建一个基于Spring Boot的书籍学习平台
搭建一个基于Spring Boot的书籍学习平台可以涵盖多个功能模块,例如用户管理、书籍管理、学习进度跟踪、笔记管理、评论和评分等。以下是一个简化的步骤指南,帮助你快速搭建一个基础的书籍学习平台。 — 1. 项目初始化 使用 Spring Initializr 生成一个…...
Go 语言的slice是如何扩容的?
Go 语言中的 slice 是一种灵活、动态的视图,是对底层数组的抽象。当对 slice 进行追加元素等操作导致其长度超过容量时,就会发生扩容。 一、扩容的基本原理 当 slice 需要扩容时,Go 语言会根据当前的容量来确定新的容量。一般来说ÿ…...
Apache Hive--排序函数解析
在大数据处理与分析中,Apache Hive是一个至关重要的数据仓库工具。其丰富的函数库为数据处理提供了诸多便利,排序函数便是其中一类非常实用的工具。通过排序函数,我们能够在查询结果集中为每一行数据分配一个排名值,这对于数据分析…...
Java 接口安全指南
Java 接口安全指南 概述 在现代 Web 应用中,接口(API)是前后端交互的核心。然而,接口的安全性常常被忽视,导致数据泄露、未授权访问等安全问题。本文将详细介绍 Java 中如何保障接口安全,涵盖以下内容&am…...
合合信息名片全能王上架原生鸿蒙应用市场,成为首批数字名片类应用
长期以来,名片都是企业商务沟通的重要工具。随着企业数字化转型,相较于传统的纸质名片,数字名片对于企业成员拓展业务、获取商机、提升企业形象等方面发挥着重要作用。近期,合合信息旗下名片全能王正式上线原生鸿蒙应用市场&#…...
38.【3】CTFHUB web sql 报错注入
进入靶场 按照提示输入1 显示查询正确 既然是报错注入,先判断整形还是字符型注入 先输入1 and 11 再输入1 and 12 都显示查询正确,可知此为字符串型注入,不是数字型注入 然后就不会了 求助AI和其他wp 由以上2张搜索结果知updatexml是适用…...
RC2在线加密工具
RC2是由著名密码学家Ron Rivest设计的一种传统对称分组加密算法,它可作为DES算法的建议替代算法。RC2是一种分组加密算法,RC2的密钥长度可变,可以从8字节到128字节,安全性选择更加灵活。 开发调试上,有时候需要进行对…...
NVIDIA 下 基于Ubuntun20.04下 使用脚本安装 ros2-foxy 和 使用docker安装 ros2-foxy
一、前提介绍: 本文主要采用两种方式在NVIDIA 下基于 Ubuntun20.04安装 ros2-foxy。 使用环境: NVIDIA 为 Jetson 系列下 Jetson Xavier NX; Ubuntun版本:20.04 二、安装方法: 1、使用脚本编译方式: 使…...
STL容器-- list的模拟实现(附源码)
STL容器-- list的模拟实现(附源码) List的实现主要考察我们对list这一容器的理解,和代码的编写能力,通过上节对list容器的使用,我们对list容器已经有了一些基本的了解,接下来就让我们来实现一些list容器常见…...
python——句柄
一、概念 句柄指的是操作系统为了标识和访问对象而提供的一个标识符,在操作系统中,每个对象都有一个唯一的句柄,通过句柄可以访问对象的属性和方法。例如文件、进程、窗口等都有句柄。在编程中,可以通过句柄来操作这些对象&#x…...
KubeSphere 与 Pig 微服务平台的整合与优化:全流程容器化部署实践
一、前言 近年来,为了满足越来越复杂的业务需求,我们从传统单体架构系统升级为微服务架构,就是把一个大型应用程序分割成可以独立部署的小型服务,每个服务之间都是松耦合的,通过 RPC 或者是 Rest 协议来进行通信,可以按照业务领域来划分成独立的单元。但是微服务系统相对…...
ESP8266-01S、手机、STM32连接
1、ESP8266-01S的工作原理 1.1、AP和STA ESP8266-01S为WIFI的透传模块,主要模式如下图: 上节说到,我们需要用到AT固件进行局域网应用(ESP8266连接的STM32和手机进行连接)。 ESP8266为一个WiFi透传模块,和…...
Web开发 -前端部分-CSS-2
一 长度单位 代码实现: <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document<…...
【QT用户登录与界面跳转】
【QT用户登录与界面跳转】 1.前言2. 项目设置3.设计登录界面3.1 login.pro参数3.2 界面设置3.2.1 登录界面3.2.2 串口主界面 4. 实现登录逻辑5.串口界面6.测试功能7.总结 1.前言 在Qt应用程序开发中,实现用户登录及界面跳转功能是构建交互式应用的重要步骤之一。下…...
记录一次关于spring映射postgresql的jsonb类型的转化器事故,并使用hutool的JSONArray完成映射
事件的起因是这样的,那次事故发生的起因是因为WebFlux和postgreSQL去重新做鱼皮的鱼图图项目(鱼图图作业)。 在做到picture表的时候,发现postgreSQL中有个jsonb的类型可以更好的支持json数组。 出于锻炼新技术的目的,…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
