Androidのステータスバーにmenu,home,backショートカットキーを追加する方法


説明しなければならないのは、androidを手に入れたばかりで、まだシステムに詳しくないので、この文章は前の投稿に基づいています.ただ、彼の方法は少し面倒だと思っています.そして、変えた効果も私が望んでいるものではありません.
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に3つのimage viewを追加しました
<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>

このようにするメリットは簡単です.同時に、右端がホームボタンであり、左端がbackボタンであり、本来の制約を受けないことを保証します.これでstatus barにこれらのボタンが表示されます.アイコンの位置は、paddingRight、paddingLeft、paddingTopの値を変更することで最適な視覚効果を得ることができます.
2.status barの高さを変更します.
status barにいくつかのボタンを追加する以上、もちろんタッチ操作を使いたいのですが、androidが持参したstatus barの高さが小さすぎて適用されません.7インチスクリーンの場合、50 pixelの高さはあまり差がないはずです.高さを修正するのは簡単で、私が回ったshinning mmの博文のようです.frameworks/base/core/res/res/values/dimensを変更します.xmlのstatus_bar_Height属性50 dipもちろんtitleの高さを変更するとFrameworks/base/core/res/res/values/themesを変更することができる.xmlのWindow attributesのwindowTitleSize値ですが、必要ないと思いますが、変更するとかえって面白くありません:)
コンパイルを実行します.
~/donut$ source ./env.sh
~/donut$ make –j8
~/donut$ emulator –skin WVGA800

ステータスバーが変わったかどうか見てみましょうか?
2ボタンにダイナミックエフェクトを追加する
ダイナミックエフェクトを追加すると、hilightをタッチして押したり、放したり、外したりして回復する動作です.これはframeworks/base/services/java/com/android/server/status/statusBarViewを変更します.JAvaが実現しました.
1.statusbarに新しく追加されたiconのhandlerを取得します.
クラスに新たに3人のメンバーを追加します(import android.widget.ImageView;):
	ImageView mHomeIcon;
	ImageView mBackIcon;
	ImageView mMenuIcon;

同時に3つの定数を増やして、これらのiconに対応するキー値を表します(これはimport 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;;

onFinishInflate()で、実際のオブジェクトを取得します.
		mHomeIcon = (ImageView)findViewById(R.id.status_home);
		mBackIcon = (ImageView)findViewById(R.id.status_back);
		mMenuIcon = (ImageView)findViewById(R.id.status_menu);

この3つのオブジェクトは私たちがstatusにいることです.bar.xmlに追加されました.
2.タッチ処理を追加します.まず、そのアイコンが押されたと判断すべきで、これはStatusBarViewにあります.JavaのonTouchEventで判断します.ここで、私は小さなボタン状態をして、押したり、弾いたり、移動したりする動作を簡単に処理しました.まず、2つのステータスメンバーを追加します.
	int mResvKeyState = -1;  //         , -1    。
	int mResvKeyCode  = -1;  //        ,-1    。

これで私のonTouchEventはこうなりました.
@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;
    }

ここで使用する2つのprivateメソッドは、以下のように簡単に実現されます.
	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関数も変更しました.
    @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を追加するには、まずframework/base/core/java/android/content/intentにintentを追加します.JAvaで追加
    @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を送信する動作を加える.
Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("keycode",   mResvKeyCode);
mService.sendIntent(intent);

このintentは登録された受信者のみが受信できます.ここでは、このintentをStatusBarServiceで送信します.
StatusBarServicesでJAvaには、次の方法が追加されました.
    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動作に追加します.
            else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {
				Log.d(TAG, "Received ACTION_ICONKEY_CHANGED");
                updateIconKeyAction(intent);
            }

メソッドupdateIconKeyActionの定義は次のとおりです.
	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、
~/donut$ source ./env.sh
~/donut$ make update-api
~/donut$ make –j8
~/donut$ emulator –skin WVGA800

またphoneでなければStatusBarPolicy.JAvaではすべてのphoneに関する処理を削除します.
テキストリンク:http://disanji.net/2011/04/13/android-statusbar-menu-home-back-shortkey/