在status bar 新增加 home,menu, return 按钮

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

Frameworks/base/core/res/res/drawable

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

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

这些图片为:

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 barlayerout文件:

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

在原来的linearlayout中新增三个image view

 

  1. <LinearLayout android:id="@+id/icons"  
  2.     android:layout_width="fill_parent"  
  3.     android:layout_height="fill_parent"  
  4.     android:orientation="horizontal">  
  5.   
  6.           <ImageView android:id="@+id/status_home"  
  7.                  android:layout_width="wrap_content"  
  8.                  android:layout_height="wrap_content"  
  9.                  android:layout_gravity="top"  
  10.                  android:paddingTop="6dip"  
  11.                  android:paddingRight="10dip"  
  12.                  android:paddingLeft="10dip"  
  13.                  android:src="@drawable/stat_home" />  
  14.   
  15.     <com.android.server.status.IconMerger android:id="@+id/notificationIcons"  
  16.         android:layout_width="0dip"  
  17.         android:layout_weight="1"  
  18.         android:layout_height="fill_parent"  
  19.         android:layout_alignParentLeft="true"  
  20.         android:paddingLeft="6dip"  
  21.         android:gravity="center_vertical"  
  22.         android:orientation="horizontal"/>    
  23.           
  24.     <LinearLayout android:id="@+id/statusIcons"  
  25.         android:layout_width="wrap_content"  
  26.         android:layout_height="fill_parent"  
  27.         android:layout_alignParentRight="true"  
  28.         android:paddingRight="6dip"  
  29.         android:gravity="center_vertical"  
  30.         android:orientation="horizontal"/>      
  31.   
  32.           <ImageView android:id="@+id/status_menu"  
  33.                  android:layout_width="wrap_content"  
  34.                  android:layout_height="wrap_content"  
  35.                  android:layout_gravity="top"  
  36.                  android:paddingTop="6dip"  
  37.                  android:paddingLeft="10dip"  
  38.                  android:paddingRight="10dip"  
  39.                  android:src="@drawable/stat_menu" />  
  40.   
  41.           <ImageView android:id="@+id/status_back"  
  42.                  android:layout_width="wrap_content"  
  43.                  android:layout_height="wrap_content"  
  44.                  android:layout_gravity="top"  
  45.                  android:paddingTop="6dip"  
  46.                  android:paddingRight="10dip"  
  47.                  android:paddingLeft="10dip"  
  48.                  android:src="@drawable/stat_back" />  
  49.   
  50. /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.xmlstatus_bar_height属性

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

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

当然,如果相改title的高度,可以修改 Frameworks/base/core/res/res/values/themes.xml中的Window attributeswindowTitleSize值,不过我觉得没必要,改了反倒不好看了 :)

 

编译运行一下:

 

  1. ~/donut$ source ./env.sh  
  2. ~/donut$ make –j8  
  3. ~/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中新增加的iconhandler

 

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

 

  1. ImageView mHomeIcon;  
  2. ImageView mBackIcon;  
  3. ImageView mMenuIcon;  

ImageView mHomeIcon; ImageView mBackIcon; ImageView mMenuIcon;

      

同时增加三个常量,表示这些icon对应的键值(这需要import android.view.KeyEvent;)

 

  1. public static final int RESV_KEY_HOME = KeyEvent.KEYCODE_HOME;  
  2. public static final int RESV_KEY_BACK = KeyEvent.KEYCODE_BACK;  
  3. 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()中,获得实际的对象:

  1. mHomeIcon = (ImageView)findViewById(R.id.status_home);  
  2. mBackIcon = (ImageView)findViewById(R.id.status_back);  
  3. 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.JavaonTouchEvent中来判断。

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

首先增加两个状态成员:

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

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

    

 

这样我的onTouchEvent就变成这样了:

  1. @Override  
  2.    public boolean onTouchEvent(MotionEvent event) {  
  3.     if(mService.mExpanded==true || mService.mTracking==true){  
  4.        if (event.getAction() != MotionEvent.ACTION_DOWN) {  
  5.            mService.interceptTouchEvent(event);  
  6.        }  
  7.         return true;  
  8.     }  
  9.   
  10.     if(mResvKeyState == -1) // remembered key state, no reserve  
  11.     {  
  12.         switch(getResvKeyArea(event)){  
  13.             case RESV_KEY_HOME:  
  14.             case RESV_KEY_BACK:  
  15.             case RESV_KEY_MENU:  
  16.             {  
  17.                 mResvKeyState = event.getAction();  
  18.                 mResvKeyCode  = getResvKeyArea(event);  
  19.   
  20.                 updateResvKeyIcon(mResvKeyState, mResvKeyCode);  
  21.             }  
  22.             break;  
  23.               
  24.             default:  
  25.             if (event.getAction() != MotionEvent.ACTION_DOWN) {  
  26.                 mService.interceptTouchEvent(event);  
  27.             }  
  28.         }  
  29.     }else{  
  30.         mResvKeyState = event.getAction(); // new state  
  31.           
  32.         if(mResvKeyState == MotionEvent.ACTION_MOVE){  
  33.             if(mResvKeyCode != getResvKeyArea(event)){  
  34.                 /* out of bound, resume the icon */  
  35.                 updateResvKeyIcon(MotionEvent.ACTION_UP, mResvKeyCode);  
  36.                   
  37.                 mResvKeyCode  = -1;  
  38.                 mResvKeyState = -1;  
  39.             }  
  40.         }else if(mResvKeyState == MotionEvent.ACTION_UP){  
  41.             updateResvKeyIcon(mResvKeyState, mResvKeyCode);  
  42.             mResvKeyCode  = -1;  
  43.             mResvKeyState = -1;  
  44.         }else{  
  45.             Log.d(TAG, "state machine error! Never be here!");  
  46.         }  
  47.     }  
  48.       
  49.        return true;  
  50.    }  

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

  1. private int getResvKeyArea(MotionEvent event)  
  2. {  
  3.     if(  (event.getX() <= mHomeIcon.getRight())  
  4.       && (event.getY() <= this.getHeight()) ){  
  5.         return RESV_KEY_HOME;  
  6.     }  
  7.     else if(  (event.getX() >= mBackIcon.getLeft())  
  8.       && (event.getY() <= this.getHeight()) ){  
  9.         return RESV_KEY_BACK;  
  10.     }  
  11.     else if(  (event.getX() >= mMenuIcon.getLeft())  
  12.       && (event.getY() <= this.getHeight()) ){  
  13.         return RESV_KEY_MENU;  
  14.     }else  
  15.         return -1;  
  16. }  
  17.   
  18. private int updateResvKeyIcon(int state, int key)  
  19. {  
  20.     if(key == RESV_KEY_BACK){  
  21.         if(state == MotionEvent.ACTION_UP){  
  22.             mBackIcon.setImageResource(com.android.internal.R.drawable.stat_back);  
  23.         }else if(state == MotionEvent.ACTION_DOWN){  
  24.             mBackIcon.setImageResource(com.android.internal.R.drawable.stat_back_pressed);  
  25.         }  
  26.     }else if(key == RESV_KEY_HOME){  
  27.         if(state == MotionEvent.ACTION_UP){  
  28.             mHomeIcon.setImageResource(com.android.internal.R.drawable.stat_home);  
  29.         }else if(state == MotionEvent.ACTION_DOWN){  
  30.             mHomeIcon.setImageResource(com.android.internal.R.drawable.stat_home_pressed);  
  31.         }  
  32.     }else if(key == RESV_KEY_MENU){  
  33.         if(state == MotionEvent.ACTION_UP){  
  34.             mMenuIcon.setImageResource(com.android.internal.R.drawable.stat_menu);  
  35.         }else if(state == MotionEvent.ACTION_DOWN){  
  36.             mMenuIcon.setImageResource(com.android.internal.R.drawable.stat_menu_pressed);  
  37.         }  
  38.     }  
  39.       
  40.     return 0;  
  41. }  

 2.3中,用systemUI  APK来管理界面,  这样直接用R.drawable.stat_menu_pressed来索引就可以了。

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

  1.  @Override  
  2.  public boolean onInterceptTouchEvent(MotionEvent event) {  
  3.     if(  (event.getX() > mHomeIcon.getRight())  
  4.  &&  (event.getX() < mMenuIcon.getLeft())){  
  5.         return mService.interceptTouchEvent(event)  
  6.              ? true : super.onInterceptTouchEvent(event);  
  7.     }  
  8.   
  9.     return false;  
  10. }  

 

再编译一下,看一下结果 : 是不是能动了?

 

三,添加相应事件

 

1. 添加新的intent

首先是新增一条intent framework/base/core/java/android/content/intent.java中增加

 

 

view plain copy to clipboard print ?
    /**
     * @hide
     */
  1. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)  
  2. public static final String ACTION_ICONKEY_CHANGED = "android.intent.action.ICONKEY_CHANGED";  

添加hide 标志,表示是系统内部intent,不向外公布  不需要make -api


 如果不想进行make -api

2. 发送intent 

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

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

在窗帘下拉时, ANR。针对测试结果,此时将back键转为home键来操作。

                Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);           
                if(mService.mExpanded == true){
                    switch(mResvKeyCode){
                    case KeyEvent.KEYCODE_BACK:
                        mResvKeyCode = KeyEvent.KEYCODE_HOME;
                        intent.putExtra("keycode",   mResvKeyCode);       
                        mService.sendIntent(intent);
                        break;
                    case KeyEvent.KEYCODE_MENU:
                        break;
                    case KeyEvent.KEYCODE_HOME:
                        intent.putExtra("keycode",   mResvKeyCode);       
                        mService.sendIntent(intent);
                    default:
                        break;
                    }   
                } else {
                    intent.putExtra("keycode",   mResvKeyCode);
                    mService.sendIntent(intent);
                }
                


 

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

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

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

  1. void sendIntent(Intent intent)  
  2. {  
  3.     mContext.sendBroadcast(intent);  
  4. }  

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

注:
2.3中有所更改:
    public void sendIntent(Intent intent) {
        // TODO Auto-generated method stub
        StatusBarService.this.sendBroadcast(intent);
    }

3.接收并处理intent

这个就要修改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. G, "Received ACTION_ICONKEY_CHANGED");  
  3.     updateIconKeyAction(intent);  
  4. }  

方法updateIconKeyAction的定义如下:

 

  1. private final void updateIconKeyAction(Intent intent){  
  2.     int     keycode = intent.getIntExtra("keycode", -1);  
  3.   
  4.     if(keycode != -1){  
  5.         long now = SystemClock.uptimeMillis();  
  6.   
  7.         try {  
  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.             (IWindowManager.Stub  
  11.                 .asInterface(ServiceManager.getService("window")))  
  12.                 .injectKeyEvent(down, false);  
  13.             (IWindowManager.Stub  
  14.                 .asInterface(ServiceManager.getService("window")))  
  15.                 .injectKeyEvent(up, false);  
  16.         } catch (RemoteException e) {  
  17.             Log.i("Input", "DeadOjbectException");  
  18.         }  
  19.               
  20.     }  
  21. }  

这样,基本上就完成了。

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

  1. ~/donut$ source ./env.sh  
  2. ~/donut$ make update-api  
  3. ~/donut$ make –j8  //交叉编译看不到编译的顺序
  4. ~/donut$ emulator –skin WVGA800  

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
The programme should have the following features: ● A menu including Open and Exit where Open starts a JFileChooser to select the file with the questions inside and Exit ends the programme. ● Once a file is loaded, the GUI should display one question and its answers at a time. ● The user should be able to select an answer and they should be informed if they were correct or not. ● The user should be made aware of the number of correctly answered and the total number of questions answered. ● The user should only be able to proceed to the next question once they answered the current one. ● Once all questions have been answered, the user should be informed of their overall score and that the game has finished. The Open menu item should now be enabled to start a new quiz. Optionally, you can add a restart menu item to redo the current quiz. Concrete sub-tasks: a) define a class called Question to hold a single question, i.e. the text, the possible answers, and the correct answer index; (0.25P) b) write a method to select a file via a JFileChooser and to read all the questions from that file into an array/list of Question objects (assume that file has the structure mentioned above); (0.25P) c) design and implement a GUI with the components mentioned above: A menu, ability to display the question and answers, ability to select an answer, show the outcome and score, and proceed to the next question. (Appropriate layout: 1P, Class extends JFrame: 0.25P, Class follows OOP principles: 0.25P, Global set-up in main method: 0.25P)1 d) write a method to display a question on the GUI you designed; (0.25P) e) implement an actionPerformed method to respond to user interactions with the GUI. Make sure to enable and disable interactive components as required, e.g. the user should not be able to skip to the next question without selecting an answer first and they should not be able to load a new quiz before finishing the current one;
05-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值