向android 的状态栏中加入快捷按钮(home,back,menu等等)的方法(续)
上一篇文章中谈到的加入快捷按钮的方法,实际上还是太过麻烦。那篇博客是在我刚接触android源代码没几天时,参考网上的介绍方法,自己看了下源代码尝试着写了一个。 不过那个方法,是我直接用贴图的方法实现了按钮特效,这实在是太浪费了,最近一直仍有朋友问我那篇文章中的问题,我想还是重写一下,用一个更简单点的方法,直接使用android的ImageButton控件,通过其OnTouchListener方法操作即可,Button的高亮与否完全由系统处理,这样也不会出现button高亮不消失的bug。以下方法在android 2.1 上编译调试通过
1。 准备资源,修改XML文件
和上篇文章一样,准备几张图,这里我们准备添加home back和menu图标,就需要准备6张图,三张普通状态,三张按下的高亮状态图标:
stat_home.png
stat_home_pressed.png
stat_back.png
stat_back_pressed.png
stat_menu.png
stat_menu_pressed.png
同时,在 Frameworks/base/core/res/res/drawable下创建三个imageButton的xml文件:
xml_stat_home.xml
view plain
copy to clipboard
print
?
- <?xml version="1.0" encoding="utf-8"?>
- <selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_focused="true"
- android:state_pressed="false"
- android:drawable="@drawable/stat_home" />
- <item
- android:state_focused="true"
- android:state_pressed="true"
- android:drawable="@drawable/stat_home_pressed" />
- <item
- android:state_focused="false"
- android:state_pressed="true"
- android:drawable="@drawable/stat_home_pressed" />
- <item
- android:drawable="@drawable/stat_home" />
- </selector>
xml_stat_back.xml
view plain
copy to clipboard
print
?
- <?xml version="1.0" encoding="utf-8"?>
- <selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_focused="true"
- android:state_pressed="false"
- android:drawable="@drawable/stat_back" />
- <item
- android:state_focused="true"
- android:state_pressed="true"
- android:drawable="@drawable/stat_back_pressed" />
- <item
- android:state_focused="false"
- android:state_pressed="true"
- android:drawable="@drawable/stat_back_pressed" />
- <item
- android:drawable="@drawable/stat_back" />
- </selector>
xml_stat_menu.xml
view plain
copy to clipboard
print
?
- <?xml version="1.0" encoding="utf-8"?>
- <selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_focused="true"
- android:state_pressed="false"
- android:drawable="@drawable/stat_menu" />
- <item
- android:state_focused="true"
- android:state_pressed="true"
- android:drawable="@drawable/stat_menu_pressed" />
- <item
- android:state_focused="false"
- android:state_pressed="true"
- android:drawable="@drawable/stat_menu_pressed" />
- <item
- android:drawable="@drawable/stat_menu" />
- </selector>
修改status_bar.xml,如下:
如上篇,修改statusbar的高度,编译一下,即可看到效果。
2。 添加按钮的动作效果
在statusBarView.java中,活的button的handler
类中新增加三个成员:
view plain
copy to clipboard
print
?
- ImageButton mHomeBtn;
- ImageButton mBackBtn;
- ImageButton mMenuBtn;
增加三个常量:
public static final int RESV_KEY_HOME = KeyEvent.KEYCODE_HOME;
public static final int RESV_KEY_BACK = KeyEvent.KEYCODE_BACK;
public static final int RESV_KEY_MENU = KeyEvent.KEYCODE_MENU;;
在onFinishInflate中,获取几个button 的handler,并设置touch事件,添加如下代码:
view plain
copy to clipboard
print
?
- mHomeBtn = (ImageButton)findViewById(R.id.go_home);
- mBackBtn = (ImageButton)findViewById(R.id.go_back);
- mMenuBtn = (ImageButton)findViewById(R.id.pop_menu);
-
- mHomeBtn.setOnTouchListener(homeOnTouch);
- mBackBtn.setOnTouchListener(backOnTouch);
- mMenuBtn.setOnTouchListener(menuOnTouch);
各button的touch事件添加如下:
view plain
copy to clipboard
print
?
- private void sendKeyIntent(int keycode){
- Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- intent.putExtra("keycode", keycode);
- mService.sendIntent(intent);
- }
-
- private OnTouchListener homeOnTouch = new OnTouchListener(){
- //@Override
- public boolean onTouch(View v, MotionEvent event)
- {
- // TODO Auto-generated method stub
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- {
- sendKeyIntent(RESV_KEY_HOME);
- }
- break;
- }
- return false;
- }
- };
-
- private OnTouchListener backOnTouch = new OnTouchListener(){
- //@Override
- public boolean onTouch(View v, MotionEvent event)
- {
- // TODO Auto-generated method stub
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- {
- sendKeyIntent(RESV_KEY_BACK);
- }
- break;
- }
- return false;
- }
- };
-
- private OnTouchListener menuOnTouch = new OnTouchListener(){
- //@Override
- public boolean onTouch(View v, MotionEvent event)
- {
- // TODO Auto-generated method stub
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- {
- sendKeyIntent(RESV_KEY_MENU);
- }
- break;
- }
- return false;
- }
- };
也就是简单的广播一个intent消息给statusBarPolicy处理。
为防止点击statusBar上的按钮, 触发标题栏的expend事件, 修改一下函数onInterceptTouchEvent,点击到不属于button区域时才允许解析Motion的event:
view plain
copy to clipboard
print
?
- public boolean onInterceptTouchEvent(MotionEvent event) {
- if( (event.getX() > mHomeBtn.getRight())
- && (event.getX() < mMenuBtn.getLeft())){
- return mService.interceptTouchEvent(event)
- ? true : super.onInterceptTouchEvent(event);
- }
- return false;
- //return mService.interceptTouchEvent(event)
- // ? true : super.onInterceptTouchEvent(event);
- }
- }
修改StatusBarService.java,发送Intent消息需要content,这个目前只能在StatusBarService中添加一个方法:
view plain
copy to clipboard
print
?
- void sendIntent(Intent intent)
- {
- mContext.sendBroadcast(intent);
- }
要发送intent,需要自己添加Intent:
在framework/base/core/java/android/content/intent.java中增加
view plain
copy to clipboard
print
?
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ICONKEY_CHANGED = "android.intent.action.ICONKEY_CHANGED";
接收并处理intent, 如前篇:
接收并处理intent
这个就要修改StatusBarPolicy.java了
首先,在构造函数中加入Intent的filter,注册号这个intent的receiver。
view plain
copy to clipboard
print
?
- filter.addAction(Intent.ACTION_ICONKEY_CHANGED);
然后再private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() 加入Intent的receiver动作;
view plain
copy to clipboard
print
?
- else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {
- Log.d(TAG, "Received ACTION_ICONKEY_CHANGED");
- updateIconKeyAction(intent);
- }
及处理函数:
view plain
copy to clipboard
print
?
- private final void updateIconKeyAction(Intent intent){
- int keycode = intent.getIntExtra("keycode", -1);
- IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
-
- if(keycode != -1){
- long now = SystemClock.uptimeMillis();
-
- KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0);
- KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0);
-
- try {
- wm.injectKeyEvent(down, false);
- }catch (RemoteException e) {
- Log.i("Input", "DeadOjbectException");
- }
-
- try{
- wm.injectKeyEvent(up, false);
- }catch(RemoteException e) {
- Log.i("Input", "DeadOjbectException");
- }
- }
- }
3. StatusBar通知栏屏蔽按钮
当拉出expand的通知栏时,按钮的响应非常慢,这时最好将按钮给屏蔽掉,我们在 statusBarView.java中增加两个方法:
view plain
copy to clipboard
print
?
- public void hiddenHotIcons(){
- mHomeBtn.setVisibility(View.INVISIBLE);
- mBackBtn.setVisibility(View.INVISIBLE);
- mMenuBtn.setVisibility(View.INVISIBLE);
- }
-
- public void showHotIcons(){
- mHomeBtn.setVisibility(View.VISIBLE);
- mBackBtn.setVisibility(View.VISIBLE);
- mMenuBtn.setVisibility(View.VISIBLE);
- }
拉出或收回通知栏中,就可以调用这个函数来显示或隐藏这几个按钮。
修改文件: statusBarService.java
view plain
copy to clipboard
print
?
- void performExpand() {
- if (SPEW) Log.d(TAG, "performExpand: mExpanded=" + mExpanded);
- if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
- return ;
- }
- if (mExpanded) {
- return;
- }
-
- // It seems strange to sometimes not expand...
- if (false) {
- synchronized (mNotificationData) {
- if (mNotificationData.size() == 0) {
- return;
- }
- }
- }
-
- mExpanded = true;
- makeExpandedVisible();
- mStatusBarView.hiddenHotIcons(); // Changed!!!
- updateExpandedViewPos(EXPANDED_FULL_OPEN);
-
- if (false) postStartTracing();
- }
-
- void performCollapse() {
- if (SPEW) Log.d(TAG, "performCollapse: mExpanded=" + mExpanded
- + " mExpandedVisible=" + mExpandedVisible);
-
- if (!mExpandedVisible) {
- return;
- }
- mExpandedVisible = false;
- panelSlightlyVisible(false);
- mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
- mTrackingView.setVisibility(View.GONE);
-
- mStatusBarView.showHotIcons(); // Changed!!!!
- if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
- setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
- }
- setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
-
- if (!mExpanded) {
- return;
- }
- mExpanded = false;
- }