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