您的位置:首页 > 移动开发 > Android开发

在android的状态栏(statusbar)中增加menu,home和back快捷键的方法

2010-10-27 17:01 429 查看
由于完全改了
status bar

,建议先做几张
png

图片,加到

Frameworks/base/core/res/res/drawable

下。最好做一张背景图,替换
statusbar_background.png

另外我又加了几张
icon

,分别是
home menu


back

的正常和按下状态。

这些图片为:

stat_home.png

stat_home_pressed.png

stat_back.png

stat_back_pressed.png

stat_menu.png

stat_menu_pressed.png

修改步骤为:

一.

修改
xml
界面

1.
增加图标

当然,更改整个
status bar

避免不要要对源码大刀修一下。我的该法是:

修改
status bar


layerout

文件:

Frameworks/base/core/res/res/layout/status_bar.xml

在原来的
linearlayout

中新增三个
image view

view plain
copy to clipboard
print
?

<
LinearLayout

android:id
=
"@+id/icons"

android:layout_width
=
"fill_parent"

android:layout_height
=
"fill_parent"

android:orientation
=
"horizontal"
>

<
ImageView

android:id
=
"@+id/status_home"

android:layout_width
=
"wrap_content"

android:layout_height
=
"wrap_content"

android:layout_gravity
=
"top"

android:paddingTop
=
"6dip"

android:paddingRight
=
"10dip"

android:paddingLeft
=
"10dip"

android:src
=
"@drawable/stat_home"

/>

<
com.android.server.status.IconMerger

android:id
=
"@+id/notificationIcons"

android:layout_width
=
"0dip"

android:layout_weight
=
"1"

android:layout_height
=
"fill_parent"

android:layout_alignParentLeft
=
"true"

android:paddingLeft
=
"6dip"

android:gravity
=
"center_vertical"

android:orientation
=
"horizontal"
/>

<
LinearLayout

android:id
=
"@+id/statusIcons"

android:layout_width
=
"wrap_content"

android:layout_height
=
"fill_parent"

android:layout_alignParentRight
=
"true"

android:paddingRight
=
"6dip"

android:gravity
=
"center_vertical"

android:orientation
=
"horizontal"
/>

<
ImageView

android:id
=
"@+id/status_menu"

android:layout_width
=
"wrap_content"

android:layout_height
=
"wrap_content"

android:layout_gravity
=
"top"

android:paddingTop
=
"6dip"

android:paddingLeft
=
"10dip"

android:paddingRight
=
"10dip"

android:src
=
"@drawable/stat_menu"

/>

<
ImageView

android:id
=
"@+id/status_back"

android:layout_width
=
"wrap_content"

android:layout_height
=
"wrap_content"

android:layout_gravity
=
"top"

android:paddingTop
=
"6dip"

android:paddingRight
=
"10dip"

android:paddingLeft
=
"10dip"

android:src
=
"@drawable/stat_back"

/>

/LinearLayout>

<LinearLayout android:id="@+id/icons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<ImageView android:id="@+id/status_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingTop="6dip"
android:paddingRight="10dip"
android:paddingLeft="10dip"
android:src="@drawable/stat_home" />
<com.android.server.status.IconMerger android:id="@+id/notificationIcons"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:paddingLeft="6dip"
android:gravity="center_vertical"
android:orientation="horizontal"/>

<LinearLayout android:id="@+id/statusIcons"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:paddingRight="6dip"
android:gravity="center_vertical"
android:orientation="horizontal"/>
<ImageView android:id="@+id/status_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingTop="6dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:src="@drawable/stat_menu" />
<ImageView android:id="@+id/status_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingTop="6dip"
android:paddingRight="10dip"
android:paddingLeft="10dip"
android:src="@drawable/stat_back" />
</LinearLayout>


这样做的好处就是简单。同时保证最右端是
home

按钮,最左端是
back

按钮,不受它本来的约束。这样
status bar

上即可看到这些按钮了。

图标的位置,可通过修改
paddingRight


paddingLeft


paddingTop

的值达到最佳视觉效果。



2.

修改
status bar

的高度。

既然要在
status bar

上增加那么几个按钮,当然是想要使用触摸操作的,
android

自带的
status bar

高度太小,不适用。对于
7

寸屏的话,
50pixel

的高度应该是差不多了。

修改高度很简单,如我转的
shinning mm

的博文。

修改
frameworks/base/core/res/res/values/dimens.xml


status_bar_height

属性

<!-- Height of the status bar -->

<dimen name="status_bar_height">50dip</dimen>

当然,如果相改
title

的高度,可以修改
Frameworks

/base/core/res/res/values/themes.xml
中的
Window attributes

windowTitleSize
值,不过我觉得没必要,改了反倒不好看了

:)

编译运行一下:

view plain
copy to clipboard
print
?

~/donut$ source ./env.sh

~/donut$ make –j8

~/donut$ emulator –skin WVGA800

~/donut$ source ./env.sh
~/donut$ make –j8
~/donut$ emulator –skin WVGA800




看状态栏是不是改变了?


为按钮添加动态效果

添加动态效果,就是触摸按下
hilight

,松开或者移出后恢复的动作。这一块,我是通过修改
frameworks/base/services/java/com/android/server/status/StatusBarView.java

实现的。

1.
获取
statusbar
中新增加的
icon

handler

在类中新增加三个成员(这需要
import android.widget.ImageView;

):

view plain
copy to clipboard
print
?

ImageView mHomeIcon;

ImageView mBackIcon;

ImageView mMenuIcon;

ImageView mHomeIcon;
ImageView mBackIcon;
ImageView mMenuIcon;


同时增加三个常量,表示这些
icon

对应的键值
(

这需要
import android.view.KeyEvent;)

view plain
copy to clipboard
print
?

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;;

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()

中,获得实际的对象:

view plain
copy to clipboard
print
?

mHomeIcon = (ImageView)findViewById(R.id.status_home);

mBackIcon = (ImageView)findViewById(R.id.status_back);

mMenuIcon = (ImageView)findViewById(R.id.status_menu);

mHomeIcon = (ImageView)findViewById(R.id.status_home);
mBackIcon = (ImageView)findViewById(R.id.status_back);
mMenuIcon = (ImageView)findViewById(R.id.status_menu);


这三个对象就是我们在
status_bar.xml

中添加的。

2.

添加触摸处理。

首先,应该判断是那个图标被按下,这个我们在
StatusBarView.Java


onTouchEvent

中来判断。

这里,我做了一个小的按键状态,已方便处理按下、弹起和移出的动作。

首先增加两个状态成员:

view plain
copy to clipboard
print
?

int
mResvKeyState = -1;
//记住的上次按键状态, -1为无状态。

int
mResvKeyCode = -1;
//记住的上次按键值,-1为无状态。

int mResvKeyState = -1;  //记住的上次按键状态, -1为无状态。
int mResvKeyCode  = -1;  //记住的上次按键值,-1为无状态。


这样我的
onTouchEvent

就变成这样了:

view plain
copy to clipboard
print
?

@Override

public

boolean
onTouchEvent(MotionEvent event) {

if
(mService.mExpanded==
true
|| mService.mTracking==
true
){

if
(event.getAction() != MotionEvent.ACTION_DOWN) {

mService.interceptTouchEvent(event);

}

return

true
;

}

if
(mResvKeyState == -
1
)
// remembered key state, no reserve

{

switch
(getResvKeyArea(event)){

case
RESV_KEY_HOME:

case
RESV_KEY_BACK:

case
RESV_KEY_MENU:

{

mResvKeyState = event.getAction();

mResvKeyCode = getResvKeyArea(event);

updateResvKeyIcon(mResvKeyState, mResvKeyCode);

}

break
;

default
:

if
(event.getAction() != MotionEvent.ACTION_DOWN) {

mService.interceptTouchEvent(event);

}

}

}else
{

mResvKeyState = event.getAction(); // new state

if
(mResvKeyState == MotionEvent.ACTION_MOVE){

if
(mResvKeyCode != getResvKeyArea(event)){

/* out of bound, resume the icon */

updateResvKeyIcon(MotionEvent.ACTION_UP, mResvKeyCode);

mResvKeyCode = -1
;

mResvKeyState = -1
;

}

}else

if
(mResvKeyState == MotionEvent.ACTION_UP){

updateResvKeyIcon(mResvKeyState, mResvKeyCode);

mResvKeyCode = -1
;

mResvKeyState = -1
;

}else
{

Log.d(TAG, "state machine error! Never be here!"
);

}

}

return

true
;

}

@Override
public boolean onTouchEvent(MotionEvent event) {
if(mService.mExpanded==true || mService.mTracking==true){
if (event.getAction() != MotionEvent.ACTION_DOWN) {
mService.interceptTouchEvent(event);
}
return true;
}
if(mResvKeyState == -1) // remembered key state, no reserve
{
switch(getResvKeyArea(event)){
case RESV_KEY_HOME:
case RESV_KEY_BACK:
case RESV_KEY_MENU:
{
mResvKeyState = event.getAction();
mResvKeyCode  = getResvKeyArea(event);
updateResvKeyIcon(mResvKeyState, mResvKeyCode);
}
break;

default:
if (event.getAction() != MotionEvent.ACTION_DOWN) {
mService.interceptTouchEvent(event);
}
}
}else{
mResvKeyState = event.getAction(); // new state

if(mResvKeyState == MotionEvent.ACTION_MOVE){
if(mResvKeyCode != getResvKeyArea(event)){
/* out of bound, resume the icon */
updateResvKeyIcon(MotionEvent.ACTION_UP, mResvKeyCode);

mResvKeyCode  = -1;
mResvKeyState = -1;
}
}else if(mResvKeyState == MotionEvent.ACTION_UP){
updateResvKeyIcon(mResvKeyState, mResvKeyCode);
mResvKeyCode  = -1;
mResvKeyState = -1;
}else{
Log.d(TAG, "state machine error! Never be here!");
}
}

return true;
}


里面用到的两个private方法简单实现如下:

view plain
copy to clipboard
print
?

private

int
getResvKeyArea(MotionEvent
event
)

{

if
( (
event
.getX() <= mHomeIcon.getRight())

&& (event
.getY() <=
this
.getHeight()) ){

return
RESV_KEY_HOME;

}

else

if
( (
event
.getX() >= mBackIcon.getLeft())

&& (event
.getY() <=
this
.getHeight()) ){

return
RESV_KEY_BACK;

}

else

if
( (
event
.getX() >= mMenuIcon.getLeft())

&& (event
.getY() <=
this
.getHeight()) ){

return
RESV_KEY_MENU;

}else

return
-1;

}

private

int
updateResvKeyIcon(
int
state,
int
key)

{

if
(key == RESV_KEY_BACK){

if
(state == MotionEvent.ACTION_UP){

mBackIcon.setImageResource(com.android.internal
.R.drawable.stat_back);

}else

if
(state == MotionEvent.ACTION_DOWN){

mBackIcon.setImageResource(com.android.internal
.R.drawable.stat_back_pressed);

}

}else

if
(key == RESV_KEY_HOME){

if
(state == MotionEvent.ACTION_UP){

mHomeIcon.setImageResource(com.android.internal
.R.drawable.stat_home);

}else

if
(state == MotionEvent.ACTION_DOWN){

mHomeIcon.setImageResource(com.android.internal
.R.drawable.stat_home_pressed);

}

}else

if
(key == RESV_KEY_MENU){

if
(state == MotionEvent.ACTION_UP){

mMenuIcon.setImageResource(com.android.internal
.R.drawable.stat_menu);

}else

if
(state == MotionEvent.ACTION_DOWN){

mMenuIcon.setImageResource(com.android.internal
.R.drawable.stat_menu_pressed);

}

}

return
0;

}

private int getResvKeyArea(MotionEvent event)
{
if(  (event.getX() <= mHomeIcon.getRight())
&& (event.getY() <= this.getHeight()) ){
return RESV_KEY_HOME;
}
else if(  (event.getX() >= mBackIcon.getLeft())
&& (event.getY() <= this.getHeight()) ){
return RESV_KEY_BACK;
}
else if(  (event.getX() >= mMenuIcon.getLeft())
&& (event.getY() <= this.getHeight()) ){
return RESV_KEY_MENU;
}else
return -1;
}
private int updateResvKeyIcon(int state, int key)
{
if(key == RESV_KEY_BACK){
if(state == MotionEvent.ACTION_UP){
mBackIcon.setImageResource(com.android.internal.R.drawable.stat_back);
}else if(state == MotionEvent.ACTION_DOWN){
mBackIcon.setImageResource(com.android.internal.R.drawable.stat_back_pressed);
}
}else if(key == RESV_KEY_HOME){
if(state == MotionEvent.ACTION_UP){
mHomeIcon.setImageResource(com.android.internal.R.drawable.stat_home);
}else if(state == MotionEvent.ACTION_DOWN){
mHomeIcon.setImageResource(com.android.internal.R.drawable.stat_home_pressed);
}
}else if(key == RESV_KEY_MENU){
if(state == MotionEvent.ACTION_UP){
mMenuIcon.setImageResource(com.android.internal.R.drawable.stat_menu);
}else if(state == MotionEvent.ACTION_DOWN){
mMenuIcon.setImageResource(com.android.internal.R.drawable.stat_menu_pressed);
}
}

return 0;
}


同时,我不想再在按下这些icon的时候,触发下拉动作,我也改了onInterceptTouchEvent函数:

view plain
copy to clipboard
print
?

@Override

public

boolean
onInterceptTouchEvent(MotionEvent event) {

if
( (event.getX() > mHomeIcon.getRight())

&& (event.getX() < mMenuIcon.getLeft())){

return
mService.interceptTouchEvent(event)

? true
:
super
.onInterceptTouchEvent(event);

}

return

false
;

}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if(  (event.getX() > mHomeIcon.getRight())
&&  (event.getX() < mMenuIcon.getLeft())){
return mService.interceptTouchEvent(event)
? true : super.onInterceptTouchEvent(event);
}
return false;
}


再编译一下,看一下结果
:



是不是能动了?



三,添加相应事件

1. 添加新的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"
;

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ICONKEY_CHANGED = "android.intent.action.ICONKEY_CHANGED";


2. 发送intent

在StatusBarView.java的OnKeyEvent中,松开按键的分支else if(mResvKeyState == MotionEvent.ACTION_UP)操作中加入发送intent的动作:

view plain
copy to clipboard
print
?

Intent intent =
new
Intent(Intent.ACTION_ICONKEY_CHANGED);

intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

intent.putExtra("keycode"
, mResvKeyCode);

mService.sendIntent(intent);

Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("keycode",   mResvKeyCode);
mService.sendIntent(intent);


这个intent是只有注册的接收者才能接收。

这里,我们是通过StatusBarService来发送这个intent的。

在StatusBarService.java中新增一个方法:

view plain
copy to clipboard
print
?

void
sendIntent(Intent intent)

{

mContext.sendBroadcast(intent);

}

void sendIntent(Intent intent)
{
mContext.sendBroadcast(intent);
}


3.接收并处理intent

这个就要修改StatusBarPolicy.java了

首先,在构造函数中加入Intent的filter,注册号这个intent的receiver。

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)) {

G, "Received ACTION_ICONKEY_CHANGED"
);

updateIconKeyAction(intent);

}

else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {
Log.d(TAG, "Received ACTION_ICONKEY_CHANGED");
updateIconKeyAction(intent);
}


方法updateIconKeyAction的定义如下:

view plain
copy to clipboard
print
?

private

final

void
updateIconKeyAction(Intent intent){

int
keycode = intent.getIntExtra(
"keycode"
, -
1
);

if
(keycode != -
1
){

long
now = SystemClock.uptimeMillis();

try
{

KeyEvent down = new
KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode,
0
);

KeyEvent up = new
KeyEvent(now, now, KeyEvent.ACTION_UP, keycode,
0
);

(IWindowManager.Stub

.asInterface(ServiceManager.getService("window"
)))

.injectKeyEvent(down, false
);

(IWindowManager.Stub

.asInterface(ServiceManager.getService("window"
)))

.injectKeyEvent(up, false
);

} catch
(RemoteException e) {

Log.i("Input"
,
"DeadOjbectException"
);

}

}

}

private final void updateIconKeyAction(Intent intent){
int     keycode = intent.getIntExtra("keycode", -1);
if(keycode != -1){
long now = SystemClock.uptimeMillis();
try {
KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0);
KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0);
(IWindowManager.Stub
.asInterface(ServiceManager.getService("window")))
.injectKeyEvent(down, false);
(IWindowManager.Stub
.asInterface(ServiceManager.getService("window")))
.injectKeyEvent(up, false);
} catch (RemoteException e) {
Log.i("Input", "DeadOjbectException");
}

}
}


这样,基本上就完成了。

编译一下, 由于新增了一个intent,因此要先make update-api,

view plain
copy to clipboard
print
?

~/donut$ source ./env.sh

~/donut$ make update-api

~/donut$ make –j8

~/donut$ emulator –skin WVGA800

~/donut$ source ./env.sh
~/donut$ make update-api
~/donut$ make –j8
~/donut$ emulator –skin WVGA800


另外,如果不是做phone,也可以在StatusBarPolicy.java中将所有phone相关的处理都删掉。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: