1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.bluetooth; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.List; 30 import java.util.Objects; 31 32 /** 33 * This class contains the broadcast group settings information for this Broadcast Group. 34 * 35 * @hide 36 */ 37 @SystemApi 38 public final class BluetoothLeBroadcastSettings implements Parcelable { 39 private final boolean mIsPublicBroadcast; 40 private final String mBroadcastName; 41 private final byte[] mBroadcastCode; 42 private final BluetoothLeAudioContentMetadata mPublicBroadcastMetadata; 43 private final List<BluetoothLeBroadcastSubgroupSettings> mSubgroupSettings; 44 BluetoothLeBroadcastSettings( boolean isPublicBroadcast, String broadcastName, byte[] broadcastCode, BluetoothLeAudioContentMetadata publicBroadcastMetadata, List<BluetoothLeBroadcastSubgroupSettings> subgroupSettings)45 private BluetoothLeBroadcastSettings( 46 boolean isPublicBroadcast, 47 String broadcastName, 48 byte[] broadcastCode, 49 BluetoothLeAudioContentMetadata publicBroadcastMetadata, 50 List<BluetoothLeBroadcastSubgroupSettings> subgroupSettings) { 51 mIsPublicBroadcast = isPublicBroadcast; 52 mBroadcastName = broadcastName; 53 mBroadcastCode = broadcastCode; 54 mPublicBroadcastMetadata = publicBroadcastMetadata; 55 mSubgroupSettings = subgroupSettings; 56 } 57 58 @Override equals(@ullable Object o)59 public boolean equals(@Nullable Object o) { 60 if (!(o instanceof BluetoothLeBroadcastSettings)) { 61 return false; 62 } 63 final BluetoothLeBroadcastSettings other = (BluetoothLeBroadcastSettings) o; 64 return mIsPublicBroadcast == other.isPublicBroadcast() 65 && Objects.equals(mBroadcastName, other.getBroadcastName()) 66 && Arrays.equals(mBroadcastCode, other.getBroadcastCode()) 67 && Objects.equals(mPublicBroadcastMetadata, other.getPublicBroadcastMetadata()) 68 && mSubgroupSettings.equals(other.getSubgroupSettings()); 69 } 70 71 @Override hashCode()72 public int hashCode() { 73 return Objects.hash( 74 mIsPublicBroadcast, 75 mBroadcastName, 76 Arrays.hashCode(mBroadcastCode), 77 mPublicBroadcastMetadata, 78 mSubgroupSettings); 79 } 80 81 /** 82 * Return {@code true} if this Broadcast Group is set to broadcast Public Broadcast Announcement 83 * otherwise return {@code false}. 84 * 85 * @hide 86 */ 87 @SystemApi isPublicBroadcast()88 public boolean isPublicBroadcast() { 89 return mIsPublicBroadcast; 90 } 91 92 /** 93 * Return the broadcast code for this Broadcast Group. 94 * 95 * @return Broadcast name for this Broadcast Group, null if no name provided 96 * @hide 97 */ 98 @SystemApi 99 @Nullable getBroadcastName()100 public String getBroadcastName() { 101 return mBroadcastName; 102 } 103 104 /** 105 * Get the Broadcast Code currently set for this broadcast group. 106 * 107 * <p>Only needed when encryption is enabled 108 * 109 * <p>As defined in Volume 3, Part C, Section 3.2.6 of Bluetooth Core Specification, Version 110 * 5.3, Broadcast Code is used to encrypt a broadcast audio stream. 111 * 112 * <p>It must be a UTF-8 string that has at least 4 octets and should not exceed 16 octets. 113 * 114 * @return Broadcast Code currently set for this broadcast group, null if code is not required 115 * or code is currently unknown 116 * @hide 117 */ 118 @SystemApi 119 @Nullable getBroadcastCode()120 public byte[] getBroadcastCode() { 121 return mBroadcastCode; 122 } 123 124 /** 125 * Get public broadcast metadata for this Broadcast Group. 126 * 127 * @return public broadcast metadata for this Broadcast Group, null if no public metadata exists 128 * @hide 129 */ 130 @SystemApi 131 @Nullable getPublicBroadcastMetadata()132 public BluetoothLeAudioContentMetadata getPublicBroadcastMetadata() { 133 return mPublicBroadcastMetadata; 134 } 135 136 /** 137 * Get available subgroup settings in the broadcast group. 138 * 139 * @return list of subgroup settings in the broadcast group 140 * @hide 141 */ 142 @SystemApi 143 @NonNull getSubgroupSettings()144 public List<BluetoothLeBroadcastSubgroupSettings> getSubgroupSettings() { 145 return mSubgroupSettings; 146 } 147 148 /** 149 * {@inheritDoc} 150 * 151 * @hide 152 */ 153 @Override describeContents()154 public int describeContents() { 155 return 0; 156 } 157 158 /** 159 * {@inheritDoc} 160 * 161 * @hide 162 */ 163 @Override writeToParcel(Parcel out, int flags)164 public void writeToParcel(Parcel out, int flags) { 165 out.writeBoolean(mIsPublicBroadcast); 166 BluetoothUtils.writeStringToParcel(out, mBroadcastName); 167 out.writeByteArray(mBroadcastCode); 168 out.writeTypedObject(mPublicBroadcastMetadata, 0); 169 out.writeTypedList(mSubgroupSettings); 170 } 171 172 /** 173 * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastSettings} from parcel. 174 * 175 * @hide 176 */ 177 @SystemApi @NonNull 178 public static final Creator<BluetoothLeBroadcastSettings> CREATOR = 179 new Creator<>() { 180 public @NonNull BluetoothLeBroadcastSettings createFromParcel(@NonNull Parcel in) { 181 Builder builder = new Builder(); 182 builder.setPublicBroadcast(in.readBoolean()); 183 builder.setBroadcastName(in.readString()); 184 byte[] broadcastCode = in.createByteArray(); 185 builder.setBroadcastCode(broadcastCode); 186 builder.setPublicBroadcastMetadata( 187 in.readTypedObject(BluetoothLeAudioContentMetadata.CREATOR)); 188 final List<BluetoothLeBroadcastSubgroupSettings> subgroupSettings = 189 new ArrayList<>(); 190 in.readTypedList( 191 subgroupSettings, BluetoothLeBroadcastSubgroupSettings.CREATOR); 192 for (BluetoothLeBroadcastSubgroupSettings setting : subgroupSettings) { 193 builder.addSubgroupSettings(setting); 194 } 195 return builder.build(); 196 } 197 198 public @NonNull BluetoothLeBroadcastSettings[] newArray(int size) { 199 return new BluetoothLeBroadcastSettings[size]; 200 } 201 }; 202 203 /** 204 * Builder for {@link BluetoothLeBroadcastSettings}. 205 * 206 * @hide 207 */ 208 @SystemApi 209 public static final class Builder { 210 private boolean mIsPublicBroadcast = false; 211 private String mBroadcastName = null; 212 private byte[] mBroadcastCode = null; 213 private BluetoothLeAudioContentMetadata mPublicBroadcastMetadata = null; 214 private List<BluetoothLeBroadcastSubgroupSettings> mSubgroupSettings = new ArrayList<>(); 215 216 /** 217 * Create an empty builder. 218 * 219 * @hide 220 */ 221 @SystemApi Builder()222 public Builder() {} 223 224 /** 225 * Create a builder with copies of information from original object. 226 * 227 * @param original original object 228 * @hide 229 */ 230 @SystemApi Builder(@onNull BluetoothLeBroadcastSettings original)231 public Builder(@NonNull BluetoothLeBroadcastSettings original) { 232 mIsPublicBroadcast = original.isPublicBroadcast(); 233 mBroadcastName = original.getBroadcastName(); 234 mBroadcastCode = original.getBroadcastCode(); 235 mPublicBroadcastMetadata = original.getPublicBroadcastMetadata(); 236 mSubgroupSettings = original.getSubgroupSettings(); 237 } 238 239 /** 240 * Set whether the Public Broadcast is on for this broadcast group. 241 * 242 * @param isPublicBroadcast whether the Public Broadcast is enabled 243 * @return this builder 244 * @hide 245 */ 246 @SystemApi 247 @NonNull setPublicBroadcast(boolean isPublicBroadcast)248 public Builder setPublicBroadcast(boolean isPublicBroadcast) { 249 mIsPublicBroadcast = isPublicBroadcast; 250 return this; 251 } 252 253 /** 254 * Set broadcast name for the broadcast group. 255 * 256 * <p>As defined in Public Broadcast Profile V1.0, section 5.1. Broadcast_Name AD Type is a 257 * UTF-8 encoded string containing a minimum of 4 characters and a maximum of 32 258 * human-readable characters. 259 * 260 * @param broadcastName Broadcast name for this broadcast group, null if no name provided 261 * @throws IllegalArgumentException if name is non-null and its length is less than 4 262 * characters or greater than 32 characters 263 * @return this builder 264 * @hide 265 */ 266 @SystemApi 267 @NonNull setBroadcastName(@ullable String broadcastName)268 public Builder setBroadcastName(@Nullable String broadcastName) { 269 if (broadcastName != null 270 && ((broadcastName.length() > 32) || (broadcastName.length() < 4))) { 271 throw new IllegalArgumentException("Invalid broadcast name length"); 272 } 273 mBroadcastName = broadcastName; 274 return this; 275 } 276 277 /** 278 * Set the Broadcast Code currently set for this broadcast group. 279 * 280 * <p>Only needed when encryption is enabled As defined in Volume 3, Part C, Section 3.2.6 281 * of Bluetooth Core Specification, Version 5.3, Broadcast Code is used to encrypt a 282 * broadcast audio stream. It must be a UTF-8 string that has at least 4 octets and should 283 * not exceed 16 octets. 284 * 285 * @param broadcastCode Broadcast Code for this broadcast group, null if code is not 286 * required for non-encrypted broadcast 287 * @throws IllegalArgumentException if name is non-null and its length is less than 4 288 * characters or greater than 16 characters 289 * @return this builder 290 * @hide 291 */ 292 @SystemApi 293 @NonNull setBroadcastCode(@ullable byte[] broadcastCode)294 public Builder setBroadcastCode(@Nullable byte[] broadcastCode) { 295 if (broadcastCode != null 296 && ((broadcastCode.length > 16) || (broadcastCode.length < 4))) { 297 throw new IllegalArgumentException("Invalid broadcast code length"); 298 } 299 mBroadcastCode = broadcastCode; 300 return this; 301 } 302 303 /** 304 * Set public broadcast metadata for this Broadcast Group. PBS should include the 305 * Program_Info length-type-value (LTV) structure metadata 306 * 307 * @param publicBroadcastMetadata public broadcast metadata for this Broadcast Group, null 308 * if no public meta data provided 309 * @return this builder 310 * @hide 311 */ 312 @SystemApi 313 @NonNull setPublicBroadcastMetadata( @ullable BluetoothLeAudioContentMetadata publicBroadcastMetadata)314 public Builder setPublicBroadcastMetadata( 315 @Nullable BluetoothLeAudioContentMetadata publicBroadcastMetadata) { 316 mPublicBroadcastMetadata = publicBroadcastMetadata; 317 return this; 318 } 319 320 /** 321 * Add a subgroup settings to the broadcast group. 322 * 323 * @param subgroupSettings contains subgroup's setting data 324 * @return this builder 325 * @hide 326 */ 327 @SystemApi 328 @NonNull addSubgroupSettings( @onNull BluetoothLeBroadcastSubgroupSettings subgroupSettings)329 public Builder addSubgroupSettings( 330 @NonNull BluetoothLeBroadcastSubgroupSettings subgroupSettings) { 331 requireNonNull(subgroupSettings); 332 mSubgroupSettings.add(subgroupSettings); 333 return this; 334 } 335 336 /** 337 * Clear subgroup settings list so that one can reset the builder 338 * 339 * @return this builder 340 * @hide 341 */ 342 @SystemApi 343 @NonNull clearSubgroupSettings()344 public Builder clearSubgroupSettings() { 345 mSubgroupSettings.clear(); 346 return this; 347 } 348 349 /** 350 * Build {@link BluetoothLeBroadcastSettings}. 351 * 352 * @return {@link BluetoothLeBroadcastSettings} 353 * @throws IllegalArgumentException if the object cannot be built 354 * @hide 355 */ 356 @SystemApi 357 @NonNull build()358 public BluetoothLeBroadcastSettings build() { 359 if (mSubgroupSettings.isEmpty()) { 360 throw new IllegalArgumentException("Must contain at least one subgroup"); 361 } 362 return new BluetoothLeBroadcastSettings( 363 mIsPublicBroadcast, 364 mBroadcastName, 365 mBroadcastCode, 366 mPublicBroadcastMetadata, 367 mSubgroupSettings); 368 } 369 } 370 } 371