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