android statusbar 的修改

原创 2012年03月23日 17:41:45

由于完全改了status bar,建议先做几张png图片,加到

Frameworks/base/core/res/res/drawable
下。最好做一张背景图,替换 statusbar_background.png

另外我又加了几张icon,分别是home menu和back的正常和按下状态。

这些图片为:
frameworks\base\core\res\res\drawable\ic_menu_back_pressed.png
frameworks\base\core\res\res\drawable\ic_menu_home_pressed.png
frameworks\base\core\res\res\drawable\ic_menu_more_pressed.png
frameworks\base\core\res\res\drawable\ic_volume_down_pressed.png
frameworks\base\core\res\res\drawable\ic_volume_up_pressed.png
frameworks\base\core\res\res\drawable\ic_menu_back.png
frameworks\base\core\res\res\drawable\ic_menu_home.png
frameworks\base\core\res\res\drawable\ic_menu_more.png
frameworks\base\core\res\res\drawable\ic_volume_down.png
frameworks\base\core\res\res\drawable\ic_volume_up.png

修改步骤为:

一.修改xml界面
1.创建按钮
frameworks\base\core\res\res\drawable\btn_sbicon_back.xml
frameworks\base\core\res\res\drawable\btn_sbicon_home.xml
frameworks\base\core\res\res\drawable\btn_sbicon_menu.xml
frameworks\base\core\res\res\drawable\btn_sbicon_vol_down.xml
frameworks\base\core\res\res\drawable\btn_sbicon_vol_up.xml
基结构如下:
<?xml version="1.0"encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_pressed="true"android:drawable="@drawable/ic_menu_back_pressed"/>
   <item android:state_pressed="false"android:drawable="@drawable/ic_menu_back" />
</selector>

2. 增加图标
更改整个status bar,我的方法是:
修改status bar的layerout文件:
Frameworks/base/core/res/res/layout/status_bar.xml
在原来的linearlayout中新增 image view

<?xml version="1.0"encoding="utf-8"?>
<com.android.server.status.StatusBarViewxmlns:android="http://schemas.android.com/apk/res/android"
   android:background="@drawable/statusbar_background"
   android:orientation="vertical"
   android:focusable="true"
   android:descendantFocusability="afterDescendants"
   >
   <LinearLayout android:id="@+id/keys"
       android:layout_width="wrap_content"
       android:layout_height="fill_parent"
       android:orientation="horizontal">
    <ImageView android:id="@+id/status_home"
     android:layout_width="40dip"
     android:layout_height="40dip"
     android:clickable="true"
     android:layout_gravity="top"
     android:paddingTop="1dip"
     android:paddingRight="1dip"
     android:paddingLeft="1dip"
     android:src="@drawable/btn_sbicon_home" />
    <ImageView android:id="@+id/status_back"
     android:layout_width="40dip"
     android:layout_height="40dip"
     android:clickable="true"
     android:layout_gravity="top"
     android:paddingTop="1dip"
     android:paddingRight="1dip"
     android:paddingLeft="1dip"
     android:src="@drawable/btn_sbicon_back" />
    <ImageView android:id="@+id/status_menu"
     android:layout_width="40dip"
     android:layout_height="40dip"
     android:clickable="true"
     android:layout_gravity="top"
     android:paddingTop="1dip"
     android:paddingRight="1dip"
     android:paddingLeft="1dip"
     android:src="@drawable/btn_sbicon_menu" />
    <ImageView android:id="@+id/status_vol_down"
     android:layout_width="40dip"
     android:layout_height="40dip"
     android:clickable="true"
     android:layout_gravity="top"
     android:paddingTop="1dip"
     android:paddingRight="1dip"
     android:paddingLeft="1dip"
     android:src="@drawable/btn_sbicon_vol_down" />
    <ImageView android:id="@+id/status_vol_up"
     android:layout_width="40dip"
     android:layout_height="40dip"
     android:clickable="true"
     android:layout_gravity="top"
     android:paddingTop="1dip"
     android:paddingRight="1dip"
     android:paddingLeft="1dip"
     android:src="@drawable/btn_sbicon_vol_up" />
   </LinearLayout>
   ......
</com.android.server.status.StatusBarView>
这样做的好处就是简单。同时保证home、menu、back按钮,不受它本来的约束。这样statusbar上即可看到这些按钮了。
图标的位置,可通过修改 paddingRight, paddingLeft 和paddingTop的值达到最佳视觉效果。

3. 修改status bar的高度。
既然要在status bar上增加那么几个按钮,当然是想要使用触摸操作的,android自带的statusbar高度太小,不适用。对于7寸屏的话,50pixel的高度应该是差不多了。
修改高度很简单,修改frameworks/base/core/res/res/values/dimens.xml的status_bar_height属性
   <!-- Height of the status bar-->
   <dimenname="status_bar_height">50dip</dimen>

也可以更改状态栏Icon的大小,frameworks\base\core\res\res\layout\status_bar_icon.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="25dp"
   android:layout_height="25dp"   >

当然,如果相改title的高度,可以修改Frameworks/base/core/res/res/values/themes.xml中的Windowattributes的windowTitleSize值

编译运行一下:


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

看状态栏是不是改变了?


二 为按钮添加模拟按键
修改frameworks\base\services\java\com\android\server\status\StatusBarView.java

1.添加各个图片按钮的引用,
android.widget.LinearLayout keysLayout;
android.widget.ImageView btnHome;
android.widget.ImageView btnBack;
android.widget.ImageView btnMenu;
android.widget.ImageView btnVolUp;
android.widget.ImageView btnVolDown;

2.修改onFinishInflate()函数,各个图片ID在上面的status_bar.xml中已经定义
@Override
protected void onFinishInflate() {
  ......   
   
    keysLayout =(android.widget.LinearLayout)findViewById(R.id.keys);
    btnHome =(android.widget.ImageView)findViewById(R.id.status_home);
    btnBack =(android.widget.ImageView)findViewById(R.id.status_back);
    btnMenu =(android.widget.ImageView)findViewById(R.id.status_menu);
    btnVolUp =(android.widget.ImageView)findViewById(R.id.status_vol_up);
    btnVolDown =(android.widget.ImageView)findViewById(R.id.status_vol_down);
   btnHome.setOnClickListener(mKeysListener);
   btnBack.setOnClickListener(mKeysListener);
   btnMenu.setOnClickListener(mKeysListener);
   btnVolUp.setOnClickListener(mKeysListener);
   btnVolDown.setOnClickListener(mKeysListener);
   
}

3.添加各个按钮的事件监听Listener
android.view.View.OnClickListener mKeysListener = newandroid.view.View.OnClickListener(){
public void onClick(View v) {
switch (v.getId()) {
case R.id.status_home:
  mKeysHandler.sendEmptyMessage(KEY_HOME);
   break;
case R.id.status_back:
  mKeysHandler.sendEmptyMessage(KEY_BACK);
   break;
case R.id.status_menu:
  mKeysHandler.sendEmptyMessage(KEY_MENU);
   break;
case R.id.status_vol_up:
  mKeysHandler.sendEmptyMessage(KEY_VOL_UP);
   break;
case R.id.status_vol_down:
  mKeysHandler.sendEmptyMessage(KEY_VOL_DOWN);
   break;
default:
   break;
}
}};

4.添加模拟按键处理

private static final int KEY_HOME = 1000;
private static final int KEY_BACK = 1001;
private static final int KEY_MENU = 1002;
private static final int KEY_VOL_UP = 1003;
private static final int KEY_VOL_DOWN = 1004;
private Handler mKeysHandler = new Handler(){
public void handleMessage(Message msg) {
   switch (msg.what) {
case KEY_HOME:
  sendKey(KeyEvent.KEYCODE_HOME);
   break;
case KEY_BACK:
  sendKey(KeyEvent.KEYCODE_BACK);
   break;
case KEY_MENU:
  sendKey(KeyEvent.KEYCODE_MENU);
   break;
case KEY_VOL_UP:
  ((android.media.AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE))
  .adjustVolume(android.media.AudioManager.ADJUST_RAISE,android.media.AudioManager.STREAM_MUSIC);
   break;
case KEY_VOL_DOWN:
  ((android.media.AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE))
  .adjustVolume(android.media.AudioManager.ADJUST_LOWER,android.media.AudioManager.STREAM_MUSIC);
   break;
default:
   break;
}
}

  private void sendKey(finalint keyCode) {
   //加此线程主要是为了后面的Thread.sleep(100),因为StatusBar在模拟按键的时候会先产生TouchEvent,如果此处不做延时,则模拟按键会与StatusBarView的Touch事件在消息队列中产生一个死锁
   Thread t =new Thread(){ 
    publicvoid run() {
     try{
      Thread.sleep(100);
     }catch (InterruptedException e1) {
      e1.printStackTrace();
     }
     longnow = SystemClock.uptimeMillis();
     longn = System.currentTimeMillis();
     Log.d("Tiger","Intent.ACTION_SOFT_" + keyCode+"_PRESSED   0=" + n);
     try{
      KeyEventdown = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode,0);
      KeyEventup = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0);
      Log.d("Tiger","Intent.ACTION_SOFT_" + keyCode+"_PRESSED   1="+(System.currentTimeMillis()));
      IWindowManagerwm =IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
      Log.d("Tiger","Intent.ACTION_SOFT_" + keyCode+"_PRESSED   2="+(System.currentTimeMillis()));
      wm.injectKeyEvent(down,false);
      Log.d("Tiger","Intent.ACTION_SOFT_" + keyCode+"_PRESSED   3="+(System.currentTimeMillis()));
      wm.injectKeyEvent(up,false);
      Log.d("Tiger","Intent.ACTION_SOFT_" + keyCode+"_PRESSED   4="+(System.currentTimeMillis()));
     }catch (RemoteException e) {
      Log.i("Input","DeadOjbectException");
     }
    }
   };
   t.start();
  }
};

 

5.避免在按下这几个按钮时,触发下拉Notification视图,影响性能
修改onInterceptTouchEvent(MotionEvent event)函数
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {

if (keysLayout.getRight() < event.getX())
   returnmService.interceptTouchEvent(event) ? true :super.onInterceptTouchEvent(event);

return false;

}

这样,基本上就完成了。

编译一下

~/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

 

补充:在打开StatusBarExpandView时按模拟按键,会出现停顿的原因分析

我们先看一下执行流程
在com.android.server.WindowManagerService.injectKeyEvent(KeyEvent,boolean)函数中我们可以看到实际上是调用dispatchKey(newEvent, pid,uid)函数,这个dispatchKey函数中:

需要先找到当前的焦点focusObj(focusObj:WindowState 就是在维护窗口ViewRoot与WindowManagerService之前的关联,这二者的通信都在WindowState中可以找到);再用focusObj把KeyEvent传递给当前焦点窗口。但在传递之前会先调用mKeyWaiter.waitForNextEventTarget()函数等待当前焦点处理完上一次事件(这包括KeyEvent,MotionEvent...等),如何判断是否处理完上一次事件,用if (mFinished &&!mDisplayFrozen)   if (targetWin != null)这两个if语句判断,而最关键就是这个mFinished,这里还得查看ViewRoot,在ViewRoot中分发事件后会调用sWindowSession.finishKey(mWindow);告诉WindowManagerService,在doFinishedKeyLocked()函数中将mFinished= true,如果mFinished不为true,则会wait(curTimeout),这就是出现停顿的直接原因

通过打印Log显示是我们的KeyEvent.Action_Down事件一直不能mFinished,这就要跟踪ViewRoot,发现每次在模拟的KeyEvent.Action_Down事件的Message根本不能被处理,原因是StatusBarView的TouchEvent没有处理完成,并且与模拟的KeyEvent.Action_Down事件在MessageQueue的next函数中卡住了而ViewRoot本身就是一个Handler,大量的Message从此经过,而StatusBar的ViewRoot既要处理Touch事件也要处理模拟按键,就出现了这种竞态死锁的现象。

延迟发送模拟的KeyEvent是我目前采用的解决方式,上面的例子中sendKey函数已经体现


相关文章推荐

Android 2.3 修改 statusbar

Android 2.2 和android 2.3 在源码结构上有一些变化:tatusbar 的位置的变化,2.3中 statusbar 的源码在 frameworks/base/packages/Sy...

android 修改statusbar(二)

如何把状态栏从顶部移动到底部; Around line 345 of frameworks/base/services/java/com/android/server/status/Stat...

android 修改statusbar(一)添加home back menu键

由于完全改了status bar,建议先做几张png图片,加到 Frameworks/base/core/res/res/drawable 下。最好做一张背景图,替换 statusbar_...

android statusbar 的修改

由于完全改了status bar,建议先做几张png图片,加到Frameworks/base/core/res/res/drawable下。最好做一张背景图,替换 statusbar_backgrou...

Android4.4修改NavigationBar/StatusBar

最新项目要求修改Navigation/StatusBar,其中涉及到了调整他们的高度等,特地记录下来。 什么是NavigationBar/StatusBar 标记1,我们称之为Status...
  • my9074
  • my9074
  • 2015年03月16日 14:38
  • 1617

android 禁用statusBar demo

  • 2017年08月23日 11:13
  • 211KB
  • 下载

ANDROID STATUSBAR

  • 2014年11月17日 23:03
  • 249KB
  • 下载

Android系统应用---SystemUI之二:Statusbar显示流程以及系统状态图标更新分析

StatusBar概述 状态栏主要用来显示一些系统图标,应用的通知图标和系统时间。Statusbar模块就是控制和管理着这些图标,以及通知信息的显示和一些系统开关的。状态栏在Android手机中位于...

Android踩坑记之沉浸式StatusBar

Android沉浸式StatusBar小总结。
  • Jeongho
  • Jeongho
  • 2016年10月12日 22:12
  • 119
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android statusbar 的修改
举报原因:
原因补充:

(最多只允许输入30个字)