Make BluetoothHeadset APIs used by Telecom into System APIs

Tag: #feature
Bug: 195156304
Test: Manual
CTS-Coverage-Bug: 211914959
Change-Id: I13d6f553f5b9d6ca7c2ae9a42450875b16cd1490
This commit is contained in:
Rahul Sabnis
2021-12-23 11:36:40 -08:00
parent d63f819bb3
commit 0eeb1d32b4
9 changed files with 214 additions and 117 deletions

View File

@@ -9742,13 +9742,14 @@ package android.bluetooth {
field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2 field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2
field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1 field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1
field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3 field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3
field public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; // 0xa field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200; // 0xc8
field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; // 0x65 field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201; // 0xc9
field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; // 0x66
field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6 field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6
field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8 field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8
field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9 field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9
field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff
field public static final int FEATURE_NOT_SUPPORTED = 11; // 0xb
field public static final int FEATURE_SUPPORTED = 10; // 0xa
field public static final int SUCCESS = 0; // 0x0 field public static final int SUCCESS = 0; // 0x0
} }

View File

@@ -2218,9 +2218,12 @@ package android.bluetooth {
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int connectAudio();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int disconnectAudio();
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioState(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInbandRingingEnabled(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isInbandRingingEnabled();
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startScoUsingVirtualVoiceCall(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startScoUsingVirtualVoiceCall();
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean stopScoUsingVirtualVoiceCall(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean stopScoUsingVirtualVoiceCall();
@@ -2299,6 +2302,14 @@ package android.bluetooth {
public final class BluetoothStatusCodes { public final class BluetoothStatusCodes {
field public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; // 0x3e8 field public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; // 0x3e8
field public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116; // 0x45c
field public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117; // 0x45d
field public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118; // 0x45e
field public static final int ERROR_CALL_ACTIVE = 1119; // 0x45f
field public static final int ERROR_NOT_ACTIVE_DEVICE = 12; // 0xc
field public static final int ERROR_NO_ACTIVE_DEVICES = 13; // 0xd
field public static final int ERROR_PROFILE_NOT_CONNECTED = 14; // 0xe
field public static final int ERROR_TIMEOUT = 15; // 0xf
} }
public final class BluetoothUuid { public final class BluetoothUuid {

View File

@@ -2249,17 +2249,17 @@ public final class BluetoothAdapter {
/** @hide */ /** @hide */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef(value = { @IntDef(value = {
BluetoothStatusCodes.SUCCESS, BluetoothStatusCodes.FEATURE_SUPPORTED,
BluetoothStatusCodes.ERROR_UNKNOWN, BluetoothStatusCodes.ERROR_UNKNOWN,
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED, BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
}) })
public @interface LeFeatureReturnValues {} public @interface LeFeatureReturnValues {}
/** /**
* Returns {@link BluetoothStatusCodes#SUCCESS} if the LE audio feature is * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if the LE audio feature is
* supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if * supported, {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not
* the feature is not supported or an error code. * supported, or an error code.
* *
* @return whether the LE audio is supported * @return whether the LE audio is supported
*/ */
@@ -2282,9 +2282,10 @@ public final class BluetoothAdapter {
} }
/** /**
* Returns {@link BluetoothStatusCodes#SUCCESS} if LE Periodic Advertising Sync Transfer Sender * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if LE Periodic Advertising Sync
* feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if the * Transfer Sender feature is supported,
* feature is not supported or an error code * {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not supported, or
* an error code
* *
* @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature * @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature
*/ */

View File

@@ -18,6 +18,7 @@ package android.bluetooth;
import static android.bluetooth.BluetoothUtils.getSyncTimeout; import static android.bluetooth.BluetoothUtils.getSyncTimeout;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
@@ -44,6 +45,8 @@ import android.util.Log;
import com.android.modules.utils.SynchronousResultReceiver; import com.android.modules.utils.SynchronousResultReceiver;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@@ -895,17 +898,36 @@ public final class BluetoothHeadset implements BluetoothProfile {
com.android.internal.R.bool.config_bluetooth_sco_off_call); com.android.internal.R.bool.config_bluetooth_sco_off_call);
} }
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
BluetoothHeadset.STATE_AUDIO_CONNECTING,
BluetoothHeadset.STATE_AUDIO_CONNECTED,
BluetoothStatusCodes.ERROR_TIMEOUT
})
public @interface GetAudioStateReturnValues {}
/** /**
* Get the current audio state of the Headset. * Get the current audio state of the Headset.
* Note: This is an internal function and shouldn't be exposed *
* @param device is the Bluetooth device for which the audio state is being queried
* @return the audio state of the device or an error code
* @throws IllegalArgumentException if the device is null
* *
* @hide * @hide
*/ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @SystemApi
@RequiresBluetoothConnectPermission @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @RequiresPermission(allOf = {
public int getAudioState(BluetoothDevice device) { android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
public @GetAudioStateReturnValues int getAudioState(@NonNull BluetoothDevice device) {
if (VDBG) log("getAudioState"); if (VDBG) log("getAudioState");
if (device == null) {
throw new IllegalArgumentException("device cannot be null");
}
final IBluetoothHeadset service = mService; final IBluetoothHeadset service = mService;
final int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; final int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
if (service == null) { if (service == null) {
@@ -916,8 +938,12 @@ public final class BluetoothHeadset implements BluetoothProfile {
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getAudioState(device, mAttributionSource, recv); service.getAudioState(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (RemoteException | TimeoutException e) { } catch (RemoteException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
throw e.rethrowFromSystemServer();
} catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
return BluetoothStatusCodes.ERROR_TIMEOUT;
} }
} }
return defaultValue; return defaultValue;
@@ -1005,103 +1031,112 @@ public final class BluetoothHeadset implements BluetoothProfile {
} }
} }
/** /** @hide */
* Check if at least one headset's SCO audio is connected or connecting @Retention(RetentionPolicy.SOURCE)
* @IntDef(value = {
* @return true if at least one device's SCO audio is connected or connecting, false otherwise BluetoothStatusCodes.SUCCESS,
* or on error BluetoothStatusCodes.ERROR_UNKNOWN,
* @hide BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
*/ BluetoothStatusCodes.ERROR_TIMEOUT,
@RequiresLegacyBluetoothPermission BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED,
@RequiresBluetoothConnectPermission BluetoothStatusCodes.ERROR_NO_ACTIVE_DEVICES,
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) BluetoothStatusCodes.ERROR_NOT_ACTIVE_DEVICE,
public boolean isAudioOn() { BluetoothStatusCodes.ERROR_AUDIO_ROUTE_BLOCKED,
if (VDBG) log("isAudioOn()"); BluetoothStatusCodes.ERROR_CALL_ACTIVE,
final IBluetoothHeadset service = mService; BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED
final boolean defaultValue = false; })
if (service == null) { public @interface ConnectAudioReturnValues {}
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) {
try {
final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
service.isAudioOn(mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
}
}
return defaultValue;
}
/** /**
* Initiates a connection of headset audio to the current active device * Initiates a connection of SCO audio to the current active HFP device. The active HFP device
* can be identified with {@link BluetoothAdapter#getActiveDevices(int)}.
* <p>
* If this function returns {@link BluetoothStatusCodes#SUCCESS}, the intent
* {@link #ACTION_AUDIO_STATE_CHANGED} will be broadcasted twice. First with {@link #EXTRA_STATE}
* set to {@link #STATE_AUDIO_CONNECTING}. This will be followed by a broadcast with
* {@link #EXTRA_STATE} set to either {@link #STATE_AUDIO_CONNECTED} if the audio connection is
* established or {@link #STATE_AUDIO_DISCONNECTED} if there was a failure in establishing the
* audio connection.
* *
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. * @return whether the connection was successfully initiated or an error code on failure
* 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
*/ */
@UnsupportedAppUsage @SystemApi
@RequiresBluetoothConnectPermission @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @RequiresPermission(allOf = {
public boolean connectAudio() { android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
public @ConnectAudioReturnValues int connectAudio() {
if (VDBG) log("connectAudio()"); if (VDBG) log("connectAudio()");
final IBluetoothHeadset service = mService; final IBluetoothHeadset service = mService;
final boolean defaultValue = false; final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN;
if (service == null) { if (service == null) {
Log.w(TAG, "Proxy not attached to service"); Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable())); if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) { } else if (isEnabled()) {
try { try {
final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.connectAudio(mAttributionSource, recv); service.connectAudio(mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (RemoteException | TimeoutException e) { } catch (RemoteException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
throw e.rethrowFromSystemServer();
} catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
return BluetoothStatusCodes.ERROR_TIMEOUT;
} }
} }
return defaultValue; return defaultValue;
} }
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BluetoothStatusCodes.SUCCESS,
BluetoothStatusCodes.ERROR_UNKNOWN,
BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
BluetoothStatusCodes.ERROR_TIMEOUT,
BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED,
BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED
})
public @interface DisconnectAudioReturnValues {}
/** /**
* Initiates a disconnection of HFP SCO audio. * Initiates a disconnection of HFP SCO audio from actively connected devices. It also tears
* Tear down voice recognition or virtual voice call if any. * down voice recognition or virtual voice call, if any exists.
* *
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. * <p> If this function returns {@link BluetoothStatusCodes#SUCCESS}, the intent
* If this function returns true, this intent will be broadcasted with * {@link #ACTION_AUDIO_STATE_CHANGED} will be broadcasted with {@link #EXTRA_STATE} set to
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}. * {@link #STATE_AUDIO_DISCONNECTED}.
* *
* @return false if audio is not connected, or on error, true otherwise * @return whether the disconnection was initiated successfully or an error code on failure
* @hide * @hide
*/ */
@UnsupportedAppUsage @SystemApi
@RequiresBluetoothConnectPermission @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @RequiresPermission(allOf = {
public boolean disconnectAudio() { android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
public @DisconnectAudioReturnValues int disconnectAudio() {
if (VDBG) log("disconnectAudio()"); if (VDBG) log("disconnectAudio()");
final IBluetoothHeadset service = mService; final IBluetoothHeadset service = mService;
final boolean defaultValue = false; final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN;
if (service == null) { if (service == null) {
Log.w(TAG, "Proxy not attached to service"); Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable())); if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) { } else if (isEnabled()) {
try { try {
final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.disconnectAudio(mAttributionSource, recv); service.disconnectAudio(mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (RemoteException | TimeoutException e) { } catch (RemoteException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
throw e.rethrowFromSystemServer();
} catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
return BluetoothStatusCodes.ERROR_TIMEOUT;
} }
} }
return defaultValue; return defaultValue;
@@ -1386,7 +1421,10 @@ public final class BluetoothHeadset implements BluetoothProfile {
@SystemApi @SystemApi
@RequiresLegacyBluetoothPermission @RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) @RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
public boolean isInbandRingingEnabled() { public boolean isInbandRingingEnabled() {
if (DBG) log("isInbandRingingEnabled()"); if (DBG) log("isInbandRingingEnabled()");
final IBluetoothHeadset service = mService; final IBluetoothHeadset service = mService;

View File

@@ -20,7 +20,7 @@ import android.annotation.SystemApi;
/** /**
* A class with constants representing possible return values for Bluetooth APIs. General return * A class with constants representing possible return values for Bluetooth APIs. General return
* values occupy the range 0 to 99. Profile-specific return values occupy the range 100-999. * values occupy the range 0 to 199. Profile-specific return values occupy the range 200-999.
* API-specific return values start at 1000. The exception to this is the "UNKNOWN" error code which * API-specific return values start at 1000. The exception to this is the "UNKNOWN" error code which
* occupies the max integer value. * occupies the max integer value.
*/ */
@@ -29,28 +29,28 @@ public final class BluetoothStatusCodes {
private BluetoothStatusCodes() {} private BluetoothStatusCodes() {}
/** /**
* Indicates that the API call was successful * Indicates that the API call was successful.
*/ */
public static final int SUCCESS = 0; public static final int SUCCESS = 0;
/** /**
* Error code indicating that Bluetooth is not enabled * Error code indicating that Bluetooth is not enabled.
*/ */
public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1;
/** /**
* Error code indicating that the API call was initiated by neither the system nor the active * Error code indicating that the API call was initiated by neither the system nor the active
* user * user.
*/ */
public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2;
/** /**
* Error code indicating that the Bluetooth Device specified is not bonded * Error code indicating that the Bluetooth Device specified is not bonded.
*/ */
public static final int ERROR_DEVICE_NOT_BONDED = 3; public static final int ERROR_DEVICE_NOT_BONDED = 3;
/** /**
* Error code indicating that the Bluetooth Device specified is not connected, but is bonded * Error code indicating that the Bluetooth Device specified is not connected, but is bonded.
* *
* @hide * @hide
*/ */
@@ -58,7 +58,7 @@ public final class BluetoothStatusCodes {
/** /**
* Error code indicating that the caller does not have the * Error code indicating that the caller does not have the
* {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission * {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission.
* *
* @hide * @hide
*/ */
@@ -66,13 +66,13 @@ public final class BluetoothStatusCodes {
/** /**
* Error code indicating that the caller does not have the * Error code indicating that the caller does not have the
* {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission.
*/ */
public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6;
/** /**
* Error code indicating that the caller does not have the * Error code indicating that the caller does not have the
* {@link android.Manifest.permission#BLUETOOTH_SCAN} permission * {@link android.Manifest.permission#BLUETOOTH_SCAN} permission.
* *
* @hide * @hide
*/ */
@@ -80,30 +80,67 @@ public final class BluetoothStatusCodes {
/** /**
* Error code indicating that the caller does not have the * Error code indicating that the caller does not have the
* {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
*/ */
public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8;
/** /**
* Error code indicating that the profile service is not bound. You can bind a profile service * Error code indicating that the profile service is not bound. You can bind a profile service
* by calling {@link BluetoothAdapter#getProfileProxy} * by calling {@link BluetoothAdapter#getProfileProxy}.
*/ */
public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9;
/** /**
* Error code indicating that the feature is not supported. * Indicates that the feature is supported.
*/ */
public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; public static final int FEATURE_SUPPORTED = 10;
/**
* Indicates that the feature is not supported.
*/
public static final int FEATURE_NOT_SUPPORTED = 11;
/**
* Error code indicating that the device is not the active device for this profile.
*
* @hide
*/
@SystemApi
public static final int ERROR_NOT_ACTIVE_DEVICE = 12;
/**
* Error code indicating that there are no active devices for the profile.
*
* @hide
*/
@SystemApi
public static final int ERROR_NO_ACTIVE_DEVICES = 13;
/**
* Indicates that the Bluetooth profile is not connected to this device.
*
* @hide
*/
@SystemApi
public static final int ERROR_PROFILE_NOT_CONNECTED = 14;
/**
* Error code indicating that the requested operation timed out.
*
* @hide
*/
@SystemApi
public static final int ERROR_TIMEOUT = 15;
/** /**
* A GATT writeCharacteristic request is not permitted on the remote device. * A GATT writeCharacteristic request is not permitted on the remote device.
*/ */
public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200;
/** /**
* A GATT writeCharacteristic request is issued to a busy remote device. * A GATT writeCharacteristic request is issued to a busy remote device.
*/ */
public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201;
/** /**
* If another application has already requested {@link OobData} then another fetch will be * If another application has already requested {@link OobData} then another fetch will be
@@ -285,6 +322,38 @@ public final class BluetoothStatusCodes {
*/ */
public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115; public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115;
/**
* Indicates that there is already one device for which SCO audio is connected or connecting.
*
* @hide
*/
@SystemApi
public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116;
/**
* Indicates that SCO audio was already not connected for this device.
*
* @hide
*/
@SystemApi
public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117;
/**
* Indicates that there audio route is currently blocked by the system.
*
* @hide
*/
@SystemApi
public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118;
/**
* Indicates that there is an active call preventing this operation from succeeding.
*
* @hide
*/
@SystemApi
public static final int ERROR_CALL_ACTIVE = 1119;
/** /**
* Indicates that an unknown error has occurred has occurred. * Indicates that an unknown error has occurred has occurred.
*/ */

View File

@@ -275,6 +275,7 @@ applications that come with the platform
<privapp-permissions package="com.android.server.telecom"> <privapp-permissions package="com.android.server.telecom">
<permission name="android.permission.BIND_CONNECTION_SERVICE"/> <permission name="android.permission.BIND_CONNECTION_SERVICE"/>
<permission name="android.permission.BIND_INCALL_SERVICE"/> <permission name="android.permission.BIND_INCALL_SERVICE"/>
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
<permission name="android.permission.CALL_PRIVILEGED"/> <permission name="android.permission.CALL_PRIVILEGED"/>
<permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/> <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/>

View File

@@ -138,13 +138,6 @@ public class HeadsetProfile implements LocalBluetoothProfile {
return mService.getActiveDevice(); return mService.getActiveDevice();
} }
public boolean isAudioOn() {
if (mService == null) {
return false;
}
return mService.isAudioOn();
}
public int getAudioState(BluetoothDevice device) { public int getAudioState(BluetoothDevice device) {
if (mService == null) { if (mService == null) {
return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; return BluetoothHeadset.STATE_AUDIO_DISCONNECTED;

View File

@@ -54,15 +54,6 @@ public class HeadsetProfileTest {
mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mService); mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mService);
} }
@Test
public void bluetoothProfile_shouldReturnTheAudioStatusFromBlueToothHeadsetService() {
when(mService.isAudioOn()).thenReturn(true);
assertThat(mProfile.isAudioOn()).isTrue();
when(mService.isAudioOn()).thenReturn(false);
assertThat(mProfile.isAudioOn()).isFalse();
}
@Test @Test
public void testHeadsetProfile_shouldReturnAudioState() { public void testHeadsetProfile_shouldReturnAudioState() {
when(mService.getAudioState(mBluetoothDevice)). when(mService.getAudioState(mBluetoothDevice)).

View File

@@ -102,8 +102,6 @@ public class BtHelper {
/*package*/ static final int SCO_MODE_UNDEFINED = -1; /*package*/ static final int SCO_MODE_UNDEFINED = -1;
// SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall()) // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
/*package*/ static final int SCO_MODE_VIRTUAL_CALL = 0; /*package*/ static final int SCO_MODE_VIRTUAL_CALL = 0;
// SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
private static final int SCO_MODE_RAW = 1;
// SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition()) // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
private static final int SCO_MODE_VR = 2; private static final int SCO_MODE_VR = 2;
// max valid SCO audio mode values // max valid SCO audio mode values
@@ -122,8 +120,6 @@ public class BtHelper {
return "SCO_MODE_UNDEFINED"; return "SCO_MODE_UNDEFINED";
case SCO_MODE_VIRTUAL_CALL: case SCO_MODE_VIRTUAL_CALL:
return "SCO_MODE_VIRTUAL_CALL"; return "SCO_MODE_VIRTUAL_CALL";
case SCO_MODE_RAW:
return "SCO_MODE_RAW";
case SCO_MODE_VR: case SCO_MODE_VR:
return "SCO_MODE_VR"; return "SCO_MODE_VR";
default: default:
@@ -812,8 +808,6 @@ public class BtHelper {
private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset, private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
BluetoothDevice device, int scoAudioMode) { BluetoothDevice device, int scoAudioMode) {
switch (scoAudioMode) { switch (scoAudioMode) {
case SCO_MODE_RAW:
return bluetoothHeadset.disconnectAudio();
case SCO_MODE_VIRTUAL_CALL: case SCO_MODE_VIRTUAL_CALL:
return bluetoothHeadset.stopScoUsingVirtualVoiceCall(); return bluetoothHeadset.stopScoUsingVirtualVoiceCall();
case SCO_MODE_VR: case SCO_MODE_VR:
@@ -826,8 +820,6 @@ public class BtHelper {
private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset, private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
BluetoothDevice device, int scoAudioMode) { BluetoothDevice device, int scoAudioMode) {
switch (scoAudioMode) { switch (scoAudioMode) {
case SCO_MODE_RAW:
return bluetoothHeadset.connectAudio();
case SCO_MODE_VIRTUAL_CALL: case SCO_MODE_VIRTUAL_CALL:
return bluetoothHeadset.startScoUsingVirtualVoiceCall(); return bluetoothHeadset.startScoUsingVirtualVoiceCall();
case SCO_MODE_VR: case SCO_MODE_VR: