2015年5月24日 星期日

監聽耳機硬體鍵事件

出處:http://blog.csdn.net/shineflowers/article/details/44857549

在工作​​中,我們有時候會處理到耳機按鍵的邏輯,主要分為兩類,一種是短按,一種是長按。

監聽耳機的按鍵事件的方法有兩種:

方法一:註冊監聽Media Button的按鍵事件
此方法即使程式在背景情況下或鎖屏情況下,按線控耳機按鈕依然可控制歌曲播放。

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;

public class MainActivity extends Activity {

private AudioManager mAudioManager;
private ComponentName mComponentName;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// AudioManager註冊一個MediaButton對象
mComponentName = new ComponentName(getPackageName(), MediaButtonReceiver.class.getName());
}



@Override
protected void onResume() {
mAudioManager.registerMediaButtonEventReceiver(mComponentName); //註冊
registerReceiver(headSetReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); 
//註冊
super.onResume();
}

@Override
protected void onPause() { 


//取消註冊,但若要背景下依然可控制歌曲播放的話,這兩項務必要移除掉。
mAudioManager.unregisterMediaButtonEventReceiver(mComponentName);
unregisterReceiver(headSetReceiver);
super.onPause();
}

@Override
protected void onDestroy() {
mAudioManager = null;
mComponentName = null;
super.onDestroy();
}

private final BroadcastReceiver headSetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
// phone headset plugged
if (intent.getIntExtra("state", 0) == 1) {
// do something
// Log.d(TAG, "耳機檢測:插入");
// Toast.makeText(context, "耳機檢測:插入", Toast.LENGTH_SHORT) .show();
mAudioManager.registerMediaButtonEventReceiver(mComponentName);
// phone head unplugged
} else {
// do something
// Log.d(TAG, "耳機檢測:没有插入");
// Toast.makeText(context, "耳機檢測:没有插入", Toast.LENGTH_SHORT).show();

mAudioManager.unregisterMediaButtonEventReceiver(mComponentName);
}
}
}
};



MediaButtonReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;

public class MediaButtonReceiver extends BroadcastReceiver {

private static String TAG = "MediaButtonReceiver";

@Override
public void onReceive(Context context, Intent intent) {
獲得
// 獲得Action
String intentAction = intent.getAction();
// KeyEvent對象 
KeyEvent keyEvent = (KeyEvent) intent
.getParcelableExtra(Intent.EXTRA_KEY_EVENT);

Log.i(TAG, "Action ---->" + intentAction + " KeyEvent----->" + keyEvent.toString());
// 按下 / 鬆開 按鈕 
int keyAction = keyEvent.getAction();

if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)
&& (KeyEvent.ACTION_DOWN == keyAction)) {
// 獲得按鍵字結碼 
int keyCode = keyEvent.getKeyCode();

// 獲得事件的時間
// long downtime = keyEvent.getEventTime();

// 獲得按件碼 keyCode
// StringBuilder sb = new StringBuilder();
//這些都是可能的按鍵碼,打印出來用戶按下的鍵
// if (KeyEvent.KEYCODE_MEDIA_NEXT == keyCode) {
// sb.append("KEYCODE_MEDIA_NEXT");
// }
// 說明:當我們按下MEDIA_BUTTON中間按鈕時,實際出發的是KEYCODE_HEADSETHOOK 而不是
// KEYCODE_MEDIA_PLAY_PAUSE

if (KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE == keyCode) {
// sb.append("KEYCODE_MEDIA_PLAY_PAUSE");

}
if (KeyEvent.KEYCODE_HEADSETHOOK == keyCode) {
// sb.append("KEYCODE_HEADSETHOOK");
}
if (KeyEvent.KEYCODE_MEDIA_PREVIOUS == keyCode) {
// sb.append("KEYCODE_MEDIA_PREVIOUS");
}
if (KeyEvent.KEYCODE_MEDIA_STOP == keyCode) {
// sb.append("KEYCODE_MEDIA_STOP");
}
//輸出點擊的按鍵碼
// Log.i(TAG, sb.toString());
// Toast.makeText(context, sb.toString(), Toast.LENGTH_SHORT).show();

} else if (KeyEvent.ACTION_UP == keyAction) {
Log.i("chengjie", "aaa");
}
}
}
注意,在AndroidManifest.xml中定義

<receiver android:name="com.lenovo.longexposure.MediaButtonReceiver" >
<intent-filter android:priority="2147483647" >
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>


注意這種方法只能監聽耳機的短按事件,如果想監聽長按事件,請用方法二。

方法二:直接監聽onKeyDown方法



@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.KEYCODE_HEADSETHOOK == keyCode) { //按下了耳機鍵
if (event.getRepeatCount() == 0) { //如果長按的话,getRepeatCount值會一值變大
//短按
} else {
//長按
}
}
}

--------------------------------分隔線-------------------------------------------------------------------

BroadcastReceiver基本使用方法:

BroadcastReceiver用於監聽被廣播的事件(Intent)

為了達到這個目的,BroadcastReceiver必須進行註冊,註冊方法有以下2種:

1. 在AndroidManifest.xml當中進行註冊

2. 在應用程式的代碼當中進行註冊

第一種方法:

activity_test.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.testbroadcastreceiver.TestActivity" >

    <Button
        android:id="@+id/sendButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="sendBroadcaster" />

</RelativeLayout>


TestActivity.java :

public class TestActivity extends Activity {

private Button sendButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);

sendButton = (Button) findViewById(R.id.sendButton);
sendButton.setOnClickListener(new BroadcastListener());
}

class BroadcastListener implements OnClickListener {

@Override
public void onClick(View v) {
System.out.println("發送intent");
    //宣告一個intent,把需要用到的廣播裝入intent再送出給Receive
    //,讓Receiver根據收到的廣播來處理自訂要做的事
Intent intent = new Intent();
intent.setAction(Intent.ACTION_EDIT);
TestActivity.this.sendBroadcast(intent);

}
}
}

TestReceiver.java:

public class TestReceiver extends BroadcastReceiver{

public TestReceiver(){
System.out.println("啟動TestReceiver");
}

@Override
public void onReceive(Context context, Intent intent) {
System.out.println("執行OnReceiver");
}

}

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testbroadcastreceiver"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".TestActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
     
          在這裡寫入TestReceiver,並把廣播動作都寫進去。
        <receiver android:name=".TestReceiver">
<intent-filter>
   <action android:name="android.intent.action.EDIT"/>
</intent-filter>            
        </receiver>
     
    </application>

</manifest>

執行結果:

發送intent

啟動TestReceiver

執行OnReceiver

第二種方法:

1 註冊BroadcastReceiver:

registerReceiver(receiver,filter);

2 取消註冊BroadcastReceiver(receiver);

如果一個BroadcastReceiver用於更新UI,那麼通常會使用這種方法進行註冊

在Activity啟動的時候註冊BroadcastReceiver,在Activity被摧毀以後取消註冊

activity_test.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.testbroadcastreceiver.TestActivity" >

    <Button
        android:id="@+id/registerButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="regBroadcaster" />

       <Button
        android:id="@+id/unregisterButton"
        android:layout_width="wrap_content"
        android:layout_below="@+id/registerButton"
        android:layout_height="wrap_content"
        android:text="UnBroadcaster" />
   
</RelativeLayout>

TestActivity.java:

public class TestActivity extends Activity {

private Button registerButton;
private Button unregisterButton;
private SMSReceiver smsReceiver = null ;
private static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);

registerButton = (Button) findViewById(R.id.registerButton);
unregisterButton = (Button) findViewById(R.id.unregisterButton);
registerButton.setOnClickListener(new RegisterButtonListener());
unregisterButton.setOnClickListener(new UnRegisterButtonListener());
}

class RegisterButtonListener implements OnClickListener {

@Override
public void onClick(View v) {
smsReceiver = new SMSReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(SMS_ACTION);
TestActivity.this.registerReceiver(smsReceiver, filter);
System.out.println("註冊廣播");
}
}

class UnRegisterButtonListener implements OnClickListener {

@Override
public void onClick(View v) {

System.out.println("取消註冊");


}
}
}

BroadcastReceiver.java

public class SMSReceiver extends BroadcastReceiver{

public SMSReceiver(){
System.out.println("啟動TestReceiver");
}

@Override
public void onReceive(Context context, Intent intent) {
System.out.println("執行OnReceiver");
}

}

當到DDMS的Emulator Control去記一封訊息,模擬器會收到訊息