diff options
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothLeBroadcast.java')
-rw-r--r-- | framework/java/android/bluetooth/BluetoothLeBroadcast.java | 460 |
1 files changed, 301 insertions, 159 deletions
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcast.java b/framework/java/android/bluetooth/BluetoothLeBroadcast.java index fed9f911d5..4537cc6f97 100644 --- a/framework/java/android/bluetooth/BluetoothLeBroadcast.java +++ b/framework/java/android/bluetooth/BluetoothLeBroadcast.java @@ -16,271 +16,413 @@ package android.bluetooth; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.content.Context; import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Collections; import java.util.List; +import java.util.concurrent.Executor; /** - * This class provides the public APIs to control the Bluetooth LE Broadcast Source profile. + * This class provides the public APIs to control the BAP Broadcast Source profile. * - * <p>BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast - * Source Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} - * to get the BluetoothLeBroadcast proxy object. + * <p>BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast Source + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothLeBroadcast + * proxy object. * * @hide */ -public final class BluetoothLeBroadcast implements BluetoothProfile { +@SystemApi +public final class BluetoothLeBroadcast implements AutoCloseable, BluetoothProfile { private static final String TAG = "BluetoothLeBroadcast"; private static final boolean DBG = true; - private static final boolean VDBG = false; /** - * Constants used by the LE Audio Broadcast profile for the Broadcast state - * - * @hide - */ - @IntDef(prefix = {"LE_AUDIO_BROADCAST_STATE_"}, value = { - LE_AUDIO_BROADCAST_STATE_DISABLED, - LE_AUDIO_BROADCAST_STATE_ENABLING, - LE_AUDIO_BROADCAST_STATE_ENABLED, - LE_AUDIO_BROADCAST_STATE_DISABLING, - LE_AUDIO_BROADCAST_STATE_PLAYING, - LE_AUDIO_BROADCAST_STATE_NOT_PLAYING - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioBroadcastState {} - - /** - * Indicates that LE Audio Broadcast mode is currently disabled - * + * Interface for receiving events related to Broadcast Source * @hide */ - public static final int LE_AUDIO_BROADCAST_STATE_DISABLED = 10; + @SystemApi + public interface Callback { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST, + BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST, + BluetoothStatusCodes.REASON_SYSTEM_POLICY, + BluetoothStatusCodes.ERROR_HARDWARE_GENERIC, + BluetoothStatusCodes.ERROR_BAD_PARAMETERS, + BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES, + BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_CODE, + BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID, + BluetoothStatusCodes.ERROR_LE_CONTENT_METADATA_INVALID_PROGRAM_INFO, + BluetoothStatusCodes.ERROR_LE_CONTENT_METADATA_INVALID_LANGUAGE, + BluetoothStatusCodes.ERROR_LE_CONTENT_METADATA_INVALID_OTHER, + }) + @interface Reason {} - /** - * Indicates that LE Audio Broadcast mode is being enabled - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_ENABLING = 11; + /** + * Callback invoked when broadcast is started, but audio may not be playing. + * + * Caller should wait for + * {@link #onBroadcastMetadataChanged(int, BluetoothLeBroadcastMetadata)} + * for the updated metadata + * + * @param reason for broadcast start + * @param broadcastId as defined by the Basic Audio Profile + * @hide + */ + @SystemApi + void onBroadcastStarted(@Reason int reason, int broadcastId); - /** - * Indicates that LE Audio Broadcast mode is currently enabled - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_ENABLED = 12; - /** - * Indicates that LE Audio Broadcast mode is being disabled - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_DISABLING = 13; + /** + * Callback invoked when broadcast failed to start + * + * @param reason for broadcast start failure + * @hide + */ + @SystemApi + void onBroadcastStartFailed(@Reason int reason); - /** - * Indicates that an LE Audio Broadcast mode is currently playing - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_PLAYING = 14; + /** + * Callback invoked when broadcast is stopped + * + * @param reason for broadcast stop + * @hide + */ + @SystemApi + void onBroadcastStopped(@Reason int reason, int broadcastId); - /** - * Indicates that LE Audio Broadcast is currently not playing - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_NOT_PLAYING = 15; + /** + * Callback invoked when broadcast failed to stop + * + * @param reason for broadcast stop failure + * @hide + */ + @SystemApi + void onBroadcastStopFailed(@Reason int reason); - /** - * Constants used by the LE Audio Broadcast profile for encryption key length - * - * @hide - */ - @IntDef(prefix = {"LE_AUDIO_BROADCAST_ENCRYPTION_KEY_"}, value = { - LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT, - LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioEncryptionKeyLength {} + /** + * Callback invoked when broadcast audio is playing + * + * @param reason for playback start + * @param broadcastId as defined by the Basic Audio Profile + * @hide + */ + @SystemApi + void onPlaybackStarted(@Reason int reason, int broadcastId); - /** - * Indicates that the LE Audio Broadcast encryption key size is 32 bits. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT = 16; + /** + * Callback invoked when broadcast audio is not playing + * + * @param reason for playback stop + * @param broadcastId as defined by the Basic Audio Profile + * @hide + */ + @SystemApi + void onPlaybackStopped(@Reason int reason, int broadcastId); - /** - * Indicates that the LE Audio Broadcast encryption key size is 128 bits. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT = 17; + /** + * Callback invoked when encryption is enabled + * + * @param reason for encryption enable + * @param broadcastId as defined by the Basic Audio Profile + * @hide + */ + @SystemApi + void onBroadcastUpdated(@Reason int reason, int broadcastId); - /** - * Interface for receiving events related to broadcasts - */ - public interface Callback { /** - * Called when broadcast state has changed + * Callback invoked when Broadcast Source failed to update * - * @param prevState broadcast state before the change - * @param newState broadcast state after the change + * @param reason for update failure + * @param broadcastId as defined by the Basic Audio Profile + * @hide */ - @LeAudioBroadcastState - void onBroadcastStateChange(int prevState, int newState); + @SystemApi + void onBroadcastUpdateFailed(int reason, int broadcastId); + /** - * Called when encryption key has been updated + * Callback invoked when Broadcast Source metadata is updated * - * @param success true if the key was updated successfully, false otherwise + * @param metadata updated Broadcast Source metadata + * @param broadcastId as defined by the Basic Audio Profile + * @hide */ - void onEncryptionKeySet(boolean success); + @SystemApi + void onBroadcastMetadataChanged(int broadcastId, + @NonNull BluetoothLeBroadcastMetadata metadata); } /** - * Create a BluetoothLeBroadcast proxy object for interacting with the local - * LE Audio Broadcast Source service. + * Create a BluetoothLeBroadcast proxy object for interacting with the local LE Audio Broadcast + * Source service. * + * @param context for to operate this API class + * @param listener listens for service callbacks across binder * @hide */ - /*package*/ BluetoothLeBroadcast(Context context, - BluetoothProfile.ServiceListener listener) { - } + /*package*/ BluetoothLeBroadcast(Context context, BluetoothProfile.ServiceListener listener) {} /** - * Not supported since LE Audio Broadcasts do not establish a connection - * - * @throws UnsupportedOperationException + * Not supported since LE Audio Broadcasts do not establish a connection. * * @hide */ @Override - public int getConnectionState(BluetoothDevice device) { - throw new UnsupportedOperationException( - "LE Audio Broadcasts are not connection-oriented."); + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public int getConnectionState(@NonNull BluetoothDevice device) { + throw new UnsupportedOperationException("LE Audio Broadcasts are not connection-oriented."); } /** - * Not supported since LE Audio Broadcasts do not establish a connection - * - * @throws UnsupportedOperationException + * Not supported since LE Audio Broadcasts do not establish a connection. * * @hide */ @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { - throw new UnsupportedOperationException( - "LE Audio Broadcasts are not connection-oriented."); + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates( + @NonNull int[] states) { + throw new UnsupportedOperationException("LE Audio Broadcasts are not connection-oriented."); } /** - * Not supported since LE Audio Broadcasts do not establish a connection - * - * @throws UnsupportedOperationException + * Not supported since LE Audio Broadcasts do not establish a connection. * * @hide */ @Override - public List<BluetoothDevice> getConnectedDevices() { - throw new UnsupportedOperationException( - "LE Audio Broadcasts are not connection-oriented."); + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @NonNull List<BluetoothDevice> getConnectedDevices() { + throw new UnsupportedOperationException("LE Audio Broadcasts are not connection-oriented."); } /** - * Enable LE Audio Broadcast mode. + * Register a {@link Callback} that will be invoked during the operation of this profile. * - * Generates a new broadcast ID and enables sending of encrypted or unencrypted - * isochronous PDUs + * Repeated registration of the same <var>callback</var> object will have no effect after + * the first call to this method, even when the <var>executor</var> is different. API caller + * would have to call {@link #unregisterCallback(Callback)} with + * the same callback object before registering it again. * + * @param executor an {@link Executor} to execute given callback + * @param callback user implementation of the {@link Callback} + * @throws IllegalArgumentException if a null executor, sink, or callback is given * @hide */ - public int enableBroadcastMode() { - if (DBG) log("enableBroadcastMode"); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED; + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void registerCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull Callback callback) { + if (executor == null) { + throw new IllegalArgumentException("executor cannot be null"); + } + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + log("registerCallback"); + throw new UnsupportedOperationException("Not Implemented"); } /** - * Disable LE Audio Broadcast mode. + * Unregister the specified {@link Callback} + * <p>The same {@link Callback} object used when calling + * {@link #registerCallback(Executor, Callback)} must be used. + * + * <p>Callbacks are automatically unregistered when application process goes away * + * @param callback user implementation of the {@link Callback} + * @throws IllegalArgumentException when callback is null or when no callback is registered * @hide */ - public int disableBroadcastMode() { - if (DBG) log("disableBroadcastMode"); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED; + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void unregisterCallback(@NonNull Callback callback) { + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + log("unregisterCallback"); + throw new UnsupportedOperationException("Not Implemented"); } /** - * Get the current LE Audio broadcast state + * Start broadcasting to nearby devices using <var>broadcastCode</var> and + * <var>contentMetadata</var> + * + * Encryption will be enabled when <var>broadcastCode</var> is not null. + * + * <p>As defined in Volume 3, Part C, Section 3.2.6 of Bluetooth Core Specification, Version + * 5.3, Broadcast Code is used to encrypt a broadcast audio stream. + * <p>It must be a UTF-8 string that has at least 4 octets and should not exceed 16 octets. * + * If the provided <var>broadcastCode</var> is non-null and does not meet the above + * requirements, encryption will fail to enable with reason code + * {@link BluetoothStatusCodes#ERROR_LE_BROADCAST_INVALID_CODE} + * + * Caller can set content metadata such as program information string in + * <var>contentMetadata</var> + * + * On success, {@link Callback#onBroadcastStarted(int, int)} will be invoked with + * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} reason code. + * On failure, {@link Callback#onBroadcastStartFailed(int)} will be invoked with reason code. + * + * In particular, when the number of Broadcast Sources reaches + * {@link #getMaximumNumberOfBroadcast()}, this method will fail with + * {@link BluetoothStatusCodes#ERROR_LOCAL_NOT_ENOUGH_RESOURCES} + * + * After broadcast is started, + * {@link Callback#onBroadcastMetadataChanged(int, BluetoothLeBroadcastMetadata)} + * will be invoked to expose the latest Broadcast Group metadata that can be shared out of band + * to set up Broadcast Sink without scanning. + * + * Alternatively, one can also get the latest Broadcast Source meta via + * {@link #getAllBroadcastMetadata()} + * + * @param contentMetadata metadata for the default Broadcast subgroup + * @param broadcastCode Encryption will be enabled when <var>broadcastCode</var> is not null + * @throws IllegalArgumentException if <var>contentMetadata</var> is null + * @throws IllegalStateException if callback was not registered * @hide */ - @LeAudioBroadcastState - public int getBroadcastState() { - if (DBG) log("getBroadcastState"); - return LE_AUDIO_BROADCAST_STATE_DISABLED; + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void startBroadcast(@NonNull BluetoothLeAudioContentMetadata contentMetadata, + @Nullable byte[] broadcastCode) { + if (DBG) log("startBroadcasting"); } /** - * Enable LE Audio broadcast encryption + * Update the broadcast with <var>broadcastId</var> with new <var>contentMetadata</var> * - * @param keyLength if useExisting is true, this specifies the length of the key that should - * be generated - * @param useExisting true, if an existing key should be used - * false, if a new key should be generated + * On success, {@link Callback#onBroadcastUpdated(int, int)} will be invoked with reason code + * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}. + * On failure, {@link Callback#onBroadcastUpdateFailed(int, int)} will be invoked with reason + * code * + * @param broadcastId broadcastId as defined by the Basic Audio Profile + * @param contentMetadata updated metadata for the default Broadcast subgroup + * @throws IllegalStateException if callback was not registered * @hide */ - @LeAudioEncryptionKeyLength - public int enableEncryption(boolean useExisting, int keyLength) { - if (DBG) log("enableEncryption useExisting=" + useExisting + " keyLength=" + keyLength); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED; + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void updateBroadcast(int broadcastId, + @NonNull BluetoothLeAudioContentMetadata contentMetadata) { + } /** - * Disable LE Audio broadcast encryption + * Stop broadcasting. * - * @param removeExisting true, if the existing key should be removed - * false, otherwise + * On success, {@link Callback#onBroadcastStopped(int, int)} will be invoked with reason code + * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} and the <var>broadcastId</var> + * On failure, {@link Callback#onBroadcastStopFailed(int)} will be invoked with reason code * + * @param broadcastId as defined by the Basic Audio Profile + * @throws IllegalStateException if callback was not registered * @hide */ - public int disableEncryption(boolean removeExisting) { - if (DBG) log("disableEncryption removeExisting=" + removeExisting); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED; + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void stopBroadcast(int broadcastId) { + if (DBG) log("disableBroadcastMode"); } /** - * Enable or disable LE Audio broadcast encryption - * - * @param key use the provided key if non-null, generate a new key if null - * @param keyLength 0 if encryption is disabled, 4 bytes (low security), - * 16 bytes (high security) + * Return true if audio is being broadcasted on the Broadcast Source as identified by the + * <var>broadcastId</var> * + * @param broadcastId as defined in the Basic Audio Profile + * @return true if audio is being broadcasted * @hide */ - @LeAudioEncryptionKeyLength - public int setEncryptionKey(byte[] key, int keyLength) { - if (DBG) log("setEncryptionKey key=" + key + " keyLength=" + keyLength); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED; + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean isPlaying(int broadcastId) { + return false; } - /** - * Get the encryption key that was set before - * - * @return encryption key as a byte array or null if no encryption key was set + * Get {@link BluetoothLeBroadcastMetadata} for all Broadcast Groups currently running on + * this device * + * @return list of {@link BluetoothLeBroadcastMetadata} * @hide */ - public byte[] getEncryptionKey() { - if (DBG) log("getEncryptionKey"); - return null; + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @NonNull List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() { + return Collections.emptyList(); } + /** + * Get the maximum number of broadcast groups supported on this device + * @return maximum number of broadcast groups supported on this device + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + public int getMaximumNumberOfBroadcast() { + return 1; + } + + /** + * {@inheritDoc} + * @hide + */ + @Override + public void close() throws Exception {} + private static void log(String msg) { Log.d(TAG, msg); } |