在Android 2.3状态栏中添加menu,home和back快捷键的方法
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/packages/SystemUI/res/drawable/目录下
同时,在frameworks/base/packages/SystemUI/res/drawable 下创建三个imageButton的xml文件
xml_stat_home.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <selector
3. xmlns:android="http://schemas.android.com/apk/res/android">
4. <item
5. android:state_focused="true"
6. android:state_pressed="false"
7. android:drawable="@drawable/stat_home" />
8. <item
9. android:state_focused="true"
10. android:state_pressed="true"
11. android:drawable="@drawable/stat_home_pressed" />
12. <item
13. android:state_focused="false"
14. android:state_pressed="true"
15. android:drawable="@drawable/stat_home_pressed" />
16. <item
17. android:drawable="@drawable/stat_home" />
18. </selector>
xml_stat_back.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <selector
3. xmlns:android="http://schemas.android.com/apk/res/android">
4. <item
5. android:state_focused="true"
6. android:state_pressed="false"
7. android:drawable="@drawable/stat_back" />
8. <item
9. android:state_focused="true"
10. android:state_pressed="true"
11. android:drawable="@drawable/stat_back_pressed" />
12. <item
13. android:state_focused="false"
14. android:state_pressed="true"
15. android:drawable="@drawable/stat_back_pressed" />
16. <item
17. android:drawable="@drawable/stat_back" />
18. </selector>
xml_stat_menu.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <selector
3. xmlns:android="http://schemas.android.com/apk/res/android">
4. <item
5. android:state_focused="true"
6. android:state_pressed="false"
7. android:drawable="@drawable/stat_menu" />
8. <item
9. android:state_focused="true"
10. android:state_pressed="true"
11. android:drawable="@drawable/stat_menu_pressed" />
12. <item
13. android:state_focused="false"
14. android:state_pressed="true"
15. android:drawable="@drawable/stat_menu_pressed" />
16. <item
17. android:drawable="@drawable/stat_menu" />
18. </selector>
修改status_bar.xml成如下
目录:frameworks/base/packages/SystemUI/res/layout/status_bar.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <!--
3. /* apps/common/assets/default/default/skins/StatusBar.xml
4. **
5. ** Copyright 2006, The Android Open Source Project
6. **
7. ** Licensed under the Apache License, Version 2.0 (the "License");
8. ** you may not use this file except in compliance with the License.
9. ** You may obtain a copy of the License at
10. **
11. ** http://www.apache.org/licenses/LICENSE-2.0
12. **
13. ** Unless required by applicable law or agreed to in writing, software
14. ** distributed under the License is distributed on an "AS IS" BASIS,
15. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16. ** See the License for the specific language governing permissions and
17. ** limitations under the License.
18. */
19. -->
20.
21. <!-- android:background="@drawable/status_bar_closed_default_background" -->
22. <com.android.systemui.statusbar.StatusBarView
23. xmlns:android="http://schemas.android.com/apk/res/android"
24. android:background="@drawable/statusbar_background"
25. android:orientation="vertical"
26. android:focusable="true"
27. android:descendantFocusability="afterDescendants"
28. >
29.
30. <LinearLayout android:id="@+id/icons"
31. android:layout_width="match_parent"
32. android:layout_height="match_parent"
33. android:orientation="horizontal">
34. <com.android.systemui.statusbar.IconMerger android:id="@+id/notificationIcons"
35. android:layout_width="0dip"
36. android:layout_weight="1"
37. android:layout_height="match_parent"
38. android:layout_alignParentLeft="true"
39. android:paddingLeft="6dip"
40. android:gravity="center_vertical"
41. android:orientation="horizontal"/>
42.
43. <LinearLayout android:id="@+id/statusIcons"
44. android:layout_width="wrap_content"
45. android:layout_height="match_parent"
46. android:layout_alignParentRight="true"
47. android:paddingRight="6dip"
48. android:gravity="center_vertical"
49. android:orientation="horizontal"/>
50. <ImageButton android:id="@+id/go_home"
51. android:layout_width="32px"
52. android:layout_height="32px"
53. android:layout_alignParentLeft="true"
54. android:paddingLeft="10dip"
55. android:paddingTop="10dip"
56. android:gravity="center_vertical"
57. android:clickable="true"
58. android:background="@drawable/xml_stat_home"
59. />
60. <ImageButton android:id="@+id/pop_menu"
61. android:layout_width="32px"
62. android:layout_height="32px"
63. android:layout_alignParentRight="true"
64. android:paddingLeft="10dip"
65. android:paddingTop="10dip"
66. android:gravity="center_vertical"
67. android:orientation="horizontal"
68. android:clickable="true"
69. android:background="@drawable/xml_stat_menu"
70. />
71. <ImageButton android:id="@+id/go_back"
72. android:layout_width="32px"
73. android:layout_height="32px"
74. android:layout_alignParentRight="true"
75. android:paddingLeft="10dip"
76. android:paddingTop="10dip"
77. android:gravity="center_vertical"
78. android:orientation="horizontal"
79. android:clickable="true"
80. android:background="@drawable/xml_stat_back"
81. />
82. <com.android.systemui.statusbar.Clock
83. android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
84. android:layout_width="wrap_content"
85. android:layout_height="match_parent"
86. android:singleLine="true"
87. android:paddingRight="6dip"
88. android:gravity="center_vertical|left"
89. />
90. </LinearLayout>
91.
92. <LinearLayout android:id="@+id/ticker"
93. android:layout_width="match_parent"
94. android:layout_height="match_parent"
95. android:paddingLeft="6dip"
96. android:animationCache="false"
97. android:orientation="horizontal" >
98. <ImageSwitcher android:id="@+id/tickerIcon"
99. android:layout_width="wrap_content"
100. android:layout_height="match_parent"
101. android:layout_marginRight="8dip"
102. >
103. <com.android.systemui.statusbar.AnimatedImageView
104. android:layout_width="25dip"
105. android:layout_height="25dip"
106. />
107. <com.android.systemui.statusbar.AnimatedImageView
108. android:layout_width="25dip"
109. android:layout_height="25dip"
110. />
111. </ImageSwitcher>
112. <com.android.systemui.statusbar.TickerView android:id="@+id/tickerText"
113. android:layout_width="0dip"
114. android:layout_weight="1"
115. android:layout_height="wrap_content"
116. android:paddingTop="2dip"
117. android:paddingRight="10dip">
118. <TextView
119. android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
120. android:layout_width="match_parent"
121. android:layout_height="wrap_content"
122. android:singleLine="true"
123. />
124. <TextView
125. android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
126. android:layout_width="match_parent"
127. android:layout_height="wrap_content"
128. android:singleLine="true"
129. />
130. </com.android.systemui.statusbar.TickerView>
131. </LinearLayout>
132.
133. <com.android.systemui.statusbar.DateView android:id="@+id/date"
134. android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
135. android:layout_width="wrap_content"
136. android:layout_height="match_parent"
137. android:singleLine="true"
138. android:gravity="center_vertical|left"
139. android:paddingLeft="6px"
140. android:paddingRight="6px"
141. android:background="@drawable/statusbar_background"
142. />
143. </com.android.systemui.statusbar.StatusBarView>
二 为按钮添加动态效果
修改frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
在类中新增加四个成员(须导入android.widget.ImageButton和android.content.Context):
1. ImageButton mHomeBtn;
2. ImageButton mBackBtn;
3. ImageButton mMenuBtn;
4. final Context mContext;
增加三个常量:(须导入android.view.KeyEvent;)
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;;
在构造函数StatusBarView中初始化mContext
1. public StatusBarView(Context context, AttributeSet attrs) {
2. super(context, attrs);
3. mContext=context;
4. }
注意”mContext=context;”须在”super(context, attrs);”后面,不然编译会报错
在onFinishInflate中,获取几个button 的handler,并设置touch事件,添加如下代码:
1. mHomeBtn = (ImageButton)findViewById(R.id.go_home);
2. mBackBtn = (ImageButton)findViewById(R.id.go_back);
3. mMenuBtn = (ImageButton)findViewById(R.id.pop_menu);
4.
5. mHomeBtn.setOnTouchListener(homeOnTouch);
6. mBackBtn.setOnTouchListener(backOnTouch);
7. mMenuBtn.setOnTouchListener(menuOnTouch);
各button的touch事件添加如下:
1. voidsendIntent(Intentintent)
2. {
3. mContext.sendBroadcast(intent);
4. }
5. private void sendKeyIntent(int keycode){
6. Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);
7. intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
8. intent.putExtra("keycode", keycode);
9. sendIntent(intent);
10. }
11.
12. private OnTouchListener homeOnTouch = new OnTouchListener(){
13. //@Override
14. public boolean onTouch(View v, MotionEvent event)
15. {
16. // TODO Auto-generated method stub
17. switch (event.getAction()) {
18. case MotionEvent.ACTION_UP:
19. {
20. sendKeyIntent(RESV_KEY_HOME);
21. }
22. break;
23. }
24. return false;
25. }
26. };
27.
28. private OnTouchListener backOnTouch = new OnTouchListener(){
29. //@Override
30. public boolean onTouch(View v, MotionEvent event)
31. {
32. // TODO Auto-generated method stub
33. switch (event.getAction()) {
34. case MotionEvent.ACTION_UP:
35. {
36. sendKeyIntent(RESV_KEY_BACK);
37. }
38. break;
39. }
40. return false;
41. }
42. };
43.
44. private OnTouchListener menuOnTouch = new OnTouchListener(){
45. //@Override
46. public boolean onTouch(View v, MotionEvent event)
47. {
48. // TODO Auto-generated method stub
49. switch (event.getAction()) {
50. case MotionEvent.ACTION_UP:
51. {
52. sendKeyIntent(RESV_KEY_MENU);
53. }
54. break;
55. }
56. return false;
57. }
58. };
为防止点击statusBar上的按钮, 触发标题栏的expend事件, 修改一下函数onInterceptTouchEvent,点击到不属于button区域时才允许解析Motion的event:
1. public boolean onInterceptTouchEvent(MotionEvent event) {
2. if( (event.getX() > mHomeBtn.getRight())
3. && (event.getX() < mMenuBtn.getLeft())){
4. return mService.interceptTouchEvent(event)
5. ? true : super.onInterceptTouchEvent(event);
6. }
7. return false;
8. //return mService.interceptTouchEvent(event)
9. // ? true : super.onInterceptTouchEvent(event);
10. }
11. }
需要自己添加Intent
打开frameworks/base/core/java/android/content/Intent.java,增加下面的内容,由于我们的使用的API不公开,须加上/**@hide*/,不然编译会报错
1. /**
2. * @hide
3. */
4. public static final String ACTION_ICONKEY_CHANGED ="android.intent.action.ICONKEY_CHANGED";
5.
接收并处理intent
修改StatusBarPolicy.java
目录:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
首先在构造函数中加入Intent的filter,注册号这个intent的receiver。
filter.addAction(Intent.ACTION_ICONKEY_CHANGED);
接着在private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() 加入Intent的receiver动作;
1. else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {
2. Log.d(TAG, "Received ACTION_ICONKEY_CHANGED");
3. updateIconKeyAction(intent);
4. }
及处理函数:
须导入以下包
import android.view.IWindowManager;
import android.os.SystemClock;
import android.view.KeyEvent;
1. private final void updateIconKeyAction(Intent intent){
2. int keycode = intent.getIntExtra("keycode", -1);
3. IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
4.
5. if(keycode != -1){
6. long now = SystemClock.uptimeMillis();
7.
8. KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0);
9. KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0);
10.
11. try {
12. wm.injectKeyEvent(down, false);
13. }catch (RemoteException e) {
14. Log.i("Input", "DeadOjbectException");
15. }
16.
17. try{
18. wm.injectKeyEvent(up, false);
19. }catch(RemoteException e) {
20. Log.i("Input", "DeadOjbectException");
21. }
22. }
23. }
StatusBar通知栏屏蔽按钮
当拉出expand的通知栏时,按钮的响应非常慢,这时最好将按钮给屏蔽掉,我们在 statusBarView.java中增加两个方法:
1. public void hiddenHotIcons(){
2. mHomeBtn.setVisibility(View.INVISIBLE);
3. mBackBtn.setVisibility(View.INVISIBLE);
4. mMenuBtn.setVisibility(View.INVISIBLE);
5. }
6.
7. public void showHotIcons(){
8. mHomeBtn.setVisibility(View.VISIBLE);
9. mBackBtn.setVisibility(View.VISIBLE);
10. mMenuBtn.setVisibility(View.VISIBLE);
11. }
拉出或收回通知栏中,就可以调用这个函数来显示或隐藏这几个按钮。
修改文件: statusBarService.java
目录:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
1. void performExpand() {
2. if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
3. if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
4. return ;
5. }
6. if (mExpanded) {
7. return;
8. }
9. mExpanded = true;
10. makeExpandedVisible();
11. mStatusBarView.hiddenHotIcons();
12. updateExpandedViewPos(EXPANDED_FULL_OPEN);
13. if (false) postStartTracing();
14. }
15. void performCollapse() {
16. if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
17. + " mExpandedVisible=" + mExpandedVisible
18. + " mTicking=" + mTicking);
19.
20. if (!mExpandedVisible) {
21. return;
22. }
23. mExpandedVisible = false;
24. visibilityChanged(false);
25. mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
26. mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
27. mExpandedDialog.getWindow().setAttributes(mExpandedParams);
28. mTrackingView.setVisibility(View.GONE);
29. mExpandedView.setVisibility(View.GONE);
30.
31. mStatusBarView.showHotIcons();
32.
33. if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
34. setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
35. }
36. if (mDateView.getVisibility() == View.VISIBLE) {
37. setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
38. }
39.
40. if (!mExpanded) {
41. return;
42. }
43. mExpanded = false;
44. }
编译工程
#source /opt/android_froyo_smdk/build/envsetup.sh
#export TARGET_PRODUCT=full_smdkv210
#mmm frameworks/base/
把编译生成的相关文件放进SD卡对应的目录即可, 在伟研科技 WY-S5PV210开发板上的效果如下图