android 状态栏(StatusBar)



 

1、SystemUI 概述

         android2.2 开始 , 本来存在与 framework-res.apk 中的状态栏和下拉通知栏界面控制被分割出一个单独的 apk文件 , 命名为 SystemUI.apk, 保存在 System/app 文件夹中。在 SystemUI.apk  , 是存在着状态栏的图标 ,XML 和控制文件等 , 这样的分割 , 使咱们能够更方便地去修改。 php

SystemUI 模块中主要包含了 USB  Statusbar 两个子模块,本文将以 Statusbar 为主导来向你们阐述 SystemUI Statusbar 的功能做用,使用方法,模块框架,以及模块内部的重要流程。 html

1.1 Statusbar 的功能做用

状态栏主要用来显示一些系统图标,应用的通知图标和系统时间。 Statusbar 模块就是控制和管理着这些图标,以及通知信息的显示和一些系统开关的。 java

Ⅰ、状态栏的通知功能(包括时间,通知,系统状态等) android

状态栏与 Toast 均可以起到通知、提醒的做用。但它们的实现原理和表现形式却彻底不同。 Toast 其实至关于一个 Widget 组件,有些相似于没有按钮的对话框。而 Statusbar 可与系统其它应用进行交互来显示在屏幕上方状态栏中的信息,而且 Statusbar 还可经过图标的显示变化来反应一些系统状态的变换,如电池电量, wifi ,系统音量,闹钟等。状态栏 是一种让你的应用程序或系统信息变化在不使用 Activity 的状况下给用户的提醒和通知。 windows

Ⅱ、状态栏的日期显示 并发

      状态栏也会显示系统时间,当前日期也会在状态栏显示,只是在默认状况下日期是隐藏的,只有在点击状态栏时才会显示。 app

 

1.2 Statusbar 的使用方法

1.2.1 notification 的使用

  Notification 主要做用和使用步骤: 框架

Notification 是看不见的程序组件( Broadcast Receiver , Service 和不活跃的 Activity )警示用户有须要注意的事件发生的最好途径 ide

下面主要介绍使用方法步骤: 函数

获取 NotificationManager 实例

获取 Notification 示例,设置属性,并发送通知

Java代码   收藏代码
  1. public class Main extends Activity {  
  2.     private Button sendBtn , cancelBtn;  
  3.     private Notification n;  
  4.     private NotificationManager nm;  
  5.     //Notification的标示ID  
  6.     private static final int ID = 1;  
  7.      
  8.     @Override  
  9.     public void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.main);  
  12.          
  13.         //实例化按钮  
  14.         sendBtn = (Button)this.findViewById(R.id.sendBtn);  
  15.         cancelBtn = (Button)this.findViewById(R.id.cancelBtn);  
  16.          
  17.         //获取NotificationManager实例  
  18.         String service = NOTIFICATION_SERVICE;  
  19.         nm = (NotificationManager)this.getSystemService(service);  
  20.          
  21.         //实例化Notification  
  22.         n = new Notification();  
  23.         //设置显示图标,该图标会在状态栏显示  
  24.         int icon = R.drawable.icon;  
  25.         //设置显示提示信息,该信息也会在状态栏显示  
  26.         String tickerText = "Test Notifaction";  
  27.         //显示时间  
  28.         long when = System.currentTimeMillis();  
  29.          
  30.         n.icon = icon;  
  31.         n.tickerText = tickerText;  
  32.         n.when = when;  
  33.         n.flags = Notification.FLAG_NO_CLEAR;  
  34.         n.flags = Notification.FLAG_ONGOING_EVENT;  
  35.          
  36.         //为按钮添加监听器  
  37.         sendBtn.setOnClickListener(sendClickListener);  
  38.         cancelBtn.setOnClickListener(cancelClickListener);  
  39.     }  
  40.      
  41.     private OnClickListener sendClickListener = new OnClickListener() {  
  42.    
  43.   @Override  
  44.   public void onClick(View v) {  
  45.    //实例化Intent  
  46.    Intent intent = new Intent(Main.this, Main.class);  
  47.    //获取PendingIntent  
  48.    PendingIntent pi = PendingIntent.getActivity(Main.this0, intent, 0);  
  49.    //设置事件信息  
  50.    n.setLatestEventInfo(Main.this"My Title""My Content", pi);  
  51.    //发出通知  
  52.    nm.notify(ID, n);  
  53.     
  54.        }  
  55. };  
  56. private OnClickListener cancelClickListener = new OnClickListener(){  
  57.    
  58.   @Override  
  59.   public void onClick(View v) {  
  60.    nm.cancel(ID);  
  61.   }  
  62. };  
  63. }     

、步骤详解

获取 NotificationManager 实例

这个类主要负责将 Notification 在状态栏中显示出来和取消。主要包括 个函数:

void cancel(int id) , void cancel(String tag, int id) , void cancelAll() , void notify(int id, Notification notification) , notify(String tag, int id, Notification notification)

看看这五个函数就知道这个类的做用了。可是在初始化对象的时候要注意:

NotificationManager nm;

String service = NOTIFICATION_SERVICE;

nm = (NotificationManager)this.getSystemService(service);

获取 Notification 示例,设置属性,并发送通知

这个类主要是设置 Notification 的相关属性,初始化。

Notification n = new Notification();

Notification 里面有不少属性下面选择几个经常使用的介绍一下(表 1.1 

icon

这个是设置通知的图标。像天气预报图标。

sound

这个是设置来通知时的提示音。

tickerText

设置提示的文字。

vibrate

来通知时振动。

when

设置来通知时的时间。

contentIntent

Notification  Intent ,即点击后转向的 Activity

flag

FLAG_NO_CLEAR

设置为这个属性那么通知栏的那个清楚按钮就不会出现

FLAG_ONGOING_EVENT

设置为这个属性那么通知就会像 QQ 图标同样一直在状态栏显示

DEFAULT_ALL

将全部属性设置为默认

DEFAULT_SOUND 

将提示声音设置为默认

DEFAULT_VIBRATE

将震动设置为默认

 1.1

填充 Notification 的各个属性:

//Notification 的 Intent ,即点击后转向的 Activity

Intent notificationIntent1 = new Intent(this, this.getClass());

notificationIntent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent contentIntent1 = PendingIntent.getActivity(this, 0, notificationIntent1, 0);


n.contentIntent=contentIntent1;

n.icon = R.drawable.notification_icon;

n.tickerText = "hello";

notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3");

notification.vibrate = vibrate;

发送通知:

private static final int ID_NOTIFICATION = 1;

mNotificationManager.notify(ID_NOTIFICATION, notification);

通知的更新

   若是须要更新一个通知,只须要在设置好 notification 以后,再调用 setLatestEventInfo ,而后从新发送一次通知便可。

自定义通知视图

   这部分能够参考官方文档,讲的很详细了。

AndroidSDK: docs/guide/topics/ui/notifiers/notifications.html

Notification.Builder

这个类通常用于管理 Notification ,动态的设置 Notification 的一些属性。即用 set 来设置。

 

问题:如何区分“正在进行的”和“通知”,谁决定一个事件是“正在进行的”仍是持续的“通知” ?

经过设置 Notification  flag 属性能够设定 notification 是正在进行的仍是持续的 notification 

FLAG_INSISTENT  FLAG_ONGOING_EVENT 标志位可让 Notification 成为持续的或正在进行的Notification 

. Notification 标记为 ONGOING, 以下面的代码所示,它就能用于表示当前正在进行的事件(如来电)。正在进行的事件与“通知” Notification 区别在扩展的状态条窗口中。


notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;


. 持续的 Notification 一直重复,直到用户取消。下面的代码给出了如何设置 Notification 为持续的:


notification.flags = notification.flags | Notification.FLAG_INSISTENT;

持续 Notification 反复重复开头的 Notification 效果,直到用户取消。持续的 Notification 应该保留给如闹钟的情形,它须要及时的采起响应.


1.2.2 系统图标的增长删除

这里主要向你们介绍如何添加一个在状态栏显示的系统图标,相似于系统默认的闹钟图标,声音图标等。

文件中加资源:

. frameworks\base\core\res\res\drawalbe 中添加系统图标的图片资源

. frameworks\base\core\res\res\values\config.xml 中添加图片引用,这些 icon 在这个 string array 的位置就决定了其在 status bar 上显示的位置了。咱们能够从 code 里面得出该结论。因此当你要调换 icon 的顺序时,改动这个 config.xml 就能够了。在 StatusBarManagerService 初始化的时候就会读取 config.xml  icons  String array 

这个文件中加代码: StatusBarPolicy.java 以闹钟为例。

.  StatusbarPolicy.java 中初始化所增长的系统图标

. 在构造函数中 SetIcon

. StatusBarPolicy 调用 registerReceiver 注册了感兴趣的 intent, 当感兴趣的 intent 发生时,对图标进行更新。例如,设置一个闹钟后,闹钟模块会发出一个叫作 Intent.ACTION_ALARM_CHANGED 的广播,而后 StatusBarPolicy接收到此广播,继而更新状态栏上的闹钟图标。

………

// Alarm clock StatusBarPolicy 构造方法中初始化闹钟图标

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(Intent intent) {

boolean alarmSet = intent.getBooleanExtra(“alarmSet”, false);

mService.setIconVisibility(“alarm_clock”, alarmSet);

}

以上是在状态栏添加显示的系统图标的步骤。


代码执行步骤:

StatusBarManagerService.java 

StatusBarIconList mIcons = new StatusBarIconList();

………

          mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));

          StatusBarPolicy.java -- > setIcon(…)

          StatusBarManager.java -- > setIcon(…)

          StatusBarManagerService.java -- > setIcon(…)

在 StatusBarService onCreate 的时候调用StatusBarManagerService 中的 registerStatusBar (…)

Statusbar 中的控制开关会作详细的描述,这里就不在赘述。

2、模块基本布局

2.1 Statusbar 布局

Android 系统顶上的状态栏是属于 FrameWork 的内容,在此先对 statusbar 的的结构作必定描述。

StatusBar 的布局文件 status_bar.xml ,文件位置:frameworks/base/packages/SystemUI/res/layout/status_bar.xml

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

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

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


LinearLayout android:id="@+id/ticker" 显示。在正常状况下 ticker 是不显示的,只有在 StatusBarService 收到通知时它才显示


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

 

3、模块内部框架

Statusbar 内部各类交互以及模块与其余应用的交互都是创建在 StatusbarService 之上的,其中包括 Statusbar视图的建立(包括 Statusbar  TrackingView  StatusbarExpandedView ),视图动画,系统图标(闹钟、 wifi SIM 卡等)的加载和管理,其余应用通知信息的加载显示、更新、删除等,其余应用的远程接口控制(如当打电话时statusbar 处于禁用状态的)对 Android 系统其余应用的通知信息(包括图标、 tracker  notification 的布局等)的处理。 SIM 卡信息的控制等。


总之 StatusbarService  Statusbar 的灵魂所在,是 Statusbar 的核心,全部关于 Statusbar 的操做处理都是创建在 StatusbarService 这个基础之上的。

 

4、模块流程

在整个 Statusbar 模块中包括了多个操做流程(例如 StatusbarService 的启动流程), Statusbar 与系统其余应用交互的处理流程(例如 Statusbar 对天气预报的通知的处理),还有系统图标的更新流程, statusbar 拖动时动画的绘制流程,以及远程接口的控制流程等。

4.1 启动流程

4.1.1 StatusbarService 的启动流程

 

首先,当系统进程 system_press 启动以后,调用系统 SystemServer.java ,在 SystemServer 中运行ServerThread.run() 方法时会注册 StatusBarManagerService 

 

Java代码   收藏代码
  1. <span style="font-size: x-small;">try {  
  2.   
  3. Slog.i(TAG, "Status Bar");  
  4.   
  5. statusBar = new StatusBarManagerService(context);  
  6.   
  7. ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);  
  8.   
  9. catch (Throwable e) {  
  10.   
  11. Slog.e(TAG, "Failure starting StatusBarManagerService", e);  
  12.   
  13. }  
  14.   
  15. 让后调用StatusBarManagerService 的systemReady2() 方法,会在systemReady2() 方法中启动StatusbarService 。  
  16.   
  17. final StatusBarManagerService statusBarF = statusBar;  
  18.   
  19. if (statusBarF != null) statusBarF.systemReady2();  
  20.   
  21. public void systemReady2() {  
  22.   
  23. ComponentName cn = ComponentName.unflattenFromString(mContext.getString(com.android.internal.R.string.config_statusBarComponent));  
  24.   
  25. Intent intent = new Intent();  
  26.   
  27. intent.setComponent(cn);  
  28.   
  29. Slog.i(TAG, "Starting service: " + cn);  
  30.   
  31. mContext.startService(intent);  
  32.   
  33. } </span>  
 

 :在 SystemUI 模块的 SystemUiApp.java  onCreate 方法中也会 startService ,这是当 Statusbar 意外退出而致使 StatusbarService 中止服务时会从新启动 StatusbarService

4.1.2 系统图标初始化流程

 

在启动 StatusBarService   StatusbarService 会调用一个 makeStatusBarView 的方法  在里面将建立StatusBarView 在建立 StatusbarView 的过程当中会加载系统图标。

在启动 StatusbarService 的过程当中会建立 StatusBarPolicy 的对象, StatusBarPolicy.java 主要负责状态栏显示策略的管理(如状态栏的图标何时显示,在什么位置显示等)。 StatusBarPolicy 的构造函数中初始化了不少系统图标(如电池信息图标,闹钟图标,声音图标,信号栏图标等)。 。 默认时有不少图标是不显示的,须要显示时再进行更新。

图标初始化,以电池电量显示为例,大概关键步骤以下:

经过 BroadcastReceiver 机制, StatusBarPolicy 中注册的 mIntentReceiver 收到 BatteryService 广播的ACTION_BATTERY_CHANGED 事件触发;

调用 updateBattery(intent) 开始更新电池状态栏;

 intent 中解析须要的字段,调用 StatusBarManager  setIcon()  StatusBarManager 是客户端使用的状态栏管理类;

经过 IBinder 机制跨进程调用 StatusBarManagerService  setIcon()  StatusBarManagerService 派生于IStatusBarService.Stub ,是状态栏管理的服务端,是具体实现;

StatusBarManagerService 有一个 mIcons 成员,这个 list 成员在 StatusBarManagerService 建立时加载。StatusBarManagerService  setIcon() 过程当中,会又 "battery" 字段得到在 mIcons 中的索引,再由包名、图片id 和等级建立 StatusBarIcon 实例,并将这个实例更新 StatusBarIconList 中所得到索引对应项;

调用 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() 

 addIcon() 为例, StatusBarService  addIcon() 会建立一个新的 StatusBarIconView ,将第步中所建立的StatusBarIcon 实例设置进去,而后把这个 view 添加到 LinearLayout  viewIndex 位置。

这样一个电池相关图标就在状态栏上添加或者更新了。删除操做相似。

4.2 通知处理

 

在应用Activity 中实现通知栏图标变化的程序中。是用NotificationManager 对象mNotificationManager 来发送通知。通知为Notification mNotification   对象,填充mNotification   的图标和消息内容以及一个when ,而后构造了一个Intent 对象intent ,包含了本Activity 对象的引用,以及本Activity 的类名,一个PendingIntent pi对象,包含上述Intent 对象以及本Activity 对象的引用,是用于消息列表中显示本Activity 项。点击时从新激活Activity 。而后调用nm.setLatestEventInfo 设置状态栏下拉列表项内容。最后调用nm.notify(1,n) 方法来发送通知,接着改变状态栏的工做就由NotificationManager StatusBarManagerService 交互了。

下面来看看NotificationManager 是如何和StatusBarManagerService 交互的。

nm.notify(1,n) 方法作了最重要的事,就是所谓的发送通知   该方法的代码以下:

public void notify(int id, Notification notification) 

     {

         notify(null, id, notification);

}

其实是调用了下面这个函数:

pu blic void notify(String tag, int id, Notification notification)

     {

         int[] idOut = new int[1];

         INotificationManager service = getService();

         String pkg = mContext.getPackageName();

         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");

         try {

             service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);

             if (id != idOut[0]) {

                 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);

             }

         } catch (RemoteException e) {

         }

     }

该函数中主要作了 件事:获取一个服务,用该服务将通知事件“入队”插入通知队列,因此应该在某个地方有人在不停的读取通知队列。

下面是 getService 的代码,这里的 INotificationManager.Stub.asInterface(b) 这个形式在好多地方出现,必定要详细理解该类代码,在 Binder 机制中。

static public INotificationManager getService()

     {

         if (sService != null) {

             return sService;

         }

         IBinder b = ServiceManager.getService("notification");

         sService = INotificationManager.Stub.asInterface(b);

         return sService;

     }

StatusBarManagerService 中添加了该消息:

位于 NotificationManagerService  enqueueNotificationInternal 函数中:

r.statusBarKey =   mStatusBar.addNotification(n);    其中 是由 notification 对象构造的 statusBarNotification 对象   mStatusBar 是一个 StutusBarManagerService 的引用。

 addNotification() 中执行了:

synchronized (mNotifications) {

             IBinder key = new Binder();

             mNotifications.put(key, notification);

             if (mBar != null) {

                 try {

                     mBar.addNotification(key, notification);

                 } catch (RemoteException ex) {

                 }

             }

             return key;

这里先执行了 mNotification.put 将该通知加入一个 hashMap 结构体中

而后执行了 mBar.addNotification(key,notification)   调用了 CommandQueue 中的addNotification 方法,该方法利用 Handler 调用了 mCallbacks.addNotification 方法,其实就是 StatusBarService 中的。

这个 mBar 是由方法:

public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,

             List<IBinder> notificationKeys, List<StatusBarNotification> notifications) {

         enforceStatusBarService();


         Slog.i(TAG, "registerStatusBar bar=" + bar);

         mBar = bar;

         synchronized (mIcons) {

             iconList.copyFrom(mIcons);

         }

         synchronized (mNotifications) {

             for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {

                 notificationKeys.add(e.getKey());

                 notifications.add(e.getValue());

             }

         }

     }

 StatusBarService 启动的时候注册的 mCommandQueue 对象的引用  

mCommandQueue = new CommandQueue(this, iconList);

由该对象的实例化以及其构造函数

public CommandQueue(Callbacks callbacks, StatusBarIconList list) {

         mCallbacks = callbacks;

         mList = list;

     }

能够看出,注册的 mCommandQueue 中的 callbacks 接口,是由 StatusBarService 实现的

public interface Callbacks {

         public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);

         public void updateIcon(String slot, int index, int viewIndex,

                 StatusBarIcon old, StatusBarIcon icon);

         public void removeIcon(String slot, int index, int viewIndex);

         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 animateCollapse();

     }

接口声明如上:

其中, StatusBarService  addNotification 的实现以下:

public void addNotification(IBinder key, StatusBarNotification notification) {

boolean shouldTick = true;

if (notification.notification.fullScreenIntent != null) {

shouldTick = false;

Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");

try {

notification.notification.fullScreenIntent.send();

} catch (PendingIntent.CanceledException e) {

}

}


StatusBarIconView iconView = addNotificationViews(key, notification);

if (iconView == null) return;


if (shouldTick) {

tick(notification);

}


// Recalculate the position of the sliding windows and the titles.

setAreThereNotifications();

updateExpandedViewPos(EXPANDED_LEAVE_ALONE);

}

因此到头来 enqueueNotificationInternal 方法中 mBar.addNotification(key, notification); 实际上是调用了 StatusBarService 实现的 addNotification 方法,即上面的代码。

上面的代码中这句 StatusBarIconView iconView = addNotificationViews(key, notification);   以及 tick(notification)   多是将图标以及信息显示在 StatusBarView 上的主要语句。接着进入这两个方法。

addNotificationViews():

StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {

         NotificationData list;

         ViewGroup parent;

         final boolean isOngoing = notification.isOngoing();

         if (isOngoing) {

             list = mOngoing;

             parent = mOngoingItems;

         } else {

             list = mLatest;

             parent = mLatestItems;

         }

         // Construct the expanded view.

         final View[] views = makeNotificationView(notification, parent);

         if (views == null) {

             handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "

                     + notification);

             return null;

         }

         final View row = views[0];

         final View content = views[1];

         final View expanded = views[2];

         // Construct the icon.

         final StatusBarIconView iconView = new StatusBarIconView(this,

                 notification.pkg + "/0x" + Integer.toHexString(notification.id));

         final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,

                     notification.notification.iconLevel, notification.notification.number);

         if (!iconView.set(ic)) {

             handleNotificationError(key, notification, "Coulding create icon: " + ic);

             return null;

         }

         // Add the expanded view.

         final int viewIndex = list.add(key, notification, row, content, expanded, iconView);

         parent.addView(row, viewIndex);

         // Add the icon.

         final int iconIndex = chooseIconIndex(isOngoing, viewIndex);

         mNotificationIcons.addView(iconView, iconIndex);

         return iconView;

     }

final StatusBarIconView iconView = new StatusBarIconView(this,

                 notification.pkg + "/0x" + Integer.toHexString(notification.id));

其中这一句利用传来的 notification 构造了图标 view

mNotificationIcons.addView(iconView, iconIndex);   其中 mNotificationIcons 是一个IconMerger 对象, IconMerger 是继承 LinearLayout 的类。

这一句将图标显示在 StatusBar 上。

如上就是当应用发送完 notification  StatusbarService 是如何将发送的信息显示到 Statusbar 上的。

4.3 图标更新

4.3.1 经过广播接收器的方式

StatusBarPolicy 调用 registerReceiver 注册了感兴趣的 intent, 当感兴趣的 intent 发生时,对图标进行更新。例如,设置一个闹钟后,闹钟模块会发出一个叫作 Intent.ACTION_ALARM_CHANGED 的广播,而后 StatusBarPolicy接收到此广播,继而更新状态栏上的闹钟图标。


………

// Alarm clock StatusBarPolicy 构造方法中初始化闹钟图标

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(Intent intent) {

boolean alarmSet = intent.getBooleanExtra(“alarmSet”, false);

mService.setIconVisibility(“alarm_clock”, alarmSet);

}


StatusBarPolicy 只是一个策略管理,实际的功能是 StatusBarService 来实现的。 StatusBarService 初始化时初始化了一个用于显示 statusbar  StatusBarView  StatusBarView 里面定义了 icon 名字,的显示顺序,对应的png 图等,在 StatusBarService 调用 makeStatusBarView 方法时实现 statusbar 的初始化

 4.3.2 经过远程代理方式

StatusBarManager 有一个更新图标的方法: public void updateIcon(IBinder key, String slot, int iconId, int iconLevel) ,不过 StatusBarManager 并未把方法公开在 sdk 中,可是应该有方法能够访问的。 
    public void updateIcon(IBinder key, String slot, int iconId, int iconLevel) {
        try {
            mService.updateIcon(key, slot, mContext.getPackageName(), iconId, iconLevel);
        } catch (RemoteException ex) {
                       throw new RuntimeException(ex);
        }
    }
mService
  StatusBarManager 的一个成员变量, StatusBarManager 被构建的时候被赋值,他是 IStatusBar 的一个代理对象

    StatusBarManager(Context context) {
        mContext = context;
        mService = IStatusBar.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
    }

4.4 拖动刷新

4.4.1 StatusbarView 从被点击到拖动

 

从点击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 走到 StatusBarServiceinterceptTouchEvent() ;

2 、interceptTouchEvent() 中会走到分支 else if (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 。

 

4.5 远程接口

4.5.1 Statusbar 远程接口简介

StatusBarManagerService 经过使用 IStatusBar  aidl 调用 CommandQueue   CommandQueue 中定义Callbacks 

StatusBarService 实现了 CommandQueue  Callbacks 的回调

public interface Callbacks {

public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);

public void updateIcon(String slot, int index, int viewIndex,

StatusBarIcon old, StatusBarIcon icon);

public void removeIcon(String slot, int index, int viewIndex);

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(boolean needForceStatusBar);

public void animateCollapse();

public void showSIMIndicator(String businessType);

public void hideSIMIndicator();

}

由上述源码咱们能够得出在 StatusbarService.java 中都有增长 / 删除状态栏图标、增长 / 更新 / 删除notification 、禁用 Statusbar  SIM 指示信息的隐藏和显示、还有 Statusbar 拖动动画的实现。

4.5.2 StatusBarManager 的使用

 4.3.2 所讲,经过远程代理方式更新状态栏图标,由于 StatusBarManager 方法在 SDK 中并未公开以下就讲述对StatusBarManager 的使用方法。

 StatusbarService.java 中的的 disable 方法,就实现并扩展了了 StatusbarManager  disable 所实现的功能(如 statusbar 的禁止拖动,不显示通知图标,不显示 ticker 等)。


Java代码   收藏代码
  1. <span style="font-size: x-small;">/** 
  2.    * State is one or more of the DISABLE constants from StatusBarManager. 
  3.    */  
  4.    public void disable(int state) {  
  5.         final int old = mDisabled;  
  6.         final int diff = state ^ old;  
  7.         mDisabled = state;  
  8.         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {  
  9.             if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {  
  10.                 if (SPEW) Slog.d(TAG, "DISABLE_EXPAND: yes");  
  11.                 animateCollapse();  
  12.             }  
  13.         }  
  14.         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {  
  15.             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {  
  16.                 if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");  
  17.                 if (mTicking) {  
  18.                     mTicker.halt();  
  19.                 } else {  
  20.                     setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);  
  21.                 }  
  22.             } else {  
  23.                 if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");  
  24.                 if (!mExpandedVisible) {  
  25.                     setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);  
  26.                 }  
  27.             }  
  28.         } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {  
  29.             if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {  
  30.                 if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");  
  31.                 mTicker.halt();  
  32.             }  
  33.         }  
  34.      }  
  35. 下面在将一种简单的对StatusBarManager的引用方法:  
  36. Object service = getSystemService ("statusbar");  
  37.     try {  
  38. Class <?> statusBarManager = Class.forName  
  39. ("android.app.StatusBarManager");  
  40. Method expand = statusBarManager.getMethod ("disable",int.class);  
  41. expand.invoke (service,0x00000001);  
  42. catch (Exception e) {  
  43. e.printStackTrace();  
  44. }</span>  

 权限:

<uses-permission android:name="android.permission.STATUS_BAR"/>

<uses-permission android:name="android.permission.DISABLE_STATUS_BAR"/>

这个方法也是禁用statusbar 的一种方法。

5、重要文件的介绍

StatusBarManagerService.java

StatusBarManagerService 是服务端 StatusBarService 的管理者

顾名思义, StatusBarManagerService  StatusBarService 的管理者,是StatusBarService 与外界通讯的桥梁,如4.2 所讲。

 StatusBarManagerService.java 中,有 addNotification removeNotification,updateNotification 等方法用于管理传递给他的通知对象。这个类是一些管理方法,实际执行相关动做的是在 IStatusBar.java 里面,这个是framework/base/core/java/com /android/internal/statusbar/IStatusBar.aidl 自动生成的用于 IPC 的类。

 5.1

 

StatusBarService.java

StatusBarservice  Statusbar 的核心

StatusBarService 这个服务是Statusbar 模块的中心点,全部关于图标的加载、更新、删除等处理,与应用的交互,对通知信息的处理,动画的完成等都是创建在StatusBarService 这个基础之上的。

 5.2

 

StatusBarPolicy.java

StatusBarPolicy 负责状态栏显示的策略管理

Android 中状态栏上有不少图标,这些图标何时显示何时不显示 ,这些都是StatusBarPolicy 来管理的。
StatusBarPolicy
 
的构造函数里初始化了好几个图标,如闹钟icon ,信号栏icon 等。默认时有不少图标是不显示的,须要显示时再进行更新。StatusBarPolicy 调用 registerReceiver注册了感兴趣的intent, 当感兴趣的intent 发生时,对图标进行更新。

StatusBarPolicy 只是一个策略管理,实际的功能是StatusBarService 来实现的。StatusBarService 初始化时初始化了一个用于显示statusbar StatusBarViewStatusBarView 里面定义了icon 名字,的显示顺序,对应的png 图等,在StatusBarService 调用makeStatusBarView 方法时实现statusbar 的初始化。

 5.3

 

CommandQueue.java

CommandQueue  StatusBarservice  StatusBarManagerService 交互的枢纽

IStatusBar.java 里面对应的方法是用 CommandQueue 的接口 callback 的形式调用的,callback 的实如今对应的服务提供类也就是 StatusBarService.java 中提供的。

最终执行状态栏更新通知等事件都是在实现的 CommandQueue.Callbacks 里面执行。

 5.4

6、总结

本文档主要讲述了 SystemUI 模块中 Statusbar 模块的主要功能和实先步骤,文档中介绍了 Statusbar 的功能,使用方法,模块框架,以及模块一些实现的主要流程等。

但愿你们在阅读文档的过程当中,若是发现文档的缺点和错误,请及时反馈,我将以最快的速度加以改进。

相关文章
相关标签/搜索