1 /* 2 * Copyright (C) 2024 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 android.bluetooth.BluetoothSocket.SocketType; 20 21 import static java.util.Objects.requireNonNull; 22 23 import android.annotation.FlaggedApi; 24 import android.annotation.IntDef; 25 import android.annotation.IntRange; 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.annotation.RequiresNoPermission; 29 import android.annotation.SystemApi; 30 31 import com.android.bluetooth.flags.Flags; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.nio.charset.StandardCharsets; 36 import java.util.UUID; 37 38 /** 39 * Defines parameters for creating Bluetooth server and client socket channels. 40 * 41 * <p>Used with {@link BluetoothAdapter#listenUsingSocketSettings} to create a server socket and 42 * {@link BluetoothDevice#createUsingSocketSettings} to create a client socket. 43 * 44 * @see BluetoothAdapter#listenUsingSocketSettings 45 * @see BluetoothDevice#createUsingSocketSettings 46 */ 47 @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API) 48 public final class BluetoothSocketSettings { 49 50 private static final int L2CAP_PSM_UNSPECIFIED = -1; 51 52 /** 53 * Annotation to define the data path used for Bluetooth socket communication. This determines 54 * how data flows between the application and the Bluetooth controller. 55 * 56 * @hide 57 */ 58 @IntDef( 59 prefix = {"DATA_PATH_"}, 60 value = {DATA_PATH_NO_OFFLOAD, DATA_PATH_HARDWARE_OFFLOAD}) 61 @Retention(RetentionPolicy.SOURCE) 62 public @interface SocketDataPath {} 63 64 /** 65 * Non-offload data path where the application's socket data is processed by the main Bluetooth 66 * stack. 67 * 68 * @hide 69 */ 70 @SystemApi public static final int DATA_PATH_NO_OFFLOAD = 0; 71 72 /** 73 * Hardware offload data path where the application's socket data is processed by a offloaded 74 * application running on the low-power processor. 75 * 76 * <p>Using this data path requires the {@code BLUETOOTH_PRIVILEGED} permission, which will be 77 * checked when a socket connection or channel is created. 78 * 79 * @hide 80 */ 81 @SystemApi public static final int DATA_PATH_HARDWARE_OFFLOAD = 1; 82 83 /** 84 * Maximum size (in bytes) of a data packet that can be received from the endpoint when using 85 * {@link #DATA_PATH_HARDWARE_OFFLOAD}. 86 */ 87 @SystemApi private static final int HARDWARE_OFFLOAD_PACKET_MAX_SIZE = 65535; 88 89 /** 90 * Maximum length (in bytes) of a socket name when using {@link #DATA_PATH_HARDWARE_OFFLOAD}. 91 */ 92 @SystemApi private static final int HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH = 127; 93 94 /** 95 * Constant representing an invalid hub ID. This value indicates that a hub ID has not been 96 * assigned or is not valid. 97 * 98 * @hide 99 */ 100 private static final long INVALID_HUB_ID = 0; 101 102 /** 103 * Constant representing an invalid hub endpoint ID. This value indicates that an endpoint ID 104 * has not been assigned or is not valid. 105 * 106 * @hide 107 */ 108 private static final long INVALID_ENDPOINT_ID = 0; 109 110 /** Type of the Bluetooth socket */ 111 @SocketType private final int mSocketType; 112 113 /** Encryption requirement for the Bluetooth socket. */ 114 private final boolean mEncryptionRequired; 115 116 /** Authentication requirement for the Bluetooth socket. */ 117 private final boolean mAuthenticationRequired; 118 119 /** L2CAP Protocol/Service Multiplexer (PSM) for the Bluetooth Socket. */ 120 private final int mL2capPsm; 121 122 /** RFCOMM service name associated with the Bluetooth socket. */ 123 private final String mRfcommServiceName; 124 125 /** RFCOMM service UUID associated with the Bluetooth socket. */ 126 private final UUID mRfcommUuid; 127 128 /** 129 * Specifies the data path used for this socket, influencing how data is transmitted and 130 * processed. Select the appropriate data path based on performance and power consumption 131 * requirements: 132 * 133 * <ul> 134 * <li>{@link #DATA_PATH_NO_OFFLOAD}: Suitable for applications that require the full 135 * processing capabilities of the main Bluetooth stack. 136 * <li>{@link #DATA_PATH_HARDWARE_OFFLOAD}: Optimized for lower power consumption by utilizing 137 * an offloaded application running on a dedicated low-power processor. 138 * </ul> 139 */ 140 private final @SocketDataPath int mDataPath; 141 142 /** 143 * A user-friendly name for this socket, primarily for debugging and logging. This name should 144 * be descriptive and can help identify the socket during development and troubleshooting. 145 * 146 * <p>When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this name is also passed to the offloaded 147 * application running on the low-power processor. This allows the offloaded application to 148 * identify and manage the socket. 149 */ 150 private final String mSocketName; 151 152 /** 153 * When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this identifies the hub hosting the endpoint. 154 * 155 * <p>Hub represents a logical/physical representation of multiple endpoints. A pair of {@code 156 * mHubId} and {@code mEndpointId} uniquely identifies the endpoint globally. 157 */ 158 private final long mHubId; 159 160 /** 161 * When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this identifies the specific endpoint within 162 * the hub that is associated with this socket. 163 */ 164 private final long mEndpointId; 165 166 /** 167 * The maximum size (in bytes) of a single data packet that can be received from the endpoint 168 * when using {@link #DATA_PATH_HARDWARE_OFFLOAD}. 169 */ 170 private final int mMaximumPacketSize; 171 172 /** 173 * Returns the type of the Bluetooth socket. 174 * 175 * <p>Defaults to {@code BluetoothSocket#TYPE_RFCOMM}. 176 */ 177 @RequiresNoPermission 178 @SocketType getSocketType()179 public int getSocketType() { 180 return mSocketType; 181 } 182 183 /** Returns the L2CAP PSM value used for a BluetoothSocket#TYPE_LE socket. */ 184 @RequiresNoPermission getL2capPsm()185 public @IntRange(from = 128, to = 255) int getL2capPsm() { 186 return mL2capPsm; 187 } 188 189 /** 190 * Returns the RFCOMM service name used for a BluetoothSocket#TYPE_RFCOMM socket. 191 * 192 * <p>Defaults to {@code null}. 193 */ 194 @Nullable 195 @RequiresNoPermission getRfcommServiceName()196 public String getRfcommServiceName() { 197 return mRfcommServiceName; 198 } 199 200 /** 201 * Returns the RFCOMM service UUID used for a BluetoothSocket#TYPE_RFCOMM socket. 202 * 203 * <p>Defaults to {@code null}. 204 */ 205 @Nullable 206 @RequiresNoPermission getRfcommUuid()207 public UUID getRfcommUuid() { 208 return mRfcommUuid; 209 } 210 211 /** 212 * Checks if encryption is enabled for the Bluetooth socket. 213 * 214 * <p>Defaults to {@code false}. 215 */ 216 @RequiresNoPermission isEncryptionRequired()217 public boolean isEncryptionRequired() { 218 return mEncryptionRequired; 219 } 220 221 /** 222 * Checks if authentication is enabled for the Bluetooth socket. 223 * 224 * <p>Defaults to {@code false}. 225 */ 226 @RequiresNoPermission isAuthenticationRequired()227 public boolean isAuthenticationRequired() { 228 return mAuthenticationRequired; 229 } 230 231 /** 232 * Returns the data path used for this socket. The data path determines how data is routed and 233 * processed for the socket connection. 234 * 235 * <p>Defaults to {@link #DATA_PATH_NO_OFFLOAD}. 236 * 237 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 238 * available through the System API. 239 * 240 * @hide 241 */ 242 @SystemApi 243 @RequiresNoPermission getDataPath()244 public @SocketDataPath int getDataPath() { 245 return mDataPath; 246 } 247 248 /** 249 * Returns the user-friendly name assigned to this socket. This name is primarily used for 250 * debugging and logging purposes. 251 * 252 * <p>When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this name is also passed to the offloaded 253 * application running on the low-power processor. 254 * 255 * <p>Defaults to {@code null} if no name was explicitly set. 256 * 257 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 258 * available through the System API. 259 * 260 * @hide 261 */ 262 @SystemApi 263 @NonNull 264 @RequiresNoPermission getSocketName()265 public String getSocketName() { 266 return mSocketName; 267 } 268 269 /** 270 * Returns the ID of the hub associated with this socket when using {@link 271 * #DATA_PATH_HARDWARE_OFFLOAD}. 272 * 273 * <p>If the data path is not set to {@link #DATA_PATH_HARDWARE_OFFLOAD}, this method returns 274 * {@link #INVALID_HUB_ID}. 275 * 276 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 277 * available through the System API. 278 * 279 * @hide 280 */ 281 @SystemApi 282 @RequiresNoPermission getHubId()283 public long getHubId() { 284 if (mDataPath != DATA_PATH_HARDWARE_OFFLOAD) { 285 return INVALID_HUB_ID; 286 } 287 return mHubId; 288 } 289 290 /** 291 * Returns the ID of the endpoint within the hub associated with this socket when using {@link 292 * #DATA_PATH_HARDWARE_OFFLOAD}. An endpoint represents a specific point of communication within 293 * the hub. 294 * 295 * <p>If the data path is not set to {@link #DATA_PATH_HARDWARE_OFFLOAD}, this method returns 296 * {@link #INVALID_ENDPOINT_ID}. 297 * 298 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 299 * available through the System API. 300 * 301 * @hide 302 */ 303 @SystemApi 304 @RequiresNoPermission getEndpointId()305 public long getEndpointId() { 306 if (mDataPath != DATA_PATH_HARDWARE_OFFLOAD) { 307 return INVALID_ENDPOINT_ID; 308 } 309 return mEndpointId; 310 } 311 312 /** 313 * Returns the requested maximum size (in bytes) of a data packet that can be received from the 314 * endpoint associated with this socket when using {@link #DATA_PATH_HARDWARE_OFFLOAD}. 315 * 316 * <p>Defaults to {@link #HARDWARE_OFFLOAD_PACKET_MAX_SIZE}. 317 * 318 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 319 * available through the System API. 320 * 321 * @hide 322 */ 323 @SystemApi 324 @RequiresNoPermission getRequestedMaximumPacketSize()325 public int getRequestedMaximumPacketSize() { 326 return mMaximumPacketSize; 327 } 328 329 /** 330 * Returns a {@link String} that describes each BluetoothSocketSettings parameter current value. 331 */ 332 @Override toString()333 public String toString() { 334 StringBuilder builder = new StringBuilder("BluetoothSocketSettings{"); 335 builder.append("mSocketType=") 336 .append(mSocketType) 337 .append(", mEncryptionRequired=") 338 .append(mEncryptionRequired) 339 .append(", mAuthenticationRequired=") 340 .append(mAuthenticationRequired); 341 if (mSocketType == BluetoothSocket.TYPE_RFCOMM) { 342 builder.append(", mRfcommServiceName=") 343 .append(mRfcommServiceName) 344 .append(", mRfcommUuid=") 345 .append(mRfcommUuid); 346 } else { 347 builder.append(", mL2capPsm=").append(mL2capPsm); 348 } 349 if (mDataPath == DATA_PATH_HARDWARE_OFFLOAD) { 350 builder.append(", mDataPath=") 351 .append(mDataPath) 352 .append(", mSocketName=") 353 .append(mSocketName) 354 .append(", mHubId=") 355 .append(mHubId) 356 .append(", mEndpointId=") 357 .append(mEndpointId) 358 .append(", mMaximumPacketSize=") 359 .append(mMaximumPacketSize); 360 } 361 builder.append("}"); 362 return builder.toString(); 363 } 364 BluetoothSocketSettings( int socketType, int l2capPsm, boolean encryptionRequired, boolean authenticationRequired, String rfcommServiceName, UUID rfcommUuid, int dataPath, String socketName, long hubId, long endpointId, int maximumPacketSize)365 private BluetoothSocketSettings( 366 int socketType, 367 int l2capPsm, 368 boolean encryptionRequired, 369 boolean authenticationRequired, 370 String rfcommServiceName, 371 UUID rfcommUuid, 372 int dataPath, 373 String socketName, 374 long hubId, 375 long endpointId, 376 int maximumPacketSize) { 377 mSocketType = socketType; 378 mL2capPsm = l2capPsm; 379 mEncryptionRequired = encryptionRequired; 380 mAuthenticationRequired = authenticationRequired; 381 mRfcommUuid = rfcommUuid; 382 mRfcommServiceName = rfcommServiceName; 383 mDataPath = dataPath; 384 mSocketName = socketName; 385 mHubId = hubId; 386 mEndpointId = endpointId; 387 mMaximumPacketSize = maximumPacketSize; 388 } 389 390 /** Builder for {@link BluetoothSocketSettings}. */ 391 @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API) 392 public static final class Builder { 393 private int mSocketType = BluetoothSocket.TYPE_RFCOMM; 394 private int mL2capPsm = L2CAP_PSM_UNSPECIFIED; 395 private boolean mEncryptionRequired = false; 396 private boolean mAuthenticationRequired = false; 397 private String mRfcommServiceName = null; 398 private UUID mRfcommUuid = null; 399 private int mDataPath = DATA_PATH_NO_OFFLOAD; 400 private String mSocketName = BluetoothSocket.DEFAULT_SOCKET_NAME; 401 private long mHubId = INVALID_HUB_ID; 402 private long mEndpointId = INVALID_ENDPOINT_ID; 403 private int mMaximumPacketSize = HARDWARE_OFFLOAD_PACKET_MAX_SIZE; 404 Builder()405 public Builder() {} 406 407 /** 408 * Sets the socket type. 409 * 410 * <p>Must be one of: 411 * 412 * <ul> 413 * <li>{@link BluetoothSocket#TYPE_RFCOMM} 414 * <li>{@link BluetoothSocket#TYPE_LE} 415 * </ul> 416 * 417 * <p>Defaults to {@code BluetoothSocket#TYPE_RFCOMM}. 418 * 419 * @param socketType The type of socket. 420 * @return This builder. 421 * @throws IllegalArgumentException If {@code socketType} is invalid. 422 */ 423 @NonNull 424 @RequiresNoPermission setSocketType(@ocketType int socketType)425 public Builder setSocketType(@SocketType int socketType) { 426 if (socketType != BluetoothSocket.TYPE_RFCOMM 427 && socketType != BluetoothSocket.TYPE_LE) { 428 throw new IllegalArgumentException("invalid socketType - " + socketType); 429 } 430 mSocketType = socketType; 431 return this; 432 } 433 434 /** 435 * Sets the L2CAP PSM (Protocol/Service Multiplexer) for the Bluetooth socket. 436 * 437 * <p>This is only used for {@link BluetoothSocket#TYPE_LE} sockets. 438 * 439 * <p>Valid PSM values for {@link BluetoothSocket#TYPE_LE} sockets is ranging from 128 440 * (0x80) to 255 (0xFF). 441 * 442 * <p>Application using this API is responsible for obtaining protocol/service multiplexer 443 * (PSM) value from remote device. 444 * 445 * @param l2capPsm The L2CAP PSM value. 446 * @return This builder. 447 * @throws IllegalArgumentException If l2cap PSM is not in given range. 448 */ 449 @NonNull 450 @RequiresNoPermission setL2capPsm(@ntRangefrom = 128, to = 255) int l2capPsm)451 public Builder setL2capPsm(@IntRange(from = 128, to = 255) int l2capPsm) { 452 if (l2capPsm < 128 || l2capPsm > 255) { 453 throw new IllegalArgumentException("invalid L2cap PSM - " + l2capPsm); 454 } 455 mL2capPsm = l2capPsm; 456 return this; 457 } 458 459 /** 460 * Sets the encryption requirement for the Bluetooth socket. 461 * 462 * <p>Defaults to {@code false}. 463 * 464 * @param encryptionRequired {@code true} if encryption is required for this socket, {@code 465 * false} otherwise. 466 * @return This builder. 467 */ 468 @NonNull 469 @RequiresNoPermission setEncryptionRequired(boolean encryptionRequired)470 public Builder setEncryptionRequired(boolean encryptionRequired) { 471 mEncryptionRequired = encryptionRequired; 472 return this; 473 } 474 475 /** 476 * Sets the authentication requirement for the Bluetooth socket. 477 * 478 * <p>Defaults to {@code false}. 479 * 480 * @param authenticationRequired {@code true} if authentication is required for this socket, 481 * {@code false} otherwise. 482 * @return This builder. 483 */ 484 @NonNull 485 @RequiresNoPermission setAuthenticationRequired(boolean authenticationRequired)486 public Builder setAuthenticationRequired(boolean authenticationRequired) { 487 mAuthenticationRequired = authenticationRequired; 488 return this; 489 } 490 491 /** 492 * Sets the RFCOMM service name associated with the Bluetooth socket. 493 * 494 * <p>This name is used to identify the service when a remote device searches for it using 495 * SDP. 496 * 497 * <p>This is only used for {@link BluetoothSocket#TYPE_RFCOMM} sockets. 498 * 499 * <p>Defaults to {@code null}. 500 * 501 * @param rfcommServiceName The RFCOMM service name. 502 * @return This builder. 503 */ 504 @NonNull 505 @RequiresNoPermission setRfcommServiceName(@onNull String rfcommServiceName)506 public Builder setRfcommServiceName(@NonNull String rfcommServiceName) { 507 mRfcommServiceName = rfcommServiceName; 508 return this; 509 } 510 511 /** 512 * Sets the RFCOMM service UUID associated with the Bluetooth socket. 513 * 514 * <p>This UUID is used to uniquely identify the service when a remote device searches for 515 * it using SDP. 516 * 517 * <p>This is only used for {@link BluetoothSocket#TYPE_RFCOMM} sockets. 518 * 519 * <p>Defaults to {@code null}. 520 * 521 * @param rfcommUuid The RFCOMM service UUID. 522 * @return This builder. 523 */ 524 @NonNull 525 @RequiresNoPermission setRfcommUuid(@onNull UUID rfcommUuid)526 public Builder setRfcommUuid(@NonNull UUID rfcommUuid) { 527 mRfcommUuid = rfcommUuid; 528 return this; 529 } 530 531 /** 532 * Sets the data path for this socket. The data path determines how data is routed and 533 * processed for the socket connection. 534 * 535 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 536 * available through the System API. 537 * 538 * @param dataPath The desired data path for the socket. 539 * @return This Builder object to allow for method chaining. 540 * @throws IllegalArgumentException If {@code dataPath} is an invalid value. 541 * @hide 542 */ 543 @SystemApi 544 @NonNull 545 @RequiresNoPermission setDataPath(@ocketDataPath int dataPath)546 public Builder setDataPath(@SocketDataPath int dataPath) { 547 if (dataPath < DATA_PATH_NO_OFFLOAD || dataPath > DATA_PATH_HARDWARE_OFFLOAD) { 548 throw new IllegalArgumentException("Invalid dataPath - " + dataPath); 549 } 550 mDataPath = dataPath; 551 return this; 552 } 553 554 /** 555 * Sets a user-friendly name for this socket. This name is primarily used for debugging and 556 * logging purposes. 557 * 558 * <p>When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this name is also passed to the 559 * offloaded application running on low-power processor. 560 * 561 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 562 * available through the System API. 563 * 564 * @param socketName The desired name for the socket. This should be a descriptive name that 565 * helps identify the socket during development and troubleshooting. The socket name 566 * cannot exceed {@link #HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH} bytes in length when 567 * encoded in UTF-8. 568 * @return This Builder object to allow for method chaining. 569 * @throws IllegalArgumentException if the provided `socketName` exceeds {@link 570 * #HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH} bytes when encoded in UTF-8. 571 * @hide 572 */ 573 @SystemApi 574 @NonNull 575 @RequiresNoPermission setSocketName(@onNull String socketName)576 public Builder setSocketName(@NonNull String socketName) { 577 byte[] socketNameBytes = requireNonNull(socketName).getBytes(StandardCharsets.UTF_8); 578 if (socketNameBytes.length > HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH) { 579 throw new IllegalArgumentException( 580 "Socket name cannot exceed " 581 + HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH 582 + " bytes in length when encoded in UTF-8."); 583 } 584 mSocketName = requireNonNull(socketName); 585 return this; 586 } 587 588 /** 589 * Sets the ID of the hub to be associated with this socket when using {@link 590 * #DATA_PATH_HARDWARE_OFFLOAD}. 591 * 592 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 593 * available through the System API. 594 * 595 * @param hubId The ID of the hub. 596 * @return This Builder object to allow for method chaining. 597 * @hide 598 */ 599 @SystemApi 600 @NonNull 601 @RequiresNoPermission setHubId(long hubId)602 public Builder setHubId(long hubId) { 603 mHubId = hubId; 604 return this; 605 } 606 607 /** 608 * Sets the ID of the endpoint within the hub to be associated with this socket when using 609 * {@link #DATA_PATH_HARDWARE_OFFLOAD}. An endpoint represents a specific point of 610 * communication within the hub. 611 * 612 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 613 * available through the System API. 614 * 615 * @param endpointId The ID of the endpoint within the hub. 616 * @return This Builder object to allow for method chaining. 617 * @hide 618 */ 619 @SystemApi 620 @NonNull 621 @RequiresNoPermission setEndpointId(long endpointId)622 public Builder setEndpointId(long endpointId) { 623 mEndpointId = endpointId; 624 return this; 625 } 626 627 /** 628 * Sets the requested maximum size (in bytes) of a data packet that can be received from the 629 * endpoint associated with this socket when using {@link #DATA_PATH_HARDWARE_OFFLOAD}. 630 * 631 * <p>The main Bluetooth stack may adjust this value based on the actual capabilities 632 * negotiated with the peer device during connection establishment. To get the final 633 * negotiated value, use {@link BluetoothSocket#getMaxReceivePacketSize()} after the socket 634 * is connected. 635 * 636 * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only 637 * available through the System API. 638 * 639 * @param maximumPacketSize The maximum packet size in bytes. 640 * @return This Builder object to allow for method chaining. 641 * @hide 642 */ 643 @SystemApi 644 @NonNull 645 @RequiresNoPermission setRequestedMaximumPacketSize(int maximumPacketSize)646 public Builder setRequestedMaximumPacketSize(int maximumPacketSize) { 647 mMaximumPacketSize = maximumPacketSize; 648 return this; 649 } 650 651 /** 652 * Builds a {@link BluetoothSocketSettings} object. 653 * 654 * @return A new {@link BluetoothSocketSettings} object with the configured parameters. 655 * @throws IllegalArgumentException on invalid parameters 656 */ 657 @NonNull 658 @RequiresNoPermission build()659 public BluetoothSocketSettings build() { 660 if (mSocketType == BluetoothSocket.TYPE_RFCOMM) { 661 if (mRfcommUuid == null) { 662 throw new IllegalArgumentException("RFCOMM socket with missing uuid"); 663 } 664 if (mL2capPsm != L2CAP_PSM_UNSPECIFIED) { 665 throw new IllegalArgumentException( 666 "Invalid Socket config: " 667 + " Socket type: " 668 + mSocketType 669 + " L2cap PSM: " 670 + mL2capPsm); 671 } 672 } 673 if (mSocketType == BluetoothSocket.TYPE_LE) { 674 if (mRfcommUuid != null) { 675 throw new IllegalArgumentException( 676 "Invalid Socket config: " 677 + "Socket type: " 678 + mSocketType 679 + " Rfcomm Service Name: " 680 + mRfcommServiceName 681 + " Rfcomm Uuid: " 682 + mRfcommUuid); 683 } 684 } 685 if (mDataPath == DATA_PATH_HARDWARE_OFFLOAD) { 686 if (mHubId == INVALID_HUB_ID || mEndpointId == INVALID_ENDPOINT_ID) { 687 throw new IllegalArgumentException( 688 "Hub ID and endpoint ID must be set for hardware data path"); 689 } 690 if (mMaximumPacketSize < 0) { 691 throw new IllegalArgumentException("invalid packet size " + mMaximumPacketSize); 692 } 693 } else { 694 if (mHubId != INVALID_HUB_ID || mEndpointId != INVALID_ENDPOINT_ID) { 695 throw new IllegalArgumentException( 696 "Hub ID and endpoint ID may not be set for software data path"); 697 } 698 } 699 return new BluetoothSocketSettings( 700 mSocketType, 701 mL2capPsm, 702 mEncryptionRequired, 703 mAuthenticationRequired, 704 mRfcommServiceName, 705 mRfcommUuid, 706 mDataPath, 707 mSocketName, 708 mHubId, 709 mEndpointId, 710 mMaximumPacketSize); 711 } 712 } 713 } 714