summaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothHeadset.java
diff options
context:
space:
mode:
authorJack He <siyuanh@google.com>2018-05-02 19:10:56 -0700
committerJack He <siyuanh@google.com>2018-05-07 12:57:26 -0700
commitc46a01e89a0aaf40196e773e2112b06894d278f5 (patch)
tree3cd1d612cd5a6a997c837abf1ac6f7e598f2509d /framework/java/android/bluetooth/BluetoothHeadset.java
parent126b03498e8c54331fba4bea60208ba1b21da0bf (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.java97
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());
}