android.hardware提供了距离感应器监听器,通过注册监听,来判断是否靠近听筒。
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()) {
// 如果耳机已插入,设置距离传感器失效
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()) {
// 用户远离听筒,音频外放,亮屏
changeToSpeaker();
if (DEBUG) {
Log.i(TAG, "onSensorChanged: 外放");
}
} else {
MediaManager.reStart();
// 用户贴近听筒,切换音频到听筒输出,并且熄屏防误触
changeToReceiver();
if (DEBUG) {
Log.i(TAG, "onSensorChanged: 听筒");
}
audioManager.setSpeakerphoneOn(false);
}
} else {
// 音频播放完了
changeToSpeaker();
}
}
MediaManager是播放器单例,维护了一个MediaPlayer,用来重新处理播放器。
Android切换听筒时,不同于IOS手机,Android会有延时,所以建议切换听筒
前,让音频重新播放。
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();
}
}
}
当靠近听筒后,通过PowerManager来熄灭屏幕,以免误触
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);
}
/**
* 切换到耳机模式
*/
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);
}
当手机插入耳机,不做任何操作。
判断是否插入耳机,isWiredHeadsetOn()已过时,根据版本采用最新的判断方式
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();
}
}
通过LifecycleObserver绑定Activity的生命周期,释放资源
//可以监听生命周期
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);
//可以监听生命周期
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;
}
/**
* 注册距离感应器监听器,监测用户是否靠近手机听筒
*/
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()) {
// 如果耳机已插入,设置距离传感器失效
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()) {
// 用户远离听筒,音频外放,亮屏
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);
}
/**
* 切换到耳机模式
*/
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;
}
}
}
网友评论