phone statusbar.java_SystemUI之StatusBar创建

本文是基于Android 10代码分析。

启动 SystemUI服务

ActivityManagerService 创建完成时会启动 SystemUI

// frameworks/base/services/java/com/android/server/SystemServer.java

private void startOtherServices() {

mActivityManagerService.systemReady(() -> {

try {

// AMS启动完成时,开启SystemUI

// 其实就是start一个叫SystemUIService的service

startSystemUi(context, windowManagerF);

} catch (Throwable e) {

reportWtf("starting System UI", e);

}

}

}

复制代码

启动 SystemUI 的入口是 SystemUIService,它是四大组件之一的 Service。

// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java

public class SystemUIService extends Service {

@Override

public void onCreate() {

super.onCreate();

// 启动各种服务

((SystemUIApplication) getApplication()).startServicesIfNeeded();

}

}

复制代码

调用了 SystemUIApplication#startServicesIfNeeded() 来启动各种服务,而这些服务不是四大组件之一的 Service, 而是继承自 SystemUI 接口的服务,我们称之为 SystemUI服务。

// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

public void startServicesIfNeeded() {

// 这个数组中定义了很多SystemUI服务

String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);

// 启动服务

startServicesIfNeeded(names);

}

复制代码

SystemUI 要启动的所有服务都是在数组 config_systemUIServiceComponents 中定义的,可以看下这个数组的定义

// frameworks/base/packages/SystemUI/res/values/config.xml

com.android.systemui.Dependency$DependencyCreator

com.android.systemui.util.NotificationChannels

com.android.systemui.statusbar.CommandQueue$CommandQueueStart

com.android.systemui.keyguard.KeyguardViewMediator

com.android.systemui.recents.Recents

com.android.systemui.volume.VolumeUI

com.android.systemui.stackdivider.Divider

com.android.systemui.SystemBars

com.android.systemui.usb.StorageNotification

com.android.systemui.power.PowerUI

com.android.systemui.media.RingtonePlayer

com.android.systemui.keyboard.KeyboardUI

com.android.systemui.pip.PipUI

com.android.systemui.shortcut.ShortcutKeyDispatcher

@string/config_systemUIVendorServiceComponent

com.android.systemui.util.leak.GarbageMonitor$Service

com.android.systemui.LatencyTester

com.android.systemui.globalactions.GlobalActionsComponent

com.android.systemui.ScreenDecorations

com.android.systemui.biometrics.BiometricDialogImpl

com.android.systemui.SliceBroadcastRelayHandler

com.android.systemui.SizeCompatModeActivityController

com.android.systemui.statusbar.notification.InstantAppNotifier

com.android.systemui.theme.ThemeOverlayController

复制代码

对这些 SystemUI服务 做一点介绍

com.android.systemui.Dependency 是为了创建全局可用的依赖关系。

com.android.systemui.SystemBars 创建整个SystemUI视图的入口类。

com.android.systemui.statusbar.CommandQueue 是一个 Binder 类,它会被StatusBar注册到 StatusBarManagerService 中,用于接收StatusBarManagerService服务端的消息。

现在接着上面,来看下如何启动这些 SystemUI服务

private void startServicesIfNeeded(String[] services) {

if (mServicesStarted) {

return;

}

mServices = new SystemUI[services.length];

if (!mBootCompleted) {

// check to see if maybe it was already completed long before we began

// see ActivityManagerService.finishBooting()

// sys.boot_completed 属性可以判断系统是否已经启动完毕

if ("1".equals(SystemProperties.get("sys.boot_completed"))) {

mBootCompleted = true;

}

}

final int N = services.length;

for (int i = 0; i < N; i++) {

String clsName = services[i];

Class cls;

try {

// 1. 通过反射创建实例

cls = Class.forName(clsName);

Object o = cls.newInstance();

if (o instanceof SystemUI.Injector) {

o = ((SystemUI.Injector) o).apply(this);

}

// 强转为SystemUI保存

mServices[i] = (SystemUI) o;

} catch(Exception ex){

throw new RuntimeException(ex);

}

mServices[i].mContext = this;

// 注意这里把mComponents也传进去了,用于全局保存变量,Class> -> Object

mServices[i].mComponents = mComponents;

// 2. 调用start()启动

mServices[i].start();

// 3. 系统启动完毕,还用启动相应的onBootCompleted()

if (mBootCompleted) {

mServices[i].onBootCompleted();

}

}

mServicesStarted = true;

}

复制代码

首先根据 SystemUI服务的类名,通过反制加载类并且创建类的对象,然后调用对象的 start() 方法和 onBootCompleted() 方法。

创建StatusBar

现在把目光集中到如何创建 StatusBar 上。前面说过,SystemBars 这个 SystemUI服务是整个System视图创建的入口类,它被启动时会调用 start() 方法

// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemBars.java

public void start() {

// 也就是调用 StatusBar#start()

createStatusBarFromConfig();

}

复制代码

createStatusBarFromConfig()很简单,就是调用了StatusBar类的start()方法。

StatusBar#start() 代码很庞大,本文主要分析状态栏的创建,至于状态栏上图标的添加留到下一篇文章进行分析。

// packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

public void start() {

// 创建整个SystemUI视图并添加到WindowManager中

createAndAddWindows(result);

}

public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {

// 创建整个SystemUI视图

makeStatusBarView(result);

// 把视图添加到Window中

mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);

mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());

}

复制代码

makeStatusBarView()负责创建整个SystemUI视图,其中包括状态栏。下面的代码主要提取了创建视图的代码,分几步进行分析

// packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {

// ...

// 1. 实例化整个SystemUI视图,包括状态栏,通知面版, 锁屏

mStatusBarWindow = (StatusBarWindowView) mInjectionInflater.injectable(

LayoutInflater.from(context)).inflate(R.layout.super_status_bar, null);

}

复制代码

首先创建整个SystemUI视图,它的布局是 super_status_bar.xml,可以大致来看下布局

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:sysui="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:fitsSystemWindows="true">

android:id="@+id/status_bar_container"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

android:layout_width="match_parent"

android:layout_height="match_parent"

android:visibility="invisible" />

android:id="@+id/lock_icon_container"

android:orientation="vertical"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="@dimen/status_bar_height"

android:layout_gravity="top|center_horizontal">

android:id="@+id/lock_icon"

android:layout_width="@dimen/keyguard_lock_width"

android:layout_height="@dimen/keyguard_lock_height"

android:layout_gravity="center_horizontal"

android:layout_marginTop="@dimen/keyguard_lock_padding"

android:contentDescription="@string/accessibility_unlock_button"

android:src="@*android:drawable/ic_lock"

android:scaleType="center" />

android:id="@+id/keyguard_message_area"

style="@style/Keyguard.TextView"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="@dimen/keyguard_lock_padding"

android:gravity="center"

android:singleLine="true"

android:ellipsize="marquee"

android:focusable="true" />

复制代码

根视图StatusBarWindowView是一个FrameLayout,那么状态栏显示在最下面,然后通知面版会覆盖状态栏,最后还有一个底部视图在最上面。

可以注意到状态栏的窗口ID为status_bar_container,一会就会向这个容器中添加状态栏视图。现在接着上面的makeStatusBarView()继续分析

// packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {

// ...

// 1. 实例化整个SystemUI视图,包括状态栏,通知面版, 锁屏

mStatusBarWindow = (StatusBarWindowView) mInjectionInflater.injectable(

LayoutInflater.from(context)).inflate(R.layout.super_status_bar, null);

// 2.创建状态栏视图

FragmentHostManager.get(mStatusBarWindow)

.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {

CollapsedStatusBarFragment statusBarFragment =

(CollapsedStatusBarFragment) fragment;

// 用通知图标控制器,初始化了通知图标区域和中心图标区域,并且显示出来

statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);

}).getFragmentManager()

.beginTransaction()

// CollapsedStatusBarFragment实现了状态栏的添加

.replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),

CollapsedStatusBarFragment.TAG)

.commit();

}

复制代码

可以看到CollapsedStatusBarFragment代表的就是状态栏视图,这个视图被添加到ID为status_bar_container的容器中。接下来只要分析CollapsedStatusBarFragment的生命周期,即可知道状态栏的创建过程,首先看的就是CollapsedStatusBarFragment#onCreateView()方法,这里就是创建视图的地方

// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,

Bundle savedInstanceState) {

// status bar视图

return inflater.inflate(R.layout.status_bar, container, false);

}

复制代码

status_bar.xml 就是状态栏视图布局,接下来再简单看下布局情况

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"

android:layout_width="match_parent"

android:layout_height="@dimen/status_bar_height"

android:id="@+id/status_bar"

android:background="@drawable/system_bar_background"

android:orientation="vertical"

android:focusable="false"

android:descendantFocusability="afterDescendants"

android:accessibilityPaneTitle="@string/status_bar"

>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingStart="@dimen/status_bar_padding_start"

android:paddingEnd="@dimen/status_bar_padding_end"

android:paddingTop="@dimen/status_bar_padding_top"

android:orientation="horizontal"

>

android:layout_height="match_parent"

android:layout_width="0dp"

android:layout_weight="1">

android:id="@+id/status_bar_left_side"

android:layout_height="match_parent"

android:layout_width="match_parent"

android:clipChildren="false"

>

android:id="@+id/operator_name"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout="@layout/operator_name" />

android:id="@+id/clock"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:textAppearance="@style/TextAppearance.StatusBar.Clock"

android:singleLine="true"

android:paddingStart="@dimen/status_bar_left_clock_starting_padding"

android:paddingEnd="@dimen/status_bar_left_clock_end_padding"

android:gravity="center_vertical|start"

/>

android:id="@+id/notification_icon_area"

android:layout_width="0dp"

android:layout_height="match_parent"

android:layout_weight="1"

android:orientation="horizontal"

android:clipChildren="false"/>

android:id="@+id/centered_icon_area"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:orientation="horizontal"

android:clipChildren="false"

android:gravity="center_horizontal|center_vertical"/>

android:layout_width="0dp"

android:layout_height="match_parent"

android:layout_weight="1"

android:orientation="horizontal"

android:gravity="center_vertical|end"

>

复制代码

从这个布局可以分析出状态栏从左到右到底显示了什么。

最左边的一块区域,依次显示运营商名字,时间,通知图标。

中间一块区域,这个我暂时还没发现显示什么。

然后是最右边一块区域,显示的是状态图标(例如bt, wifi),以及电池图标。

这样一来,我们就对整个状态栏上的布局有个了解,接下来分析下状态上的状态图标(例如bt, wifi)是如何显示上去的,这就是后面一篇文章分析的主要内容。

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[SystemUI之StatusBar创建]http://www.zyiz.net/tech/detail-129805.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值