Merge "Bluetooth: Fix HFP SCO logic and documentation" into pi-dev
am: 1ae21127da
Change-Id: I9b4fcac73a283aac1794e13cce464728612fd0dc
This commit is contained in:
committed by
android-build-merger
commit
e3e55b865b
@@ -571,8 +571,8 @@ Landroid/bluetooth/BluetoothHeadset;->connectAudio()Z
|
|||||||
Landroid/bluetooth/BluetoothHeadset;->disconnectAudio()Z
|
Landroid/bluetooth/BluetoothHeadset;->disconnectAudio()Z
|
||||||
Landroid/bluetooth/BluetoothHeadset;->getActiveDevice()Landroid/bluetooth/BluetoothDevice;
|
Landroid/bluetooth/BluetoothHeadset;->getActiveDevice()Landroid/bluetooth/BluetoothDevice;
|
||||||
Landroid/bluetooth/BluetoothHeadset;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
|
Landroid/bluetooth/BluetoothHeadset;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
|
||||||
Landroid/bluetooth/BluetoothHeadset;->startScoUsingVirtualVoiceCall(Landroid/bluetooth/BluetoothDevice;)Z
|
Landroid/bluetooth/BluetoothHeadset;->startScoUsingVirtualVoiceCall()Z
|
||||||
Landroid/bluetooth/BluetoothHeadset;->stopScoUsingVirtualVoiceCall(Landroid/bluetooth/BluetoothDevice;)Z
|
Landroid/bluetooth/BluetoothHeadset;->stopScoUsingVirtualVoiceCall()Z
|
||||||
Landroid/bluetooth/BluetoothHearingAid;->ACTION_ACTIVE_DEVICE_CHANGED:Ljava/lang/String;
|
Landroid/bluetooth/BluetoothHearingAid;->ACTION_ACTIVE_DEVICE_CHANGED:Ljava/lang/String;
|
||||||
Landroid/bluetooth/BluetoothHearingAid;->getActiveDevices()Ljava/util/List;
|
Landroid/bluetooth/BluetoothHearingAid;->getActiveDevices()Ljava/util/List;
|
||||||
Landroid/bluetooth/BluetoothHearingAid;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
|
Landroid/bluetooth/BluetoothHearingAid;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package android.bluetooth;
|
package android.bluetooth;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.RequiresPermission;
|
import android.annotation.RequiresPermission;
|
||||||
import android.annotation.SdkConstant;
|
import android.annotation.SdkConstant;
|
||||||
@@ -633,8 +634,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
|||||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
||||||
*
|
*
|
||||||
* @param device Bluetooth headset
|
* @param device Bluetooth headset
|
||||||
* @return false if there is no headset connected of if the connected headset doesn't support
|
* @return false if there is no headset connected, or the connected headset doesn't support
|
||||||
* voice recognition or on error, true otherwise
|
* voice recognition, or voice recognition is already started, or audio channel is occupied,
|
||||||
|
* or on error, true otherwise
|
||||||
*/
|
*/
|
||||||
public boolean startVoiceRecognition(BluetoothDevice device) {
|
public boolean startVoiceRecognition(BluetoothDevice device) {
|
||||||
if (DBG) log("startVoiceRecognition()");
|
if (DBG) log("startVoiceRecognition()");
|
||||||
@@ -654,10 +656,15 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
|||||||
* Stop Bluetooth Voice Recognition mode, and shut down the
|
* Stop Bluetooth Voice Recognition mode, and shut down the
|
||||||
* Bluetooth audio path.
|
* Bluetooth audio path.
|
||||||
*
|
*
|
||||||
|
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
|
||||||
|
* If this function returns true, this intent will be broadcasted with
|
||||||
|
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
|
||||||
|
*
|
||||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
||||||
*
|
*
|
||||||
* @param device Bluetooth headset
|
* @param device Bluetooth headset
|
||||||
* @return false if there is no headset connected or on error, true otherwise
|
* @return false if there is no headset connected, or voice recognition has not started,
|
||||||
|
* or voice recognition has ended on this headset, or on error, true otherwise
|
||||||
*/
|
*/
|
||||||
public boolean stopVoiceRecognition(BluetoothDevice device) {
|
public boolean stopVoiceRecognition(BluetoothDevice device) {
|
||||||
if (DBG) log("stopVoiceRecognition()");
|
if (DBG) log("stopVoiceRecognition()");
|
||||||
@@ -798,11 +805,12 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if Bluetooth SCO audio is connected.
|
* Check if at least one headset's SCO audio is connected or connecting
|
||||||
*
|
*
|
||||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
||||||
*
|
*
|
||||||
* @return true if SCO is connected, false otherwise or on error
|
* @return true if at least one device's SCO audio is connected or connecting, false otherwise
|
||||||
|
* or on error
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public boolean isAudioOn() {
|
public boolean isAudioOn() {
|
||||||
@@ -821,11 +829,21 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a connection of headset audio.
|
* Initiates a connection of headset audio to the current active device
|
||||||
* It setup SCO channel with remote connected headset device.
|
|
||||||
*
|
*
|
||||||
* @return true if successful false if there was some error such as there is no connected
|
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
|
||||||
* headset
|
* If this function returns true, this intent will be broadcasted with
|
||||||
|
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
|
||||||
|
*
|
||||||
|
* <p> {@link #EXTRA_STATE} will transition from
|
||||||
|
* {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
|
||||||
|
* audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
|
||||||
|
* in case of failure to establish the audio connection.
|
||||||
|
*
|
||||||
|
* Note that this intent will not be sent if {@link BluetoothHeadset#isAudioOn()} is true
|
||||||
|
* before calling this method
|
||||||
|
*
|
||||||
|
* @return false if there was some error such as there is no active headset
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public boolean connectAudio() {
|
public boolean connectAudio() {
|
||||||
@@ -844,11 +862,14 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a disconnection of headset audio.
|
* Initiates a disconnection of HFP SCO audio.
|
||||||
* It tears down the SCO channel from remote headset device.
|
* Tear down voice recognition or virtual voice call if any.
|
||||||
*
|
*
|
||||||
* @return true if successful false if there was some error such as there is no connected SCO
|
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
|
||||||
* channel
|
* If this function returns true, this intent will be broadcasted with
|
||||||
|
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
|
||||||
|
*
|
||||||
|
* @return false if audio is not connected, or on error, true otherwise
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public boolean disconnectAudio() {
|
public boolean disconnectAudio() {
|
||||||
@@ -867,22 +888,33 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a SCO channel connection with the headset (if connected).
|
* Initiates a SCO channel connection as a virtual voice call to the current active device
|
||||||
* Also initiates a virtual voice call for Handsfree devices as many devices
|
* Active handsfree device will be notified of incoming call and connected call.
|
||||||
* do not accept SCO audio without a call.
|
|
||||||
* This API allows the handsfree device to be used for routing non-cellular
|
|
||||||
* call audio.
|
|
||||||
*
|
*
|
||||||
* @param device Remote Bluetooth Device
|
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
|
||||||
* @return true if successful, false if there was some error.
|
* If this function returns true, this intent will be broadcasted with
|
||||||
|
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
|
||||||
|
*
|
||||||
|
* <p> {@link #EXTRA_STATE} will transition from
|
||||||
|
* {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
|
||||||
|
* audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
|
||||||
|
* in case of failure to establish the audio connection.
|
||||||
|
*
|
||||||
|
* @return true if successful, false if one of the following case applies
|
||||||
|
* - SCO audio is not idle (connecting or connected)
|
||||||
|
* - virtual call has already started
|
||||||
|
* - there is no active device
|
||||||
|
* - a Telecom managed call is going on
|
||||||
|
* - binder is dead or Bluetooth is disabled or other error
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) {
|
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
|
||||||
|
public boolean startScoUsingVirtualVoiceCall() {
|
||||||
if (DBG) log("startScoUsingVirtualVoiceCall()");
|
if (DBG) log("startScoUsingVirtualVoiceCall()");
|
||||||
final IBluetoothHeadset service = mService;
|
final IBluetoothHeadset service = mService;
|
||||||
if (service != null && isEnabled() && isValidDevice(device)) {
|
if (service != null && isEnabled()) {
|
||||||
try {
|
try {
|
||||||
return service.startScoUsingVirtualVoiceCall(device);
|
return service.startScoUsingVirtualVoiceCall();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, e.toString());
|
Log.e(TAG, e.toString());
|
||||||
}
|
}
|
||||||
@@ -894,19 +926,24 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminates an ongoing SCO connection and the associated virtual
|
* Terminates an ongoing SCO connection and the associated virtual call.
|
||||||
* call.
|
|
||||||
*
|
*
|
||||||
* @param device Remote Bluetooth Device
|
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
|
||||||
* @return true if successful, false if there was some error.
|
* If this function returns true, this intent will be broadcasted with
|
||||||
|
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
|
||||||
|
*
|
||||||
|
* @return true if successful, false if one of the following case applies
|
||||||
|
* - virtual voice call is not started or has ended
|
||||||
|
* - binder is dead or Bluetooth is disabled or other error
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) {
|
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
|
||||||
|
public boolean stopScoUsingVirtualVoiceCall() {
|
||||||
if (DBG) log("stopScoUsingVirtualVoiceCall()");
|
if (DBG) log("stopScoUsingVirtualVoiceCall()");
|
||||||
final IBluetoothHeadset service = mService;
|
final IBluetoothHeadset service = mService;
|
||||||
if (service != null && isEnabled() && isValidDevice(device)) {
|
if (service != null && isEnabled()) {
|
||||||
try {
|
try {
|
||||||
return service.stopScoUsingVirtualVoiceCall(device);
|
return service.stopScoUsingVirtualVoiceCall();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, e.toString());
|
Log.e(TAG, e.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4558,8 +4558,7 @@ public class AudioManager {
|
|||||||
/**
|
/**
|
||||||
* The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
|
* The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
|
||||||
*/
|
*/
|
||||||
private ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>
|
private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
|
||||||
mDeviceCallbacks =
|
|
||||||
new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
|
new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -4859,22 +4858,21 @@ public class AudioManager {
|
|||||||
calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
|
calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
|
||||||
AudioDeviceInfo[] removed_devices =
|
AudioDeviceInfo[] removed_devices =
|
||||||
calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
|
calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
|
||||||
|
|
||||||
if (added_devices.length != 0 || removed_devices.length != 0) {
|
if (added_devices.length != 0 || removed_devices.length != 0) {
|
||||||
synchronized (mDeviceCallbacks) {
|
synchronized (mDeviceCallbacks) {
|
||||||
for (int i = 0; i < mDeviceCallbacks.size(); i++) {
|
for (int i = 0; i < mDeviceCallbacks.size(); i++) {
|
||||||
handler = mDeviceCallbacks.valueAt(i).getHandler();
|
handler = mDeviceCallbacks.valueAt(i).getHandler();
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
if (added_devices.length != 0) {
|
|
||||||
handler.sendMessage(Message.obtain(handler,
|
|
||||||
MSG_DEVICES_DEVICES_ADDED,
|
|
||||||
added_devices));
|
|
||||||
}
|
|
||||||
if (removed_devices.length != 0) {
|
if (removed_devices.length != 0) {
|
||||||
handler.sendMessage(Message.obtain(handler,
|
handler.sendMessage(Message.obtain(handler,
|
||||||
MSG_DEVICES_DEVICES_REMOVED,
|
MSG_DEVICES_DEVICES_REMOVED,
|
||||||
removed_devices));
|
removed_devices));
|
||||||
}
|
}
|
||||||
|
if (added_devices.length != 0) {
|
||||||
|
handler.sendMessage(Message.obtain(handler,
|
||||||
|
MSG_DEVICES_DEVICES_ADDED,
|
||||||
|
added_devices));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -525,6 +525,8 @@ public class AudioService extends IAudioService.Stub
|
|||||||
private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
|
private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
|
||||||
// SCO audio deactivation request waiting for headset service to connect
|
// SCO audio deactivation request waiting for headset service to connect
|
||||||
private static final int SCO_STATE_DEACTIVATE_REQ = 5;
|
private static final int SCO_STATE_DEACTIVATE_REQ = 5;
|
||||||
|
// SCO audio deactivation in progress, waiting for Bluetooth audio intent
|
||||||
|
private static final int SCO_STATE_DEACTIVATING = 6;
|
||||||
|
|
||||||
// SCO audio state is active due to an action in BT handsfree (either voice recognition or
|
// SCO audio state is active due to an action in BT handsfree (either voice recognition or
|
||||||
// in call audio)
|
// in call audio)
|
||||||
@@ -2714,9 +2716,13 @@ public class AudioService extends IAudioService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
|
int oldModeOwnerPid = 0;
|
||||||
int newModeOwnerPid = 0;
|
int newModeOwnerPid = 0;
|
||||||
synchronized(mSetModeDeathHandlers) {
|
synchronized(mSetModeDeathHandlers) {
|
||||||
Log.w(TAG, "setMode() client died");
|
Log.w(TAG, "setMode() client died");
|
||||||
|
if (!mSetModeDeathHandlers.isEmpty()) {
|
||||||
|
oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
|
||||||
|
}
|
||||||
int index = mSetModeDeathHandlers.indexOf(this);
|
int index = mSetModeDeathHandlers.indexOf(this);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
Log.w(TAG, "unregistered setMode() client died");
|
Log.w(TAG, "unregistered setMode() client died");
|
||||||
@@ -2725,8 +2731,8 @@ public class AudioService extends IAudioService.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
|
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
|
||||||
// SCO connections not started by the application changing the mode
|
// SCO connections not started by the application changing the mode when pid changes
|
||||||
if (newModeOwnerPid != 0) {
|
if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
disconnectBluetoothSco(newModeOwnerPid);
|
disconnectBluetoothSco(newModeOwnerPid);
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
@@ -2770,17 +2776,21 @@ public class AudioService extends IAudioService.Stub
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int oldModeOwnerPid = 0;
|
||||||
int newModeOwnerPid = 0;
|
int newModeOwnerPid = 0;
|
||||||
synchronized(mSetModeDeathHandlers) {
|
synchronized(mSetModeDeathHandlers) {
|
||||||
|
if (!mSetModeDeathHandlers.isEmpty()) {
|
||||||
|
oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
|
||||||
|
}
|
||||||
if (mode == AudioSystem.MODE_CURRENT) {
|
if (mode == AudioSystem.MODE_CURRENT) {
|
||||||
mode = mMode;
|
mode = mMode;
|
||||||
}
|
}
|
||||||
newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
|
newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
|
||||||
}
|
}
|
||||||
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
|
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
|
||||||
// SCO connections not started by the application changing the mode
|
// SCO connections not started by the application changing the mode when pid changes
|
||||||
if (newModeOwnerPid != 0) {
|
if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
|
||||||
disconnectBluetoothSco(newModeOwnerPid);
|
disconnectBluetoothSco(newModeOwnerPid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3196,28 +3206,17 @@ public class AudioService extends IAudioService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setBluetoothScoOnInt(boolean on, String eventSource) {
|
public void setBluetoothScoOnInt(boolean on, String eventSource) {
|
||||||
if (DEBUG_DEVICES) {
|
Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
|
||||||
Log.d(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
|
|
||||||
}
|
|
||||||
if (on) {
|
if (on) {
|
||||||
// do not accept SCO ON if SCO audio is not connected
|
// do not accept SCO ON if SCO audio is not connected
|
||||||
synchronized (mScoClients) {
|
synchronized (mScoClients) {
|
||||||
if (mBluetoothHeadset != null) {
|
if ((mBluetoothHeadset != null)
|
||||||
if (mBluetoothHeadsetDevice == null) {
|
&& (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
|
||||||
BluetoothDevice activeDevice = mBluetoothHeadset.getActiveDevice();
|
!= BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
|
||||||
if (activeDevice != null) {
|
mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
|
||||||
// setBtScoActiveDevice() might trigger resetBluetoothSco() which
|
Log.w(TAG, "setBluetoothScoOnInt(true) failed because "
|
||||||
// will call setBluetoothScoOnInt(false, "resetBluetoothSco")
|
+ mBluetoothHeadsetDevice + " is not in audio connected mode");
|
||||||
setBtScoActiveDevice(activeDevice);
|
return;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
|
|
||||||
!= BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
|
||||||
mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
|
|
||||||
Log.w(TAG, "setBluetoothScoOnInt(true) failed because "
|
|
||||||
+ mBluetoothHeadsetDevice + " is not in audio connected mode");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
|
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
|
||||||
@@ -3397,9 +3396,8 @@ public class AudioService extends IAudioService.Stub
|
|||||||
public int totalCount() {
|
public int totalCount() {
|
||||||
synchronized(mScoClients) {
|
synchronized(mScoClients) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int size = mScoClients.size();
|
for (ScoClient mScoClient : mScoClients) {
|
||||||
for (int i = 0; i < size; i++) {
|
count += mScoClient.getCount();
|
||||||
count += mScoClients.get(i).getCount();
|
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -3407,128 +3405,161 @@ public class AudioService extends IAudioService.Stub
|
|||||||
|
|
||||||
private void requestScoState(int state, int scoAudioMode) {
|
private void requestScoState(int state, int scoAudioMode) {
|
||||||
checkScoAudioState();
|
checkScoAudioState();
|
||||||
if (totalCount() == 0) {
|
int clientCount = totalCount();
|
||||||
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
if (clientCount != 0) {
|
||||||
// Make sure that the state transitions to CONNECTING even if we cannot initiate
|
Log.i(TAG, "requestScoState: state=" + state + ", scoAudioMode=" + scoAudioMode
|
||||||
// the connection.
|
+ ", clientCount=" + clientCount);
|
||||||
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
|
return;
|
||||||
// Accept SCO audio activation only in NORMAL audio mode or if the mode is
|
}
|
||||||
// currently controlled by the same client process.
|
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
||||||
synchronized(mSetModeDeathHandlers) {
|
// Make sure that the state transitions to CONNECTING even if we cannot initiate
|
||||||
if ((mSetModeDeathHandlers.isEmpty() ||
|
// the connection.
|
||||||
mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
|
||||||
(mScoAudioState == SCO_STATE_INACTIVE ||
|
// Accept SCO audio activation only in NORMAL audio mode or if the mode is
|
||||||
mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
|
// currently controlled by the same client process.
|
||||||
if (mScoAudioState == SCO_STATE_INACTIVE) {
|
synchronized(mSetModeDeathHandlers) {
|
||||||
mScoAudioMode = scoAudioMode;
|
int modeOwnerPid = mSetModeDeathHandlers.isEmpty()
|
||||||
if (scoAudioMode == SCO_MODE_UNDEFINED) {
|
? 0 : mSetModeDeathHandlers.get(0).getPid();
|
||||||
if (mBluetoothHeadsetDevice != null) {
|
if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) {
|
||||||
mScoAudioMode = new Integer(Settings.Global.getInt(
|
Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid "
|
||||||
mContentResolver,
|
+ modeOwnerPid + " != creatorPid " + mCreatorPid);
|
||||||
"bluetooth_sco_channel_"+
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
mBluetoothHeadsetDevice.getAddress(),
|
return;
|
||||||
SCO_MODE_VIRTUAL_CALL));
|
|
||||||
if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
|
|
||||||
mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mScoAudioMode = SCO_MODE_RAW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
|
|
||||||
boolean status = false;
|
|
||||||
if (mScoAudioMode == SCO_MODE_RAW) {
|
|
||||||
status = mBluetoothHeadset.connectAudio();
|
|
||||||
} else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
|
|
||||||
status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
|
|
||||||
mBluetoothHeadsetDevice);
|
|
||||||
} else if (mScoAudioMode == SCO_MODE_VR) {
|
|
||||||
status = mBluetoothHeadset.startVoiceRecognition(
|
|
||||||
mBluetoothHeadsetDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
|
||||||
} else {
|
|
||||||
broadcastScoConnectionState(
|
|
||||||
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
|
||||||
}
|
|
||||||
} else if (getBluetoothHeadset()) {
|
|
||||||
mScoAudioState = SCO_STATE_ACTIVATE_REQ;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
|
||||||
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
|
switch (mScoAudioState) {
|
||||||
(mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
|
case SCO_STATE_INACTIVE:
|
||||||
mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
|
mScoAudioMode = scoAudioMode;
|
||||||
if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
|
if (scoAudioMode == SCO_MODE_UNDEFINED) {
|
||||||
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
|
mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
|
||||||
boolean status = false;
|
if (mBluetoothHeadsetDevice != null) {
|
||||||
if (mScoAudioMode == SCO_MODE_RAW) {
|
mScoAudioMode = Settings.Global.getInt(mContentResolver,
|
||||||
status = mBluetoothHeadset.disconnectAudio();
|
"bluetooth_sco_channel_"
|
||||||
} else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
|
+ mBluetoothHeadsetDevice.getAddress(),
|
||||||
status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
|
SCO_MODE_VIRTUAL_CALL);
|
||||||
mBluetoothHeadsetDevice);
|
if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
|
||||||
} else if (mScoAudioMode == SCO_MODE_VR) {
|
mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
|
||||||
status = mBluetoothHeadset.stopVoiceRecognition(
|
}
|
||||||
mBluetoothHeadsetDevice);
|
}
|
||||||
}
|
}
|
||||||
|
if (mBluetoothHeadset == null) {
|
||||||
|
if (getBluetoothHeadset()) {
|
||||||
|
mScoAudioState = SCO_STATE_ACTIVATE_REQ;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
|
||||||
|
+ " connection, mScoAudioMode=" + mScoAudioMode);
|
||||||
|
broadcastScoConnectionState(
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mBluetoothHeadsetDevice == null) {
|
||||||
|
Log.w(TAG, "requestScoState: no active device while connecting,"
|
||||||
|
+ " mScoAudioMode=" + mScoAudioMode);
|
||||||
|
broadcastScoConnectionState(
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (connectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
|
mBluetoothHeadsetDevice, mScoAudioMode)) {
|
||||||
|
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice
|
||||||
|
+ " failed, mScoAudioMode=" + mScoAudioMode);
|
||||||
|
broadcastScoConnectionState(
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SCO_STATE_DEACTIVATING:
|
||||||
|
mScoAudioState = SCO_STATE_ACTIVATE_REQ;
|
||||||
|
break;
|
||||||
|
case SCO_STATE_DEACTIVATE_REQ:
|
||||||
|
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
||||||
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.w(TAG, "requestScoState: failed to connect in state "
|
||||||
|
+ mScoAudioState + ", scoAudioMode=" + scoAudioMode);
|
||||||
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
break;
|
||||||
|
|
||||||
if (!status) {
|
}
|
||||||
|
}
|
||||||
|
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
|
||||||
|
switch (mScoAudioState) {
|
||||||
|
case SCO_STATE_ACTIVE_INTERNAL:
|
||||||
|
if (mBluetoothHeadset == null) {
|
||||||
|
if (getBluetoothHeadset()) {
|
||||||
|
mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
|
||||||
|
+ " disconnection, mScoAudioMode=" + mScoAudioMode);
|
||||||
mScoAudioState = SCO_STATE_INACTIVE;
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
broadcastScoConnectionState(
|
broadcastScoConnectionState(
|
||||||
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
}
|
}
|
||||||
} else if (getBluetoothHeadset()) {
|
break;
|
||||||
mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
|
|
||||||
}
|
}
|
||||||
} else {
|
if (mBluetoothHeadsetDevice == null) {
|
||||||
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
|
broadcastScoConnectionState(
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
|
mBluetoothHeadsetDevice, mScoAudioMode)) {
|
||||||
|
mScoAudioState = SCO_STATE_DEACTIVATING;
|
||||||
|
} else {
|
||||||
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
|
broadcastScoConnectionState(
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SCO_STATE_ACTIVATE_REQ:
|
||||||
mScoAudioState = SCO_STATE_INACTIVE;
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
|
Log.w(TAG, "requestScoState: failed to disconnect in state "
|
||||||
|
+ mScoAudioState + ", scoAudioMode=" + scoAudioMode);
|
||||||
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkScoAudioState() {
|
private void checkScoAudioState() {
|
||||||
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
|
synchronized (mScoClients) {
|
||||||
mScoAudioState == SCO_STATE_INACTIVE &&
|
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
|
||||||
mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
|
mScoAudioState == SCO_STATE_INACTIVE &&
|
||||||
!= BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
|
mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
|
||||||
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
|
!= BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
|
||||||
|
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ScoClient getScoClient(IBinder cb, boolean create) {
|
private ScoClient getScoClient(IBinder cb, boolean create) {
|
||||||
synchronized(mScoClients) {
|
synchronized(mScoClients) {
|
||||||
ScoClient client = null;
|
for (ScoClient existingClient : mScoClients) {
|
||||||
int size = mScoClients.size();
|
if (existingClient.getBinder() == cb) {
|
||||||
for (int i = 0; i < size; i++) {
|
return existingClient;
|
||||||
client = mScoClients.get(i);
|
}
|
||||||
if (client.getBinder() == cb)
|
|
||||||
return client;
|
|
||||||
}
|
}
|
||||||
if (create) {
|
if (create) {
|
||||||
client = new ScoClient(cb);
|
ScoClient newClient = new ScoClient(cb);
|
||||||
mScoClients.add(client);
|
mScoClients.add(newClient);
|
||||||
|
return newClient;
|
||||||
}
|
}
|
||||||
return client;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearAllScoClients(int exceptPid, boolean stopSco) {
|
public void clearAllScoClients(int exceptPid, boolean stopSco) {
|
||||||
synchronized(mScoClients) {
|
synchronized(mScoClients) {
|
||||||
ScoClient savedClient = null;
|
ScoClient savedClient = null;
|
||||||
int size = mScoClients.size();
|
for (ScoClient cl : mScoClients) {
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
ScoClient cl = mScoClients.get(i);
|
|
||||||
if (cl.getPid() != exceptPid) {
|
if (cl.getPid() != exceptPid) {
|
||||||
cl.clearCount(stopSco);
|
cl.clearCount(stopSco);
|
||||||
} else {
|
} else {
|
||||||
@@ -3565,10 +3596,17 @@ public class AudioService extends IAudioService.Stub
|
|||||||
mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
|
mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
|
||||||
if (mBluetoothHeadsetDevice != null) {
|
if (mBluetoothHeadsetDevice != null) {
|
||||||
if (mBluetoothHeadset != null) {
|
if (mBluetoothHeadset != null) {
|
||||||
if (!mBluetoothHeadset.stopVoiceRecognition(
|
boolean status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
mBluetoothHeadsetDevice)) {
|
mBluetoothHeadsetDevice, SCO_MODE_RAW)
|
||||||
sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
|
|| disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
SENDMSG_REPLACE, 0, 0, null, 0);
|
mBluetoothHeadsetDevice, SCO_MODE_VIRTUAL_CALL)
|
||||||
|
|| disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
|
mBluetoothHeadsetDevice, SCO_MODE_VR);
|
||||||
|
if (status) {
|
||||||
|
mScoAudioState = SCO_STATE_DEACTIVATING;
|
||||||
|
} else {
|
||||||
|
clearAllScoClients(exceptPid, false);
|
||||||
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
}
|
}
|
||||||
} else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
|
} else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
|
||||||
getBluetoothHeadset()) {
|
getBluetoothHeadset()) {
|
||||||
@@ -3581,6 +3619,34 @@ public class AudioService extends IAudioService.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
|
||||||
|
BluetoothDevice device, int scoAudioMode) {
|
||||||
|
switch (scoAudioMode) {
|
||||||
|
case SCO_MODE_RAW:
|
||||||
|
return bluetoothHeadset.disconnectAudio();
|
||||||
|
case SCO_MODE_VIRTUAL_CALL:
|
||||||
|
return bluetoothHeadset.stopScoUsingVirtualVoiceCall();
|
||||||
|
case SCO_MODE_VR:
|
||||||
|
return bluetoothHeadset.stopVoiceRecognition(device);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
|
||||||
|
BluetoothDevice device, int scoAudioMode) {
|
||||||
|
switch (scoAudioMode) {
|
||||||
|
case SCO_MODE_RAW:
|
||||||
|
return bluetoothHeadset.connectAudio();
|
||||||
|
case SCO_MODE_VIRTUAL_CALL:
|
||||||
|
return bluetoothHeadset.startScoUsingVirtualVoiceCall();
|
||||||
|
case SCO_MODE_VR:
|
||||||
|
return bluetoothHeadset.startVoiceRecognition(device);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void resetBluetoothSco() {
|
private void resetBluetoothSco() {
|
||||||
synchronized(mScoClients) {
|
synchronized(mScoClients) {
|
||||||
clearAllScoClients(0, false);
|
clearAllScoClients(0, false);
|
||||||
@@ -3638,11 +3704,9 @@ public class AudioService extends IAudioService.Stub
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBtScoActiveDevice(BluetoothDevice btDevice) {
|
private void setBtScoActiveDevice(BluetoothDevice btDevice) {
|
||||||
if (DEBUG_DEVICES) {
|
|
||||||
Log.d(TAG, "setBtScoActiveDevice(" + btDevice + ")");
|
|
||||||
}
|
|
||||||
synchronized (mScoClients) {
|
synchronized (mScoClients) {
|
||||||
|
Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
|
||||||
final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
|
final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
|
||||||
if (!Objects.equals(btDevice, previousActiveDevice)) {
|
if (!Objects.equals(btDevice, previousActiveDevice)) {
|
||||||
if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
|
if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
|
||||||
@@ -3722,37 +3786,36 @@ public class AudioService extends IAudioService.Stub
|
|||||||
boolean status = false;
|
boolean status = false;
|
||||||
if (mBluetoothHeadsetDevice != null) {
|
if (mBluetoothHeadsetDevice != null) {
|
||||||
switch (mScoAudioState) {
|
switch (mScoAudioState) {
|
||||||
case SCO_STATE_ACTIVATE_REQ:
|
case SCO_STATE_ACTIVATE_REQ:
|
||||||
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
status = connectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
if (mScoAudioMode == SCO_MODE_RAW) {
|
mBluetoothHeadsetDevice, mScoAudioMode);
|
||||||
status = mBluetoothHeadset.connectAudio();
|
if (status) {
|
||||||
} else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
|
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
||||||
status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
|
}
|
||||||
mBluetoothHeadsetDevice);
|
break;
|
||||||
} else if (mScoAudioMode == SCO_MODE_VR) {
|
case SCO_STATE_DEACTIVATE_REQ:
|
||||||
status = mBluetoothHeadset.startVoiceRecognition(
|
status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
mBluetoothHeadsetDevice);
|
mBluetoothHeadsetDevice, mScoAudioMode);
|
||||||
}
|
if (status) {
|
||||||
break;
|
mScoAudioState = SCO_STATE_DEACTIVATING;
|
||||||
case SCO_STATE_DEACTIVATE_REQ:
|
}
|
||||||
if (mScoAudioMode == SCO_MODE_RAW) {
|
break;
|
||||||
status = mBluetoothHeadset.disconnectAudio();
|
case SCO_STATE_DEACTIVATE_EXT_REQ:
|
||||||
} else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
|
status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
|
mBluetoothHeadsetDevice, SCO_MODE_RAW) ||
|
||||||
mBluetoothHeadsetDevice);
|
disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
} else if (mScoAudioMode == SCO_MODE_VR) {
|
mBluetoothHeadsetDevice, SCO_MODE_VIRTUAL_CALL) ||
|
||||||
status = mBluetoothHeadset.stopVoiceRecognition(
|
disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
mBluetoothHeadsetDevice);
|
mBluetoothHeadsetDevice, SCO_MODE_VR);
|
||||||
}
|
if (status) {
|
||||||
break;
|
mScoAudioState = SCO_STATE_DEACTIVATING;
|
||||||
case SCO_STATE_DEACTIVATE_EXT_REQ:
|
}
|
||||||
status = mBluetoothHeadset.stopVoiceRecognition(
|
break;
|
||||||
mBluetoothHeadsetDevice);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!status) {
|
if (!status) {
|
||||||
sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
SENDMSG_REPLACE, 0, 0, null, 0);
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6322,33 +6385,47 @@ public class AudioService extends IAudioService.Stub
|
|||||||
if (!mScoClients.isEmpty() &&
|
if (!mScoClients.isEmpty() &&
|
||||||
(mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
|
(mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
|
||||||
mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
|
mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
|
||||||
mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
|
mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
|
||||||
|
mScoAudioState == SCO_STATE_DEACTIVATING)) {
|
||||||
broadcast = true;
|
broadcast = true;
|
||||||
}
|
}
|
||||||
switch (btState) {
|
switch (btState) {
|
||||||
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
|
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
|
||||||
scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
|
scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
|
||||||
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
|
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
|
||||||
mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
|
mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
|
||||||
mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
|
mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
|
||||||
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
|
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
|
||||||
}
|
}
|
||||||
break;
|
setBluetoothScoOn(true);
|
||||||
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
|
break;
|
||||||
scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
|
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
|
||||||
mScoAudioState = SCO_STATE_INACTIVE;
|
setBluetoothScoOn(false);
|
||||||
clearAllScoClients(0, false);
|
scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
|
||||||
break;
|
// startBluetoothSco called after stopBluetoothSco
|
||||||
case BluetoothHeadset.STATE_AUDIO_CONNECTING:
|
if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
|
||||||
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
|
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
|
||||||
mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
|
&& connectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
|
mBluetoothHeadsetDevice, mScoAudioMode)) {
|
||||||
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
|
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
||||||
}
|
broadcast = false;
|
||||||
default:
|
break;
|
||||||
// do not broadcast CONNECTING or invalid state
|
}
|
||||||
broadcast = false;
|
}
|
||||||
break;
|
// Tear down SCO if disconnected from external
|
||||||
|
clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
|
||||||
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
|
break;
|
||||||
|
case BluetoothHeadset.STATE_AUDIO_CONNECTING:
|
||||||
|
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
|
||||||
|
mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
|
||||||
|
mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
|
||||||
|
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// do not broadcast CONNECTING or invalid state
|
||||||
|
broadcast = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (broadcast) {
|
if (broadcast) {
|
||||||
|
|||||||
Reference in New Issue
Block a user