1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > android 状态栏(StatusBar)

android 状态栏(StatusBar)

时间:2023-08-06 06:45:53

相关推荐

android 状态栏(StatusBar)

一、SystemUI概述

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

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

1.1 Statusbar的功能作用

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

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

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

Ⅱ、状态栏的日期显示

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

1.2 Statusbar的使用方法

1.2.1 notification的使用

Notification主要作用和使用步骤:

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

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

获取NotificationManager实例

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

Java代码publicclassMainextendsActivity{ privateButtonsendBtn,cancelBtn; privateNotificationn; privateNotificationManagernm; //Notification的标示ID privatestaticfinalintID=1; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //实例化按钮 sendBtn=(Button)this.findViewById(R.id.sendBtn); cancelBtn=(Button)this.findViewById(R.id.cancelBtn); //获取NotificationManager实例 Stringservice=NOTIFICATION_SERVICE; nm=(NotificationManager)this.getSystemService(service); //实例化Notification n=newNotification(); //设置显示图标,该图标会在状态栏显示 inticon=R.drawable.icon; //设置显示提示信息,该信息也会在状态栏显示 StringtickerText="TestNotifaction"; //显示时间 longwhen=System.currentTimeMillis(); n.icon=icon; n.tickerText=tickerText; n.when=when; n.flags=Notification.FLAG_NO_CLEAR; n.flags=Notification.FLAG_ONGOING_EVENT; //为按钮添加监听器 sendBtn.setOnClickListener(sendClickListener); cancelBtn.setOnClickListener(cancelClickListener); } privateOnClickListenersendClickListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //实例化Intent Intentintent=newIntent(Main.this,Main.class); //获取PendingIntent PendingIntentpi=PendingIntent.getActivity(Main.this,0,intent,0); //设置事件信息 n.setLatestEventInfo(Main.this,"MyTitle","MyContent",pi); //发出通知 nm.notify(ID,n); } }; privateOnClickListenercancelClickListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ nm.cancel(ID); } }; }

、步骤详解

获取NotificationManager实例

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

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)

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 = newStatusBarIconList();

………

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.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时才显示的,默认是隐藏的

三、模块内部框架

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

总之StatusbarService是Statusbar的灵魂所在,是Statusbar的核心,所有关于Statusbar的操作处理都是建立在StatusbarService这个基础之上的。

四、模块流程

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

4.1启动流程

4.1.1 StatusbarService的启动流程

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

Java代码<spanstyle="font-size:x-small;">try{ Slog.i(TAG,"StatusBar"); statusBar=newStatusBarManagerService(context); ServiceManager.addService(Context.STATUS_BAR_SERVICE,statusBar); }catch(Throwablee){ Slog.e(TAG,"FailurestartingStatusBarManagerService",e); } 让后调用StatusBarManagerService的systemReady2()方法,会在systemReady2()方法中启动StatusbarService。 finalStatusBarManagerServicestatusBarF=statusBar; if(statusBarF!=null)statusBarF.systemReady2(); publicvoidsystemReady2(){ ComponentNamecn=ComponentName.unflattenFromString(mContext.getString(com.android.internal.R.string.config_statusBarComponent)); Intentintent=newIntent(); intent.setComponent(cn); Slog.i(TAG,"Startingservice:"+cn); mContext.startService(intent); }</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交互的。

在StatusBarManagerService中添加了该消息:

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

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

这个mBar是由方法:

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

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

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

接口声明如上:

其中,StatusBarService对addNotification的实现如下:

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

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

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走到StatusBarService:interceptTouchEvent();

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代码<spanstyle="font-size:x-small;">/** *StateisoneormoreoftheDISABLEconstantsfromStatusBarManager. */ publicvoiddisable(intstate){ finalintold=mDisabled; finalintdiff=state^old; mDisabled=state; if((diff&StatusBarManager.DISABLE_EXPAND)!=0){ if((state&StatusBarManager.DISABLE_EXPAND)!=0){ if(SPEW)Slog.d(TAG,"DISABLE_EXPAND:yes"); animateCollapse(); } } if((diff&StatusBarManager.DISABLE_NOTIFICATION_ICONS)!=0){ if((state&StatusBarManager.DISABLE_NOTIFICATION_ICONS)!=0){ if(SPEW)Slog.d(TAG,"DISABLE_NOTIFICATION_ICONS:yes"); if(mTicking){ mTicker.halt(); }else{ setNotificationIconVisibility(false,com.android.internal.R.anim.fade_out); } }else{ if(SPEW)Slog.d(TAG,"DISABLE_NOTIFICATION_ICONS:no"); if(!mExpandedVisible){ setNotificationIconVisibility(true,com.android.internal.R.anim.fade_in); } } }elseif((diff&StatusBarManager.DISABLE_NOTIFICATION_TICKER)!=0){ if(mTicking&&(state&StatusBarManager.DISABLE_NOTIFICATION_TICKER)!=0){ if(SPEW)Slog.d(TAG,"DISABLE_NOTIFICATION_TICKER:yes"); mTicker.halt(); } } } 下面在将一种简单的对StatusBarManager的引用方法: Objectservice=getSystemService("statusbar"); try{ Class<?>statusBarManager=Class.forName ("android.app.StatusBarManager"); Methodexpand=statusBarManager.getMethod("disable",int.class); expand.invoke(service,0x00000001); }catch(Exceptione){ e.printStackTrace(); }</span>

权限:

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

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

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

五、重要文件的介绍

5.1

5.2

5.3

5.4

六、总结

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

希望大家在阅读文档的过程中,如果发现文档的缺点和错误,请及时反馈,我将以最快的速度加以改进。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。