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