在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.
void
sendIntent
(
Intent
intent
)
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开发板上的效果如下图