›一、SystemUI 概述
›二、模块基本布局
›三、模块内部框架
›四、模块流程
五、重要文件的介绍
一、SystemUI 概述
1.Statusbar 的功能作用
1.1 状态栏的通知功能(包括时间,通知,系统状态等)
1.2 状态栏的日期显示
2.Statusbar 的使用方法
2.1 notification 的使用
2.2 系统图标的增加删除
* notification 的使用
Notification n = new Notification(); //实例化Notification
n.icon = R.drawable.icon; //设置状态栏显示图标
n.tickerText = "Test Notifaction"; //设置显示提示信息
n.when = System.currentTimeMillis(); //显示时间
n.flags = Notification.FLAG_NO_CLEAR;
n.flags = Notification.FLAG_ONGOING_EVENT;
static final int ID = 1;
NotificationManager nm =(NotificationManager)this.getSystemService(NOTIFICATION_SERVICE);
Intent intent = new Intent(Main.this, Main.class);
PendingIntent pi = PendingIntent.getActivity(Main.this,0, intent, 0);
n.setLatestEventInfo(Main.this, "My Title","My Content", pi);
nm.notify(ID, n); //发出通知
nm.cancel(ID); //取消通知
如何区分“正在进行的”和“通知”,谁决定一个事件是“正在进行的”还是持续的“通知”?
通过设置Notification的flag属性可以设定notification是正在进行的还是持续的notification。FLAG_INSISTENT和FLAG_ONGOING_EVENT标志位可以让Notification成为持续的或正在进行的Notification。
正在进行的事件的通知:
notification.flags =notification.flags | Notification.FLAG_ONGOING_EVENT;
持续的Notification一直重复,直到用户取消:
notification.flags =notification.flags | Notification.FLAG_INSISTENT;
* 系统图标的增加删除
状态栏添加显示的系统图标的步骤
1.frameworks\base\core\res\res\drawalbe中添加系统图标的图片资源
2.frameworks\base\core\res\res\values\config.xml 中添加图片引用,这些 icon 在这个stringarray的位置就决定了其在status bar 上显示的位置了。
3.在 StatusbarPolicy.java 中初始化所增加的系统图标
4.在构造函数中 SetIcon
5.StatusBarPolicy 调用registerReceiver注册了感兴趣的 intent,当感兴趣的 intent 发生时,对图标进行更新
6..添加图标更新函数
删除时删除相关代码图片即可
二、模块基本布局
1.StatusBar的布局文件:frameworks/base/packages/SystemUI/res/layout/status_bar.xml
2.LinearLayoutandroid:id="@+id/icons"我们看到的状态栏,系统默认是左边放通知图标 notificationIcons,右边放状态图标 statusIcons :
--通知图标区域:IconMerger android:id="@+id/notificationIcons"
--状态图标区域:LinearLayout android:id="@+id/statusIcons"
--时间图标区域:com.android.systemui.statusbar.Clock
3.LinearLayoutandroid:id="@+id/ticker"显示。在正常情况下ticker 是不显示的,只有在 StatusBarService收到通知时它才显示
4.最后一个是DateView ,它是在点击statusbar时才显示的,默认是隐藏的
5.StatusBar的下拉布局文件:frameworks/base/packages/SystemUI/res/layout/
status_bar_expanded.xml
三、模块内部框架
Statusbar内部各种交互以及模块与其他应用的交互都是建立在StatusbarService之上的,其中包括Statusbar 视图的创建(包括 Statusbar 、 TrackingView和 StatusbarExpandedView),视图动画,系统图标(闹钟、 wifi 、SIM卡等)的加载和管理,其他应用通知信息的加载显示、更新、删除等,其他应用的远程接口控制(如当打电话时statusbar处于禁用状态的)对Android系统其他应用的通知信息(包括图标、 tracker 、notification的布局等)的处理。SIM 卡信息的控制等。
总之StatusbarService是 Statusbar 的灵魂所在,是 Statusbar的核心,所有关于Statusbar 的操作处理都是建立在 StatusbarService 这个基础之上的。
StatusbarService所在目录:\frameworks\base\packages\SystemUI\src\com\android\systemui\
statusbar\StatusBarService.java
四、 模块流程
1.启动流程
1.1 StatusbarService的启动流程
1.2 系统图标初始化流程
2.通知处理
3.图标更新
2.1 通过广播接收器的方式
2.2 通过远程代理方式
4.拖动刷新
5.远程接口
1.启动流程
1.1 StatusbarService的启动流程
1.当系统进程system_press启动之后,调用系统SystemServer.java,在SystemServer 中运行 ServerThread.run()方法时会注册 StatusBarManagerService:
statusBar = newStatusBarManagerService(context);
ServiceManager.addService(Context.STATUS_BAR_SERVICE,statusBar);
2.让后调用StatusBarManagerService的systemReady2() 方法,会在systemReady2() 方法中启动StatusbarService:
ComponentName cn =ComponentName.unflattenFromString(mContext.getString(com.android.internal.R.string.config_statusBarComponent));
Intent intent = new Intent();
intent.setComponent(cn);
mContext.startService(intent);
3.在SystemUI模块的SystemUiApp.java的onCreate方法中也会startService,这是当Statusbar意外退出而导致StatusbarService停止服务时会重新启动StatusbarService
1.2 系统图标初始化流程
在启动StatusBarService后,StatusbarService会调用一个makeStatusBarView的方法,在里面将创建StatusBarView,
在创建StatusbarView的过程中会加载系统图标。
在启动StatusbarService的过程中会创建StatusBarPolicy的对象,StatusBarPolicy.java主要负责状态栏显示策略的管理(如状态栏的图标什么时候显示,在什么位置显示等)。StatusBarPolicy的构造函数中初始化了很多系统图标(如电池信息图标,闹钟图标,声音图标,信号栏图标等)。默认时有很多图标是不显示的,需要显示时再进行更新。
以电池电量显示为例,大概关键步骤如下:
1.通过BroadcastReceiver机制,StatusBarPolicy中注册的 mIntentReceiver收到BatteryService广播的 ACTION_BATTERY_CHANGED事件触发;
2.调用updateBattery(intent)开始更新电池状态栏;
3.从intent中解析需要的字段,调用StatusBarManager的setIcon(); (StatusBarManager是客户端使用的状态栏管理类)
4.通过IBinder机制跨进程调用StatusBarManagerService的setIcon(); (StatusBarManagerService派生于IStatusBarService.Stub,是状态栏管理的服务端,是具体实现,StatusBarManagerService有一个mIcons成员,这个list成员在StatusBarManagerService创建时加载。StatusBarManagerService的setIcon()过程中,会又"battery"字段获得在mIcons中的索引,再由包名、图片id和等级创建StatusBarIcon实例,并将这个实例更新StatusBarIconList中所获得索引对应项)
5.调用CommandQueue的setIcon();
(CommandQueue派生于IStatusBar.Stub,有一个内部接口Callbacks,这个接口的实现就是StatusBarService。CommandQueue、StatusBarService和StatusBarManager属于同一个进程,而StatusBarManagerService是一个系统级服务,它们之间必然需要通过IBinder进程间通信。CommandQueue用于处理状态栏、通知相关的请求,内部维护了一个事件队列,setIcon()会创建一个OP_SET_ICON的massege,发送给Handler处理(CommandQueue内部也有一个StatusBarIconList实例,这个实例是由StatusBarService创建。在处理OP_SET_ICON的massege前,会先通过getViewIndex获得图标View的位置索引viewIndex,(因为有些图标有可能为空)再更新StatusBarIconList,最后调用Callbacks,也就是StatusBarService的addIcon()或者updateIcon());
6.以addIcon()为例,StatusBarService的addIcon()会创建一个新的StatusBarIconView,将第步中所创建的StatusBarIcon实例设置进去,然后把这个view添加到LinearLayout的viewIndex位置。
这样一个电池相关图标就在状态栏上添加或者更新了。
2.通知处理
在应用Activity中实现通知栏图标变化的程序中,是用NotificationManager对象mNotificationManager来发送通知。
1.通知为Notification mNotification 对象,填充mNotification 的图标和消息内容以及一个when;
2.然后构造了一个Intent对象intent,包含了本Activity对象的引用,以及本Activity的类名,一个PendingIntentpi对象,包含上述Intent对象以及本Activity对象的引用,是用于消息列表中显示本Activity项。
3.点击时重新激活Activity,然后调用nm.setLatestEventInfo设置状态栏下拉列表项内容;
4.最后调用nm.notify(1,n)方法来发送通知。
接着改变状态栏的工作就由NotificationManager和StatusBarManagerService交互了。
3.图标更新
2.1 通过广播接收器的方式
StatusBarPolicy调用registerReceiver注册了感兴趣的 intent, 当感兴趣的intent 发生时,对图标进行更新。例如,设置一个闹钟后,闹钟模块会发出一个叫做Intent.ACTION_ALARM_CHANGED 的广播,然后 StatusBarPolicy接收到此广播,继而更新状态栏上的闹钟图标。
代码示例:
// Alarm clockStatusBarPolicy构造方法中初始化闹钟图标
mService.setIcon("alarm_clock",R.drawable.stat_notify_alarm,0);
mService.setIconVisibility("alarm_clock",false);
// StatusBarPolicy构造方法中注册闹钟改变广播
filter.addAction(Intent.ACTION_ALARM_CHANGED);
//改变闹钟图标
private final void updateAlarm(Intentintent) {
boolean alarmSet =intent.getBooleanExtra(“alarmSet”, false);
mService.setIconVisibility(“alarm_clock”,alarmSet);
}
2.2 通过远程代理方式
StatusBarManager有一个更新图标的方法: publicvoid updateIcon(IBinder key, String slot, int iconId, int iconLevel),不过StatusBarManager 并未把方法公开在 sdk 中,但是应该有方法可以访问的。
public voidupdateIcon(IBinder key, String slot, int iconId, int iconLevel) {
try {
mService.updateIcon(key, slot,mContext.getPackageName(), iconId, iconLevel);
} catch (RemoteException ex) {
throw newRuntimeException(ex);
}
}
mService 是StatusBarManager的一个成员变量,StatusBarManager 被构建的时候被赋值,他是 IStatusBar 的一个代理对象
StatusBarManager(Contextcontext) {
mContext = context;
mService =IStatusBar.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
4.拖动刷新
从点击StatusBar会出现新的View,它的流程如下:
StatusBarView 就是StatusBar 所代表的View,那么查看它的代码,看它处理点击的方法。
它属性变量保存了StatusBarService的引用mService,它的点击处理函数onTouchEvent()和onInterceptTouchEvent()都会调用到StatusBarService类中的interceptTouchEvent()方法。
当我们点击StatusBar 时,会先走到onInterceptTouchEvent()这个函数,而且这个函数只会在第一次走到,然后会走到onTouchEvent() 方法,这个方法每收到一个TouchEvent() 就会走到,因此会走到多次。
函数onInterceptTouchEvent() 的处理:
1 、调用到StatusBarService中的interceptTouchEvent() ,在这里又会走到event.getAction() == MotionEvent.ACTION_DOWN分支,在分支中,由于mExpanded == false 且y < hitSize会继续调用prepareTracking(y) 。
2 、函数prepareTracking()处理:这里由于mExpanded == false所以会向H 中发送MSG_ANIMATE_REVEAL 消息,进入StatusBarService自己的消息循环。执行doRevealAnimation() 函数。
3 、函数doRevealAnimation()处理:这个实现的功能很简单,就是在TrackingView( 就是点击时StatusBar 下出现的View)还没有完全显示出来的时候,通过动画的方式,一点一点的将TrackingView 显示出来。
当我们手指离开时调用顺序如下:
1 、StatusBarView :onTouchEvent(),此时Action != MotionEvent.ACTION_DOWN 走到 StatusBarService :interceptTouchEvent();
2 、interceptTouchEvent() 中会走到分支elseif (mTracking) ;
3 、由于ACTION_UP所以会调用performFling(),在这里会向Handler 发送 MSG_ANIMATE消息,然后进入函数doAnimation() 。
4 、在doAnimation() 由于mAnimY <mStatusBarView.getHeight() 分支成立,会继续调用updateExpandedViewPos(0)和performCollapse();
5 、在performCollapse()中,通过mTrackingView.setVisibility(View.GONE)实现了让mTrackingView的隐藏,其实这个函数还实现了其他的View 的隐藏,比如我们点击后进行拖动所出现的其他View 。
5.远程接口
StatusBarManagerService通过使用 IStatusBar 的 aidl调用CommandQueue 在 CommandQueue 中定义Callbacks
StatusBarService实现了 CommandQueue 中 Callbacks的回调
public interface Callbacks {
public void addIcon(String slot, int index, intviewIndex, StatusBarIcon icon);
public void updateIcon(String slot, int index, intviewIndex,
StatusBarIcon old, StatusBarIcon icon);
public void removeIcon(String slot, int index, intviewIndex);
public void addNotification(IBinder key,StatusBarNotification notification);
public void updateNotification(IBinder key,StatusBarNotification notification);
public void removeNotification(IBinder key);
public void disable(int state);
public void animateExpand();
public void animateExpandToggles(booleanneedForceStatusBar);
public void animateCollapse();
public void showSIMIndicator(String businessType);
public void hideSIMIndicator();
}
五、重要文件的介绍
1.StatusBarManagerService是服务端StatusBarService的管理者
2.StatusBarservice是Statusbar 的核心
3.StatusBarPolicy负责状态栏显示的策略管理
4.CommandQueue是StatusBarservice 和
StatusBarManagerService 交互的枢纽
StatusBarManagerService是服务端StatusBarService的管理者
frameworks\base\services\java\com\android\server\
StatusBarManagerService.java
StatusBarManagerService是StatusBarService的管理者,是StatusBarService与外界通信的桥梁,在 StatusBarManagerService.java中,有 addNotification, removeNotification,updateNotification等方法用于管理传递给他的通知对象。这个类是一些管理方法,实际执行相关动作的是在IStatusBar.java里面,这个是framework/base/core/java/com /android/internal/statusbar/IStatusBar.aidl自动生成的用于IPC 的类。
StatusBarservice是Statusbar 的核心
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\StatusBarService.java
StatusBarService这个服务是Statusbar模块的中心点,所有关于图标的加载、更新、删除等处理,与应用的交互,对通知信息的处理,动画的完成等都是建立在StatusBarService这个基础之上的。
StatusBarPolicy负责状态栏显示的策略管理
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\StatusBarPolicy.java
Android中状态栏上有很多图标,这些图标什么时候显示什么时候不显示,这些都是StatusBarPolicy来管理的。StatusBarPolicy的构造函数里初始化了好几个图标,如闹钟icon,信号栏icon等。默认时有很多图标是不显示的,需要显示时再进行更新。StatusBarPolicy调用registerReceiver注册了感兴趣的intent,当感兴趣的intent发生时,对图标进行更新。StatusBarPolicy只是一个策略管理,实际的功能是StatusBarService来实现的。StatusBarService初始化时初始化了一个用于显示statusbar的StatusBarView。StatusBarView里面定义了icon名字,的显示顺序,对应的png图等,在StatusBarService调用makeStatusBarView方法时实现statusbar的初始化。
CommandQueue是StatusBarservice 和
StatusBarManagerService交互的枢纽
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\
CommandQueue.java
IStatusBar.java里面对应的方法是用CommandQueue 的接口callback 的形式调用的,callback的实现在对应的服务提供类也就是StatusBarService.java中提供的。最终执行状态栏更新通知等事件都是在实现的CommandQueue.Callbacks里面执行。