diff options
author | Jack He <siyuanh@google.com> | 2018-05-02 19:10:56 -0700 |
---|---|---|
committer | Jack He <siyuanh@google.com> | 2018-05-07 12:57:26 -0700 |
commit | c46a01e89a0aaf40196e773e2112b06894d278f5 (patch) | |
tree | 3cd1d612cd5a6a997c837abf1ac6f7e598f2509d /framework/java/android/bluetooth/BluetoothHeadset.java | |
parent | 126b03498e8c54331fba4bea60208ba1b21da0bf (diff) |
Bluetooth: Fix HFP SCO logic and documentation
AudioService:
* Call setBtScoActiveDevice and setBluetoothScoOn both in AudioService's
broadcast receiver so that these two methods must be triggerred in
the same sequence as ACTIVE_DEVICE_CHANGED and AUDIO_STATE_CHANGED
intents are sent and we no longer need to handle race condition by
synchronously checking active device in setBluetoothScoOn
* Default sco audio mode when no headset is active should be virtual
voice call, as many HFP devices do not accept SCO audio without an
ongoing call
* Synchronize checkScoAudioState() method with mScoClients
* Add helper functions connectBluetoothScoHelper and
disconnectBluetoothScoHelper to call various SCO setup and tear down
methods based on sco audio mode
* Try raw, virtual call, and voice recognition mode when disconnecting
externally started SCO
* Add new sco state SCO_STATE_DEACTIVATING to allow back to back calling
of startBluetoothSco and stopBluetoothSco
Audio Manager:
* Modified AudioManager logic so that removed devices callback is called
before newly added devices
BluetoothHeadset:
* Modified BluetoothHeadset so that start and stop SCO using virtual
voice call no longer need a parameter and will use active device by
default
* Modified documentation around various sco mangement APIs to match
their expected behaviors
Bug: 76114959
Test: VoIP calls sanity test cases
Change-Id: Id50db88f4ff36069b0f392c81dd9d90c24cd2206
(cherry picked from commit 09ca4a4c07d360218ab9ca40e6c2ae7fbf485aec)
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothHeadset.java')
-rw-r--r-- | framework/java/android/bluetooth/BluetoothHeadset.java | 97 |
1 files changed, 67 insertions, 30 deletions
diff --git a/framework/java/android/bluetooth/BluetoothHeadset.java b/framework/java/android/bluetooth/BluetoothHeadset.java index a68f485f43..0c91a2054b 100644 --- a/framework/java/android/bluetooth/BluetoothHeadset.java +++ b/framework/java/android/bluetooth/BluetoothHeadset.java @@ -16,6 +16,7 @@ package android.bluetooth; +import android.Manifest; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; @@ -633,8 +634,9 @@ public final class BluetoothHeadset implements BluetoothProfile { * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * @param device Bluetooth headset - * @return false if there is no headset connected of if the connected headset doesn't support - * voice recognition or on error, true otherwise + * @return false if there is no headset connected, or the connected headset doesn't support + * voice recognition, or voice recognition is already started, or audio channel is occupied, + * or on error, true otherwise */ public boolean startVoiceRecognition(BluetoothDevice device) { if (DBG) log("startVoiceRecognition()"); @@ -654,10 +656,15 @@ public final class BluetoothHeadset implements BluetoothProfile { * Stop Bluetooth Voice Recognition mode, and shut down the * 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. * * @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) { 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. * - * @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 */ public boolean isAudioOn() { @@ -821,11 +829,21 @@ public final class BluetoothHeadset implements BluetoothProfile { } /** - * Initiates a connection of headset audio. - * It setup SCO channel with remote connected headset device. + * Initiates a connection of headset audio to the current active device + * + * <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_CONNECTING}. * - * @return true if successful false if there was some error such as there is no connected - * headset + * <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 */ public boolean connectAudio() { @@ -844,11 +862,14 @@ public final class BluetoothHeadset implements BluetoothProfile { } /** - * Initiates a disconnection of headset audio. - * It tears down the SCO channel from remote headset device. + * Initiates a disconnection of HFP SCO audio. + * Tear down voice recognition or virtual voice call if any. + * + * <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}. * - * @return true if successful false if there was some error such as there is no connected SCO - * channel + * @return false if audio is not connected, or on error, true otherwise * @hide */ public boolean disconnectAudio() { @@ -867,22 +888,33 @@ public final class BluetoothHeadset implements BluetoothProfile { } /** - * Initiates a SCO channel connection with the headset (if connected). - * Also initiates a virtual voice call for Handsfree devices as many devices - * do not accept SCO audio without a call. - * This API allows the handsfree device to be used for routing non-cellular - * call audio. + * Initiates a SCO channel connection as a virtual voice call to the current active device + * Active handsfree device will be notified of incoming call and connected call. * - * @param device Remote Bluetooth Device - * @return true if successful, false if there was some error. + * <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_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 */ - public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) { + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean startScoUsingVirtualVoiceCall() { if (DBG) log("startScoUsingVirtualVoiceCall()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + if (service != null && isEnabled()) { try { - return service.startScoUsingVirtualVoiceCall(device); + return service.startScoUsingVirtualVoiceCall(); } catch (RemoteException e) { Log.e(TAG, e.toString()); } @@ -894,19 +926,24 @@ public final class BluetoothHeadset implements BluetoothProfile { } /** - * Terminates an ongoing SCO connection and the associated virtual - * call. + * Terminates an ongoing SCO connection and the associated virtual call. * - * @param device Remote Bluetooth Device - * @return true if successful, false if there was some error. + * <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}. + * + * @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 */ - public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) { + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean stopScoUsingVirtualVoiceCall() { if (DBG) log("stopScoUsingVirtualVoiceCall()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + if (service != null && isEnabled()) { try { - return service.stopScoUsingVirtualVoiceCall(device); + return service.stopScoUsingVirtualVoiceCall(); } catch (RemoteException e) { Log.e(TAG, e.toString()); } |