1 /* 2 * Copyright (C) 2019 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.net.wifi; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.SystemApi; 25 import android.app.compat.CompatChanges; 26 import android.compat.annotation.ChangeId; 27 import android.compat.annotation.EnabledAfter; 28 import android.net.MacAddress; 29 import android.net.wifi.util.HexEncoding; 30 import android.os.Build; 31 import android.os.Parcel; 32 import android.os.Parcelable; 33 import android.text.TextUtils; 34 import android.util.Log; 35 import android.util.SparseIntArray; 36 37 import androidx.annotation.RequiresApi; 38 import androidx.annotation.VisibleForTesting; 39 40 import com.android.internal.util.Preconditions; 41 import com.android.modules.utils.build.SdkLevel; 42 import com.android.wifi.flags.Flags; 43 44 import java.lang.annotation.Retention; 45 import java.lang.annotation.RetentionPolicy; 46 import java.nio.charset.StandardCharsets; 47 import java.util.ArrayList; 48 import java.util.HashSet; 49 import java.util.List; 50 import java.util.Objects; 51 import java.util.Set; 52 import java.util.stream.Collectors; 53 import java.util.stream.IntStream; 54 55 /** 56 * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot). 57 * 58 * <p>This is input for the framework provided by a client app, i.e. it exposes knobs to instruct 59 * the framework how it should configure a hotspot. 60 * 61 * <p>System apps can use this to configure a tethered hotspot or local-only hotspot. 62 * 63 * <p>Instances of this class are immutable. 64 */ 65 public final class SoftApConfiguration implements Parcelable { 66 67 private static final String TAG = "SoftApConfiguration"; 68 69 @VisibleForTesting 70 static final int PSK_MIN_LEN = 8; 71 72 @VisibleForTesting 73 static final int PSK_MAX_LEN = 63; 74 75 /** 76 * 2GHz band. 77 * @hide 78 */ 79 @SystemApi 80 public static final int BAND_2GHZ = 1 << 0; 81 82 /** 83 * 5GHz band. 84 * @hide 85 */ 86 @SystemApi 87 public static final int BAND_5GHZ = 1 << 1; 88 89 /** 90 * 6GHz band. 91 * @hide 92 */ 93 @SystemApi 94 public static final int BAND_6GHZ = 1 << 2; 95 96 /** 97 * 60GHz band. 98 * @hide 99 */ 100 @SystemApi 101 public static final int BAND_60GHZ = 1 << 3; 102 103 /** 104 * Device is allowed to choose the optimal band (2GHz, 5GHz, 6GHz) based on device capability, 105 * operating country code and current radio conditions. 106 * @hide 107 * 108 * @deprecated This is no longer supported. The value is fixed at 109 * (BAND_2GHZ | BAND_5GHZ | BAND_6GHZ) even if a new band is supported in the future, for 110 * instance {@code BAND_60GHZ}. The bands are a bit mask - use any combination of 111 * {@code BAND_}, for instance {@code BAND_2GHZ | BAND_5GHZ}. 112 */ 113 @SystemApi 114 public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ; 115 116 /** 117 * A default value used to configure shut down timeout setting to default value. 118 * See {@link Builder#setShutdownTimeoutMillis(long)} or 119 * {@link Builder#setBridgedModeOpportunisticShutdownTimeoutMillis(long)} for details. 120 * 121 * @hide 122 */ 123 @SystemApi 124 public static final long DEFAULT_TIMEOUT = -1; 125 126 /** @hide */ 127 @Retention(RetentionPolicy.SOURCE) 128 @IntDef(flag = true, prefix = { "BAND_TYPE_" }, value = { 129 BAND_2GHZ, 130 BAND_5GHZ, 131 BAND_6GHZ, 132 BAND_60GHZ, 133 }) 134 public @interface BandType {} 135 136 /** 137 * All of the supported band types. 138 * @hide 139 */ 140 public static int[] BAND_TYPES = {BAND_2GHZ, BAND_5GHZ, BAND_6GHZ, BAND_60GHZ}; 141 isBandValid(@andType int band)142 private static boolean isBandValid(@BandType int band) { 143 int bandAny = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ | BAND_60GHZ; 144 return ((band != 0) && ((band & ~bandAny) == 0)); 145 } 146 147 private static final int MIN_CH_2G_BAND = 1; 148 private static final int MAX_CH_2G_BAND = 14; 149 private static final int MIN_CH_5G_BAND = 34; 150 private static final int MAX_CH_5G_BAND = 196; 151 private static final int MIN_CH_6G_BAND = 1; 152 private static final int MAX_CH_6G_BAND = 253; 153 private static final int MIN_CH_60G_BAND = 1; 154 private static final int MAX_CH_60G_BAND = 6; 155 156 /** 157 * Requires to configure MAC randomization setting to None when configuring BSSID. 158 */ 159 @ChangeId 160 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) 161 private static final long FORCE_MUTUAL_EXCLUSIVE_BSSID_MAC_RAMDONIZATION_SETTING = 215656264L; 162 163 /** 164 * Removes zero support on 165 * {@link android.net.wifi.SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}. 166 * 167 * @hide 168 */ 169 @ChangeId 170 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) 171 public static final long REMOVE_ZERO_FOR_TIMEOUT_SETTING = 213289672L; 172 isChannelBandPairValid(int channel, @BandType int band)173 private static boolean isChannelBandPairValid(int channel, @BandType int band) { 174 switch (band) { 175 case BAND_2GHZ: 176 if (channel < MIN_CH_2G_BAND || channel > MAX_CH_2G_BAND) { 177 return false; 178 } 179 break; 180 181 case BAND_5GHZ: 182 if (channel < MIN_CH_5G_BAND || channel > MAX_CH_5G_BAND) { 183 return false; 184 } 185 break; 186 187 case BAND_6GHZ: 188 if (channel < MIN_CH_6G_BAND || channel > MAX_CH_6G_BAND) { 189 return false; 190 } 191 break; 192 193 case BAND_60GHZ: 194 if (channel < MIN_CH_60G_BAND || channel > MAX_CH_60G_BAND) { 195 return false; 196 } 197 break; 198 199 default: 200 return false; 201 } 202 return true; 203 } 204 205 /** 206 * SSID for the AP, or null for a framework-determined SSID. 207 */ 208 private final @Nullable WifiSsid mWifiSsid; 209 210 /** 211 * BSSID for the AP, or null to use a framework-determined BSSID. 212 */ 213 private final @Nullable MacAddress mBssid; 214 215 /** 216 * Vendor elements for the AP, structured as dd+len+elements 217 */ 218 private final @NonNull List<ScanResult.InformationElement> mVendorElements; 219 220 /** 221 * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on 222 * the security type. 223 */ 224 private final @Nullable String mPassphrase; 225 226 /** 227 * This is a network that does not broadcast its SSID, so an 228 * SSID-specific probe request must be used for scans. 229 */ 230 private final boolean mHiddenSsid; 231 232 /** 233 * The operating channels of the dual APs. 234 * 235 * The SparseIntArray that consists the band and the channel of matching the band. 236 */ 237 @NonNull 238 private final SparseIntArray mChannels; 239 240 /** 241 * The set of allowed channels in 2.4GHz band to select from using ACS (Automatic Channel 242 * Selection) algorithm. 243 * 244 * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}. 245 * Otherwise, this set will be ignored. 246 * 247 * If the set is empty, then all channels in 2.4GHz band are allowed. 248 */ 249 private final @NonNull Set<Integer> mAllowedAcsChannels2g; 250 251 /** 252 * The set of allowed channels in 5GHz band to select from using ACS (Automatic Channel 253 * Selection) algorithm. 254 * 255 * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}. 256 * Otherwise, this set will be ignored. 257 * 258 * If the set is empty, then all channels in 5GHz are allowed. 259 */ 260 private final @NonNull Set<Integer> mAllowedAcsChannels5g; 261 262 /** 263 * The set of allowed channels in 6GHz band to select from using ACS (Automatic Channel 264 * Selection) algorithm. 265 * 266 * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}. 267 * Otherwise, this set will be ignored. 268 * 269 * If the set is empty, then all channels in 6GHz are allowed. 270 */ 271 private final @NonNull Set<Integer> mAllowedAcsChannels6g; 272 273 /** 274 * The maximum channel bandwidth for SoftAp operation 275 * 276 * Default value is SoftApInfo#CHANNEL_WIDTH_AUTO which means the channel bandwidth 277 * is to be selected by the chip based on device capabilities. 278 * <p> 279 * 280 * Valid values: {@link SoftApInfo#CHANNEL_WIDTH_AUTO}, 281 * {@link SoftApInfo#CHANNEL_WIDTH_20MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_40MHZ}, 282 * {@link SoftApInfo#CHANNEL_WIDTH_80MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_160MHZ}, 283 * {@link SoftApInfo#CHANNEL_WIDTH_320MHZ} 284 * 285 */ 286 private final @WifiAnnotations.Bandwidth int mMaxChannelBandwidth; 287 288 /** 289 * The maximim allowed number of clients that can associate to the AP. 290 */ 291 private final int mMaxNumberOfClients; 292 293 /** 294 * The operating security type of the AP. 295 * One of the following security types: 296 * {@link #SECURITY_TYPE_OPEN}, 297 * {@link #SECURITY_TYPE_WPA2_PSK}, 298 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 299 * {@link #SECURITY_TYPE_WPA3_SAE}, 300 * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION}, 301 * {@link #SECURITY_TYPE_WPA3_OWE} 302 */ 303 private final @SecurityType int mSecurityType; 304 305 /** 306 * The flag to indicate client need to authorize by user 307 * when client is connecting to AP. 308 */ 309 private final boolean mClientControlByUser; 310 311 /** 312 * The list of blocked client that can't associate to the AP. 313 */ 314 private final List<MacAddress> mBlockedClientList; 315 316 /** 317 * The list of allowed client that can associate to the AP. 318 */ 319 private final List<MacAddress> mAllowedClientList; 320 321 /** 322 * Whether auto shutdown of soft AP is enabled or not. 323 */ 324 private final boolean mAutoShutdownEnabled; 325 326 /** 327 * Delay in milliseconds before shutting down soft AP when 328 * there are no connected devices. 329 */ 330 private final long mShutdownTimeoutMillis; 331 332 /** @hide */ 333 @Retention(RetentionPolicy.SOURCE) 334 @IntDef(prefix = {"RANDOMIZATION_"}, value = { 335 RANDOMIZATION_NONE, 336 RANDOMIZATION_PERSISTENT, 337 RANDOMIZATION_NON_PERSISTENT}) 338 public @interface MacRandomizationSetting {} 339 340 /** 341 * Use the factory MAC address as the BSSID of the AP. 342 * 343 * @hide 344 */ 345 @SystemApi 346 public static final int RANDOMIZATION_NONE = 0; 347 348 /** 349 * Generate a persistent randomized MAC address as the BSSID of the AP. 350 * The MAC address is persisted per SSID - i.e. as long as the SSID of the AP doesn't change 351 * then it will have a persistent MAC address (which is initially random and is not the factory 352 * MAC address). 353 * 354 * @hide 355 */ 356 @SystemApi 357 public static final int RANDOMIZATION_PERSISTENT = 1; 358 359 /** 360 * Generate a randomized MAC address as the BSSID of the AP. The MAC address is not persisted 361 * - it is re-generated every time the AP is re-enabled. 362 * @hide 363 */ 364 @SystemApi 365 public static final int RANDOMIZATION_NON_PERSISTENT = 2; 366 367 /** 368 * Level of MAC randomization for the AP BSSID. 369 */ 370 @MacRandomizationSetting 371 private int mMacRandomizationSetting; 372 373 374 /** 375 * Whether opportunistic shutdown of an instance in bridged AP is enabled or not. 376 */ 377 private boolean mBridgedModeOpportunisticShutdownEnabled; 378 379 /** 380 * Whether 802.11ax AP is enabled or not. 381 */ 382 private boolean mIeee80211axEnabled; 383 384 /** 385 * Whether 802.11be AP is enabled or not. 386 */ 387 private boolean mIeee80211beEnabled; 388 389 /** 390 * Whether the current configuration is configured by user or not. 391 */ 392 private boolean mIsUserConfiguration; 393 394 /** 395 * Randomized MAC address to use with this configuration when MAC randomization setting 396 * is {@link #RANDOMIZATION_PERSISTENT}. 397 */ 398 private final @Nullable MacAddress mPersistentRandomizedMacAddress; 399 400 /** 401 * Delay in milliseconds before shutting down an instance in bridged AP. 402 */ 403 private final long mBridgedModeOpportunisticShutdownTimeoutMillis; 404 405 /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ 406 private @NonNull List<OuiKeyedData> mVendorData; 407 408 /** 409 * THe definition of security type OPEN. 410 */ 411 public static final int SECURITY_TYPE_OPEN = 0; 412 413 /** 414 * The definition of security type WPA2-PSK. 415 */ 416 public static final int SECURITY_TYPE_WPA2_PSK = 1; 417 418 /** 419 * The definition of security type WPA3-SAE Transition mode. 420 */ 421 public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2; 422 423 /** 424 * The definition of security type WPA3-SAE. 425 */ 426 public static final int SECURITY_TYPE_WPA3_SAE = 3; 427 428 /** 429 * The definition of security type WPA3-OWE Transition. 430 */ 431 public static final int SECURITY_TYPE_WPA3_OWE_TRANSITION = 4; 432 433 /** 434 * The definition of security type WPA3-OWE. 435 */ 436 public static final int SECURITY_TYPE_WPA3_OWE = 5; 437 438 /** @hide */ 439 @Retention(RetentionPolicy.SOURCE) 440 @IntDef(prefix = { "SECURITY_TYPE_" }, value = { 441 SECURITY_TYPE_OPEN, 442 SECURITY_TYPE_WPA2_PSK, 443 SECURITY_TYPE_WPA3_SAE_TRANSITION, 444 SECURITY_TYPE_WPA3_SAE, 445 SECURITY_TYPE_WPA3_OWE_TRANSITION, 446 SECURITY_TYPE_WPA3_OWE, 447 }) 448 public @interface SecurityType {} 449 450 /** Private constructor for Builder and Parcelable implementation. */ SoftApConfiguration( @ullable WifiSsid ssid, @Nullable MacAddress bssid, @Nullable String passphrase, boolean hiddenSsid, @NonNull SparseIntArray channels, @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled, long shutdownTimeoutMillis, boolean clientControlByUser, @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList, int macRandomizationSetting, boolean bridgedModeOpportunisticShutdownEnabled, boolean ieee80211axEnabled, boolean ieee80211beEnabled, boolean isUserConfiguration, long bridgedModeOpportunisticShutdownTimeoutMillis, @NonNull List<ScanResult.InformationElement> vendorElements, @Nullable MacAddress persistentRandomizedMacAddress, @NonNull Set<Integer> allowedAcsChannels24g, @NonNull Set<Integer> allowedAcsChannels5g, @NonNull Set<Integer> allowedAcsChannels6g, @WifiAnnotations.Bandwidth int maxChannelBandwidth, @Nullable List<OuiKeyedData> vendorData)451 private SoftApConfiguration( 452 @Nullable WifiSsid ssid, 453 @Nullable MacAddress bssid, 454 @Nullable String passphrase, 455 boolean hiddenSsid, 456 @NonNull SparseIntArray channels, 457 @SecurityType int securityType, 458 int maxNumberOfClients, 459 boolean shutdownTimeoutEnabled, 460 long shutdownTimeoutMillis, 461 boolean clientControlByUser, 462 @NonNull List<MacAddress> blockedList, 463 @NonNull List<MacAddress> allowedList, 464 int macRandomizationSetting, 465 boolean bridgedModeOpportunisticShutdownEnabled, 466 boolean ieee80211axEnabled, 467 boolean ieee80211beEnabled, 468 boolean isUserConfiguration, 469 long bridgedModeOpportunisticShutdownTimeoutMillis, 470 @NonNull List<ScanResult.InformationElement> vendorElements, 471 @Nullable MacAddress persistentRandomizedMacAddress, 472 @NonNull Set<Integer> allowedAcsChannels24g, 473 @NonNull Set<Integer> allowedAcsChannels5g, 474 @NonNull Set<Integer> allowedAcsChannels6g, 475 @WifiAnnotations.Bandwidth int maxChannelBandwidth, 476 @Nullable List<OuiKeyedData> vendorData) { 477 mWifiSsid = ssid; 478 mBssid = bssid; 479 mPassphrase = passphrase; 480 mHiddenSsid = hiddenSsid; 481 if (channels.size() != 0) { 482 mChannels = channels.clone(); 483 } else { 484 mChannels = new SparseIntArray(1); 485 mChannels.put(BAND_2GHZ, 0); 486 } 487 mSecurityType = securityType; 488 mMaxNumberOfClients = maxNumberOfClients; 489 mAutoShutdownEnabled = shutdownTimeoutEnabled; 490 mShutdownTimeoutMillis = shutdownTimeoutMillis; 491 mClientControlByUser = clientControlByUser; 492 mBlockedClientList = new ArrayList<>(blockedList); 493 mAllowedClientList = new ArrayList<>(allowedList); 494 mMacRandomizationSetting = macRandomizationSetting; 495 mBridgedModeOpportunisticShutdownEnabled = bridgedModeOpportunisticShutdownEnabled; 496 mIeee80211axEnabled = ieee80211axEnabled; 497 mIeee80211beEnabled = ieee80211beEnabled; 498 mIsUserConfiguration = isUserConfiguration; 499 mBridgedModeOpportunisticShutdownTimeoutMillis = 500 bridgedModeOpportunisticShutdownTimeoutMillis; 501 mVendorElements = new ArrayList<>(vendorElements); 502 mPersistentRandomizedMacAddress = persistentRandomizedMacAddress; 503 mAllowedAcsChannels2g = new HashSet<>(allowedAcsChannels24g); 504 mAllowedAcsChannels5g = new HashSet<>(allowedAcsChannels5g); 505 mAllowedAcsChannels6g = new HashSet<>(allowedAcsChannels6g); 506 mMaxChannelBandwidth = maxChannelBandwidth; 507 mVendorData = new ArrayList<>(vendorData); 508 } 509 510 @Override equals(Object otherObj)511 public boolean equals(Object otherObj) { 512 if (this == otherObj) { 513 return true; 514 } 515 if (!(otherObj instanceof SoftApConfiguration)) { 516 return false; 517 } 518 SoftApConfiguration other = (SoftApConfiguration) otherObj; 519 return Objects.equals(mWifiSsid, other.mWifiSsid) 520 && Objects.equals(mBssid, other.mBssid) 521 && Objects.equals(mPassphrase, other.mPassphrase) 522 && mHiddenSsid == other.mHiddenSsid 523 && mChannels.toString().equals(other.mChannels.toString()) 524 && mSecurityType == other.mSecurityType 525 && mMaxNumberOfClients == other.mMaxNumberOfClients 526 && mAutoShutdownEnabled == other.mAutoShutdownEnabled 527 && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis 528 && mClientControlByUser == other.mClientControlByUser 529 && Objects.equals(mBlockedClientList, other.mBlockedClientList) 530 && Objects.equals(mAllowedClientList, other.mAllowedClientList) 531 && mMacRandomizationSetting == other.mMacRandomizationSetting 532 && mBridgedModeOpportunisticShutdownEnabled 533 == other.mBridgedModeOpportunisticShutdownEnabled 534 && mIeee80211axEnabled == other.mIeee80211axEnabled 535 && mIeee80211beEnabled == other.mIeee80211beEnabled 536 && mIsUserConfiguration == other.mIsUserConfiguration 537 && mBridgedModeOpportunisticShutdownTimeoutMillis 538 == other.mBridgedModeOpportunisticShutdownTimeoutMillis 539 && Objects.equals(mVendorElements, other.mVendorElements) 540 && Objects.equals( 541 mPersistentRandomizedMacAddress, other.mPersistentRandomizedMacAddress) 542 && Objects.equals(mAllowedAcsChannels2g, other.mAllowedAcsChannels2g) 543 && Objects.equals(mAllowedAcsChannels5g, other.mAllowedAcsChannels5g) 544 && Objects.equals(mAllowedAcsChannels6g, other.mAllowedAcsChannels6g) 545 && mMaxChannelBandwidth == other.mMaxChannelBandwidth 546 && Objects.equals(mVendorData, other.mVendorData); 547 } 548 549 @Override hashCode()550 public int hashCode() { 551 return Objects.hash( 552 mWifiSsid, 553 mBssid, 554 mPassphrase, 555 mHiddenSsid, 556 mChannels.toString(), 557 mSecurityType, 558 mMaxNumberOfClients, 559 mAutoShutdownEnabled, 560 mShutdownTimeoutMillis, 561 mClientControlByUser, 562 mBlockedClientList, 563 mAllowedClientList, 564 mMacRandomizationSetting, 565 mBridgedModeOpportunisticShutdownEnabled, 566 mIeee80211axEnabled, 567 mIeee80211beEnabled, 568 mIsUserConfiguration, 569 mBridgedModeOpportunisticShutdownTimeoutMillis, 570 mVendorElements, 571 mPersistentRandomizedMacAddress, 572 mAllowedAcsChannels2g, 573 mAllowedAcsChannels5g, 574 mAllowedAcsChannels6g, 575 mMaxChannelBandwidth, 576 mVendorData); 577 } 578 579 @Override toString()580 public String toString() { 581 StringBuilder sbuf = new StringBuilder(); 582 sbuf.append("ssid = ").append(mWifiSsid == null ? null : mWifiSsid.toString()); 583 if (mBssid != null) sbuf.append(" \n bssid = ").append(mBssid.toString()); 584 sbuf.append(" \n Passphrase = ").append( 585 TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>"); 586 sbuf.append(" \n HiddenSsid = ").append(mHiddenSsid); 587 sbuf.append(" \n Channels = ").append(mChannels); 588 sbuf.append(" \n SecurityType = ").append(getSecurityType()); 589 sbuf.append(" \n MaxClient = ").append(mMaxNumberOfClients); 590 sbuf.append(" \n AutoShutdownEnabled = ").append(mAutoShutdownEnabled); 591 sbuf.append(" \n ShutdownTimeoutMillis = ").append(mShutdownTimeoutMillis); 592 sbuf.append(" \n ClientControlByUser = ").append(mClientControlByUser); 593 sbuf.append(" \n BlockedClientList = ").append(mBlockedClientList); 594 sbuf.append(" \n AllowedClientList= ").append(mAllowedClientList); 595 sbuf.append(" \n MacRandomizationSetting = ").append(mMacRandomizationSetting); 596 sbuf.append(" \n BridgedModeInstanceOpportunisticEnabled = ") 597 .append(mBridgedModeOpportunisticShutdownEnabled); 598 sbuf.append(" \n BridgedModeOpportunisticShutdownTimeoutMillis = ") 599 .append(mBridgedModeOpportunisticShutdownTimeoutMillis); 600 sbuf.append(" \n Ieee80211axEnabled = ").append(mIeee80211axEnabled); 601 sbuf.append(" \n Ieee80211beEnabled = ").append(mIeee80211beEnabled); 602 sbuf.append(" \n isUserConfiguration = ").append(mIsUserConfiguration); 603 sbuf.append(" \n vendorElements = ").append(mVendorElements); 604 sbuf.append(" \n mPersistentRandomizedMacAddress = ") 605 .append(mPersistentRandomizedMacAddress); 606 sbuf.append(" \n mAllowedAcsChannels2g = ").append(mAllowedAcsChannels2g); 607 sbuf.append(" \n mAllowedAcsChannels5g = ").append(mAllowedAcsChannels5g); 608 sbuf.append(" \n mAllowedAcsChannels6g = ").append(mAllowedAcsChannels6g); 609 sbuf.append(" \n mMaxChannelBandwidth = ").append(mMaxChannelBandwidth); 610 sbuf.append(" \n mVendorData = ").append(mVendorData); 611 return sbuf.toString(); 612 } 613 614 @Override writeToParcel(@onNull Parcel dest, int flags)615 public void writeToParcel(@NonNull Parcel dest, int flags) { 616 dest.writeParcelable(mWifiSsid, 0); 617 dest.writeParcelable(mBssid, flags); 618 dest.writeString(mPassphrase); 619 dest.writeBoolean(mHiddenSsid); 620 writeSparseIntArray(dest, mChannels); 621 dest.writeInt(mSecurityType); 622 dest.writeInt(mMaxNumberOfClients); 623 dest.writeBoolean(mAutoShutdownEnabled); 624 dest.writeLong(mShutdownTimeoutMillis); 625 dest.writeBoolean(mClientControlByUser); 626 dest.writeTypedList(mBlockedClientList); 627 dest.writeTypedList(mAllowedClientList); 628 dest.writeInt(mMacRandomizationSetting); 629 dest.writeBoolean(mBridgedModeOpportunisticShutdownEnabled); 630 dest.writeBoolean(mIeee80211axEnabled); 631 dest.writeBoolean(mIeee80211beEnabled); 632 dest.writeBoolean(mIsUserConfiguration); 633 dest.writeLong(mBridgedModeOpportunisticShutdownTimeoutMillis); 634 dest.writeTypedList(mVendorElements); 635 dest.writeParcelable(mPersistentRandomizedMacAddress, flags); 636 writeHashSetInt(dest, mAllowedAcsChannels2g); 637 writeHashSetInt(dest, mAllowedAcsChannels5g); 638 writeHashSetInt(dest, mAllowedAcsChannels6g); 639 dest.writeInt(mMaxChannelBandwidth); 640 dest.writeList(mVendorData); 641 } 642 643 /* Reference from frameworks/base/core/java/android/os/Parcel.java */ writeSparseIntArray(@onNull Parcel dest, @Nullable SparseIntArray val)644 private static void writeSparseIntArray(@NonNull Parcel dest, 645 @Nullable SparseIntArray val) { 646 if (val == null) { 647 dest.writeInt(-1); 648 return; 649 } 650 int n = val.size(); 651 dest.writeInt(n); 652 int i = 0; 653 while (i < n) { 654 dest.writeInt(val.keyAt(i)); 655 dest.writeInt(val.valueAt(i)); 656 i++; 657 } 658 } 659 660 /* Reference from frameworks/base/core/java/android/os/Parcel.java */ 661 @NonNull readSparseIntArray(@onNull Parcel in)662 private static SparseIntArray readSparseIntArray(@NonNull Parcel in) { 663 int n = in.readInt(); 664 if (n < 0) { 665 return new SparseIntArray(); 666 } 667 SparseIntArray sa = new SparseIntArray(n); 668 while (n > 0) { 669 int key = in.readInt(); 670 int value = in.readInt(); 671 sa.append(key, value); 672 n--; 673 } 674 return sa; 675 } 676 677 /* Write HashSet<Integer> into Parcel */ writeHashSetInt(@onNull Parcel dest, @NonNull Set<Integer> set)678 private static void writeHashSetInt(@NonNull Parcel dest, @NonNull Set<Integer> set) { 679 if (set.isEmpty()) { 680 dest.writeInt(-1); 681 return; 682 } 683 684 dest.writeInt(set.size()); 685 for (int val : set) { 686 dest.writeInt(val); 687 } 688 } 689 690 /* Read HashSet<Integer> from Parcel */ 691 @NonNull readHashSetInt(@onNull Parcel in)692 private static Set<Integer> readHashSetInt(@NonNull Parcel in) { 693 Set<Integer> set = new HashSet<>(); 694 int len = in.readInt(); 695 if (len < 0) { 696 return set; 697 } 698 699 for (int i = 0; i < len; i++) { 700 set.add(in.readInt()); 701 } 702 return set; 703 } 704 705 /* Read List<OuiKeyedData> from Parcel */ 706 @NonNull readOuiKeyedDataList(@onNull Parcel in)707 private static List<OuiKeyedData> readOuiKeyedDataList(@NonNull Parcel in) { 708 List<OuiKeyedData> dataList = new ArrayList<>(); 709 if (SdkLevel.isAtLeastT()) { 710 in.readList(dataList, OuiKeyedData.class.getClassLoader(), OuiKeyedData.class); 711 } else { 712 in.readList(dataList, OuiKeyedData.class.getClassLoader()); 713 } 714 return dataList; 715 } 716 717 @Override describeContents()718 public int describeContents() { 719 return 0; 720 } 721 722 @NonNull 723 public static final Creator<SoftApConfiguration> CREATOR = 724 new Creator<SoftApConfiguration>() { 725 @Override 726 public SoftApConfiguration createFromParcel(Parcel in) { 727 return new SoftApConfiguration( 728 in.readParcelable(WifiSsid.class.getClassLoader()), 729 in.readParcelable(MacAddress.class.getClassLoader()), 730 in.readString(), 731 in.readBoolean(), 732 readSparseIntArray(in), 733 in.readInt(), 734 in.readInt(), 735 in.readBoolean(), 736 in.readLong(), 737 in.readBoolean(), 738 in.createTypedArrayList(MacAddress.CREATOR), 739 in.createTypedArrayList(MacAddress.CREATOR), 740 in.readInt(), 741 in.readBoolean(), 742 in.readBoolean(), 743 in.readBoolean(), 744 in.readBoolean(), 745 in.readLong(), 746 in.createTypedArrayList(ScanResult.InformationElement.CREATOR), 747 in.readParcelable(MacAddress.class.getClassLoader()), 748 readHashSetInt(in), 749 readHashSetInt(in), 750 readHashSetInt(in), 751 in.readInt(), 752 readOuiKeyedDataList(in)); 753 } 754 755 @Override 756 public SoftApConfiguration[] newArray(int size) { 757 return new SoftApConfiguration[size]; 758 } 759 }; 760 761 /** 762 * Return the UTF-8 String set to be the SSID for the AP. If the SSID cannot be decoded as 763 * UTF-8, then this will return {@link WifiManager#UNKNOWN_SSID}. 764 * 765 * @deprecated Use {@link #getWifiSsid()} instead. 766 */ 767 @Nullable 768 @Deprecated getSsid()769 public String getSsid() { 770 if (mWifiSsid == null) { 771 return null; 772 } 773 CharSequence utf8Text = mWifiSsid.getUtf8Text(); 774 return utf8Text != null ? utf8Text.toString() : WifiManager.UNKNOWN_SSID; 775 } 776 777 /** 778 * Return WifiSsid set to be the SSID for the AP. 779 */ 780 @Nullable getWifiSsid()781 public WifiSsid getWifiSsid() { 782 return mWifiSsid; 783 } 784 785 /** 786 * Return VendorElements for the AP. 787 * @hide 788 */ 789 @NonNull 790 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 791 @SystemApi getVendorElements()792 public List<ScanResult.InformationElement> getVendorElements() { 793 if (!SdkLevel.isAtLeastT()) { 794 throw new UnsupportedOperationException(); 795 } 796 return getVendorElementsInternal(); 797 } 798 799 /** 800 * @see #getVendorElements() 801 * @hide 802 */ getVendorElementsInternal()803 public List<ScanResult.InformationElement> getVendorElementsInternal() { 804 return new ArrayList<>(mVendorElements); 805 } 806 807 /** 808 * Returns MAC address set to be BSSID for the AP. 809 */ 810 @Nullable getBssid()811 public MacAddress getBssid() { 812 return mBssid; 813 } 814 815 /** 816 * Returns String set to be passphrase for current AP. 817 */ 818 @Nullable getPassphrase()819 public String getPassphrase() { 820 return mPassphrase; 821 } 822 823 /** 824 * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or 825 * not (false: broadcasts its SSID) for the AP. 826 */ isHiddenSsid()827 public boolean isHiddenSsid() { 828 return mHiddenSsid; 829 } 830 831 /** 832 * Returns band type set to be the band for the AP. 833 * 834 * One or combination of {@code BAND_}, for instance 835 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}. 836 * 837 * Note: Returns the lowest band when more than one band is set. 838 * Use {@link #getChannels()} to get dual bands setting. 839 * 840 * See also {@link Builder#setBand(int)}. 841 * 842 * @deprecated This API is deprecated. Use {@link #getChannels()} instead. 843 * @hide 844 */ 845 @Deprecated 846 @SystemApi getBand()847 public @BandType int getBand() { 848 return mChannels.keyAt(0); 849 } 850 851 /** 852 * Returns a sorted array in ascending order that consists of the configured band types 853 * for the APs. 854 * 855 * The band type is one or combination of {@code BAND_}, for instance 856 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}. 857 * 858 * Note: return array may only include one band when current setting is single AP mode. 859 * See also {@link Builder#setBands(int[])}. 860 * 861 * @hide 862 */ getBands()863 public @NonNull int[] getBands() { 864 int[] bands = new int[mChannels.size()]; 865 for (int i = 0; i < bands.length; i++) { 866 bands[i] = mChannels.keyAt(i); 867 } 868 return bands; 869 } 870 871 /** 872 * Returns Integer set to be the channel for the AP. 873 * 874 * Note: Returns the channel which associated to the lowest band if more than one channel 875 * is set. Use {@link Builder#getChannels()} to get dual channel setting. 876 * See also {@link Builder#setChannel(int, int)}. 877 * 878 * @deprecated This API is deprecated. Use {@link #getChannels()} instead. 879 * @hide 880 */ 881 @Deprecated 882 @SystemApi getChannel()883 public int getChannel() { 884 return mChannels.valueAt(0); 885 } 886 887 888 /** 889 * Returns SparseIntArray (key: {@code BandType} , value: channel) that consists of 890 * the configured bands and channels for the AP(s). 891 * 892 * The returned channel value is Wi-Fi channel numbering. 893 * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016 894 * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6. 895 * 896 * Note: return array may only include one channel when current setting is single AP mode. 897 * See also {@link Builder#setChannels(SparseIntArray)}. 898 * 899 * @hide 900 */ 901 @RequiresApi(Build.VERSION_CODES.S) 902 @SystemApi getChannels()903 public @NonNull SparseIntArray getChannels() { 904 if (!SdkLevel.isAtLeastS()) { 905 throw new UnsupportedOperationException(); 906 } 907 return mChannels.clone(); 908 } 909 910 /** 911 * Get security type params which depends on which security passphrase to set. 912 * 913 * @return One of: 914 * {@link #SECURITY_TYPE_OPEN}, 915 * {@link #SECURITY_TYPE_WPA2_PSK}, 916 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 917 * {@link #SECURITY_TYPE_WPA3_SAE}, 918 * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION}, 919 * {@link #SECURITY_TYPE_WPA3_OWE} 920 */ getSecurityType()921 public @SecurityType int getSecurityType() { 922 return mSecurityType; 923 } 924 925 /** 926 * Returns the maximum number of clients that can associate to the AP. 927 * See also {@link Builder#setMaxNumberOfClients(int)}. 928 * 929 * @hide 930 */ 931 @SystemApi getMaxNumberOfClients()932 public int getMaxNumberOfClients() { 933 return mMaxNumberOfClients; 934 } 935 936 /** 937 * Returns whether auto shutdown is enabled or not. 938 * The Soft AP will shutdown when there are no devices associated to it for 939 * the timeout duration. See also {@link Builder#setAutoShutdownEnabled(boolean)}. 940 * 941 * @hide 942 */ 943 @SystemApi isAutoShutdownEnabled()944 public boolean isAutoShutdownEnabled() { 945 return mAutoShutdownEnabled; 946 } 947 948 /** 949 * Returns the shutdown timeout in milliseconds. 950 * The Soft AP will shutdown when there are no devices associated to it for 951 * the timeout duration. See also {@link Builder#setShutdownTimeoutMillis(long)}. 952 * 953 * @hide 954 */ 955 @SystemApi getShutdownTimeoutMillis()956 public long getShutdownTimeoutMillis() { 957 if (!CompatChanges.isChangeEnabled( 958 REMOVE_ZERO_FOR_TIMEOUT_SETTING) && mShutdownTimeoutMillis == DEFAULT_TIMEOUT) { 959 // For legacy application, return 0 when setting is DEFAULT_TIMEOUT. 960 return 0; 961 } 962 return mShutdownTimeoutMillis; 963 } 964 965 /** 966 * Returns a flag indicating whether clients need to be pre-approved by the user. 967 * (true: authorization required) or not (false: not required). 968 * See also {@link Builder#setClientControlByUserEnabled(Boolean)}. 969 * 970 * @hide 971 */ 972 @SystemApi isClientControlByUserEnabled()973 public boolean isClientControlByUserEnabled() { 974 return mClientControlByUser; 975 } 976 977 /** 978 * Returns List of clients which aren't allowed to associate to the AP. 979 * 980 * Clients are configured using {@link Builder#setBlockedClientList(List)} 981 * 982 * @hide 983 */ 984 @NonNull 985 @SystemApi getBlockedClientList()986 public List<MacAddress> getBlockedClientList() { 987 return mBlockedClientList; 988 } 989 990 /** 991 * List of clients which are allowed to associate to the AP. 992 * Clients are configured using {@link Builder#setAllowedClientList(List)} 993 * 994 * @hide 995 */ 996 @NonNull 997 @SystemApi getAllowedClientList()998 public List<MacAddress> getAllowedClientList() { 999 return mAllowedClientList; 1000 } 1001 1002 /** 1003 * Returns the level of MAC randomization for the AP BSSID. 1004 * See also {@link Builder#setMacRandomizationSetting(int)}. 1005 * 1006 * @hide 1007 */ 1008 @RequiresApi(Build.VERSION_CODES.S) 1009 @SystemApi 1010 @MacRandomizationSetting getMacRandomizationSetting()1011 public int getMacRandomizationSetting() { 1012 if (!SdkLevel.isAtLeastS()) { 1013 throw new UnsupportedOperationException(); 1014 } 1015 return getMacRandomizationSettingInternal(); 1016 } 1017 1018 /** 1019 * @hide 1020 */ 1021 @MacRandomizationSetting getMacRandomizationSettingInternal()1022 public int getMacRandomizationSettingInternal() { 1023 return mMacRandomizationSetting; 1024 } 1025 1026 /** 1027 * Returns whether opportunistic shutdown of an instance in bridged AP is enabled or not. 1028 * 1029 * See also {@link Builder#setBridgedModeOpportunisticShutdownEnabled(boolean}} 1030 * @hide 1031 */ 1032 @RequiresApi(Build.VERSION_CODES.S) 1033 @SystemApi isBridgedModeOpportunisticShutdownEnabled()1034 public boolean isBridgedModeOpportunisticShutdownEnabled() { 1035 if (!SdkLevel.isAtLeastS()) { 1036 throw new UnsupportedOperationException(); 1037 } 1038 return isBridgedModeOpportunisticShutdownEnabledInternal(); 1039 } 1040 1041 /** 1042 * @see #isBridgedModeOpportunisticShutdownEnabled() 1043 * @hide 1044 */ isBridgedModeOpportunisticShutdownEnabledInternal()1045 public boolean isBridgedModeOpportunisticShutdownEnabledInternal() { 1046 return mBridgedModeOpportunisticShutdownEnabled; 1047 } 1048 1049 /** 1050 * @see #isIeee80211axEnabled() 1051 * @hide 1052 */ isIeee80211axEnabledInternal()1053 public boolean isIeee80211axEnabledInternal() { 1054 return mIeee80211axEnabled; 1055 } 1056 1057 /** 1058 * Returns whether or not 802.11ax is enabled on the SoftAP. 1059 * This is an indication that if the device support 802.11ax AP then to enable or disable 1060 * that feature. If the device does not support 802.11ax AP then this flag is ignored. 1061 * See also {@link Builder#setIeee80211axEnabled(boolean}} 1062 * @hide 1063 */ 1064 @RequiresApi(Build.VERSION_CODES.S) 1065 @SystemApi isIeee80211axEnabled()1066 public boolean isIeee80211axEnabled() { 1067 if (!SdkLevel.isAtLeastS()) { 1068 throw new UnsupportedOperationException(); 1069 } 1070 return isIeee80211axEnabledInternal(); 1071 } 1072 1073 /** 1074 * Returns whether or not the Soft AP is configured to enable 802.11be. 1075 * This is an indication that if the device support 802.11be AP then to enable or disable 1076 * that feature. If the device does not support 802.11be AP then this flag is ignored. 1077 * See also {@link Builder#setIeee80211beEnabled(boolean}} 1078 * @hide 1079 */ 1080 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 1081 @SystemApi isIeee80211beEnabled()1082 public boolean isIeee80211beEnabled() { 1083 if (!SdkLevel.isAtLeastT()) { 1084 throw new UnsupportedOperationException(); 1085 } 1086 return mIeee80211beEnabled; 1087 } 1088 1089 /** 1090 * Returns the allowed channels for ACS in a selected band. 1091 * 1092 * If an empty array is returned, then all channels in that band are allowed 1093 * The channels are configured using {@link Builder#setAllowedAcsChannels(int, int[])} 1094 * 1095 * @param band one of the following band types: 1096 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 1097 * 1098 * @return array of the allowed channels for ACS in that band 1099 * 1100 * @hide 1101 */ 1102 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 1103 @NonNull 1104 @SystemApi getAllowedAcsChannels(@andType int band)1105 public int[] getAllowedAcsChannels(@BandType int band) { 1106 if (!SdkLevel.isAtLeastT()) { 1107 throw new UnsupportedOperationException(); 1108 } 1109 switch(band) { 1110 case BAND_2GHZ: 1111 return mAllowedAcsChannels2g.stream().mapToInt(Integer::intValue).toArray(); 1112 case BAND_5GHZ: 1113 return mAllowedAcsChannels5g.stream().mapToInt(Integer::intValue).toArray(); 1114 case BAND_6GHZ: 1115 return mAllowedAcsChannels6g.stream().mapToInt(Integer::intValue).toArray(); 1116 default: 1117 throw new IllegalArgumentException("getAllowedAcsChannels: Invalid band: " + band); 1118 } 1119 } 1120 1121 /** 1122 * Returns configured maximum channel bandwidth for the SoftAp connection. 1123 * 1124 * If not configured, it will return {@link SoftApInfo#CHANNEL_WIDTH_AUTO} 1125 * 1126 * @hide 1127 */ 1128 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 1129 @SystemApi getMaxChannelBandwidth()1130 public @WifiAnnotations.Bandwidth int getMaxChannelBandwidth() { 1131 if (!SdkLevel.isAtLeastT()) { 1132 throw new UnsupportedOperationException(); 1133 } 1134 return mMaxChannelBandwidth; 1135 } 1136 1137 /** 1138 * Returns whether or not the {@link SoftApConfiguration} was configured by the user 1139 * (as opposed to the default system configuration). 1140 * <p> 1141 * The {@link SoftApConfiguration} is considered user edited once the 1142 * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)} is called 1143 * - whether or not that configuration is the same as the default system configuration! 1144 * 1145 * @hide 1146 */ 1147 @RequiresApi(Build.VERSION_CODES.S) 1148 @SystemApi isUserConfiguration()1149 public boolean isUserConfiguration() { 1150 if (!SdkLevel.isAtLeastS()) { 1151 throw new UnsupportedOperationException(); 1152 } 1153 return isUserConfigurationInternal(); 1154 } 1155 1156 /** 1157 * Returns the randomized MAC address to be used by this configuration. 1158 * 1159 * The Soft AP may be configured to use a persistent randomized MAC address with 1160 * {@link Builder#setMacRandomizationSetting(int)}. This method returns the persistent 1161 * randomized MAC address which will be used for the Soft AP controlled by this configuration. 1162 * 1163 * @hide 1164 */ 1165 @SystemApi getPersistentRandomizedMacAddress()1166 public @NonNull MacAddress getPersistentRandomizedMacAddress() { 1167 return mPersistentRandomizedMacAddress; 1168 } 1169 1170 /** 1171 * @hide 1172 */ isUserConfigurationInternal()1173 public boolean isUserConfigurationInternal() { 1174 return mIsUserConfiguration; 1175 } 1176 1177 /** 1178 * Returns the bridged mode opportunistic shutdown timeout in milliseconds. 1179 * An instance in bridged AP will shutdown when there is no device associated to it for 1180 * the timeout duration. See also 1181 * {@link Builder#setBridgedModeOpportunisticShutdownTimeoutMillis(long)}. 1182 * 1183 * @hide 1184 */ 1185 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 1186 @SystemApi getBridgedModeOpportunisticShutdownTimeoutMillis()1187 public long getBridgedModeOpportunisticShutdownTimeoutMillis() { 1188 if (!SdkLevel.isAtLeastT()) { 1189 throw new UnsupportedOperationException(); 1190 } 1191 return mBridgedModeOpportunisticShutdownTimeoutMillis; 1192 } 1193 1194 1195 /** 1196 * @hide 1197 */ getBridgedModeOpportunisticShutdownTimeoutMillisInternal()1198 public long getBridgedModeOpportunisticShutdownTimeoutMillisInternal() { 1199 return mBridgedModeOpportunisticShutdownTimeoutMillis; 1200 } 1201 1202 /** 1203 * Return the vendor-provided configuration data, if it exists. See also {@link 1204 * Builder#setVendorData(List)} 1205 * 1206 * @return Vendor configuration data, or empty list if it does not exist. 1207 * @hide 1208 */ 1209 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) 1210 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 1211 @NonNull 1212 @SystemApi getVendorData()1213 public List<OuiKeyedData> getVendorData() { 1214 if (!SdkLevel.isAtLeastV()) { 1215 throw new UnsupportedOperationException(); 1216 } 1217 return mVendorData; 1218 } 1219 1220 /** 1221 * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}. 1222 * Note that SoftApConfiguration may contain configuration which is cannot be represented 1223 * by the legacy WifiConfiguration, in such cases a null will be returned. 1224 * 1225 * To maintain legacy behavior, the SSID of the WifiConfiguration will be the UTF-8 1226 * representation of the SSID without double quotes, as opposed to the double-quoted UTF-8 1227 * format documented in {@link WifiConfiguration#SSID}. If the SSID cannot be decoded as UTF-8, 1228 * then the SSID of the WifiConfiguration will be {@link WifiManager#UNKNOWN_SSID}. 1229 * 1230 * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports 1231 * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li> 1232 * 1233 * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports 1234 * NONE, WPA2_PSK, so conversion is limited to these security type.</li> 1235 * @hide 1236 */ 1237 @Nullable 1238 @SystemApi toWifiConfiguration()1239 public WifiConfiguration toWifiConfiguration() { 1240 WifiConfiguration wifiConfig = new WifiConfiguration(); 1241 CharSequence utf8Text = mWifiSsid != null ? mWifiSsid.getUtf8Text() : null; 1242 wifiConfig.SSID = utf8Text != null ? utf8Text.toString() : WifiManager.UNKNOWN_SSID; 1243 wifiConfig.preSharedKey = mPassphrase; 1244 wifiConfig.hiddenSSID = mHiddenSsid; 1245 wifiConfig.apChannel = getChannel(); 1246 switch (mSecurityType) { 1247 case SECURITY_TYPE_OPEN: 1248 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 1249 break; 1250 case SECURITY_TYPE_WPA2_PSK: 1251 case SECURITY_TYPE_WPA3_SAE_TRANSITION: 1252 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK); 1253 break; 1254 default: 1255 Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType); 1256 return null; 1257 } 1258 1259 switch (getBand()) { 1260 case BAND_2GHZ: 1261 wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ; 1262 break; 1263 case BAND_5GHZ: 1264 wifiConfig.apBand = WifiConfiguration.AP_BAND_5GHZ; 1265 break; 1266 case BAND_2GHZ | BAND_5GHZ: 1267 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 1268 break; 1269 case BAND_ANY: 1270 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 1271 break; 1272 default: 1273 Log.e(TAG, "Convert fail, unsupported band setting :" + getBand()); 1274 return null; 1275 } 1276 return wifiConfig; 1277 } 1278 1279 /** 1280 * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a 1281 * Soft AP. 1282 * 1283 * All fields are optional. By default, SSID and BSSID are automatically chosen by the 1284 * framework, and an open network is created. 1285 * 1286 * @hide 1287 */ 1288 @SystemApi 1289 public static final class Builder { 1290 private WifiSsid mWifiSsid; 1291 private MacAddress mBssid; 1292 private String mPassphrase; 1293 private boolean mHiddenSsid; 1294 private SparseIntArray mChannels; 1295 private int mMaxNumberOfClients; 1296 private int mSecurityType; 1297 private boolean mAutoShutdownEnabled; 1298 private long mShutdownTimeoutMillis; 1299 private boolean mClientControlByUser; 1300 private List<MacAddress> mBlockedClientList; 1301 private List<MacAddress> mAllowedClientList; 1302 private int mMacRandomizationSetting; 1303 private boolean mBridgedModeOpportunisticShutdownEnabled; 1304 private boolean mIeee80211axEnabled; 1305 private boolean mIeee80211beEnabled; 1306 private boolean mIsUserConfiguration; 1307 private long mBridgedModeOpportunisticShutdownTimeoutMillis; 1308 private List<ScanResult.InformationElement> mVendorElements; 1309 private MacAddress mPersistentRandomizedMacAddress; 1310 private Set<Integer> mAllowedAcsChannels2g; 1311 private Set<Integer> mAllowedAcsChannels5g; 1312 private Set<Integer> mAllowedAcsChannels6g; 1313 private @WifiAnnotations.Bandwidth int mMaxChannelBandwidth; 1314 private @Nullable List<OuiKeyedData> mVendorData; 1315 1316 /** 1317 * Constructs a Builder with default values (see {@link Builder}). 1318 */ Builder()1319 public Builder() { 1320 mWifiSsid = null; 1321 mBssid = null; 1322 mPassphrase = null; 1323 mHiddenSsid = false; 1324 mChannels = new SparseIntArray(1); 1325 mChannels.put(BAND_2GHZ, 0); 1326 mMaxNumberOfClients = 0; 1327 mSecurityType = SECURITY_TYPE_OPEN; 1328 mAutoShutdownEnabled = true; // enabled by default. 1329 mShutdownTimeoutMillis = DEFAULT_TIMEOUT; 1330 mClientControlByUser = false; 1331 mBlockedClientList = new ArrayList<>(); 1332 mAllowedClientList = new ArrayList<>(); 1333 if (SdkLevel.isAtLeastT()) { 1334 mMacRandomizationSetting = RANDOMIZATION_NON_PERSISTENT; 1335 } else { 1336 mMacRandomizationSetting = RANDOMIZATION_PERSISTENT; 1337 } 1338 mBridgedModeOpportunisticShutdownEnabled = true; 1339 mIeee80211axEnabled = true; 1340 mIeee80211beEnabled = true; 1341 mIsUserConfiguration = true; 1342 mBridgedModeOpportunisticShutdownTimeoutMillis = DEFAULT_TIMEOUT; 1343 mVendorElements = new ArrayList<>(); 1344 mPersistentRandomizedMacAddress = null; 1345 mAllowedAcsChannels2g = new HashSet<>(); 1346 mAllowedAcsChannels5g = new HashSet<>(); 1347 mAllowedAcsChannels6g = new HashSet<>(); 1348 mMaxChannelBandwidth = SoftApInfo.CHANNEL_WIDTH_AUTO; 1349 mVendorData = new ArrayList<>(); 1350 } 1351 1352 /** 1353 * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance. 1354 */ Builder(@onNull SoftApConfiguration other)1355 public Builder(@NonNull SoftApConfiguration other) { 1356 if (other == null) { 1357 Log.e(TAG, "Cannot provide a null SoftApConfiguration"); 1358 return; 1359 } 1360 1361 mWifiSsid = other.mWifiSsid; 1362 mBssid = other.mBssid; 1363 mPassphrase = other.mPassphrase; 1364 mHiddenSsid = other.mHiddenSsid; 1365 mChannels = other.mChannels.clone(); 1366 mMaxNumberOfClients = other.mMaxNumberOfClients; 1367 mSecurityType = other.mSecurityType; 1368 mAutoShutdownEnabled = other.mAutoShutdownEnabled; 1369 mShutdownTimeoutMillis = other.mShutdownTimeoutMillis; 1370 mClientControlByUser = other.mClientControlByUser; 1371 mBlockedClientList = new ArrayList<>(other.mBlockedClientList); 1372 mAllowedClientList = new ArrayList<>(other.mAllowedClientList); 1373 mMacRandomizationSetting = other.mMacRandomizationSetting; 1374 mBridgedModeOpportunisticShutdownEnabled = 1375 other.mBridgedModeOpportunisticShutdownEnabled; 1376 mIeee80211axEnabled = other.mIeee80211axEnabled; 1377 mIeee80211beEnabled = other.mIeee80211beEnabled; 1378 mIsUserConfiguration = other.mIsUserConfiguration; 1379 mBridgedModeOpportunisticShutdownTimeoutMillis = 1380 other.mBridgedModeOpportunisticShutdownTimeoutMillis; 1381 mVendorElements = new ArrayList<>(other.mVendorElements); 1382 mPersistentRandomizedMacAddress = other.mPersistentRandomizedMacAddress; 1383 mAllowedAcsChannels2g = new HashSet<>(other.mAllowedAcsChannels2g); 1384 mAllowedAcsChannels5g = new HashSet<>(other.mAllowedAcsChannels5g); 1385 mAllowedAcsChannels6g = new HashSet<>(other.mAllowedAcsChannels6g); 1386 mMaxChannelBandwidth = other.mMaxChannelBandwidth; 1387 if (SdkLevel.isAtLeastS() && mBssid != null) { 1388 // Auto set correct MAC randomization setting for the legacy SoftApConfiguration 1389 // to avoid the exception happen when framework (system server) copy 1390 // SoftApConfiguration. 1391 mMacRandomizationSetting = RANDOMIZATION_NONE; 1392 } 1393 mVendorData = new ArrayList<>(other.mVendorData); 1394 } 1395 1396 /** 1397 * Builds the {@link SoftApConfiguration}. 1398 * 1399 * @return A new {@link SoftApConfiguration}, as configured by previous method calls. 1400 */ 1401 @NonNull build()1402 public SoftApConfiguration build() { 1403 for (MacAddress client : mAllowedClientList) { 1404 if (mBlockedClientList.contains(client)) { 1405 throw new IllegalArgumentException("A MacAddress exist in both client list"); 1406 } 1407 } 1408 1409 // mMacRandomizationSetting supported from S. 1410 if (SdkLevel.isAtLeastS() && CompatChanges.isChangeEnabled( 1411 FORCE_MUTUAL_EXCLUSIVE_BSSID_MAC_RAMDONIZATION_SETTING) 1412 && mBssid != null && mMacRandomizationSetting != RANDOMIZATION_NONE) { 1413 throw new IllegalArgumentException("A BSSID had configured but MAC randomization" 1414 + " setting is not NONE"); 1415 } 1416 1417 if (!CompatChanges.isChangeEnabled( 1418 REMOVE_ZERO_FOR_TIMEOUT_SETTING) && mShutdownTimeoutMillis == DEFAULT_TIMEOUT) { 1419 mShutdownTimeoutMillis = 0; // Use 0 for legacy app. 1420 } 1421 return new SoftApConfiguration( 1422 mWifiSsid, 1423 mBssid, 1424 mPassphrase, 1425 mHiddenSsid, 1426 mChannels, 1427 mSecurityType, 1428 mMaxNumberOfClients, 1429 mAutoShutdownEnabled, 1430 mShutdownTimeoutMillis, 1431 mClientControlByUser, 1432 mBlockedClientList, 1433 mAllowedClientList, 1434 mMacRandomizationSetting, 1435 mBridgedModeOpportunisticShutdownEnabled, 1436 mIeee80211axEnabled, 1437 mIeee80211beEnabled, 1438 mIsUserConfiguration, 1439 mBridgedModeOpportunisticShutdownTimeoutMillis, 1440 mVendorElements, 1441 mPersistentRandomizedMacAddress, 1442 mAllowedAcsChannels2g, 1443 mAllowedAcsChannels5g, 1444 mAllowedAcsChannels6g, 1445 mMaxChannelBandwidth, 1446 mVendorData); 1447 } 1448 1449 /** 1450 * Specifies a UTF-8 SSID for the AP. 1451 * <p> 1452 * Null SSID only support when configure a local-only hotspot. 1453 * <p> 1454 * <li>If not set, defaults to null.</li> 1455 * 1456 * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically 1457 * chosen by the framework. 1458 * @return Builder for chaining. 1459 * @throws IllegalArgumentException when the SSID is empty, not unicode, or if the byte 1460 * representation is longer than 32 bytes. 1461 * 1462 * @deprecated Use {@link #setWifiSsid(WifiSsid)} instead. 1463 */ 1464 @NonNull 1465 @Deprecated setSsid(@ullable String ssid)1466 public Builder setSsid(@Nullable String ssid) { 1467 if (ssid == null) { 1468 mWifiSsid = null; 1469 return this; 1470 } 1471 1472 Preconditions.checkStringNotEmpty(ssid); 1473 Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid)); 1474 mWifiSsid = WifiSsid.fromUtf8Text(ssid); 1475 return this; 1476 } 1477 1478 /** 1479 * Specifies an SSID for the AP in the form of WifiSsid. 1480 * <p> 1481 * Null SSID only support when configure a local-only hotspot. 1482 * <p> 1483 * <li>If not set, defaults to null.</li> 1484 * 1485 * @param wifiSsid SSID, or null ot have the SSID automatically chosen by the framework. 1486 * @return Builder for chaining. 1487 */ 1488 @NonNull 1489 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setWifiSsid(@ullable WifiSsid wifiSsid)1490 public Builder setWifiSsid(@Nullable WifiSsid wifiSsid) { 1491 if (!SdkLevel.isAtLeastT()) { 1492 throw new UnsupportedOperationException(); 1493 } 1494 mWifiSsid = wifiSsid; 1495 return this; 1496 } 1497 1498 /** 1499 * Specify vendor-specific information elements for the (Soft) AP to transmit in its beacons 1500 * and probe responses. Method also validates the structure and throws 1501 * IllegalArgumentException in cases when ID of IE is not 0xDD (221) or incoming list 1502 * contain duplicate elements. 1503 * 1504 * @param vendorElements VendorElements 1505 * @return Builder for chaining. 1506 */ 1507 @NonNull 1508 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setVendorElements( @onNull List<ScanResult.InformationElement> vendorElements)1509 public Builder setVendorElements( 1510 @NonNull List<ScanResult.InformationElement> vendorElements) { 1511 if (!SdkLevel.isAtLeastT()) { 1512 throw new UnsupportedOperationException(); 1513 } 1514 for (ScanResult.InformationElement e : vendorElements) { 1515 if (e.id != ScanResult.InformationElement.EID_VSA) { 1516 throw new IllegalArgumentException("received InformationElement which is not " 1517 + "related to VendorElements. VendorElement block should start with " 1518 + HexEncoding.encodeToString( 1519 new byte[]{ (byte) ScanResult.InformationElement.EID_VSA })); 1520 } 1521 } 1522 final HashSet<ScanResult.InformationElement> set = new HashSet<>(vendorElements); 1523 if (set.size() < vendorElements.size()) { 1524 throw new IllegalArgumentException("vendor elements array contain duplicates. " 1525 + "Please avoid passing duplicated and keep structure clean."); 1526 } 1527 mVendorElements = new ArrayList<>(vendorElements); 1528 return this; 1529 } 1530 1531 /** 1532 * Specifies a BSSID for the AP. 1533 * <p> 1534 * <li>If not set, defaults to null.</li> 1535 * 1536 * When this method is called, the caller needs to configure MAC randomization settings to 1537 * {@link #RANDOMIZATION_NONE}. See {@link #setMacRandomizationSetting(int)} for details. 1538 * 1539 * If multiple bands are requested via {@link #setBands(int[])} or 1540 * {@link #setChannels(SparseIntArray)}, HAL will derive 2 MAC addresses since framework 1541 * only sends down 1 MAC address. 1542 * 1543 * An example (but different implementation may perform a different mapping): 1544 * <li>MAC address 1: copy value of MAC address, 1545 * and set byte 1 = (0xFF - BSSID[1])</li> 1546 * <li>MAC address 2: copy value of MAC address, 1547 * and set byte 2 = (0xFF - BSSID[2])</li> 1548 * 1549 * Example BSSID argument: e2:38:60:c4:0e:b7 1550 * Derived MAC address 1: e2:c7:60:c4:0e:b7 1551 * Derived MAC address 2: e2:38:9f:c4:0e:b7 1552 * 1553 * <p> 1554 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1555 * {@link SoftApCapability#areFeaturesSupported(long)} 1556 * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine 1557 * whether or not this feature is supported. 1558 * 1559 * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is 1560 * responsible for avoiding collisions. 1561 * @return Builder for chaining. 1562 * @throws IllegalArgumentException when the given BSSID is the all-zero 1563 * , multicast or broadcast MAC address. 1564 */ 1565 @NonNull setBssid(@ullable MacAddress bssid)1566 public Builder setBssid(@Nullable MacAddress bssid) { 1567 if (bssid != null) { 1568 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS)); 1569 if (bssid.getAddressType() != MacAddress.TYPE_UNICAST) { 1570 throw new IllegalArgumentException("bssid doesn't support " 1571 + "multicast or broadcast mac address"); 1572 } 1573 } 1574 mBssid = bssid; 1575 return this; 1576 } 1577 1578 /** 1579 * Specifies that this AP should use specific security type with the given ASCII passphrase. 1580 * 1581 * @param securityType One of the following security types: 1582 * {@link #SECURITY_TYPE_OPEN}, 1583 * {@link #SECURITY_TYPE_WPA2_PSK}, 1584 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 1585 * {@link #SECURITY_TYPE_WPA3_SAE}, 1586 * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION}, 1587 * {@link #SECURITY_TYPE_WPA3_OWE}. 1588 * @param passphrase The passphrase to use for sepcific {@code securityType} configuration 1589 * or null with {@link #SECURITY_TYPE_OPEN}, {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION}, 1590 * and {@link #SECURITY_TYPE_WPA3_OWE}. 1591 * 1592 * @return Builder for chaining. 1593 * @throws IllegalArgumentException when the passphrase is non-null for 1594 * - {@link #SECURITY_TYPE_OPEN} 1595 * - {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION} 1596 * - {@link #SECURITY_TYPE_WPA3_OWE} 1597 * @throws IllegalArgumentException when the passphrase is empty for 1598 * - {@link #SECURITY_TYPE_WPA2_PSK}, 1599 * - {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 1600 * - {@link #SECURITY_TYPE_WPA3_SAE}, 1601 * @throws IllegalArgumentException before {@link android.os.Build.VERSION_CODES#TIRAMISU}) 1602 * when the passphrase is not between 8 and 63 bytes (inclusive) for 1603 * - {@link #SECURITY_TYPE_WPA2_PSK} 1604 * - {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION} 1605 */ 1606 @NonNull setPassphrase(@ullable String passphrase, @SecurityType int securityType)1607 public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) { 1608 if (!SdkLevel.isAtLeastT() 1609 && (securityType == SECURITY_TYPE_WPA3_OWE_TRANSITION 1610 || securityType == SECURITY_TYPE_WPA3_OWE)) { 1611 throw new UnsupportedOperationException(); 1612 } 1613 if (securityType == SECURITY_TYPE_OPEN 1614 || securityType == SECURITY_TYPE_WPA3_OWE_TRANSITION 1615 || securityType == SECURITY_TYPE_WPA3_OWE) { 1616 if (passphrase != null) { 1617 throw new IllegalArgumentException( 1618 "passphrase should be null when security type is open"); 1619 } 1620 } else { 1621 Preconditions.checkStringNotEmpty(passphrase); 1622 if (!SdkLevel.isAtLeastT() && (securityType == SECURITY_TYPE_WPA2_PSK 1623 || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION)) { 1624 int passphraseByteLength = 0; 1625 if (!TextUtils.isEmpty(passphrase)) { 1626 passphraseByteLength = passphrase.getBytes(StandardCharsets.UTF_8).length; 1627 } 1628 if (passphraseByteLength < PSK_MIN_LEN || passphraseByteLength > PSK_MAX_LEN) { 1629 throw new IllegalArgumentException( 1630 "Passphrase length must be at least " + PSK_MIN_LEN 1631 + " and no more than " + PSK_MAX_LEN 1632 + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode"); 1633 } 1634 } 1635 } 1636 mSecurityType = securityType; 1637 mPassphrase = passphrase; 1638 return this; 1639 } 1640 1641 /** 1642 * Specifies whether the AP is hidden (doesn't broadcast its SSID) or 1643 * not (broadcasts its SSID). 1644 * <p> 1645 * <li>If not set, defaults to false (i.e not a hidden network).</li> 1646 * 1647 * @param hiddenSsid true for a hidden SSID, false otherwise. 1648 * @return Builder for chaining. 1649 */ 1650 @NonNull setHiddenSsid(boolean hiddenSsid)1651 public Builder setHiddenSsid(boolean hiddenSsid) { 1652 mHiddenSsid = hiddenSsid; 1653 return this; 1654 } 1655 1656 /** 1657 * Specifies the band for the AP. 1658 * <p> 1659 * <li>If not set, defaults to {@link #BAND_2GHZ}.</li> 1660 * 1661 * @param band One or combination of the following band type: 1662 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 1663 * @return Builder for chaining. 1664 * @throws IllegalArgumentException when an invalid band type is provided. 1665 */ 1666 @NonNull setBand(@andType int band)1667 public Builder setBand(@BandType int band) { 1668 if (!isBandValid(band)) { 1669 throw new IllegalArgumentException("Invalid band type: " + band); 1670 } 1671 mChannels = new SparseIntArray(1); 1672 mChannels.put(band, 0); 1673 return this; 1674 } 1675 1676 /** 1677 * Specifies the bands for the APs. 1678 * If more than 1 band is set, this will bring up concurrent APs. 1679 * on the requested bands (if possible). 1680 * <p> 1681 * 1682 * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine 1683 * whether or not concurrent APs are supported. 1684 * 1685 * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1686 * when multiple bands are configured. Otherwise, 1687 * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code 1688 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1689 * 1690 * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error 1691 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1692 * 1693 * @param bands Array of the {@link #BandType}. 1694 * @return Builder for chaining. 1695 * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type 1696 * is provided. 1697 */ 1698 @RequiresApi(Build.VERSION_CODES.S) 1699 @NonNull setBands(@onNull int[] bands)1700 public Builder setBands(@NonNull int[] bands) { 1701 if (!SdkLevel.isAtLeastS()) { 1702 throw new UnsupportedOperationException(); 1703 } 1704 if (bands.length == 0 || bands.length > 2) { 1705 throw new IllegalArgumentException("Unsupported number of bands(" 1706 + bands.length + ") configured"); 1707 } 1708 SparseIntArray channels = new SparseIntArray(bands.length); 1709 for (int val : bands) { 1710 if (!isBandValid(val)) { 1711 throw new IllegalArgumentException("Invalid band type: " + val); 1712 } 1713 channels.put(val, 0); 1714 } 1715 mChannels = channels; 1716 return this; 1717 } 1718 1719 1720 /** 1721 * Specifies the channel and associated band for the AP. 1722 * 1723 * The channel which AP resides on. Valid channels are country dependent. 1724 * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain 1725 * valid channels. 1726 * 1727 * <p> 1728 * If not set, the default for the channel is the special value 0 which has the 1729 * framework auto-select a valid channel from the band configured with 1730 * {@link #setBand(int)}. 1731 * 1732 * The channel auto selection will be offloaded to driver when 1733 * {@link SoftApCapability#areFeaturesSupported(long)} 1734 * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1735 * return true. The driver will auto select the best channel (e.g. best performance) 1736 * based on environment interference. Check {@link SoftApCapability} for more detail. 1737 * 1738 * The API contains (band, channel) input since the 6GHz band uses the same channel 1739 * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to 1740 * uniquely identify individual channels. 1741 * 1742 * <p> 1743 * @param channel operating channel of the AP. 1744 * @param band containing this channel. 1745 * @return Builder for chaining. 1746 * @throws IllegalArgumentException when the invalid channel or band type is configured. 1747 */ 1748 @NonNull setChannel(int channel, @BandType int band)1749 public Builder setChannel(int channel, @BandType int band) { 1750 if (!isChannelBandPairValid(channel, band)) { 1751 throw new IllegalArgumentException("Invalid channel(" + channel 1752 + ") & band (" + band + ") configured"); 1753 } 1754 mChannels = new SparseIntArray(1); 1755 mChannels.put(band, channel); 1756 return this; 1757 } 1758 1759 /** 1760 * Specifies the channels and associated bands for the APs. 1761 * 1762 * When more than 1 channel is set, this will bring up concurrent APs on the requested 1763 * channels and bands (if possible). 1764 * 1765 * Valid channels are country dependent. 1766 * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain 1767 * valid channels in each band. 1768 * 1769 * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine 1770 * whether or not concurrent APs are supported. 1771 * 1772 * <p> 1773 * If not set, the default for the channel is the special value 0 which has the framework 1774 * auto-select a valid channel from the band configured with {@link #setBands(int[])}. 1775 * 1776 * The channel auto selection will be offloaded to driver when 1777 * {@link SoftApCapability#areFeaturesSupported(long)} 1778 * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1779 * returns true. The driver will auto select the best channel (e.g. best performance) 1780 * based on environment interference. Check {@link SoftApCapability} for more detail. 1781 * 1782 * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1783 * when multiple bands are configured without specified channel value (i.e. channel is 1784 * the special value 0). Otherwise, 1785 * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code 1786 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1787 * 1788 * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error 1789 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1790 * 1791 * The API contains (band, channel) input since the 6GHz band uses the same channel 1792 * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to 1793 * uniquely identify individual channels. 1794 * 1795 * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016 1796 * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6. 1797 * 1798 * <p> 1799 * @param channels SparseIntArray (key: {@code #BandType} , value: channel) consists of 1800 * {@code BAND_} and corresponding channel. 1801 * @return Builder for chaining. 1802 * @throws IllegalArgumentException when more than 2 channels are set or the invalid 1803 * channel or band type is configured. 1804 */ 1805 @RequiresApi(Build.VERSION_CODES.S) 1806 @NonNull setChannels(@onNull SparseIntArray channels)1807 public Builder setChannels(@NonNull SparseIntArray channels) { 1808 if (!SdkLevel.isAtLeastS()) { 1809 throw new UnsupportedOperationException(); 1810 } 1811 if (channels.size() == 0 || channels.size() > 2) { 1812 throw new IllegalArgumentException("Unsupported number of channels(" 1813 + channels.size() + ") configured"); 1814 } 1815 for (int i = 0; i < channels.size(); i++) { 1816 int channel = channels.valueAt(i); 1817 int band = channels.keyAt(i); 1818 if (channel == 0) { 1819 if (!isBandValid(band)) { 1820 throw new IllegalArgumentException("Invalid band type: " + band); 1821 } 1822 } else { 1823 if (!isChannelBandPairValid(channel, band)) { 1824 throw new IllegalArgumentException("Invalid channel(" + channel 1825 + ") & band (" + band + ") configured"); 1826 } 1827 } 1828 } 1829 mChannels = channels.clone(); 1830 return this; 1831 } 1832 1833 1834 /** 1835 * Specifies the maximum number of clients that can associate to the AP. 1836 * 1837 * The maximum number of clients (STAs) which can associate to the AP. 1838 * The AP will reject association from any clients above this number. 1839 * Specify a value of 0 to have the framework automatically use the maximum number 1840 * which the device can support (based on hardware and carrier constraints). 1841 * <p> 1842 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1843 * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients 1844 * which the device supports (based on hardware and carrier constraints). 1845 * 1846 * <p> 1847 * <li>If not set, defaults to 0.</li> 1848 * 1849 * This method requires HAL support. If the method is used to set a 1850 * non-zero {@code maxNumberOfClients} value then 1851 * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code 1852 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1853 * 1854 * <p> 1855 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1856 * {@link SoftApCapability#areFeaturesSupported(long)} 1857 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether 1858 * or not this feature is supported. 1859 * 1860 * @param maxNumberOfClients maximum client number of the AP. 1861 * @return Builder for chaining. 1862 */ 1863 @NonNull setMaxNumberOfClients(@ntRangefrom = 0) int maxNumberOfClients)1864 public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) { 1865 if (maxNumberOfClients < 0) { 1866 throw new IllegalArgumentException("maxNumberOfClients should be not negative"); 1867 } 1868 mMaxNumberOfClients = maxNumberOfClients; 1869 return this; 1870 } 1871 1872 /** 1873 * Specifies whether auto shutdown is enabled or not. 1874 * The Soft AP will shut down when there are no devices connected to it for 1875 * the timeout duration. 1876 * 1877 * <p> 1878 * <li>If not set, defaults to true</li> 1879 * 1880 * @param enable true to enable, false to disable. 1881 * @return Builder for chaining. 1882 * 1883 * @see #setShutdownTimeoutMillis(long) 1884 */ 1885 @NonNull setAutoShutdownEnabled(boolean enable)1886 public Builder setAutoShutdownEnabled(boolean enable) { 1887 mAutoShutdownEnabled = enable; 1888 return this; 1889 } 1890 1891 /** 1892 * Specifies the shutdown timeout in milliseconds. 1893 * The Soft AP will shut down when there are no devices connected to it for 1894 * the timeout duration. 1895 * 1896 * Specify a value of {@link #DEFAULT_TIMEOUT} to have the framework automatically use 1897 * default timeout setting which defined in 1898 * {@link R.integer.config_wifi_framework_soft_ap_timeout_delay} 1899 * 1900 * <p> 1901 * <li>If not set, defaults to {@link #DEFAULT_TIMEOUT}</li> 1902 * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is 1903 * set to true</li> 1904 * 1905 * @param timeoutMillis milliseconds of the timeout delay. Any value less than 1 is invalid 1906 * except {@link #DEFAULT_TIMEOUT}. 1907 * @return Builder for chaining. 1908 * 1909 * @see #setAutoShutdownEnabled(boolean) 1910 */ 1911 @NonNull setShutdownTimeoutMillis(@ntRangefrom = -1) long timeoutMillis)1912 public Builder setShutdownTimeoutMillis(@IntRange(from = -1) long timeoutMillis) { 1913 if (CompatChanges.isChangeEnabled( 1914 REMOVE_ZERO_FOR_TIMEOUT_SETTING) && timeoutMillis < 1) { 1915 if (timeoutMillis != DEFAULT_TIMEOUT) { 1916 throw new IllegalArgumentException("Invalid timeout value: " + timeoutMillis); 1917 } 1918 } else if (timeoutMillis < 0) { 1919 throw new IllegalArgumentException("Invalid timeout value from legacy app: " 1920 + timeoutMillis); 1921 } 1922 mShutdownTimeoutMillis = timeoutMillis; 1923 return this; 1924 } 1925 1926 /** 1927 * Configure the Soft AP to require manual user control of client association. 1928 * If disabled (the default) then any client which isn't in the blocked list 1929 * {@link #getBlockedClientList()} can associate to this Soft AP using the 1930 * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier, 1931 * or user limited - using {@link #setMaxNumberOfClients(int)}). 1932 * 1933 * If manual user control is enabled then clients will be accepted, rejected, or require 1934 * a user approval based on the configuration provided by 1935 * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}. 1936 * 1937 * <p> 1938 * This method requires HAL support. HAL support can be determined using 1939 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1940 * {@link SoftApCapability#areFeaturesSupported(long)} 1941 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 1942 * 1943 * <p> 1944 * If the method is called on a device without HAL support then starting the soft AP 1945 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 1946 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1947 * 1948 * <p> 1949 * <li>If not set, defaults to false (i.e The authoriztion is not required).</li> 1950 * 1951 * @param enabled true for enabling the control by user, false otherwise. 1952 * @return Builder for chaining. 1953 */ 1954 @NonNull setClientControlByUserEnabled(boolean enabled)1955 public Builder setClientControlByUserEnabled(boolean enabled) { 1956 mClientControlByUser = enabled; 1957 return this; 1958 } 1959 1960 /** 1961 * Configures the set of channel numbers in the specified band that are allowed 1962 * to be selected by the Automatic Channel Selection (ACS) algorithm. 1963 * <p> 1964 * 1965 * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}. 1966 * Otherwise, these sets will be ignored. 1967 * <p> 1968 * 1969 * @param band one of the following band types: 1970 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 1971 * 1972 * @param channels that are allowed to be used by ACS algorithm in this band. If it is 1973 * configured to an empty array or not configured, then all channels within that band 1974 * will be allowed. 1975 * <p> 1976 * 1977 * @return Builder for chaining. 1978 */ 1979 @NonNull 1980 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setAllowedAcsChannels(@andType int band, @NonNull int[] channels)1981 public Builder setAllowedAcsChannels(@BandType int band, @NonNull int[] channels) { 1982 if (!SdkLevel.isAtLeastT()) { 1983 throw new UnsupportedOperationException(); 1984 } 1985 1986 if (channels == null) { 1987 throw new IllegalArgumentException( 1988 "Passing a null object to setAllowedAcsChannels"); 1989 } 1990 1991 if ((band != BAND_2GHZ) && (band != BAND_5GHZ) && (band != BAND_6GHZ)) { 1992 throw new IllegalArgumentException( 1993 "Passing an invalid band to setAllowedAcsChannels"); 1994 } 1995 1996 for (int channel : channels) { 1997 if (!isChannelBandPairValid(channel, band)) { 1998 throw new IllegalArgumentException( 1999 "Invalid channel to setAllowedAcsChannels: band: " + band 2000 + "channel: " + channel); 2001 } 2002 } 2003 2004 HashSet<Integer> set = IntStream.of(channels).boxed() 2005 .collect(Collectors.toCollection(HashSet::new)); 2006 switch(band) { 2007 case BAND_2GHZ: 2008 mAllowedAcsChannels2g = set; 2009 break; 2010 case BAND_5GHZ: 2011 mAllowedAcsChannels5g = set; 2012 break; 2013 case BAND_6GHZ: 2014 mAllowedAcsChannels6g = set; 2015 break; 2016 } 2017 2018 return this; 2019 } 2020 2021 /** 2022 * Sets maximum channel bandwidth for the SoftAp Connection 2023 * 2024 * If not set, the SoftAp connection will seek the maximum channel bandwidth achievable on 2025 * the device. However, in some cases the caller will need to put a cap on the channel 2026 * bandwidth through this API. 2027 * 2028 * @param maxChannelBandwidth one of {@link SoftApInfo#CHANNEL_WIDTH_AUTO}, 2029 * {@link SoftApInfo#CHANNEL_WIDTH_20MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_40MHZ}, 2030 * {@link SoftApInfo#CHANNEL_WIDTH_80MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_160MHZ}, 2031 * or {@link SoftApInfo#CHANNEL_WIDTH_320MHZ} 2032 * 2033 * @return builder for chaining 2034 */ 2035 @NonNull 2036 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setMaxChannelBandwidth(@ifiAnnotations.Bandwidth int maxChannelBandwidth)2037 public Builder setMaxChannelBandwidth(@WifiAnnotations.Bandwidth int maxChannelBandwidth) { 2038 if (!SdkLevel.isAtLeastT()) { 2039 throw new UnsupportedOperationException(); 2040 } 2041 2042 switch (maxChannelBandwidth) { 2043 case SoftApInfo.CHANNEL_WIDTH_AUTO: 2044 case SoftApInfo.CHANNEL_WIDTH_20MHZ: 2045 case SoftApInfo.CHANNEL_WIDTH_40MHZ: 2046 case SoftApInfo.CHANNEL_WIDTH_80MHZ: 2047 case SoftApInfo.CHANNEL_WIDTH_160MHZ: 2048 case SoftApInfo.CHANNEL_WIDTH_320MHZ: 2049 mMaxChannelBandwidth = maxChannelBandwidth; 2050 break; 2051 default: 2052 throw new IllegalArgumentException( 2053 "Invalid channel bandwidth value(" 2054 + maxChannelBandwidth + ") configured"); 2055 } 2056 return this; 2057 } 2058 2059 /** 2060 * This method together with {@link setClientControlByUserEnabled(boolean)} control client 2061 * connections to the AP. If client control by user is disabled using the above method then 2062 * this API has no effect and clients are allowed to associate to the AP (within limit of 2063 * max number of clients). 2064 * 2065 * If client control by user is enabled then this API configures the list of clients 2066 * which are explicitly allowed. These are auto-accepted. 2067 * 2068 * All other clients which attempt to associate, whose MAC addresses are on neither list, 2069 * are: 2070 * <ul> 2071 * <li>Rejected</li> 2072 * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)} 2073 * is issued (which allows the user to add them to the allowed client list if desired).<li> 2074 * </ul> 2075 * 2076 * @param allowedClientList list of clients which are allowed to associate to the AP 2077 * without user pre-approval. 2078 * @return Builder for chaining. 2079 */ 2080 @NonNull setAllowedClientList(@onNull List<MacAddress> allowedClientList)2081 public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) { 2082 mAllowedClientList = new ArrayList<>(allowedClientList); 2083 return this; 2084 } 2085 2086 /** 2087 * This API configures the list of clients which are blocked and cannot associate 2088 * to the Soft AP. 2089 * 2090 * <p> 2091 * This method requires HAL support. HAL support can be determined using 2092 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 2093 * {@link SoftApCapability#areFeaturesSupported(long)} 2094 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 2095 * 2096 * <p> 2097 * If the method is called on a device without HAL support then starting the soft AP 2098 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 2099 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 2100 * 2101 * @param blockedClientList list of clients which are not allowed to associate to the AP. 2102 * @return Builder for chaining. 2103 */ 2104 @NonNull setBlockedClientList(@onNull List<MacAddress> blockedClientList)2105 public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) { 2106 mBlockedClientList = new ArrayList<>(blockedClientList); 2107 return this; 2108 } 2109 2110 /** 2111 * Specifies the level of MAC randomization for the AP BSSID. 2112 * The Soft AP BSSID will be randomized only if the BSSID isn't set 2113 * {@link #setBssid(MacAddress)} and this method is either uncalled 2114 * or called with {@link #RANDOMIZATION_PERSISTENT} or 2115 * {@link #RANDOMIZATION_NON_PERSISTENT}. When this method is called with 2116 * {@link #RANDOMIZATION_PERSISTENT} or {@link #RANDOMIZATION_NON_PERSISTENT}, the caller 2117 * the caller must not call {@link #setBssid(MacAddress)}. 2118 * 2119 * <p> 2120 * <li>If not set, defaults to {@link #RANDOMIZATION_NON_PERSISTENT}</li> 2121 * 2122 * <p> 2123 * Requires HAL support when set to {@link #RANDOMIZATION_PERSISTENT} or 2124 * {@link #RANDOMIZATION_NON_PERSISTENT}. 2125 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 2126 * {@link SoftApCapability#areFeaturesSupported(long)} 2127 * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine 2128 * whether or not this feature is supported. 2129 * 2130 * @param macRandomizationSetting One of the following setting: 2131 * {@link #RANDOMIZATION_NONE}, {@link #RANDOMIZATION_PERSISTENT} or 2132 * {@link #RANDOMIZATION_NON_PERSISTENT}. 2133 * @return Builder for chaining. 2134 * 2135 * @see #setBssid(MacAddress) 2136 */ 2137 @RequiresApi(Build.VERSION_CODES.S) 2138 @NonNull setMacRandomizationSetting( @acRandomizationSetting int macRandomizationSetting)2139 public Builder setMacRandomizationSetting( 2140 @MacRandomizationSetting int macRandomizationSetting) { 2141 if (!SdkLevel.isAtLeastS()) { 2142 throw new UnsupportedOperationException(); 2143 } 2144 mMacRandomizationSetting = macRandomizationSetting; 2145 return this; 2146 } 2147 2148 2149 /** 2150 * Specifies whether or not opportunistic shut down of an AP instance in bridged mode 2151 * is enabled. 2152 * 2153 * <p> 2154 * If enabled, the framework will shutdown one of the AP instances if it is idle for 2155 * the timeout duration - meaning there are no devices connected to it. 2156 * If both AP instances are idle for the timeout duration then the framework will 2157 * shut down the AP instance operating on the higher frequency. For instance, 2158 * if the AP instances operate at 2.4GHz and 5GHz and are both idle for the 2159 * timeout duration then the 5GHz AP instance will be shut down. 2160 * <p> 2161 * 2162 * Note: the opportunistic timeout only applies to one AP instance of the bridge AP. 2163 * If one of the AP instances has already been disabled for any reason, including due to 2164 * an opportunistic timeout or hardware issues or coexistence issues, 2165 * then the opportunistic timeout is no longer active. 2166 * 2167 * <p> 2168 * The shutdown timer specified by {@link #setShutdownTimeoutMillis(long)} controls the 2169 * overall shutdown of the bridged AP and is still in use independently of the opportunistic 2170 * timer controlled by this AP. 2171 * 2172 * <p> 2173 * <li>If not set, defaults to true</li> 2174 * 2175 * @param enable true to enable, false to disable. 2176 * @return Builder for chaining. 2177 * 2178 */ 2179 @RequiresApi(Build.VERSION_CODES.S) 2180 @NonNull setBridgedModeOpportunisticShutdownEnabled(boolean enable)2181 public Builder setBridgedModeOpportunisticShutdownEnabled(boolean enable) { 2182 if (!SdkLevel.isAtLeastS()) { 2183 throw new UnsupportedOperationException(); 2184 } 2185 mBridgedModeOpportunisticShutdownEnabled = enable; 2186 return this; 2187 } 2188 2189 /** 2190 * Specifies whether or not to enable 802.11ax on the Soft AP. 2191 * 2192 * <p> 2193 * Note: Only relevant when the device supports 802.11ax on the Soft AP. 2194 * If enabled on devices that do not support 802.11ax then ignored. 2195 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 2196 * {@link SoftApCapability#areFeaturesSupported(long)} 2197 * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX} to determine 2198 * whether or not 802.11ax is supported on the Soft AP. 2199 * <p> 2200 * <li>If not set, defaults to true - which will be ignored on devices 2201 * which do not support 802.11ax</li> 2202 * 2203 * @param enable true to enable, false to disable. 2204 * @return Builder for chaining. 2205 * 2206 */ 2207 @RequiresApi(Build.VERSION_CODES.S) 2208 @NonNull setIeee80211axEnabled(boolean enable)2209 public Builder setIeee80211axEnabled(boolean enable) { 2210 if (!SdkLevel.isAtLeastS()) { 2211 throw new UnsupportedOperationException(); 2212 } 2213 mIeee80211axEnabled = enable; 2214 return this; 2215 } 2216 2217 /** 2218 * Specifies whether or not to enable 802.11be on the Soft AP. 2219 * 2220 * <p> 2221 * Note: Only relevant when the device supports 802.11be on the Soft AP. 2222 * If enabled on devices that do not support 802.11be then ignored. 2223 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 2224 * {@link SoftApCapability#areFeaturesSupported(long)} 2225 * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE} to determine 2226 * whether or not 802.11be is supported on the Soft AP. 2227 * <p> 2228 * <li>If not set, defaults to true - which will be ignored on devices 2229 * which do not support 802.11be</li> 2230 * 2231 * @param enable true to enable, false to disable. 2232 * @return Builder for chaining. 2233 * 2234 */ 2235 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 2236 @NonNull setIeee80211beEnabled(boolean enable)2237 public Builder setIeee80211beEnabled(boolean enable) { 2238 if (!SdkLevel.isAtLeastT()) { 2239 throw new UnsupportedOperationException(); 2240 } 2241 mIeee80211beEnabled = enable; 2242 return this; 2243 } 2244 2245 /** 2246 * Specifies whether or not the configuration is configured by user. 2247 * 2248 * @param isUserConfigured true to user configuration, false otherwise. 2249 * @return Builder for chaining. 2250 * 2251 * @hide 2252 */ 2253 @NonNull setUserConfiguration(boolean isUserConfigured)2254 public Builder setUserConfiguration(boolean isUserConfigured) { 2255 mIsUserConfiguration = isUserConfigured; 2256 return this; 2257 } 2258 2259 /** 2260 * Specifies bridged mode opportunistic shutdown timeout in milliseconds. 2261 * An instance of bridged Soft AP will shut down when there is no device connected to it 2262 * for this timeout duration. 2263 * 2264 * Specify a value of {@link DEFAULT_TIMEOUT} to have the framework automatically use 2265 * default timeout setting defined by 2266 * {@link 2267 * R.integer.config_wifiFrameworkSoftApShutDownIdleInstanceInBridgedModeTimeoutMillisecond} 2268 * 2269 * <p> 2270 * <li>If not set, defaults to {@link #DEFAULT_TIMEOUT}</li> 2271 * <li>The shut down timeout will apply when 2272 * {@link #setBridgedModeOpportunisticShutdownEnabled(boolean)} is set to true</li> 2273 * 2274 * @param timeoutMillis milliseconds of the timeout delay. Any value less than 1 is invalid 2275 * except {@link #DEFAULT_TIMEOUT}. 2276 * @return Builder for chaining. 2277 * 2278 * @see #setBridgedModeOpportunisticShutdownEnabled(boolean) 2279 */ 2280 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 2281 @NonNull setBridgedModeOpportunisticShutdownTimeoutMillis( @ntRangefrom = -1) long timeoutMillis)2282 public Builder setBridgedModeOpportunisticShutdownTimeoutMillis( 2283 @IntRange(from = -1) long timeoutMillis) { 2284 if (!SdkLevel.isAtLeastT()) { 2285 throw new UnsupportedOperationException(); 2286 } 2287 if (timeoutMillis < 1 && timeoutMillis != DEFAULT_TIMEOUT) { 2288 throw new IllegalArgumentException("Invalid timeout value: " + timeoutMillis); 2289 } 2290 mBridgedModeOpportunisticShutdownTimeoutMillis = timeoutMillis; 2291 return this; 2292 } 2293 2294 /** 2295 * @param mac persistent randomized MacAddress generated by the frameworks. 2296 * @hide 2297 */ 2298 @NonNull setRandomizedMacAddress(@onNull MacAddress mac)2299 public Builder setRandomizedMacAddress(@NonNull MacAddress mac) { 2300 if (mac == null) { 2301 throw new IllegalArgumentException("setRandomizedMacAddress received" 2302 + " null MacAddress."); 2303 } 2304 mPersistentRandomizedMacAddress = mac; 2305 return this; 2306 } 2307 2308 /** 2309 * Set additional vendor-provided configuration data. 2310 * 2311 * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided 2312 * configuration data. Note that multiple elements with the same OUI are allowed. 2313 * @return Builder for chaining. 2314 */ 2315 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) 2316 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 2317 @NonNull setVendorData(@onNull List<OuiKeyedData> vendorData)2318 public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { 2319 if (!SdkLevel.isAtLeastV()) { 2320 throw new UnsupportedOperationException(); 2321 } 2322 if (vendorData == null) { 2323 throw new IllegalArgumentException("setVendorData received a null value"); 2324 } 2325 mVendorData = vendorData; 2326 return this; 2327 } 2328 } 2329 } 2330