当前位置: 首页 > article >正文

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>() {
		@Override
		public 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_PANEL
		return 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 对象的创建。 

 


http://www.kler.cn/a/509459.html

相关文章:

  • 基础入门-反弹Shell渗透命令Reverse反向Bind正向利用语言文件下载多姿势
  • Java基础(一)
  • 深入理解 Entity、VO、QO、DTO 的区别及其在 MVC 架构中的应用
  • JavaWeb 前端基础 html + CSS 快速入门 | 018
  • 无人机技术架构剖析!
  • 使用 ChatGPT 生成和改进你的论文
  • Debian终端高亮(显示不同颜色)
  • JVM加载
  • Social LSTM:Human Trajectory Prediction in Crowded Spaces | 文献翻译
  • 学生信息管理系统数据库设计(sql server)
  • 【three.js】纹理贴图
  • 1.4走向不同:GPT 与 BERT 的选择——两大NLP模型的深度解析
  • HTML元素新视角:置换元素与非置换元素的区分与理解
  • Golang笔记——常用库reflect和unsafe
  • 今天你学C++了吗?——C++中的STL
  • Docker部署php-fpm服务器详细教程
  • 嵌入式知识点总结(一)-C/C++关键字
  • HunyuanVideo 文生视频模型实践
  • # [游戏开发] [Unity游戏开发]3D滚球游戏设计与实现教程
  • 构建core模块
  • 接口测试Day10-接口对象封装封装TpShop登录接口
  • mono3d汇总
  • Go语言之路————数组、切片、map
  • PL/SQL语言的文件操作
  • macOS 安装JDK17
  • 【HarmonyOS-开发指南】