近期接到一个要求,在手及连接到多个蓝牙设备时(如蓝牙耳机、蓝牙音箱等),其中一个断开后,能够自动切换掉另外一个蓝牙设备的连接。
此方案为framwork层的修改。
在/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
中有一个监听蓝牙设备断开和连接的方法。
private class AudioManagerAudioDeviceCallback extends AudioDeviceCallback {
361 private boolean isWiredAudioHeadset(AudioDeviceInfo deviceInfo) {
362 switch (deviceInfo.getType()) {
363 case AudioDeviceInfo.TYPE_WIRED_HEADSET:
364 case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
365 case AudioDeviceInfo.TYPE_USB_HEADSET:
366 return true;
367 default:
368 break;
369 }
370 return false;
371 }
372
373 @Override
374 public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
375 if (DBG) {
376 Log.d(TAG, "onAudioDevicesAdded");
377 }
378 boolean hasAddedWiredDevice = false;
379 for (AudioDeviceInfo deviceInfo : addedDevices) {
380 if (DBG) {
381 Log.d(TAG, "Audio device added: " + deviceInfo.getProductName() + " type: "
382 + deviceInfo.getType());
383 }
384 if (isWiredAudioHeadset(deviceInfo)) {
385 hasAddedWiredDevice = true;
386 break;
387 }
388 }
389 if (hasAddedWiredDevice) {
390 wiredAudioDeviceConnected();
391 }
392 }
393
394 @Override
395 public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
396 }
397 }
所以我们就可以在监听蓝牙断开的地方添加我们想要进行的操作。
@Override
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
// No need to switch when setting Bluetooth devices to inactive state
for (BluetoothDevice mA2dpConnectedDevice : mA2dpConnectedDevices) {
if (mA2dpConnectedDevice.getAddress().equals(removedDevices[0].getAddress())) return;
}
// removedDevices 为被移除的蓝牙数组
// 判断手机是否还存在其他的蓝牙连接,以及是否插入耳机,因为耳机的优先级较高,插入耳机时保持默认行为即可。
if (mA2dpConnectedDevices.size() != 0 && !(mAudioManager.isWiredHeadsetOn())) {
// 判断是否在通话模式,因为在通话时蓝牙通路的切换方法有所不同,
// 在通话时应由通话服务去切换(试过setA2dpActiveDevice在通话时不起作用)
// 非通话时主要由AudioManager去管理 ,通话时由CallAudioManager管理。
if (mAudioManager.getMode() == AudioManager.MODE_IN_CALL) {
// BluetoothInCallService继承的InCallServices,调用父类的方法,
//也就是requestBluetoothAudio() 方法,切换蓝牙通路。这里最终会调用到CallAudioManager.setAudioRoute()里面
BluetoothInCallService.getInstance().requestBluetoothAudio(mA2dpConnectedDevices.get(0));
}else {
// 此方法用于一般情况下将已连接的蓝牙变为活动状态。此方法就在这个类定义的
// ,可以自己研究具体的流程。mA2dpConnectedDevices为已连接设备的集合。
setA2dpActiveDevice(mA2dpConnectedDevices.get(0));
}
}
}
如果想要去切换扬声器,或者听筒也是可以的。可以调用
BluetoothInCallService.getInstance().setAudioRoute(int route)
BluetoothInCallService.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
BluetoothInCallService.getInstance().setAudioRoute(CallAudioState.ROUTE_EARPIECE);
/** Direct the audio stream through the device's earpiece. */
public static final int ROUTE_EARPIECE = 0x00000001;
/** Direct the audio stream through Bluetooth. */
public static final int ROUTE_BLUETOOTH = 0x00000002;
/** Direct the audio stream through a wired headset. */
public static final int ROUTE_WIRED_HEADSET = 0x00000004;
/** Direct the audio stream through the device's speakerphone. */
public static final int ROUTE_SPEAKER = 0x00000008;
/**
* Direct the audio stream through the device's earpiece or wired headset if one is
* connected.
*/
public static final int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
/**
* Bit mask of all possible audio routes.
*
* @hide
**/
public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
ROUTE_SPEAKER;