diff options
author | Rahul Sabnis <rahulsabnis@google.com> | 2022-01-12 22:10:46 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2022-01-12 22:10:46 +0000 |
commit | 3224d197364a7da8f95f5df540c5590cd669e58e (patch) | |
tree | 4732a2ca707524a407a1e19f9fbb13454df34009 /framework/java | |
parent | c24a7e89f1698a2bf002d93c326381241099dba0 (diff) | |
parent | 5ed1b8446ec81205c9c5d2949572e57d322e5716 (diff) |
Merge "Make BluetoothHeadset APIs used by Telecom into System APIs"
Diffstat (limited to 'framework/java')
3 files changed, 197 insertions, 89 deletions
diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 7e5e96d802..a695f6d2e7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2249,17 +2249,17 @@ public final class BluetoothAdapter { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { - BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.FEATURE_SUPPORTED, BluetoothStatusCodes.ERROR_UNKNOWN, BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, - BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED, + BluetoothStatusCodes.FEATURE_NOT_SUPPORTED, }) public @interface LeFeatureReturnValues {} /** - * Returns {@link BluetoothStatusCodes#SUCCESS} if the LE audio feature is - * supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if - * the feature is not supported or an error code. + * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if the LE audio feature is + * supported, {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not + * supported, or an error code. * * @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 - * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if the - * feature is not supported or an error code + * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if LE Periodic Advertising Sync + * Transfer Sender feature is supported, + * {@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 */ diff --git a/framework/java/android/bluetooth/BluetoothHeadset.java b/framework/java/android/bluetooth/BluetoothHeadset.java index f2a6276ce8..2ed1eb40f8 100644 --- a/framework/java/android/bluetooth/BluetoothHeadset.java +++ b/framework/java/android/bluetooth/BluetoothHeadset.java @@ -18,6 +18,7 @@ package android.bluetooth; import static android.bluetooth.BluetoothUtils.getSyncTimeout; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -44,6 +45,8 @@ import android.util.Log; import com.android.modules.utils.SynchronousResultReceiver; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; 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); } + /** @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. - * 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 */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getAudioState(BluetoothDevice device) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @GetAudioStateReturnValues int getAudioState(@NonNull BluetoothDevice device) { if (VDBG) log("getAudioState"); + if (device == null) { + throw new IllegalArgumentException("device cannot be null"); + } final IBluetoothHeadset service = mService; final int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; if (service == null) { @@ -916,8 +938,12 @@ public final class BluetoothHeadset implements BluetoothProfile { final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); service.getAudioState(device, mAttributionSource, recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { + } catch (RemoteException e) { 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; @@ -1005,103 +1031,112 @@ public final class BluetoothHeadset implements BluetoothProfile { } } - /** - * Check if at least one headset's SCO audio is connected or connecting - * - * @return true if at least one device's SCO audio is connected or connecting, false otherwise - * or on error - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isAudioOn() { - if (VDBG) log("isAudioOn()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - 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; - } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, + BluetoothStatusCodes.ERROR_TIMEOUT, + BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED, + BluetoothStatusCodes.ERROR_NO_ACTIVE_DEVICES, + BluetoothStatusCodes.ERROR_NOT_ACTIVE_DEVICE, + BluetoothStatusCodes.ERROR_AUDIO_ROUTE_BLOCKED, + BluetoothStatusCodes.ERROR_CALL_ACTIVE, + BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED + }) + public @interface ConnectAudioReturnValues {} /** - * 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}. - * - * <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 + * 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. * - * @return false if there was some error such as there is no active headset + * @return whether the connection was successfully initiated or an error code on failure * @hide */ - @UnsupportedAppUsage + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean connectAudio() { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @ConnectAudioReturnValues int connectAudio() { if (VDBG) log("connectAudio()"); final IBluetoothHeadset service = mService; - final boolean defaultValue = false; + final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN; if (service == null) { 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(); + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); service.connectAudio(mAttributionSource, recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { + } catch (RemoteException e) { 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; } + /** @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. - * Tear down voice recognition or virtual voice call if any. + * Initiates a disconnection of HFP SCO audio from actively connected devices. It also tears + * down voice recognition or virtual voice call, if any exists. * - * <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> If this function returns {@link BluetoothStatusCodes#SUCCESS}, the intent + * {@link #ACTION_AUDIO_STATE_CHANGED} 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 + * @return whether the disconnection was initiated successfully or an error code on failure * @hide */ - @UnsupportedAppUsage + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disconnectAudio() { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @DisconnectAudioReturnValues int disconnectAudio() { if (VDBG) log("disconnectAudio()"); final IBluetoothHeadset service = mService; - final boolean defaultValue = false; + final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN; if (service == null) { 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(); + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); service.disconnectAudio(mAttributionSource, recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { + } catch (RemoteException e) { 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; @@ -1386,7 +1421,10 @@ public final class BluetoothHeadset implements BluetoothProfile { @SystemApi @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean isInbandRingingEnabled() { if (DBG) log("isInbandRingingEnabled()"); final IBluetoothHeadset service = mService; diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java index fff32fffd8..a8ce4b4118 100644 --- a/framework/java/android/bluetooth/BluetoothStatusCodes.java +++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java @@ -20,7 +20,7 @@ import android.annotation.SystemApi; /** * 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 * occupies the max integer value. */ @@ -29,28 +29,28 @@ public final class BluetoothStatusCodes { private BluetoothStatusCodes() {} /** - * Indicates that the API call was successful + * Indicates that the API call was successful. */ 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; /** * 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; /** - * 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; /** - * 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 */ @@ -58,7 +58,7 @@ public final class BluetoothStatusCodes { /** * 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 */ @@ -66,13 +66,13 @@ public final class BluetoothStatusCodes { /** * 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; /** * 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 */ @@ -80,30 +80,67 @@ public final class BluetoothStatusCodes { /** * 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; /** * 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; /** - * 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. */ - 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. */ - 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 @@ -286,6 +323,38 @@ public final class BluetoothStatusCodes { 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. */ public static final int ERROR_UNKNOWN = Integer.MAX_VALUE; |