android.hardware提供了距離感應(yīng)器監(jiān)聽器定欧,通過(guò)注冊(cè)監(jiān)聽,來(lái)判斷是否靠近聽筒怒竿。
private void registerProximitySensorListener() {
if (getActivity() == null) {
return;
}
sensorManager = (SensorManager) getActivity().getSystemService(SENSOR_SERVICE);
if (sensorManager == null) {
return;
}
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (audioManager == null) {
return;
}
if (isHeadphonesPlugged()) {
// 如果耳機(jī)已插入砍鸠,設(shè)置距離傳感器失效
return;
}
if (DEBUG) {
Log.i(TAG, "onSensorChanged: " + MediaManager.isPlaying() + " event.values[0]: " + event.values[0]);
}
if (MediaManager.isPlaying()) {
// 如果音頻正在播放
float distance = event.values[0];
if (distance >= sensor.getMaximumRange()) {
// 用戶遠(yuǎn)離聽筒,音頻外放耕驰,亮屏
changeToSpeaker();
if (DEBUG) {
Log.i(TAG, "onSensorChanged: 外放");
}
} else {
MediaManager.reStart();
// 用戶貼近聽筒爷辱,切換音頻到聽筒輸出,并且熄屏防誤觸
changeToReceiver();
if (DEBUG) {
Log.i(TAG, "onSensorChanged: 聽筒");
}
audioManager.setSpeakerphoneOn(false);
}
} else {
// 音頻播放完了
changeToSpeaker();
}
}
MediaManager是播放器單例朦肘,維護(hù)了一個(gè)MediaPlayer,用來(lái)重新處理播放器托嚣。
Android切換聽筒時(shí),不同于IOS手機(jī)厚骗,Android會(huì)有延時(shí),所以建議切換聽筒
前兢哭,讓音頻重新播放领舰。
public static void reStart() {
if (mPlayer != null) {
try {
mPlayer.seekTo(0);
mPlayer.start();
} catch (Exception e) {
if (DEBUG) {
Log.i(TAG, "reStart: " + e.getMessage());
}
e.printStackTrace();
}
}
}
當(dāng)靠近聽筒后,通過(guò)PowerManager來(lái)熄滅屏幕迟螺,以免誤觸
private PowerManager.WakeLock wakeLock;
private final PowerManager mPowerManager;
private void setScreenOff() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Log.i(TAG, "setScreenOff: 熄滅屏幕");
if (wakeLock == null) {
wakeLock = mPowerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
}
wakeLock.acquire(10 * 60 * 1000L /*10 minutes*/);
}
}
private void setScreenOn() {
if (wakeLock != null) {
wakeLock.setReferenceCounted(false);
wakeLock.release();
wakeLock = null;
}
}
切換聽筒和外放
/**
* 切換到外放
*/
public void changeToSpeaker() {
setScreenOn();
if (audioManager == null) {
return;
}
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.setSpeakerphoneOn(true);
}
/**
* 切換到耳機(jī)模式
*/
public void changeToHeadset() {
if (audioManager == null) {
return;
}
audioManager.setSpeakerphoneOn(false);
}
/**
* 切換到聽筒
*/
public void changeToReceiver() {
setScreenOff();
if (audioManager == null) {
return;
}
audioManager.setSpeakerphoneOn(false);
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
當(dāng)手機(jī)插入耳機(jī)冲秽,不做任何操作。
判斷是否插入耳機(jī)矩父,isWiredHeadsetOn()已過(guò)時(shí)锉桑,根據(jù)版本采用最新的判斷方式
private boolean isHeadphonesPlugged() {
if (audioManager == null) {
return false;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
AudioDeviceInfo[] audioDevices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
for (AudioDeviceInfo deviceInfo : audioDevices) {
if (deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
|| deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
return true;
}
}
return false;
} else {
return audioManager.isWiredHeadsetOn();
}
}
通過(guò)LifecycleObserver綁定Activity的生命周期,釋放資源
//可以監(jiān)聽生命周期
if (getActivity() != null) {
getActivity().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
sensorManager.unregisterListener(this);
sensorManager = null;
wakeLock = null;
mActivity = null;
}
綜上窍株,代碼如下
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
import android.os.PowerManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import java.lang.ref.WeakReference;
import static android.content.Context.POWER_SERVICE;
import static android.content.Context.SENSOR_SERVICE;
/**
* Created by walkingMen on 2018/12/24.
*/
public class AudioSensorBinder implements LifecycleObserver, SensorEventListener {
private final AudioManager audioManager;
private final PowerManager mPowerManager;
@Nullable
private WeakReference<AppCompatActivity> mActivity;
private SensorManager sensorManager;
private Sensor sensor;
private PowerManager.WakeLock wakeLock;
public AudioSensorBinder(@NonNull AppCompatActivity activity) {
mActivity = new WeakReference<>(activity);
//可以監(jiān)聽生命周期
if (getActivity() != null) {
getActivity().getLifecycle().addObserver(this);
}
audioManager = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
mPowerManager = (PowerManager) activity.getSystemService(POWER_SERVICE);
registerProximitySensorListener();
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
sensorManager.unregisterListener(this);
sensorManager = null;
wakeLock = null;
mActivity = null;
}
/**
* 注冊(cè)距離感應(yīng)器監(jiān)聽器民轴,監(jiān)測(cè)用戶是否靠近手機(jī)聽筒
*/
private void registerProximitySensorListener() {
if (getActivity() == null) {
return;
}
sensorManager = (SensorManager) getActivity().getSystemService(SENSOR_SERVICE);
if (sensorManager == null) {
return;
}
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
private AppCompatActivity getActivity() {
if (mActivity != null) {
return mActivity.get();
}
return null;
}
private static final String TAG = "AudioSensorBinder";
@Override
public void onSensorChanged(SensorEvent event) {
if (audioManager == null) {
return;
}
if (isHeadphonesPlugged()) {
// 如果耳機(jī)已插入,設(shè)置距離傳感器失效
return;
}
if (DEBUG) {
Log.i(TAG, "onSensorChanged: " + MediaManager.isPlaying() + " event.values[0]: " + event.values[0]);
}
if (MediaManager.isPlaying()) {
// 如果音頻正在播放
float distance = event.values[0];
if (distance >= sensor.getMaximumRange()) {
// 用戶遠(yuǎn)離聽筒球订,音頻外放后裸,亮屏
changeToSpeaker();
if (DEBUG) {
Log.i(TAG, "onSensorChanged: 外放");
}
} else {
MediaManager.reStart();
// 用戶貼近聽筒,切換音頻到聽筒輸出冒滩,并且熄屏防誤觸
changeToReceiver();
if (DEBUG) {
Log.i(TAG, "onSensorChanged: 聽筒");
}
audioManager.setSpeakerphoneOn(false);
}
} else {
// 音頻播放完了
changeToSpeaker();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private boolean isHeadphonesPlugged() {
if (audioManager == null) {
return false;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
AudioDeviceInfo[] audioDevices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
for (AudioDeviceInfo deviceInfo : audioDevices) {
if (deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
|| deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
return true;
}
}
return false;
} else {
return audioManager.isWiredHeadsetOn();
}
}
/**
* 切換到外放
*/
public void changeToSpeaker() {
setScreenOn();
if (audioManager == null) {
return;
}
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.setSpeakerphoneOn(true);
}
/**
* 切換到耳機(jī)模式
*/
public void changeToHeadset() {
if (audioManager == null) {
return;
}
audioManager.setSpeakerphoneOn(false);
}
/**
* 切換到聽筒
*/
public void changeToReceiver() {
setScreenOff();
if (audioManager == null) {
return;
}
audioManager.setSpeakerphoneOn(false);
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
private void setScreenOff() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Log.i(TAG, "setScreenOff: 熄滅屏幕");
if (wakeLock == null) {
wakeLock = mPowerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
}
wakeLock.acquire(10 * 60 * 1000L /*10 minutes*/);
}
}
private void setScreenOn() {
if (wakeLock != null) {
wakeLock.setReferenceCounted(false);
wakeLock.release();
wakeLock = null;
}
}
}