这章主要说明,在Android4.0上添加一个长按键发送消息打开系统通知面板功能,中间涉及到按键的响应的添加,Broadcast的注册和监听,以及SystemUI的修改。。
按键分为长按或者短按,KeyEvent.FLAG_LONG_PRESS标志按键处于长按状态,而KeyEvent的getFlags能够获取当前按键的状态。在/PhoneWindowManager.java(拦截消息的处理类)中interceptKeyBeforeDispatching找到按键处理【以菜单键为例】。
1.添加按键的响应配置: /frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
[1]定义消息名称:
static final String NOTIFICATION_ACTION = "com.android.action.OPEN_NOTIFICATION";
[2]按键消息处理:
菜单键为 KeyEvent.KEYCODE_MENU,先查看是否已经有了该按键的配置,若没有直接添加以下代码:
} else if (keyCode == KeyEvent.KEYCODE_MENU) { //liusl--add--open notification panel--on ipanel Remote Control Slog.i(TAG,"----down"+down+" Flags"+event.getFlags()); if (down&&(event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0){ Intent intent = new Intent(); intent.setAction(NOTIFICATION_ACTION); intent.putExtra("msg", "MSG_OPEN_NOTIFICATION_PANEL"); mContext.sendBroadcast(intent);//发送消息 return -1; }
2.在SystemUI中定义一个消息接受类并注册消息:
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tablet\TabletStatusBar.java
[1]注册消息:
在makeStatusBarView()中添加Broadcast的注册和监听:
NotificationReceiver hNotificationReceiver;//全局变量
hNotificationReceiver = new NotificationReceiver(mContext); hNotificationReceiver.registerReceiver();
public class NotificationReceiver extends BroadcastReceiver { private final String TAG = "StatusBar.NotificationReceiver"; private final String NOTIFICATION_ACTION = "com.android.action.OPEN_NOTIFICATION"; Context mContext; public NotificationReceiver(Context context) { mContext = context; } @Override public void onReceive(Context context, Intent intent) {//重写onReceive方法 String msg = intent.getStringExtra("msg"); if(msg.equals("MSG_OPEN_NOTIFICATION_PANEL")) { displayNotificationPanel();//打开通知面板 } } public void registerReceiver() {//动态注册消息监听器 final IntentFilter filter = new IntentFilter(); filter.addAction(NOTIFICATION_ACTION); final Intent val = mContext.registerReceiver(this, filter); } }
3.通知面板的打开:
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tablet\TabletStatusBar.java
public void displayNotificationPanel() { setTitle(); animateExpand(); visibilityChanged(true); }
注:
本文主要实现在PhoneWindowManager中添加一个长按菜单键的事件响应,发送一个MSG_OPEN_NOTIFICATION_PANEL打开通知面板的消息出去。在SystemUI中动态注册一个自定义的BroadcastReceiver,当接收到MSG_OPEN_NOTIFICATION_PANEL消息时,将打开通知面板的窗口。
-------------------------------------------------------------------
BroadcastReceiver的调用过程:
首先在需要发送信息的地方,把要发送的信息和用于过滤的信息(如Action、Category)装入一个Intent对象,然后通过调用 Context.sendBroadcast()、sendOrderBroadcast()或sendStickyBroadcast()方法,把 Intent对象以广播方式发送出去。
当Intent发送以后,所有已经注册的BroadcastReceiver会检查注册时的IntentFilter是否与发送的Intent相匹配,若匹配则就会调用BroadcastReceiver的onReceive()方法。所以当我们定义一个BroadcastReceiver的时候,都需要实现onReceive()方法。
注册BroadcastReceiver有两种方式:
1.静态的在AndroidManifest.xml中用<receiver>标签生命注册,并在标签内用<intent- filter>标签设置过滤器。
2.动态的在代码中先定义并设置好一个 IntentFilter 对象,然后在需要注册的地方调Context.registerReceiver()方法,如果取消时就调用 Context.unregisterReceiver()方法。如果用动态方式注册的BroadcastReceiver的Context对象被销毁时,BroadcastReceiver也就自动取消注册了。(特别注意,有些可能需要后台监听的,如短信消息,SystemUI是一个系统的apk,会一直处于后台运行,context不会销毁,所以可以采用动态注册的方式。)