Be Smart

FANTAISIE

SmartPhone - iPhone, iPad, Android

My Links

Blog Stats

News

[Android 問題] How to Add Virtual Keys on Status Bar?

How to add virtual keys on status bar?

(for the version before Froyo) 

 

There are 6 .png for touch up and touch down of 3 buttons

Put 72 dpi and 48 dpi which can be found in Google native source code into

 

frameworks/base/core/res/res/drawable-hdpi

frameworks/base/core/res/res/drawable-mdpi

 

respectively (P.S. it has xhdpi for supporting tablet device in Gingerbread)

 

(in Gingerbread the directory has been changed to frameworks/base/packages/SystemUI/res/... )

 

and add 3 ImageView in frameworks/base/core/res/res/layout/status_bar.xml

status_search, status_back, and status_menu

 

<ImageView android:id="@+id/status_search"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="top"
  android:paddingTop="1dip"
  android:src="@drawable/search"/>
 <ImageView android:id="@+id/status_back"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="top"
  android:paddingTop="1dip"
  android:src="@drawable/back"/>
 <ImageView android:id="@+id/status_menu"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="top"
  android:paddingTop="1dip"
  android:src="@@drawable/menu"/>

  

in frameworks/base/core/res/res/value/dimens.xml

you can simply change the height of status bar by assigning

 

<!-- Height of the status bar -->
    <dimen name="status_bar_height">34dip</dimen>

 

in frameworks/base/services/java/com/android/server/status/StatusBarView.java

(in Gingerbread the directory has been changed to frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/... )

add

 

//ImageView for virtual key

    ImageView mSearchIcon;
    ImageView mBackIcon;
    ImageView mMenuIcon;

//KeyEevent set

    public static final int RESV_KEY_SEARCH = KeyEvent.KEYCODE_SEARCH;
    public static final int RESV_KEY_BACK = KeyEvent.KEYCODE_BACK;
    public static final int RESV_KEY_MENU = KeyEvent.KEYCODE_MENU;

//Handle touch event

    int mResvKeyState = -1;
    int mResvKeyCode = -1;

 

in protected void onFinishInflate() {}

add

 

//ImageView for virtual key

 mSearchIcon = (ImageView)findViewById(R.id.status_search);
 mBackIcon = (ImageView)findViewById(R.id.status_back);
 mMenuIcon = (ImageView)findViewById(R.id.status_menu);

in public boolean onTouchEvent(MotionEvent event) {}

add

 

//Added

 if(mResvKeyState == -1){
  switch(getResvKeyArea(event)){
  case RESV_KEY_SEARCH:
  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);
  }
  break;
  } 
 }
 else{
  mResvKeyState = event.getAction();
  
  if(mResvKeyState == MotionEvent.ACTION_MOVE){
   if(mResvKeyCode != getResvKeyArea(event)){
   updateResvKeyIcon(MotionEvent.ACTION_UP, mResvKeyCode);

   mResvKeyCode = -1;
   mResvKeyState = -1;
   }
  }
  else if (mResvKeyState == MotionEvent.ACTION_UP){
   updateResvKeyIcon(mResvKeyState, mResvKeyCode);
   
   Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);  
   intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);  
   intent.putExtra("keycode",   mResvKeyCode);  
   mService.sendIntent(intent); 


   mResvKeyCode = -1;
   mResvKeyState = -1;
  }
  else{
   Slog.d(TAG, "error");
  }

 

Add 2 private functions

 

 //Private methods

    private int getResvKeyArea(MotionEvent event){
 if((event.getX() >= mSearchIcon.getLeft() && event.getX() <= mSearchIcon.getRight())
 && (event.getY() <= this.getHeight())){
  return RESV_KEY_SEARCH;
 }
 else if((event.getX() >= mBackIcon.getLeft() && event.getX() <= mBackIcon.getRight())
 && (event.getY() <= this.getHeight())){
  return RESV_KEY_BACK;
 }
 else if((event.getX() >= mMenuIcon.getLeft() && event.getX() <= mMenuIcon.getRight())
 && (event.getY() <= this.getHeight())){
  return RESV_KEY_MENU;
 }
 else
  return -1;
    }

    //Private methods added
    private int updateResvKeyIcon(int state, int key){
 if(key == RESV_KEY_SEARCH){
  if(state == MotionEvent.ACTION_UP){
  mSearchIcon.setImageResource(com.android.internal.R.drawable.search);
  }
  else if(state == MotionEvent.ACTION_DOWN){
  mSearchIcon.setImageResource(com.android.internal.R.drawable.search_pressed);
  }
 }
 else if(key == RESV_KEY_BACK){
  if(state == MotionEvent.ACTION_UP){
  mBackIcon.setImageResource(com.android.internal.R.drawable.back);
  }
  else if(state == MotionEvent.ACTION_DOWN){
  mBackIcon.setImageResource(com.android.internal.R.drawable.back_pressed);
  }
 }
 else if(key == RESV_KEY_MENU){
  if(state == MotionEvent.ACTION_UP){
  mMenuIcon.setImageResource(com.android.internal.R.drawable.menu);
  }
  else if(state == MotionEvent.ACTION_DOWN){
  mMenuIcon.setImageResource(com.android.internal.R.drawable.menu_pressed);
  }
 }
 return 0;
    }

  

Change public boolean onInterceptTouchEvent(MotionEvent event) {} to

  

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

 

in  frameworks/base/core/java/android/content/intent.java

add our new intent 

 

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)   

public static final String ACTION_ICONKEY_CHANGED = "android.intent.action.ICONKEY_CHANGED";

 

in  frameworks/base/services/java/com/android/server/status/StatusBarService.java

add

//function added

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

in  frameworks/base/services/java/com/android/server/status/StatusBaPolicy.java

find the field where to add registration for intents and add

//Action added

   filter.addAction(Intent.ACTION_ICONKEY_CHANGED);
       mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);

in private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {}

add

//added

     else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {   
     updateIconKeyAction(intent);
     }

 

add our private function

 

 //added

 private final void updateIconKeyAction(Intent intent){   
   int keycode = intent.getIntExtra("keycode", -1);  

   if(keycode != -1){   
     long now = SystemClock.suptimeMillis();  

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

 

Done

 

Remember to make update-api to update frameworks/base/api/current.xml and see if our intent is already added

 

<field name="ACTION_ICONKEY_CHANGED"
 type="java.lang.String"
 transient="false"
 volatile="false"
 value="&quot;android.intent.action.ICONKEY_CHANGED&quot;"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>

 

Result

posted on 2011-01-25 16:50 FANTAISIE 阅读(...) 评论(...) 编辑 收藏