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.net.MacAddress; 25 import android.os.Build; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.text.TextUtils; 29 import android.util.Log; 30 import android.util.SparseIntArray; 31 32 import androidx.annotation.RequiresApi; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.internal.util.Preconditions; 36 import com.android.modules.utils.build.SdkLevel; 37 38 import java.lang.annotation.Retention; 39 import java.lang.annotation.RetentionPolicy; 40 import java.nio.charset.StandardCharsets; 41 import java.util.ArrayList; 42 import java.util.List; 43 import java.util.Objects; 44 45 /** 46 * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot). 47 * 48 * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the 49 * framework how it should configure a hotspot. 50 * 51 * System apps can use this to configure a tethered hotspot using 52 * {@code WifiManager#startTetheredHotspot(SoftApConfiguration)} and 53 * {@code WifiManager#setSoftApConfiguration(SoftApConfiguration)} 54 * or local-only hotspot using 55 * {@code WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor, 56 * WifiManager.LocalOnlyHotspotCallback)}. 57 * 58 * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to 59 * create a new instance. 60 * 61 */ 62 public final class SoftApConfiguration implements Parcelable { 63 64 private static final String TAG = "SoftApConfiguration"; 65 66 @VisibleForTesting 67 static final int PSK_MIN_LEN = 8; 68 69 @VisibleForTesting 70 static final int PSK_MAX_LEN = 63; 71 72 /** 73 * 2GHz band. 74 * @hide 75 */ 76 @SystemApi 77 public static final int BAND_2GHZ = 1 << 0; 78 79 /** 80 * 5GHz band. 81 * @hide 82 */ 83 @SystemApi 84 public static final int BAND_5GHZ = 1 << 1; 85 86 /** 87 * 6GHz band. 88 * @hide 89 */ 90 @SystemApi 91 public static final int BAND_6GHZ = 1 << 2; 92 93 /** 94 * 60GHz band. 95 * @hide 96 */ 97 @SystemApi 98 public static final int BAND_60GHZ = 1 << 3; 99 100 /** 101 * Device is allowed to choose the optimal band (2GHz, 5GHz, 6GHz) based on device capability, 102 * operating country code and current radio conditions. 103 * @hide 104 * 105 * @deprecated This is no longer supported. The value is fixed at 106 * (BAND_2GHZ | BAND_5GHZ | BAND_6GHZ) even if a new band is supported in the future, for 107 * instance {@code BAND_60GHZ}. The bands are a bit mask - use any combination of 108 * {@code BAND_}, for instance {@code BAND_2GHZ | BAND_5GHZ}. 109 */ 110 @SystemApi 111 public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ; 112 113 /** @hide */ 114 @Retention(RetentionPolicy.SOURCE) 115 @IntDef(flag = true, prefix = { "BAND_TYPE_" }, value = { 116 BAND_2GHZ, 117 BAND_5GHZ, 118 BAND_6GHZ, 119 BAND_60GHZ, 120 }) 121 public @interface BandType {} 122 123 /** 124 * All of the supported band types. 125 * @hide 126 */ 127 public static int[] BAND_TYPES = {BAND_2GHZ, BAND_5GHZ, BAND_6GHZ, BAND_60GHZ}; 128 isBandValid(@andType int band)129 private static boolean isBandValid(@BandType int band) { 130 int bandAny = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ | BAND_60GHZ; 131 return ((band != 0) && ((band & ~bandAny) == 0)); 132 } 133 134 private static final int MIN_CH_2G_BAND = 1; 135 private static final int MAX_CH_2G_BAND = 14; 136 private static final int MIN_CH_5G_BAND = 34; 137 private static final int MAX_CH_5G_BAND = 196; 138 private static final int MIN_CH_6G_BAND = 1; 139 private static final int MAX_CH_6G_BAND = 253; 140 private static final int MIN_CH_60G_BAND = 1; 141 private static final int MAX_CH_60G_BAND = 6; 142 143 144 isChannelBandPairValid(int channel, @BandType int band)145 private static boolean isChannelBandPairValid(int channel, @BandType int band) { 146 switch (band) { 147 case BAND_2GHZ: 148 if (channel < MIN_CH_2G_BAND || channel > MAX_CH_2G_BAND) { 149 return false; 150 } 151 break; 152 153 case BAND_5GHZ: 154 if (channel < MIN_CH_5G_BAND || channel > MAX_CH_5G_BAND) { 155 return false; 156 } 157 break; 158 159 case BAND_6GHZ: 160 if (channel < MIN_CH_6G_BAND || channel > MAX_CH_6G_BAND) { 161 return false; 162 } 163 break; 164 165 case BAND_60GHZ: 166 if (channel < MIN_CH_60G_BAND || channel > MAX_CH_60G_BAND) { 167 return false; 168 } 169 break; 170 171 default: 172 return false; 173 } 174 return true; 175 } 176 177 /** 178 * SSID for the AP, or null for a framework-determined SSID. 179 */ 180 private final @Nullable String mSsid; 181 182 /** 183 * BSSID for the AP, or null to use a framework-determined BSSID. 184 */ 185 private final @Nullable MacAddress mBssid; 186 187 /** 188 * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on 189 * the security type. 190 */ 191 private final @Nullable String mPassphrase; 192 193 /** 194 * This is a network that does not broadcast its SSID, so an 195 * SSID-specific probe request must be used for scans. 196 */ 197 private final boolean mHiddenSsid; 198 199 /** 200 * The operating channels of the dual APs. 201 * 202 * The SparseIntArray that consists the band and the channel of matching the band. 203 */ 204 @NonNull 205 private final SparseIntArray mChannels; 206 207 /** 208 * The maximim allowed number of clients that can associate to the AP. 209 */ 210 private final int mMaxNumberOfClients; 211 212 /** 213 * The operating security type of the AP. 214 * One of the following security types: 215 * {@link #SECURITY_TYPE_OPEN}, 216 * {@link #SECURITY_TYPE_WPA2_PSK}, 217 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 218 * {@link #SECURITY_TYPE_WPA3_SAE} 219 */ 220 private final @SecurityType int mSecurityType; 221 222 /** 223 * The flag to indicate client need to authorize by user 224 * when client is connecting to AP. 225 */ 226 private final boolean mClientControlByUser; 227 228 /** 229 * The list of blocked client that can't associate to the AP. 230 */ 231 private final List<MacAddress> mBlockedClientList; 232 233 /** 234 * The list of allowed client that can associate to the AP. 235 */ 236 private final List<MacAddress> mAllowedClientList; 237 238 /** 239 * Whether auto shutdown of soft AP is enabled or not. 240 */ 241 private final boolean mAutoShutdownEnabled; 242 243 /** 244 * Delay in milliseconds before shutting down soft AP when 245 * there are no connected devices. 246 */ 247 private final long mShutdownTimeoutMillis; 248 249 /** @hide */ 250 @Retention(RetentionPolicy.SOURCE) 251 @IntDef(prefix = {"RANDOMIZATION_"}, value = { 252 RANDOMIZATION_NONE, 253 RANDOMIZATION_PERSISTENT}) 254 public @interface MacRandomizationSetting {} 255 256 /** 257 * Use factory MAC as BSSID for the AP 258 * @hide 259 */ 260 @SystemApi 261 public static final int RANDOMIZATION_NONE = 0; 262 /** 263 * Generate a randomized MAC as BSSID for the AP 264 * @hide 265 */ 266 @SystemApi 267 public static final int RANDOMIZATION_PERSISTENT = 1; 268 269 /** 270 * Level of MAC randomization for the AP BSSID. 271 */ 272 @MacRandomizationSetting 273 private int mMacRandomizationSetting; 274 275 276 /** 277 * Whether opportunistic shutdown of an instance in bridged AP is enabled or not. 278 */ 279 private boolean mBridgedModeOpportunisticShutdownEnabled; 280 281 /** 282 * Whether 802.11ax AP is enabled or not. 283 */ 284 private boolean mIeee80211axEnabled; 285 286 /** 287 * Whether the current configuration is configured by user or not. 288 */ 289 private boolean mIsUserConfiguration; 290 291 292 /** 293 * THe definition of security type OPEN. 294 */ 295 public static final int SECURITY_TYPE_OPEN = 0; 296 297 /** 298 * The definition of security type WPA2-PSK. 299 */ 300 public static final int SECURITY_TYPE_WPA2_PSK = 1; 301 302 /** 303 * The definition of security type WPA3-SAE Transition mode. 304 */ 305 public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2; 306 307 /** 308 * The definition of security type WPA3-SAE. 309 */ 310 public static final int SECURITY_TYPE_WPA3_SAE = 3; 311 312 /** @hide */ 313 @Retention(RetentionPolicy.SOURCE) 314 @IntDef(prefix = { "SECURITY_TYPE_" }, value = { 315 SECURITY_TYPE_OPEN, 316 SECURITY_TYPE_WPA2_PSK, 317 SECURITY_TYPE_WPA3_SAE_TRANSITION, 318 SECURITY_TYPE_WPA3_SAE, 319 }) 320 public @interface SecurityType {} 321 322 /** Private constructor for Builder and Parcelable implementation. */ SoftApConfiguration(@ullable String 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 isUserConfiguration)323 private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid, 324 @Nullable String passphrase, boolean hiddenSsid, @NonNull SparseIntArray channels, 325 @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled, 326 long shutdownTimeoutMillis, boolean clientControlByUser, 327 @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList, 328 int macRandomizationSetting, boolean bridgedModeOpportunisticShutdownEnabled, 329 boolean ieee80211axEnabled, boolean isUserConfiguration) { 330 mSsid = ssid; 331 mBssid = bssid; 332 mPassphrase = passphrase; 333 mHiddenSsid = hiddenSsid; 334 if (channels.size() != 0) { 335 mChannels = channels.clone(); 336 } else { 337 mChannels = new SparseIntArray(1); 338 mChannels.put(BAND_2GHZ, 0); 339 } 340 mSecurityType = securityType; 341 mMaxNumberOfClients = maxNumberOfClients; 342 mAutoShutdownEnabled = shutdownTimeoutEnabled; 343 mShutdownTimeoutMillis = shutdownTimeoutMillis; 344 mClientControlByUser = clientControlByUser; 345 mBlockedClientList = new ArrayList<>(blockedList); 346 mAllowedClientList = new ArrayList<>(allowedList); 347 mMacRandomizationSetting = macRandomizationSetting; 348 mBridgedModeOpportunisticShutdownEnabled = bridgedModeOpportunisticShutdownEnabled; 349 mIeee80211axEnabled = ieee80211axEnabled; 350 mIsUserConfiguration = isUserConfiguration; 351 } 352 353 @Override equals(Object otherObj)354 public boolean equals(Object otherObj) { 355 if (this == otherObj) { 356 return true; 357 } 358 if (!(otherObj instanceof SoftApConfiguration)) { 359 return false; 360 } 361 SoftApConfiguration other = (SoftApConfiguration) otherObj; 362 return Objects.equals(mSsid, other.mSsid) 363 && Objects.equals(mBssid, other.mBssid) 364 && Objects.equals(mPassphrase, other.mPassphrase) 365 && mHiddenSsid == other.mHiddenSsid 366 && mChannels.toString().equals(other.mChannels.toString()) 367 && mSecurityType == other.mSecurityType 368 && mMaxNumberOfClients == other.mMaxNumberOfClients 369 && mAutoShutdownEnabled == other.mAutoShutdownEnabled 370 && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis 371 && mClientControlByUser == other.mClientControlByUser 372 && Objects.equals(mBlockedClientList, other.mBlockedClientList) 373 && Objects.equals(mAllowedClientList, other.mAllowedClientList) 374 && mMacRandomizationSetting == other.mMacRandomizationSetting 375 && mBridgedModeOpportunisticShutdownEnabled 376 == other.mBridgedModeOpportunisticShutdownEnabled 377 && mIeee80211axEnabled == other.mIeee80211axEnabled 378 && mIsUserConfiguration == other.mIsUserConfiguration; 379 } 380 381 @Override hashCode()382 public int hashCode() { 383 return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid, 384 mChannels.toString(), mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled, 385 mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, 386 mAllowedClientList, mMacRandomizationSetting, 387 mBridgedModeOpportunisticShutdownEnabled, mIeee80211axEnabled, 388 mIsUserConfiguration); 389 } 390 391 @Override toString()392 public String toString() { 393 StringBuilder sbuf = new StringBuilder(); 394 sbuf.append("ssid = ").append(mSsid); 395 if (mBssid != null) sbuf.append(" \n bssid = ").append(mBssid.toString()); 396 sbuf.append(" \n Passphrase = ").append( 397 TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>"); 398 sbuf.append(" \n HiddenSsid = ").append(mHiddenSsid); 399 sbuf.append(" \n Channels = ").append(mChannels); 400 sbuf.append(" \n SecurityType = ").append(getSecurityType()); 401 sbuf.append(" \n MaxClient = ").append(mMaxNumberOfClients); 402 sbuf.append(" \n AutoShutdownEnabled = ").append(mAutoShutdownEnabled); 403 sbuf.append(" \n ShutdownTimeoutMillis = ").append(mShutdownTimeoutMillis); 404 sbuf.append(" \n ClientControlByUser = ").append(mClientControlByUser); 405 sbuf.append(" \n BlockedClientList = ").append(mBlockedClientList); 406 sbuf.append(" \n AllowedClientList= ").append(mAllowedClientList); 407 sbuf.append(" \n MacRandomizationSetting = ").append(mMacRandomizationSetting); 408 sbuf.append(" \n BridgedModeInstanceOpportunisticEnabled = ") 409 .append(mBridgedModeOpportunisticShutdownEnabled); 410 sbuf.append(" \n Ieee80211axEnabled = ").append(mIeee80211axEnabled); 411 sbuf.append(" \n isUserConfiguration = ").append(mIsUserConfiguration); 412 return sbuf.toString(); 413 } 414 415 @Override writeToParcel(@onNull Parcel dest, int flags)416 public void writeToParcel(@NonNull Parcel dest, int flags) { 417 dest.writeString(mSsid); 418 dest.writeParcelable(mBssid, flags); 419 dest.writeString(mPassphrase); 420 dest.writeBoolean(mHiddenSsid); 421 writeSparseIntArray(dest, mChannels); 422 dest.writeInt(mSecurityType); 423 dest.writeInt(mMaxNumberOfClients); 424 dest.writeBoolean(mAutoShutdownEnabled); 425 dest.writeLong(mShutdownTimeoutMillis); 426 dest.writeBoolean(mClientControlByUser); 427 dest.writeTypedList(mBlockedClientList); 428 dest.writeTypedList(mAllowedClientList); 429 dest.writeInt(mMacRandomizationSetting); 430 dest.writeBoolean(mBridgedModeOpportunisticShutdownEnabled); 431 dest.writeBoolean(mIeee80211axEnabled); 432 dest.writeBoolean(mIsUserConfiguration); 433 } 434 435 /* Reference from frameworks/base/core/java/android/os/Parcel.java */ writeSparseIntArray(@onNull Parcel dest, @Nullable SparseIntArray val)436 private static void writeSparseIntArray(@NonNull Parcel dest, 437 @Nullable SparseIntArray val) { 438 if (val == null) { 439 dest.writeInt(-1); 440 return; 441 } 442 int n = val.size(); 443 dest.writeInt(n); 444 int i = 0; 445 while (i < n) { 446 dest.writeInt(val.keyAt(i)); 447 dest.writeInt(val.valueAt(i)); 448 i++; 449 } 450 } 451 452 453 /* Reference from frameworks/base/core/java/android/os/Parcel.java */ 454 @NonNull readSparseIntArray(@onNull Parcel in)455 private static SparseIntArray readSparseIntArray(@NonNull Parcel in) { 456 int n = in.readInt(); 457 if (n < 0) { 458 return new SparseIntArray(); 459 } 460 SparseIntArray sa = new SparseIntArray(n); 461 while (n > 0) { 462 int key = in.readInt(); 463 int value = in.readInt(); 464 sa.append(key, value); 465 n--; 466 } 467 return sa; 468 } 469 470 471 @Override describeContents()472 public int describeContents() { 473 return 0; 474 } 475 476 @NonNull 477 public static final Creator<SoftApConfiguration> CREATOR = new Creator<SoftApConfiguration>() { 478 @Override 479 public SoftApConfiguration createFromParcel(Parcel in) { 480 return new SoftApConfiguration( 481 in.readString(), 482 in.readParcelable(MacAddress.class.getClassLoader()), 483 in.readString(), in.readBoolean(), readSparseIntArray(in), in.readInt(), 484 in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(), 485 in.createTypedArrayList(MacAddress.CREATOR), 486 in.createTypedArrayList(MacAddress.CREATOR), in.readInt(), in.readBoolean(), 487 in.readBoolean(), in.readBoolean()); 488 } 489 490 @Override 491 public SoftApConfiguration[] newArray(int size) { 492 return new SoftApConfiguration[size]; 493 } 494 }; 495 496 /** 497 * Return String set to be the SSID for the AP. 498 * See also {@link Builder#setSsid(String)}. 499 */ 500 @Nullable getSsid()501 public String getSsid() { 502 return mSsid; 503 } 504 505 /** 506 * Returns MAC address set to be BSSID for the AP. 507 * See also {@link Builder#setBssid(MacAddress)}. 508 */ 509 @Nullable getBssid()510 public MacAddress getBssid() { 511 return mBssid; 512 } 513 514 /** 515 * Returns String set to be passphrase for current AP. 516 * See also {@link Builder#setPassphrase(String, int)}. 517 */ 518 @Nullable getPassphrase()519 public String getPassphrase() { 520 return mPassphrase; 521 } 522 523 /** 524 * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or 525 * not (false: broadcasts its SSID) for the AP. 526 * See also {@link Builder#setHiddenSsid(boolean)}. 527 */ isHiddenSsid()528 public boolean isHiddenSsid() { 529 return mHiddenSsid; 530 } 531 532 /** 533 * Returns band type set to be the band for the AP. 534 * 535 * One or combination of {@code BAND_}, for instance 536 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}. 537 * 538 * Note: Returns the lowest band when more than one band is set. 539 * Use {@link #getChannels()} to get dual bands setting. 540 * 541 * See also {@link Builder#setBand(int)}. 542 * 543 * @deprecated This API is deprecated. Use {@link #getChannels()} instead. 544 * @hide 545 */ 546 @Deprecated 547 @SystemApi getBand()548 public @BandType int getBand() { 549 return mChannels.keyAt(0); 550 } 551 552 /** 553 * Returns a sorted array in ascending order that consists of the configured band types 554 * for the APs. 555 * 556 * The band type is one or combination of {@code BAND_}, for instance 557 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}. 558 * 559 * Note: return array may only include one band when current setting is single AP mode. 560 * See also {@link Builder#setBands(int[])}. 561 * 562 * @hide 563 */ getBands()564 public @NonNull int[] getBands() { 565 int[] bands = new int[mChannels.size()]; 566 for (int i = 0; i < bands.length; i++) { 567 bands[i] = mChannels.keyAt(i); 568 } 569 return bands; 570 } 571 572 /** 573 * Returns Integer set to be the channel for the AP. 574 * 575 * Note: Returns the channel which associated to the lowest band if more than one channel 576 * is set. Use {@link Builder#getChannels()} to get dual channel setting. 577 * See also {@link Builder#setChannel(int, int)}. 578 * 579 * @deprecated This API is deprecated. Use {@link #getChannels()} instead. 580 * @hide 581 */ 582 @Deprecated 583 @SystemApi getChannel()584 public int getChannel() { 585 return mChannels.valueAt(0); 586 } 587 588 589 /** 590 * Returns SparseIntArray (key: {@code BandType} , value: channel) that consists of 591 * the configured bands and channels for the AP(s). 592 * 593 * The returned channel value is Wi-Fi channel numbering. 594 * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016 595 * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6. 596 * 597 * Note: return array may only include one channel when current setting is single AP mode. 598 * See also {@link Builder#setChannels(SparseIntArray)}. 599 * 600 * @hide 601 */ 602 @RequiresApi(Build.VERSION_CODES.S) 603 @SystemApi getChannels()604 public @NonNull SparseIntArray getChannels() { 605 if (!SdkLevel.isAtLeastS()) { 606 throw new UnsupportedOperationException(); 607 } 608 return mChannels.clone(); 609 } 610 611 /** 612 * Get security type params which depends on which security passphrase to set. 613 * 614 * @return One of: 615 * {@link #SECURITY_TYPE_OPEN}, 616 * {@link #SECURITY_TYPE_WPA2_PSK}, 617 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 618 * {@link #SECURITY_TYPE_WPA3_SAE} 619 */ getSecurityType()620 public @SecurityType int getSecurityType() { 621 return mSecurityType; 622 } 623 624 /** 625 * Returns the maximum number of clients that can associate to the AP. 626 * See also {@link Builder#setMaxNumberOfClients(int)}. 627 * 628 * @hide 629 */ 630 @SystemApi getMaxNumberOfClients()631 public int getMaxNumberOfClients() { 632 return mMaxNumberOfClients; 633 } 634 635 /** 636 * Returns whether auto shutdown is enabled or not. 637 * The Soft AP will shutdown when there are no devices associated to it for 638 * the timeout duration. See also {@link Builder#setAutoShutdownEnabled(boolean)}. 639 * 640 * @hide 641 */ 642 @SystemApi isAutoShutdownEnabled()643 public boolean isAutoShutdownEnabled() { 644 return mAutoShutdownEnabled; 645 } 646 647 /** 648 * Returns the shutdown timeout in milliseconds. 649 * The Soft AP will shutdown when there are no devices associated to it for 650 * the timeout duration. See also {@link Builder#setShutdownTimeoutMillis(long)}. 651 * 652 * @hide 653 */ 654 @SystemApi getShutdownTimeoutMillis()655 public long getShutdownTimeoutMillis() { 656 return mShutdownTimeoutMillis; 657 } 658 659 /** 660 * Returns a flag indicating whether clients need to be pre-approved by the user. 661 * (true: authorization required) or not (false: not required). 662 * See also {@link Builder#setClientControlByUserEnabled(Boolean)}. 663 * 664 * @hide 665 */ 666 @SystemApi isClientControlByUserEnabled()667 public boolean isClientControlByUserEnabled() { 668 return mClientControlByUser; 669 } 670 671 /** 672 * Returns List of clients which aren't allowed to associate to the AP. 673 * 674 * Clients are configured using {@link Builder#setBlockedClientList(List)} 675 * 676 * @hide 677 */ 678 @NonNull 679 @SystemApi getBlockedClientList()680 public List<MacAddress> getBlockedClientList() { 681 return mBlockedClientList; 682 } 683 684 /** 685 * List of clients which are allowed to associate to the AP. 686 * Clients are configured using {@link Builder#setAllowedClientList(List)} 687 * 688 * @hide 689 */ 690 @NonNull 691 @SystemApi getAllowedClientList()692 public List<MacAddress> getAllowedClientList() { 693 return mAllowedClientList; 694 } 695 696 /** 697 * Returns the level of MAC randomization for the AP BSSID. 698 * See also {@link Builder#setMacRandomizationSetting(int)}. 699 * 700 * @hide 701 */ 702 @RequiresApi(Build.VERSION_CODES.S) 703 @SystemApi 704 @MacRandomizationSetting getMacRandomizationSetting()705 public int getMacRandomizationSetting() { 706 if (!SdkLevel.isAtLeastS()) { 707 throw new UnsupportedOperationException(); 708 } 709 return getMacRandomizationSettingInternal(); 710 } 711 712 /** 713 * @hide 714 */ 715 @MacRandomizationSetting getMacRandomizationSettingInternal()716 public int getMacRandomizationSettingInternal() { 717 return mMacRandomizationSetting; 718 } 719 720 /** 721 * Returns whether opportunistic shutdown of an instance in bridged AP is enabled or not. 722 * 723 * See also {@link Builder#setBridgedModeOpportunisticShutdownEnabled(boolean}} 724 * @hide 725 */ 726 @RequiresApi(Build.VERSION_CODES.S) 727 @SystemApi isBridgedModeOpportunisticShutdownEnabled()728 public boolean isBridgedModeOpportunisticShutdownEnabled() { 729 if (!SdkLevel.isAtLeastS()) { 730 throw new UnsupportedOperationException(); 731 } 732 return isBridgedModeOpportunisticShutdownEnabledInternal(); 733 } 734 735 /** 736 * @see #isBridgedModeOpportunisticShutdownEnabled() 737 * @hide 738 */ isBridgedModeOpportunisticShutdownEnabledInternal()739 public boolean isBridgedModeOpportunisticShutdownEnabledInternal() { 740 return mBridgedModeOpportunisticShutdownEnabled; 741 } 742 743 /** 744 * @see #isIeee80211axEnabled() 745 * @hide 746 */ isIeee80211axEnabledInternal()747 public boolean isIeee80211axEnabledInternal() { 748 return mIeee80211axEnabled; 749 } 750 751 /** 752 * Returns whether or not 802.11ax is enabled on the SoftAP. 753 * This is an indication that if the device support 802.11ax AP then to enable or disable 754 * that feature. If the device does not support 802.11ax AP then this flag is ignored. 755 * See also {@link Builder#setIeee80211axEnabled(boolean}} 756 * @hide 757 */ 758 @RequiresApi(Build.VERSION_CODES.S) 759 @SystemApi isIeee80211axEnabled()760 public boolean isIeee80211axEnabled() { 761 if (!SdkLevel.isAtLeastS()) { 762 throw new UnsupportedOperationException(); 763 } 764 return isIeee80211axEnabledInternal(); 765 } 766 767 /** 768 * Returns whether or not the {@link SoftApConfiguration} was configured by the user 769 * (as opposed to the default system configuration). 770 * <p> 771 * The {@link SoftApConfiguration} is considered user edited once the 772 * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)} is called 773 * - whether or not that configuration is the same as the default system configuration! 774 * 775 * @hide 776 */ 777 @RequiresApi(Build.VERSION_CODES.S) 778 @SystemApi isUserConfiguration()779 public boolean isUserConfiguration() { 780 if (!SdkLevel.isAtLeastS()) { 781 throw new UnsupportedOperationException(); 782 } 783 return isUserConfigurationInternal(); 784 } 785 786 /** 787 * @hide 788 */ isUserConfigurationInternal()789 public boolean isUserConfigurationInternal() { 790 return mIsUserConfiguration; 791 } 792 793 /** 794 * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}. 795 * Note that SoftApConfiguration may contain configuration which is cannot be represented 796 * by the legacy WifiConfiguration, in such cases a null will be returned. 797 * 798 * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports 799 * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li> 800 * 801 * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports 802 * NONE, WPA2_PSK, so conversion is limited to these security type.</li> 803 * @hide 804 */ 805 @Nullable 806 @SystemApi toWifiConfiguration()807 public WifiConfiguration toWifiConfiguration() { 808 WifiConfiguration wifiConfig = new WifiConfiguration(); 809 wifiConfig.SSID = mSsid; 810 wifiConfig.preSharedKey = mPassphrase; 811 wifiConfig.hiddenSSID = mHiddenSsid; 812 wifiConfig.apChannel = getChannel(); 813 switch (mSecurityType) { 814 case SECURITY_TYPE_OPEN: 815 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 816 break; 817 case SECURITY_TYPE_WPA2_PSK: 818 case SECURITY_TYPE_WPA3_SAE_TRANSITION: 819 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK); 820 break; 821 default: 822 Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType); 823 return null; 824 } 825 826 switch (getBand()) { 827 case BAND_2GHZ: 828 wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ; 829 break; 830 case BAND_5GHZ: 831 wifiConfig.apBand = WifiConfiguration.AP_BAND_5GHZ; 832 break; 833 case BAND_2GHZ | BAND_5GHZ: 834 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 835 break; 836 case BAND_ANY: 837 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 838 break; 839 default: 840 Log.e(TAG, "Convert fail, unsupported band setting :" + getBand()); 841 return null; 842 } 843 return wifiConfig; 844 } 845 846 /** 847 * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a 848 * Soft AP. 849 * 850 * All fields are optional. By default, SSID and BSSID are automatically chosen by the 851 * framework, and an open network is created. 852 * 853 * @hide 854 */ 855 @SystemApi 856 public static final class Builder { 857 private String mSsid; 858 private MacAddress mBssid; 859 private String mPassphrase; 860 private boolean mHiddenSsid; 861 private SparseIntArray mChannels; 862 private int mMaxNumberOfClients; 863 private int mSecurityType; 864 private boolean mAutoShutdownEnabled; 865 private long mShutdownTimeoutMillis; 866 private boolean mClientControlByUser; 867 private List<MacAddress> mBlockedClientList; 868 private List<MacAddress> mAllowedClientList; 869 private int mMacRandomizationSetting; 870 private boolean mBridgedModeOpportunisticShutdownEnabled; 871 private boolean mIeee80211axEnabled; 872 private boolean mIsUserConfiguration; 873 874 /** 875 * Constructs a Builder with default values (see {@link Builder}). 876 */ Builder()877 public Builder() { 878 mSsid = null; 879 mBssid = null; 880 mPassphrase = null; 881 mHiddenSsid = false; 882 mChannels = new SparseIntArray(1); 883 mChannels.put(BAND_2GHZ, 0); 884 mMaxNumberOfClients = 0; 885 mSecurityType = SECURITY_TYPE_OPEN; 886 mAutoShutdownEnabled = true; // enabled by default. 887 mShutdownTimeoutMillis = 0; 888 mClientControlByUser = false; 889 mBlockedClientList = new ArrayList<>(); 890 mAllowedClientList = new ArrayList<>(); 891 mMacRandomizationSetting = RANDOMIZATION_PERSISTENT; 892 mBridgedModeOpportunisticShutdownEnabled = true; 893 mIeee80211axEnabled = true; 894 mIsUserConfiguration = true; 895 } 896 897 /** 898 * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance. 899 */ Builder(@onNull SoftApConfiguration other)900 public Builder(@NonNull SoftApConfiguration other) { 901 Objects.requireNonNull(other); 902 903 mSsid = other.mSsid; 904 mBssid = other.mBssid; 905 mPassphrase = other.mPassphrase; 906 mHiddenSsid = other.mHiddenSsid; 907 mChannels = other.mChannels.clone(); 908 mMaxNumberOfClients = other.mMaxNumberOfClients; 909 mSecurityType = other.mSecurityType; 910 mAutoShutdownEnabled = other.mAutoShutdownEnabled; 911 mShutdownTimeoutMillis = other.mShutdownTimeoutMillis; 912 mClientControlByUser = other.mClientControlByUser; 913 mBlockedClientList = new ArrayList<>(other.mBlockedClientList); 914 mAllowedClientList = new ArrayList<>(other.mAllowedClientList); 915 mMacRandomizationSetting = other.mMacRandomizationSetting; 916 mBridgedModeOpportunisticShutdownEnabled = 917 other.mBridgedModeOpportunisticShutdownEnabled; 918 mIeee80211axEnabled = other.mIeee80211axEnabled; 919 mIsUserConfiguration = other.mIsUserConfiguration; 920 } 921 922 /** 923 * Builds the {@link SoftApConfiguration}. 924 * 925 * @return A new {@link SoftApConfiguration}, as configured by previous method calls. 926 */ 927 @NonNull build()928 public SoftApConfiguration build() { 929 for (MacAddress client : mAllowedClientList) { 930 if (mBlockedClientList.contains(client)) { 931 throw new IllegalArgumentException("A MacAddress exist in both client list"); 932 } 933 } 934 return new SoftApConfiguration(mSsid, mBssid, mPassphrase, 935 mHiddenSsid, mChannels, mSecurityType, mMaxNumberOfClients, 936 mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser, 937 mBlockedClientList, mAllowedClientList, mMacRandomizationSetting, 938 mBridgedModeOpportunisticShutdownEnabled, mIeee80211axEnabled, 939 mIsUserConfiguration); 940 } 941 942 /** 943 * Specifies an SSID for the AP. 944 * <p> 945 * Null SSID only support when configure a local-only hotspot. 946 * <p> 947 * <li>If not set, defaults to null.</li> 948 * 949 * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically 950 * chosen by the framework. 951 * @return Builder for chaining. 952 * @throws IllegalArgumentException when the SSID is empty or not valid Unicode. 953 */ 954 @NonNull setSsid(@ullable String ssid)955 public Builder setSsid(@Nullable String ssid) { 956 if (ssid != null) { 957 Preconditions.checkStringNotEmpty(ssid); 958 Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid)); 959 } 960 mSsid = ssid; 961 return this; 962 } 963 964 /** 965 * Specifies a BSSID for the AP. 966 * <p> 967 * <li>If not set, defaults to null.</li> 968 * 969 * If multiple bands are requested via {@link #setBands(int[])} or 970 * {@link #setChannels(SparseIntArray)}, HAL will derive 2 MAC addresses since framework 971 * only sends down 1 MAC address. 972 * 973 * An example (but different implementation may perform a different mapping): 974 * <li>MAC address 1: copy value of MAC address, 975 * and set byte 1 = (0xFF - BSSID[1])</li> 976 * <li>MAC address 2: copy value of MAC address, 977 * and set byte 2 = (0xFF - BSSID[2])</li> 978 * 979 * Example BSSID argument: e2:38:60:c4:0e:b7 980 * Derived MAC address 1: e2:c7:60:c4:0e:b7 981 * Derived MAC address 2: e2:38:9f:c4:0e:b7 982 * 983 * <p> 984 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 985 * {@link SoftApCapability#areFeaturesSupported(long)} 986 * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine 987 * whether or not this feature is supported. 988 * 989 * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is 990 * responsible for avoiding collisions. 991 * @return Builder for chaining. 992 * @throws IllegalArgumentException when the given BSSID is the all-zero 993 * , multicast or broadcast MAC address. 994 */ 995 @NonNull setBssid(@ullable MacAddress bssid)996 public Builder setBssid(@Nullable MacAddress bssid) { 997 if (bssid != null) { 998 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS)); 999 if (bssid.getAddressType() != MacAddress.TYPE_UNICAST) { 1000 throw new IllegalArgumentException("bssid doesn't support " 1001 + "multicast or broadcast mac address"); 1002 } 1003 } 1004 mBssid = bssid; 1005 return this; 1006 } 1007 1008 /** 1009 * Specifies that this AP should use specific security type with the given ASCII passphrase. 1010 * 1011 * @param securityType One of the following security types: 1012 * {@link #SECURITY_TYPE_OPEN}, 1013 * {@link #SECURITY_TYPE_WPA2_PSK}, 1014 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 1015 * {@link #SECURITY_TYPE_WPA3_SAE}. 1016 * @param passphrase The passphrase to use for sepcific {@code securityType} configuration 1017 * or null with {@link #SECURITY_TYPE_OPEN}. 1018 * 1019 * @return Builder for chaining. 1020 * @throws IllegalArgumentException when the passphrase length is invalid and 1021 * {@code securityType} is not {@link #SECURITY_TYPE_OPEN} 1022 * or non-null passphrase and {@code securityType} is 1023 * {@link #SECURITY_TYPE_OPEN}. 1024 */ 1025 @NonNull setPassphrase(@ullable String passphrase, @SecurityType int securityType)1026 public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) { 1027 if (securityType == SECURITY_TYPE_OPEN) { 1028 if (passphrase != null) { 1029 throw new IllegalArgumentException( 1030 "passphrase should be null when security type is open"); 1031 } 1032 } else { 1033 Preconditions.checkStringNotEmpty(passphrase); 1034 if (securityType == SECURITY_TYPE_WPA2_PSK 1035 || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) { 1036 if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) { 1037 throw new IllegalArgumentException( 1038 "Password size must be at least " + PSK_MIN_LEN 1039 + " and no more than " + PSK_MAX_LEN 1040 + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode"); 1041 } 1042 } 1043 } 1044 mSecurityType = securityType; 1045 mPassphrase = passphrase; 1046 return this; 1047 } 1048 1049 /** 1050 * Specifies whether the AP is hidden (doesn't broadcast its SSID) or 1051 * not (broadcasts its SSID). 1052 * <p> 1053 * <li>If not set, defaults to false (i.e not a hidden network).</li> 1054 * 1055 * @param hiddenSsid true for a hidden SSID, false otherwise. 1056 * @return Builder for chaining. 1057 */ 1058 @NonNull setHiddenSsid(boolean hiddenSsid)1059 public Builder setHiddenSsid(boolean hiddenSsid) { 1060 mHiddenSsid = hiddenSsid; 1061 return this; 1062 } 1063 1064 /** 1065 * Specifies the band for the AP. 1066 * <p> 1067 * <li>If not set, defaults to {@link #BAND_2GHZ}.</li> 1068 * 1069 * @param band One or combination of the following band type: 1070 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 1071 * @return Builder for chaining. 1072 * @throws IllegalArgumentException when an invalid band type is provided. 1073 */ 1074 @NonNull setBand(@andType int band)1075 public Builder setBand(@BandType int band) { 1076 if (!isBandValid(band)) { 1077 throw new IllegalArgumentException("Invalid band type: " + band); 1078 } 1079 mChannels = new SparseIntArray(1); 1080 mChannels.put(band, 0); 1081 return this; 1082 } 1083 1084 /** 1085 * Specifies the bands for the APs. 1086 * If more than 1 band is set, this will bring up concurrent APs. 1087 * on the requested bands (if possible). 1088 * <p> 1089 * 1090 * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine 1091 * whether or not concurrent APs are supported. 1092 * 1093 * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1094 * when multiple bands are configured. Otherwise, 1095 * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code 1096 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1097 * 1098 * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error 1099 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1100 * 1101 * @param bands Array of the {@link #BandType}. 1102 * @return Builder for chaining. 1103 * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type 1104 * is provided. 1105 */ 1106 @RequiresApi(Build.VERSION_CODES.S) 1107 @NonNull setBands(@onNull int[] bands)1108 public Builder setBands(@NonNull int[] bands) { 1109 if (!SdkLevel.isAtLeastS()) { 1110 throw new UnsupportedOperationException(); 1111 } 1112 if (bands.length == 0 || bands.length > 2) { 1113 throw new IllegalArgumentException("Unsupported number of bands(" 1114 + bands.length + ") configured"); 1115 } 1116 SparseIntArray channels = new SparseIntArray(bands.length); 1117 for (int val : bands) { 1118 if (!isBandValid(val)) { 1119 throw new IllegalArgumentException("Invalid band type: " + val); 1120 } 1121 channels.put(val, 0); 1122 } 1123 mChannels = channels; 1124 return this; 1125 } 1126 1127 1128 /** 1129 * Specifies the channel and associated band for the AP. 1130 * 1131 * The channel which AP resides on. Valid channels are country dependent. 1132 * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain 1133 * valid channels. 1134 * 1135 * <p> 1136 * If not set, the default for the channel is the special value 0 which has the 1137 * framework auto-select a valid channel from the band configured with 1138 * {@link #setBand(int)}. 1139 * 1140 * The channel auto selection will be offloaded to driver when 1141 * {@link SoftApCapability#areFeaturesSupported(long)} 1142 * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1143 * return true. The driver will auto select the best channel (e.g. best performance) 1144 * based on environment interference. Check {@link SoftApCapability} for more detail. 1145 * 1146 * The API contains (band, channel) input since the 6GHz band uses the same channel 1147 * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to 1148 * uniquely identify individual channels. 1149 * 1150 * <p> 1151 * @param channel operating channel of the AP. 1152 * @param band containing this channel. 1153 * @return Builder for chaining. 1154 * @throws IllegalArgumentException when the invalid channel or band type is configured. 1155 */ 1156 @NonNull setChannel(int channel, @BandType int band)1157 public Builder setChannel(int channel, @BandType int band) { 1158 if (!isChannelBandPairValid(channel, band)) { 1159 throw new IllegalArgumentException("Invalid channel(" + channel 1160 + ") & band (" + band + ") configured"); 1161 } 1162 mChannels = new SparseIntArray(1); 1163 mChannels.put(band, channel); 1164 return this; 1165 } 1166 1167 /** 1168 * Specifies the channels and associated bands for the APs. 1169 * 1170 * When more than 1 channel is set, this will bring up concurrent APs on the requested 1171 * channels and bands (if possible). 1172 * 1173 * Valid channels are country dependent. 1174 * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain 1175 * valid channels in each band. 1176 * 1177 * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine 1178 * whether or not concurrent APs are supported. 1179 * 1180 * <p> 1181 * If not set, the default for the channel is the special value 0 which has the framework 1182 * auto-select a valid channel from the band configured with {@link #setBands(int[])}. 1183 * 1184 * The channel auto selection will be offloaded to driver when 1185 * {@link SoftApCapability#areFeaturesSupported(long)} 1186 * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1187 * returns true. The driver will auto select the best channel (e.g. best performance) 1188 * based on environment interference. Check {@link SoftApCapability} for more detail. 1189 * 1190 * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD} 1191 * when multiple bands are configured without specified channel value (i.e. channel is 1192 * the special value 0). Otherwise, 1193 * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code 1194 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1195 * 1196 * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error 1197 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1198 * 1199 * The API contains (band, channel) input since the 6GHz band uses the same channel 1200 * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to 1201 * uniquely identify individual channels. 1202 * 1203 * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016 1204 * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6. 1205 * 1206 * <p> 1207 * @param channels SparseIntArray (key: {@code #BandType} , value: channel) consists of 1208 * {@code BAND_} and corresponding channel. 1209 * @return Builder for chaining. 1210 * @throws IllegalArgumentException when more than 2 channels are set or the invalid 1211 * channel or band type is configured. 1212 */ 1213 @RequiresApi(Build.VERSION_CODES.S) 1214 @NonNull setChannels(@onNull SparseIntArray channels)1215 public Builder setChannels(@NonNull SparseIntArray channels) { 1216 if (!SdkLevel.isAtLeastS()) { 1217 throw new UnsupportedOperationException(); 1218 } 1219 if (channels.size() == 0 || channels.size() > 2) { 1220 throw new IllegalArgumentException("Unsupported number of channels(" 1221 + channels.size() + ") configured"); 1222 } 1223 for (int i = 0; i < channels.size(); i++) { 1224 int channel = channels.valueAt(i); 1225 int band = channels.keyAt(i); 1226 if (channel == 0) { 1227 if (!isBandValid(band)) { 1228 throw new IllegalArgumentException("Invalid band type: " + band); 1229 } 1230 } else { 1231 if (!isChannelBandPairValid(channel, band)) { 1232 throw new IllegalArgumentException("Invalid channel(" + channel 1233 + ") & band (" + band + ") configured"); 1234 } 1235 } 1236 } 1237 mChannels = channels.clone(); 1238 return this; 1239 } 1240 1241 1242 /** 1243 * Specifies the maximum number of clients that can associate to the AP. 1244 * 1245 * The maximum number of clients (STAs) which can associate to the AP. 1246 * The AP will reject association from any clients above this number. 1247 * Specify a value of 0 to have the framework automatically use the maximum number 1248 * which the device can support (based on hardware and carrier constraints). 1249 * <p> 1250 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1251 * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients 1252 * which the device supports (based on hardware and carrier constraints). 1253 * 1254 * <p> 1255 * <li>If not set, defaults to 0.</li> 1256 * 1257 * This method requires HAL support. If the method is used to set a 1258 * non-zero {@code maxNumberOfClients} value then 1259 * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code 1260 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1261 * 1262 * <p> 1263 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1264 * {@link SoftApCapability#areFeaturesSupported(long)} 1265 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether 1266 * or not this feature is supported. 1267 * 1268 * @param maxNumberOfClients maximum client number of the AP. 1269 * @return Builder for chaining. 1270 */ 1271 @NonNull setMaxNumberOfClients(@ntRangefrom = 0) int maxNumberOfClients)1272 public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) { 1273 if (maxNumberOfClients < 0) { 1274 throw new IllegalArgumentException("maxNumberOfClients should be not negative"); 1275 } 1276 mMaxNumberOfClients = maxNumberOfClients; 1277 return this; 1278 } 1279 1280 /** 1281 * Specifies whether auto shutdown is enabled or not. 1282 * The Soft AP will shut down when there are no devices connected to it for 1283 * the timeout duration. 1284 * 1285 * <p> 1286 * <li>If not set, defaults to true</li> 1287 * 1288 * @param enable true to enable, false to disable. 1289 * @return Builder for chaining. 1290 * 1291 * @see #setShutdownTimeoutMillis(long) 1292 */ 1293 @NonNull setAutoShutdownEnabled(boolean enable)1294 public Builder setAutoShutdownEnabled(boolean enable) { 1295 mAutoShutdownEnabled = enable; 1296 return this; 1297 } 1298 1299 /** 1300 * Specifies the shutdown timeout in milliseconds. 1301 * The Soft AP will shut down when there are no devices connected to it for 1302 * the timeout duration. 1303 * 1304 * Specify a value of 0 to have the framework automatically use default timeout 1305 * setting which defined in {@link R.integer.config_wifi_framework_soft_ap_timeout_delay} 1306 * 1307 * <p> 1308 * <li>If not set, defaults to 0</li> 1309 * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is 1310 * set to true</li> 1311 * 1312 * @param timeoutMillis milliseconds of the timeout delay. 1313 * @return Builder for chaining. 1314 * 1315 * @see #setAutoShutdownEnabled(boolean) 1316 */ 1317 @NonNull setShutdownTimeoutMillis(@ntRangefrom = 0) long timeoutMillis)1318 public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) { 1319 if (timeoutMillis < 0) { 1320 throw new IllegalArgumentException("Invalid timeout value"); 1321 } 1322 mShutdownTimeoutMillis = timeoutMillis; 1323 return this; 1324 } 1325 1326 /** 1327 * Configure the Soft AP to require manual user control of client association. 1328 * If disabled (the default) then any client which isn't in the blocked list 1329 * {@link #getBlockedClientList()} can associate to this Soft AP using the 1330 * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier, 1331 * or user limited - using {@link #setMaxNumberOfClients(int)}). 1332 * 1333 * If manual user control is enabled then clients will be accepted, rejected, or require 1334 * a user approval based on the configuration provided by 1335 * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}. 1336 * 1337 * <p> 1338 * This method requires HAL support. HAL support can be determined using 1339 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1340 * {@link SoftApCapability#areFeaturesSupported(long)} 1341 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 1342 * 1343 * <p> 1344 * If the method is called on a device without HAL support then starting the soft AP 1345 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 1346 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1347 * 1348 * <p> 1349 * <li>If not set, defaults to false (i.e The authoriztion is not required).</li> 1350 * 1351 * @param enabled true for enabling the control by user, false otherwise. 1352 * @return Builder for chaining. 1353 */ 1354 @NonNull setClientControlByUserEnabled(boolean enabled)1355 public Builder setClientControlByUserEnabled(boolean enabled) { 1356 mClientControlByUser = enabled; 1357 return this; 1358 } 1359 1360 1361 /** 1362 * This method together with {@link setClientControlByUserEnabled(boolean)} control client 1363 * connections to the AP. If client control by user is disabled using the above method then 1364 * this API has no effect and clients are allowed to associate to the AP (within limit of 1365 * max number of clients). 1366 * 1367 * If client control by user is enabled then this API configures the list of clients 1368 * which are explicitly allowed. These are auto-accepted. 1369 * 1370 * All other clients which attempt to associate, whose MAC addresses are on neither list, 1371 * are: 1372 * <ul> 1373 * <li>Rejected</li> 1374 * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)} 1375 * is issued (which allows the user to add them to the allowed client list if desired).<li> 1376 * </ul> 1377 * 1378 * @param allowedClientList list of clients which are allowed to associate to the AP 1379 * without user pre-approval. 1380 * @return Builder for chaining. 1381 */ 1382 @NonNull setAllowedClientList(@onNull List<MacAddress> allowedClientList)1383 public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) { 1384 mAllowedClientList = new ArrayList<>(allowedClientList); 1385 return this; 1386 } 1387 1388 /** 1389 * This API configures the list of clients which are blocked and cannot associate 1390 * to the Soft AP. 1391 * 1392 * <p> 1393 * This method requires HAL support. HAL support can be determined using 1394 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1395 * {@link SoftApCapability#areFeaturesSupported(long)} 1396 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 1397 * 1398 * <p> 1399 * If the method is called on a device without HAL support then starting the soft AP 1400 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 1401 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 1402 * 1403 * @param blockedClientList list of clients which are not allowed to associate to the AP. 1404 * @return Builder for chaining. 1405 */ 1406 @NonNull setBlockedClientList(@onNull List<MacAddress> blockedClientList)1407 public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) { 1408 mBlockedClientList = new ArrayList<>(blockedClientList); 1409 return this; 1410 } 1411 1412 /** 1413 * Specifies the level of MAC randomization for the AP BSSID. 1414 * The Soft AP BSSID will be randomized only if the BSSID isn't set 1415 * {@link #setBssid(MacAddress)} and this method is either uncalled 1416 * or called with {@link #RANDOMIZATION_PERSISTENT}. 1417 * 1418 * <p> 1419 * <li>If not set, defaults to {@link #RANDOMIZATION_PERSISTENT}</li> 1420 * 1421 * <p> 1422 * Requires HAL support when set to {@link #RANDOMIZATION_PERSISTENT}. 1423 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1424 * {@link SoftApCapability#areFeaturesSupported(long)} 1425 * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine 1426 * whether or not this feature is supported. 1427 * 1428 * @param macRandomizationSetting One of the following setting: 1429 * {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}. 1430 * @return Builder for chaining. 1431 * 1432 * @see #setBssid(MacAddress) 1433 */ 1434 @RequiresApi(Build.VERSION_CODES.S) 1435 @NonNull setMacRandomizationSetting( @acRandomizationSetting int macRandomizationSetting)1436 public Builder setMacRandomizationSetting( 1437 @MacRandomizationSetting int macRandomizationSetting) { 1438 if (!SdkLevel.isAtLeastS()) { 1439 throw new UnsupportedOperationException(); 1440 } 1441 mMacRandomizationSetting = macRandomizationSetting; 1442 return this; 1443 } 1444 1445 1446 /** 1447 * Specifies whether or not opportunistic shut down of an AP instance in bridged mode 1448 * is enabled. 1449 * 1450 * <p> 1451 * If enabled, the framework will shutdown one of the AP instances if it is idle for 1452 * the timeout duration - meaning there are no devices connected to it. 1453 * If both AP instances are idle for the timeout duration then the framework will 1454 * shut down the AP instance operating on the higher frequency. For instance, 1455 * if the AP instances operate at 2.4GHz and 5GHz and are both idle for the 1456 * timeout duration then the 5GHz AP instance will be shut down. 1457 * <p> 1458 * 1459 * Note: the opportunistic timeout only applies to one AP instance of the bridge AP. 1460 * If one of the AP instances has already been disabled for any reason, including due to 1461 * an opportunistic timeout or hardware issues or coexistence issues, 1462 * then the opportunistic timeout is no longer active. 1463 * 1464 * <p> 1465 * The shutdown timer specified by {@link #setShutdownTimeoutMillis(long)} controls the 1466 * overall shutdown of the bridged AP and is still in use independently of the opportunistic 1467 * timer controlled by this AP. 1468 * 1469 * <p> 1470 * <li>If not set, defaults to true</li> 1471 * 1472 * @param enable true to enable, false to disable. 1473 * @return Builder for chaining. 1474 * 1475 */ 1476 @RequiresApi(Build.VERSION_CODES.S) 1477 @NonNull setBridgedModeOpportunisticShutdownEnabled(boolean enable)1478 public Builder setBridgedModeOpportunisticShutdownEnabled(boolean enable) { 1479 if (!SdkLevel.isAtLeastS()) { 1480 throw new UnsupportedOperationException(); 1481 } 1482 mBridgedModeOpportunisticShutdownEnabled = enable; 1483 return this; 1484 } 1485 1486 /** 1487 * Specifies whether or not to enable 802.11ax on the Soft AP. 1488 * 1489 * <p> 1490 * Note: Only relevant when the device supports 802.11ax on the Soft AP. 1491 * If enabled on devices that do not support 802.11ax then ignored. 1492 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 1493 * {@link SoftApCapability#areFeaturesSupported(long)} 1494 * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX} to determine 1495 * whether or not 802.11ax is supported on the Soft AP. 1496 * <p> 1497 * <li>If not set, defaults to true - which will be ignored on devices 1498 * which do not support 802.11ax</li> 1499 * 1500 * @param enable true to enable, false to disable. 1501 * @return Builder for chaining. 1502 * 1503 */ 1504 @RequiresApi(Build.VERSION_CODES.S) 1505 @NonNull setIeee80211axEnabled(boolean enable)1506 public Builder setIeee80211axEnabled(boolean enable) { 1507 if (!SdkLevel.isAtLeastS()) { 1508 throw new UnsupportedOperationException(); 1509 } 1510 mIeee80211axEnabled = enable; 1511 return this; 1512 } 1513 1514 /** 1515 * Specifies whether or not the configuration is configured by user. 1516 * 1517 * @param isUserConfigured true to user configuration, false otherwise. 1518 * @return Builder for chaining. 1519 * 1520 * @hide 1521 */ 1522 @NonNull setUserConfiguration(boolean isUserConfigured)1523 public Builder setUserConfiguration(boolean isUserConfigured) { 1524 mIsUserConfiguration = isUserConfigured; 1525 return this; 1526 } 1527 } 1528 } 1529