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

Android SystemUI——CarSystemBar视图解析(十一)

        前面文章我们已经把 CarSystemBar 从启动到构建视图,再到将视图添加到 Window 的流程分析完毕,我们知道默认情况下在车载系统中只显示顶部栏和底部栏视图的。这里我们在前面文章的基础上以顶部栏为例具体解析其视图的结构。

一、顶部栏解析

        通过《CarSystemBar车载状态栏》这篇文章我们知道车载系统对应的顶部状态栏为 mTopSystemBarView,其布局文件为 car_top_system_bar。

1、car_top_system_bar.xml

源码位置:/packages/apps/Car/SystemUI/res/layout/car_top_system_bar.xml

<com.android.systemui.car.systembar.CarSystemBarView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:systemui="http://schemas.android.com/apk/res-auto"
    android:id="@+id/car_top_bar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/system_bar_background"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layoutDirection="ltr">

        <FrameLayout
            android:id="@+id/system_icon_area"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginTop="@dimen/car_padding_2"
            android:layout_marginStart="@dimen/car_padding_2"
            android:layout_centerVertical="true"
            android:layout_alignParentStart="true"
            android:gravity="center_vertical"
        >
            <com.android.systemui.car.systembar.CarSystemBarButton
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:background="@drawable/system_bar_background_pill"
                android:layout_weight="1"
                android:gravity="center_vertical"
                systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end">

                <include
                    layout="@layout/system_icons"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:layout_marginStart="@dimen/car_padding_2"
                    android:layout_marginEnd="@dimen/car_padding_2"
                    android:gravity="center_vertical"
                />
            </com.android.systemui.car.systembar.CarSystemBarButton>
        </FrameLayout>

        <com.android.systemui.car.systembar.CarSystemBarButton
            android:id="@+id/clock_container"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="@drawable/system_bar_pill_rotary_background"
            android:paddingStart="@dimen/car_padding_2"
            android:paddingEnd="@dimen/car_padding_2"
            android:layout_centerInParent="true"
            systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end">
            <com.android.systemui.statusbar.policy.Clock
                android:id="@+id/clock"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:elevation="5dp"
                android:singleLine="true"
                android:textAppearance="@style/TextAppearance.SystemBar.Clock"
                systemui:amPmStyle="normal"
            />
        </com.android.systemui.car.systembar.CarSystemBarButton>

        <include layout="@layout/mic_privacy_chip"
            android:layout_width="@dimen/privacy_chip_width"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@id/clock_container"
            android:layout_toLeftOf="@id/user_name_container" />

        <FrameLayout
            android:id="@+id/user_name_container"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_marginTop="@dimen/car_padding_2"
        >
            <com.android.systemui.car.systembar.CarSystemBarButton
                android:id="@+id/user_name"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginEnd="@dimen/car_padding_2"
                android:background="@drawable/system_bar_background_pill"
                android:gravity="center_vertical"
                systemui:intent="intent:#Intent;component=com.android.car.settings/.profiles.ProfileSwitcherActivity;launchFlags=0x24000000;end"
            >
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="horizontal"
                    android:layout_marginStart="@dimen/car_padding_2"
                    android:layout_marginEnd="@dimen/car_padding_2"
                    android:gravity="center_vertical"
                >
                    <ImageView
                        android:id="@+id/user_avatar"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:src="@drawable/car_ic_user_icon"
                        android:layout_marginEnd="@dimen/system_bar_user_icon_padding"
                    />
                    <TextView
                        android:id="@+id/user_name_text"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:gravity="center_vertical"
                        android:textAppearance="@style/TextAppearance.SystemBar.Username"
                        android:singleLine="true"
                        android:maxWidth="@dimen/car_system_bar_user_name_max_width"
                        android:layout_marginEnd="@dimen/system_bar_user_icon_padding"
                    />
                </LinearLayout>
            </com.android.systemui.car.systembar.CarSystemBarButton>
        </FrameLayout>
    </RelativeLayout>

</com.android.systemui.car.systembar.CarSystemBarView>

        其实 car_top_system_bar 所构建是视图其实就是车载系统最终显示在桌面上的状态栏视图。

2、CarSystemBarViewFactory

        通过前面状态栏视图的构建构成我们知道,最终调用了 CarSystemBarViewFactory 的 getBarCached() 方法。

源码位置:/packages/apps/Car/SystemUI/src/com/android/systemui/car/systembar/CarSystemBarViewFactory.java

getBarCached

private CarSystemBarView getBarCached(Type type, @LayoutRes int barLayout) {
	……
	CarSystemBarView view = (CarSystemBarView) View.inflate(mContext, barLayout,
			/* root= */ null);
 
    // 设置图标控制器
	view.setupIconController(mFeatureFlags, mIconController);
 
	view.addView(new FocusParkingView(mContext), 0);
 
	mCachedViewMap.put(type, view);
	return mCachedViewMap.get(type);
}

         这里调用了 setupIconController() 方法为存储快捷图标的容器控件设置控制器。

3、CarSystemBarView

源码位置:/packages/apps/Car/SystemUI/src/com/android/systemui/car/systembar/CarSystemBarView.java

setupIconController

void setupIconController(FeatureFlags featureFlags, StatusBarIconController iconController) {
    // 查找状态图标容器	
    View mStatusIcons = findViewById(R.id.statusIcons);
	if (mStatusIcons != null) {
		// 如果标准容器在视图中,则为状态图标(如wifi和蓝牙)附加控制器
        // 创建 DarkIconManager,它负责管理状态图标的显示
		StatusBarIconController.DarkIconManager mDarkIconManager =
				new StatusBarIconController.DarkIconManager(
						mStatusIcons.findViewById(R.id.statusIcons), featureFlags);
		mDarkIconManager.setShouldLog(true);
		iconController.addIconGroup(mDarkIconManager);
	}
}

        该方法用于配置和初始化状态栏图标控制器(StatusBarIconController),以便管理状态栏中的图标,例如 Wi-Fi、蓝牙等连接状态的图标。同时可以看到图标容器的 id 为 statusIcons,位于 car_top_system_bar.xml 中的引用布局 system_icons 内。

system_icons.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/system_icons"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical">

    <com.android.systemui.statusbar.phone.StatusIconContainer
        android:id="@+id/statusIcons"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:paddingEnd="4dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
    />
</LinearLayout>

        可以看到图标容器是一个 StatusIconContainer 自定义的控件。下面来看一下上面的 addIconGroup() 方法,该方法在 StatusBarIconController 定义,真正实现是在 StatusBarIconControllerImpl 中。

4、StatusBarIconControllerImpl

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java

addIconGroup

@Override
public void addIconGroup(IconManager group) {
    // 将新的 IconManager 添加到管理列表中
	mIconGroups.add(group);

    // 获取所有槽位列表
	List<Slot> allSlots = getSlots();
	for (int i = 0; i < allSlots.size(); i++) {
        // 获取当前槽位
		Slot slot = allSlots.get(i);
        // 获取槽位内的图标持有者列表,按视图顺序排列
		List<StatusBarIconHolder> holders = slot.getHolderListInViewOrder();
        // 检查该槽位的图标是否被隐藏
		boolean hidden = mIconHideList.contains(slot.getName());

		for (StatusBarIconHolder holder : holders) {
            // 获取图标的标识符
			int tag = holder.getTag();
            // 计算图标在视图中的索引位
			int viewIndex = getViewIndex(getSlotIndex(slot.getName()), holder.getTag());
            // 通知 IconManager 图标已被添加
			group.onIconAdded(viewIndex, slot.getName(), hidden, holder);
		}
	}
}

        该方法有效地将新的 IconManager 集成到现有的图标管理系统中,并确保它可以立即开始管理工作。最终调用 onIconAdded 通知图标已经添加。

5、StatusBarIconController

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java

onIconAdded

class DarkIconManager extends IconManager {
    private final DarkIconDispatcher mDarkIconDispatcher;

	@Override
	protected void onIconAdded(int index, String slot, boolean blocked,
			StatusBarIconHolder holder) {
		StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
		mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
	}
}

        这里先调用了 addHolder() 方法来添加图标持有者,然后调用了 DarkIconDispatcher 的 addDarkReceiver() 方法,用于可以接收深色模式的变化通知。

addHolder

protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
		StatusBarIconHolder holder) {
	// 检查当前槽位是否存在于屏蔽列表中
	if (mBlockList.contains(slot)) {
		blocked = true;
	}
    // 根据图标类型调用相应的方法来添加图标
	switch (holder.getType()) {
		case TYPE_ICON: // 普通图标
			return addIcon(index, slot, blocked, holder.getIcon());

		case TYPE_WIFI: // Wi-Fi信号图标
			return addSignalIcon(index, slot, holder.getWifiState());

		case TYPE_MOBILE: // 移动网络图标 
			return addMobileIcon(index, slot, holder.getMobileState());
	}

	return null;
}

        该方法负责处理状态栏中各种类型的图标添加逻辑。它不仅确保了图标能够根据其类型正确地显示,还提供了对特定图标进行阻止显示的能力。 可以看到这里的 switch 中包含三个图标控件的处理,这里我们以移动网络图标为例继续看一下。

@VisibleForTesting
protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
    // 创建移动网络图标视图
	StatusBarMobileView view = onCreateStatusBarMobileView(slot);
    // 应用移动网络状态到视图
	view.applyMobileState(state);
    // 将视图添加到视图组中
	mGroup.addView(view, index, onCreateLayoutParams());

    // 如果处于演示模式,则更新演示状态
	if (mIsInDemoMode) {
		mDemoStatusIcons.addMobileView(state);
	}
	return view;
}

        通过 @VisibleForTesting 注释我们知道该方法是为了测试目的而设计的,实际开发中我们需要根据自己的需求去创建需要的对象。这里的 StatusBarMobileView 位于 /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ 下,这里我们就不在详细分析了。

6、DarkIconDispatcherImpl

        再来看一下深色模式状态变化的通知流程,DarkIconDispatcher 中只定义了接口,真正实现该接口是在 DarkIconDispatcherImpl 中。

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java

addDarkReceiver

 

public void addDarkReceiver(DarkReceiver receiver) {
    mReceivers.put(receiver, receiver);
    receiver.onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
}

         该方法调用 DarkReceiver 中的 onDarkChanged() 方法,真正的通知到控件深色模式状态变化。

 


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

相关文章:

  • 消息队列实战指南:三大MQ 与 Kafka 适用场景全解析
  • windows 远程链接 Ubuntu 图形界面
  • 华为数据中心CE系列交换机级联M-LAG配置示例
  • 4.Spring AI Prompt:与大模型进行有效沟通
  • 【机器学习实战入门】使用OpenCV和Keras的驾驶员疲劳检测系统
  • 从 SQL 语句到数据库操作
  • springboot使用websocket
  • 什么是FPGA开发?
  • Java 接口安全指南
  • TOSUN同星TsMaster使用入门——3、使用系统变量及c小程序结合panel面板发送报文
  • AttributeError: ‘super‘ object has no attribute ‘__sklearn_tags__‘
  • InVideo AI技术浅析(三):计算机视觉
  • 深入理解 Windows Server 的核心功能:现代 IT 架构的基石
  • springboot基于微信小程序的健康管理系统
  • 力扣7-删除有序数组中的重复项
  • Python在多个Excel文件中找出缺失数据行数多的文件
  • OA-CNN:用于 3D 语义分割的全自适应稀疏 CNN
  • 数据增强方法及其工具
  • 模板编辑器(PHP)(小迪网络安全笔记~
  • 尺取法(算法优化技巧)
  • 瑞利衰落信道机理的详解
  • 利用逻辑回归进行分类
  • 了解MyBatis:一个灵活高效的O/R Mapping解决方案
  • 【博客之星2024】技术洞察:前沿技术趋势与创新实践
  • java项目之陕理工图书馆管理系统的设计与实现源码(ssm)
  • react中,如何使用antd的Row栅格系统使元素左对齐