Android FrameWork——StatusBar
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相关推荐
- android 状态栏(StatusBar)
一.SystemUI 概述 自 android2.2 开始 , 原本存在与 framework-res.apk 中的状态栏和下拉通知栏界面控制被分割出一个单独的 apk文件 , 命名为 SystemU ...
- android framework学习回忆
好久没来这里了,这2天开发板不够用,所以暂时闲下来学习东西.顺便回忆一下学到的会用的东西. 刚踏入Android Framework大门,是从电源管理开始的.记得当时拼命的google搜索相关资料,因 ...
- Android Framework 简介
Android Framework 简介 简介 之前的研究太偏向应用层功能实现了,很多原理不了解没有详记,结果被很多公司技术人员鄙视了,为了减少自己的短板,重新复习了一遍C++.java.Androi ...
- android framework架构文件详情
摘要:转自:http://www.tuicool.com/articles/777r6rB,感谢博主分享.简介之前的研究太偏向应用层功能实现了,很多原理不了解没有详记,为了全面了解,重新梳理应用框架层 ...
- Android Framework 学习
Android Framework 1. 之前的研究太偏向应用层功能实现了,很多原理不了解没有深究,现在研究framework面存一些资料待有空查看. 2.Android系统的层次如下: 3.项目目录 ...
- Android 系统的分区和文件系统(5)- Android Framework层上的工具和命令
声明 Android系统中包含很多命令行工具,包括一些Linux继承来的工具,也有不少Android系统特有工具/命令,此篇介绍一些比较重要的工具/命令. 这些命令来自Android框架层(源码位置: ...
- Android Framework学习总结
经过一段时间的学习,对于Android Framework大部分有一定的了解,现在将之前的学习进行总结并分类. 1.Android系统启动相关 Android系统SystemServer启动(上) A ...
- 如何调试Android Framework?
Linus有一句名言广为人知:Read the fucking source code. 但其实,要深入理解某个软件.框架或者系统的工作原理,仅仅「看」代码是远远不够的.就拿Android Frame ...
- Android FrameWork学习(二)Android系统源码调试
点击打开链接 通过上一篇 Android FrameWork学习(一)Android 7.0系统源码下载\编译 我们了解了如何进行系统源码的下载和编译工作. 为了更进一步地学习跟研究 Android ...
最新文章
- nyoj-205--求余数--(大整数取模)
- wds+mdt 分布式自动部署 操作系统
- windows服务器的DDOS防御,
- Makefile (二)
- Kafka : kafka无法消费的情况
- C语言新手写扫雷攻略1
- LINUX SHELL 中if的使用
- retrofit2 上传图片
- [2018.07.17 T2] Palindromes
- 科研绘图图表类型种类繁多,本文告诉你如何选择!
- 艾司博讯:拼多多推广投放时间设置步骤
- win32 WaitCommEvent
- Hz ms 频率 时间
- jxl创建excel加水印
- 《阿里云的这群疯子》
- 基于Python pdfplumber实现PDF转WORD
- Pygame实战之外星人入侵NO.9——消灭外星人
- 呕心沥血整理出的史上最简单的IntelliJ IDEA教程,快来看哟!
- RabbitMq应用
- 一秒钟看懂SaaS、CRM、OA、ERP、HR、进销存
热门文章
- 【转】马拉松式学习与技术人员的成长性
- django 创建项目
- 弄了一个数学论坛,感觉不错,欢迎加入讨论
- 创建生成级联上级字符的函数
- Android UI系列-----ScrollView和HorizontalScrollView
- Android程序的“现场保护”
- post 下载文件 (excel)
- Java 集合系列:Vector源码深入解析
- GI OPatch升级 The opatch Component check failed. This patch is not applicable for...
- 算法导论 - 函数的增长。