Android系统顶上的状态栏是属于FrameWork的东东,由于项目上需要对状态栏进行一些修改调整,我对其作了一个初步研究,写出来大家共享一下,其实这些早已写了,只是想等研究StatusBar中ExtendsView后再整理一个blog,不过现在已经没有时间了,目前深入研究Android Binder机制,废话不多少,开始进入statusbar的探索

1.先从StatusBar的布局文件入手,文件位置位置:frameworks/base/core/res/res/layout/status_bar.xml

2.我对status_bar.xml布局文件进行分析,画出结构图,以便对StatusBar有一个整体的了解:

3.com.android.server.status.StatusBarView--statusbar的最顶层view,直观上我们是看不到它的

4.LinearLayout android:id="@+id/icons" 我们看到的状态栏,系统默认是左边放通知图标notificationIcons,右边放状态图标statusIcons

--1.通知图标区域:IconMerger android:id="@+id/notificationIcons"

--2.状态图标区域:LinearLayout android:id="@+id/statusIcons"

我对status_bar.xml做了修改,notificationIcons的background="#ff0000",statusIcons的background="#0000ff",下面就是现实效果

(图1)

5.那么LinearLayout android:id="@+id/ticker"显示在哪里呢,在正常情况下ticker是不显示的,只有在StatusBarService收到通知时它才显示,比如SD卡拔出时,我也截了一张图,在前面我已经修改了status_bar.xml并修改它android:background="#0000ff"大家可以看一下效果:

(图2)

6.最后一个是DateView,它是在点击statusbar时才显示的,默认是隐藏的

7.StatusBar的ui框架就这些,是不是很简单,接下来,我们肯定还有些问题:StatusBarView是如何被创建的呢?上面那个状态时钟图标如何被加载的呢?通知图标如何被加载的?下面我将继续讲解。
8.StatusBarView创建
StatusBarView是如何被创建的呢,这得从system_process说起,在system_process构建时,会运行ServerThread.run方法加载各种系统服务,其中有一个服务就是StatusBarService:

看上面调用堆栈图,StatusBarService会调用一个makeStatusBarView的方法,在里面它创建了StatusBarView

9.状态图标的加载

我们前面讲过,StatusBarView的子View LinearLayout android:id="@+id/icons"它包含一个通知图标栏,见(图1)中的红色部分,一个状态图标栏:见(图1)中的蓝色部分,但是这个并没有包含上面的图标,如时间图标(注意右边显示的时间也是一个Text类型的图标,刚开始我也不理解,在status_bar.xml中找了半天没有找到它),那么这些图标又是怎么样被加载上去的呢?还是看ServerThread.run,在ServerThread.run中调用了

com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);//装载状态栏的图标

进入这个函数看它如何实现的,installIcons静态方法直接调用了构造函数StatusBarPolicy去实现这个操作了:

private StatusBarPolicy(Context context, StatusBarService service) {
// 构建设置图标...
// 注册广播接收器,接收各种图标状态变化消息,以此更新状态栏图标
}

代码太多,我就以时间图标为例,进行代码说明,代码在StatusBarPolicy构造函数中:

//构建时间图标的IconData对象,类型为TEXT
IconData mClockData = IconData.makeText("clock", "");
--IconData.makeText(String slot, CharSequence text) {
IconData data = new IconData();
data.type = TEXT;
data.slot = slot;
data.text = text;
return data;
}
//调用addIcon方法添加一个状态图标到状态栏
IBinder mClockIcon = service.addIcon(mClockData, null);

-->IBinder service.addIcon(IconData data, NotificationData n) {
int slot;
// assert early-on if they using a slot that doesn't exist.
if (data != null && n == null) {
slot = getRightIconIndex(data.slot);
if (slot < 0) {
throw new SecurityException("invalid status bar icon slot: "
+ (data.slot != null ? "'" + data.slot + "'" : "null"));
}
} else {
slot = -1;
}
IBinder key = new Binder();
addPendingOp(OP_ADD_ICON, key, data, n, -1);
return key;
}

//获取系统时间,并更新时间图标
updateClock();
-->updateClock() {
mCalendar.setTimeInMillis(System.currentTimeMillis());
mClockData.text = getSmallTime();
mService.updateIcon(mClockIcon, mClockData, null);
}

注意代码中我标注为绿色的一个StatusBarService.addPendingOp方法,它会创建一个PendingOp对象op,然后
设置op.code=OP_ADD_ICON,然后交给StatusBarService.mHandler去处理,我们根据OP_ADD_ICON搜索mHandler.handleMessage方法:

//前面函数逻辑我省略了
if (doOp) {
switch (op.code) {
case OP_ADD_ICON:
case OP_UPDATE_ICON:
performAddUpdateIcon(op.key, op.iconData, op.notificationData);
break;

根据op.code==OP_ADD_ICON,线程会调用performAddUpdateIcon方法:
void performAddUpdateIcon(IBinder key, IconData data, NotificationData n)
由于这个函数是更新状态图标和通知图标的统一入口函数,它提供了两个入口参数,IconData data, NotificationData n,当我们添加的是时间图标的时候,n==null:

void performAddUpdateIcon(IBinder key, IconData data, NotificationData n){
// n != null means to add or update notification
if (n != null) {
...
}
// to add or update icon ,this also incluce Notification icons
synchronized (mIconMap) {//mIconMap中缓存了所有显示的和不显示的通知图标和状态图标
StatusBarIcon icon = mIconMap.get(key);//first to get icon from mIconMap
if (icon == null) {//if get icon from mIconMap is null,we should to add it
// add icon
LinearLayout v = n == null ? mStatusIcons : mNotificationIcons;
//创建一个状态图标
icon = new StatusBarIcon(mContext, data, v);
mIconMap.put(key, icon);
mIconList.add(icon);//mIconList应该是显示的状态图标

if (n == null) {//n==null,说明在添加状态图标
int slotIndex = getRightIconIndex(data.slot);
StatusBarIcon[] rightIcons = mRightIcons;
if (rightIcons[slotIndex] == null) {
int pos = 0;
for (int i=mRightIcons.length-1; i>slotIndex; i--) {
StatusBarIcon ic = rightIcons[i];
if (ic != null) {
pos++;
}
}
rightIcons[slotIndex] = icon;
mStatusIcons.addView(icon.view, pos);//mStatusIcons==LinearLayout android:id="@+id/statusIcons"
} else {
Slog.e(TAG, "duplicate icon in slot " + slotIndex + "/" + data.slot);
mIconMap.remove(key);
mIconList.remove(icon);
return ;
}
} else {// is notification add notification icon
...
}
} else {//icon!=null说明是图标更新
if (n == null) {//状态图标更新
// right hand side icons -- these don't reorder
icon.update(mContext, data);
} else {//is notification to update notification icon
...
}
}
}

结合我的红色部分的注释,认真看完该函数的代码,相信你已经知道状态图标添加的详细过程。

10.通知图标的加载

我以sd卡插入状态栏通知为例进行说明。当sd 插入,代码会执行怎样的逻辑,先看一下调用堆栈:

StatusBarService.addIcon(IconData, NotificationData) line: 423
NotificationManagerService.enqueueNotificationWithTag(String, String, int, Notification, int[]) line: 745
NotificationManager.notify(String, int, Notification) line: 110
NotificationManager.notify(int, Notification) line: 90
StorageNotification.setMediaStorageNotification(int, int, int, boolean, boolean, PendingIntent) line: 478

调用进入了StatusBarService.addIcon函数,跟前面添加状态图标调用的是同一个函数,只是参数IconData==null,而NotificationData!=null。接下来执行逻辑差不多,StatusBarService.addPendingOp方法,它会创建一个PendingOp对象op,然后
设置op.code=OP_ADD_ICON,然后交给StatusBarService.mHandler去处理,根据op.code==OP_ADD_ICON,线程会调用performAddUpdateIcon方法:

void performAddUpdateIcon(IBinder key, IconData data, NotificationData n)
throws StatusBarException {
//省略无关代码
if (n != null) {
//这里我省略了一段逻辑了,是跟ExpandedView相关,当我们点击statusbar往下拖动会展开一个ExpandedView,这个以后再说
//不深入展开了,当收到一个通知,这里判断通知view列表中是否存在这个通知view,若不存在添加,若存在,更新

// 添加要显示的通知到队列中,tickerview会依次显示出来,效果如(图2)
if (n.tickerText != null && mStatusBarView.getWindowToken() != null
&& (oldData == null
|| oldData.tickerText == null
|| !CharSequences.equals(oldData.tickerText, n.tickerText))) {
if (0 == (mDisabled &
(StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
mTicker.addEntry(n, StatusBarIcon.getIcon(mContext, data), n.tickerText);//添加一个通知到tickerview
}
}
}

// to add or update icon ,this also incluce Notification icons
synchronized (mIconMap) {
StatusBarIcon icon = mIconMap.get(key);//从缓存中查看是否已存在该图标
if (icon == null) {//if get icon from mIconMap is null,we should to add it
// add
LinearLayout v = n == null ? mStatusIcons : mNotificationIcons;

icon = new StatusBarIcon(mContext, data, v);
mIconMap.put(key, icon);
mIconList.add(icon);

if (n == null) {
//状态图标处理
} else {// is notification add notification icon
//添加左边通知图标,如sd卡,usb图标等,mNotificationIcons=IconMerger android:id="@+id/notificationIcons"
int iconIndex = mNotificationData.getIconIndex(n);
mNotificationIcons.addView(icon.view, iconIndex);
}
} else {
if (n == null) {
// right hand side icons -- these don't reorder
icon.update(mContext, data);
} else {//is notification to update notification icon
//更新通知图标
// remove old
ViewGroup parent = (ViewGroup)icon.view.getParent();
parent.removeView(icon.view);
// add new
icon.update(mContext, data);
int iconIndex = mNotificationData.getIconIndex(n);
mNotificationIcons.addView(icon.view, iconIndex);
}
}
}
}

11.状态图标更新
--1.通过广播接收器的方式

当StatusBarPolicy被构建的时候,会注册一个广播消息接收器mIntentReceiver:
IntentFilter filter = new IntentFilter();

// Register for Intent broadcasts for...
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
......
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
一旦接收到状态图标变化消息,就会通知StatusBarService去变更状态图标,还是以状态栏的时钟为例:
if (action.equals(Intent.ACTION_TIME_TICK)) {
updateClock();//此处接收时间变化消息
}
else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
updateClock();//此处接收时间变更消息

-->updateClock()
-->StatusBarService.updateIcon(IBinder key, IconData data, NotificationData n)
-->addPendingOp(OP_UPDATE_ICON, key, data, n, -1);
}

这个跟前面添加状态图标调用是一致的,只是addIcon中addPendingOp(OP_UPDATE_ICON, key, data, n, -1);操作是 OP_UPDATE_ICON,所以,同样,
方法会执行到performAddUpdateIcon,后面逻辑见前面讲述的状态图标更新。

--2.通过远程代理方式

StatusBarManager有一个更新图标的方法: public void updateIcon(IBinder key, String slot, int iconId, int iconLevel),不过StatusBarManager并未把方法公开在sdk中,但是应该有方法可以访问的,
像launcher就有访问framework中未公开在sdk中的方法,如何实现这里我不作讨论。
//StatusBarManager.updateIcon//
public void updateIcon(IBinder key, String slot, int iconId, int iconLevel) {
try {
mService.updateIcon(key, slot, mContext.getPackageName(), iconId, iconLevel);
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
mService是StatusBarManager的一个成员变量,StatusBarManager被构建的时候被赋值,他是IStatusBar的一个代理对象

StatusBarManager(Context context) {
mContext = context;

//
mService = IStatusBar.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}

就这么些内容,希望对准备修改StatusBar的同仁们有所帮助!

Android FrameWork——StatusBar相关推荐

  1. android 状态栏(StatusBar)

    一.SystemUI 概述 自 android2.2 开始 , 原本存在与 framework-res.apk 中的状态栏和下拉通知栏界面控制被分割出一个单独的 apk文件 , 命名为 SystemU ...

  2. android framework学习回忆

    好久没来这里了,这2天开发板不够用,所以暂时闲下来学习东西.顺便回忆一下学到的会用的东西. 刚踏入Android Framework大门,是从电源管理开始的.记得当时拼命的google搜索相关资料,因 ...

  3. Android Framework 简介

    Android Framework 简介 简介 之前的研究太偏向应用层功能实现了,很多原理不了解没有详记,结果被很多公司技术人员鄙视了,为了减少自己的短板,重新复习了一遍C++.java.Androi ...

  4. android framework架构文件详情

    摘要:转自:http://www.tuicool.com/articles/777r6rB,感谢博主分享.简介之前的研究太偏向应用层功能实现了,很多原理不了解没有详记,为了全面了解,重新梳理应用框架层 ...

  5. Android Framework 学习

    Android Framework 1. 之前的研究太偏向应用层功能实现了,很多原理不了解没有深究,现在研究framework面存一些资料待有空查看. 2.Android系统的层次如下: 3.项目目录 ...

  6. Android 系统的分区和文件系统(5)- Android Framework层上的工具和命令

    声明 Android系统中包含很多命令行工具,包括一些Linux继承来的工具,也有不少Android系统特有工具/命令,此篇介绍一些比较重要的工具/命令. 这些命令来自Android框架层(源码位置: ...

  7. Android Framework学习总结

    经过一段时间的学习,对于Android Framework大部分有一定的了解,现在将之前的学习进行总结并分类. 1.Android系统启动相关 Android系统SystemServer启动(上) A ...

  8. 如何调试Android Framework?

    Linus有一句名言广为人知:Read the fucking source code. 但其实,要深入理解某个软件.框架或者系统的工作原理,仅仅「看」代码是远远不够的.就拿Android Frame ...

  9. Android FrameWork学习(二)Android系统源码调试

    点击打开链接 通过上一篇 Android FrameWork学习(一)Android 7.0系统源码下载\编译 我们了解了如何进行系统源码的下载和编译工作. 为了更进一步地学习跟研究 Android ...

最新文章

  1. nyoj-205--求余数--(大整数取模)
  2. wds+mdt 分布式自动部署 操作系统
  3. windows服务器的DDOS防御,
  4. Makefile (二)
  5. Kafka : kafka无法消费的情况
  6. C语言新手写扫雷攻略1
  7. LINUX SHELL 中if的使用
  8. retrofit2 上传图片
  9. [2018.07.17 T2] Palindromes
  10. 科研绘图图表类型种类繁多,本文告诉你如何选择!
  11. 艾司博讯:拼多多推广投放时间设置步骤
  12. win32 WaitCommEvent
  13. Hz ms 频率 时间
  14. jxl创建excel加水印
  15. 《阿里云的这群疯子》
  16. 基于Python pdfplumber实现PDF转WORD
  17. Pygame实战之外星人入侵NO.9——消灭外星人
  18. 呕心沥血整理出的史上最简单的IntelliJ IDEA教程,快来看哟!
  19. RabbitMq应用
  20. 一秒钟看懂SaaS、CRM、OA、ERP、HR、进销存

热门文章

  1. 【转】马拉松式学习与技术人员的成长性
  2. django 创建项目
  3. 弄了一个数学论坛,感觉不错,欢迎加入讨论
  4. 创建生成级联上级字符的函数
  5. Android UI系列-----ScrollView和HorizontalScrollView
  6. Android程序的“现场保护”
  7. post 下载文件 (excel)
  8. Java 集合系列:Vector源码深入解析
  9. GI OPatch升级 The opatch Component check failed. This patch is not applicable for...
  10. 算法导论 - 函数的增长。