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.Parcel; 26 import android.os.Parcelable; 27 import android.text.TextUtils; 28 import android.util.Log; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.internal.util.Preconditions; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.nio.charset.CharsetEncoder; 36 import java.nio.charset.StandardCharsets; 37 import java.util.ArrayList; 38 import java.util.List; 39 import java.util.Objects; 40 41 /** 42 * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot). 43 * 44 * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the 45 * framework how it should configure a hotspot. 46 * 47 * System apps can use this to configure a tethered hotspot using 48 * {@code WifiManager#startTetheredHotspot(SoftApConfiguration)} and 49 * {@code WifiManager#setSoftApConfiguration(SoftApConfiguration)} 50 * or local-only hotspot using 51 * {@code WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor, 52 * WifiManager.LocalOnlyHotspotCallback)}. 53 * 54 * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to 55 * create a new instance. 56 * 57 */ 58 public final class SoftApConfiguration implements Parcelable { 59 60 private static final String TAG = "SoftApConfiguration"; 61 62 @VisibleForTesting 63 static final int PSK_MIN_LEN = 8; 64 65 @VisibleForTesting 66 static final int PSK_MAX_LEN = 63; 67 68 /** 69 * 2GHz band. 70 * @hide 71 */ 72 @SystemApi 73 public static final int BAND_2GHZ = 1 << 0; 74 75 /** 76 * 5GHz band. 77 * @hide 78 */ 79 @SystemApi 80 public static final int BAND_5GHZ = 1 << 1; 81 82 /** 83 * 6GHz band. 84 * @hide 85 */ 86 @SystemApi 87 public static final int BAND_6GHZ = 1 << 2; 88 89 /** 90 * Device is allowed to choose the optimal band (2Ghz, 5Ghz, 6Ghz) based on device capability, 91 * operating country code and current radio conditions. 92 * @hide 93 */ 94 @SystemApi 95 public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ; 96 97 /** @hide */ 98 @Retention(RetentionPolicy.SOURCE) 99 @IntDef(flag = true, prefix = { "BAND_TYPE_" }, value = { 100 BAND_2GHZ, 101 BAND_5GHZ, 102 BAND_6GHZ, 103 }) 104 public @interface BandType {} 105 isBandValid(@andType int band)106 private static boolean isBandValid(@BandType int band) { 107 return ((band != 0) && ((band & ~BAND_ANY) == 0)); 108 } 109 110 private static final int MIN_CH_2G_BAND = 1; 111 private static final int MAX_CH_2G_BAND = 14; 112 private static final int MIN_CH_5G_BAND = 34; 113 private static final int MAX_CH_5G_BAND = 196; 114 private static final int MIN_CH_6G_BAND = 1; 115 private static final int MAX_CH_6G_BAND = 253; 116 117 118 isChannelBandPairValid(int channel, @BandType int band)119 private static boolean isChannelBandPairValid(int channel, @BandType int band) { 120 switch (band) { 121 case BAND_2GHZ: 122 if (channel < MIN_CH_2G_BAND || channel > MAX_CH_2G_BAND) { 123 return false; 124 } 125 break; 126 127 case BAND_5GHZ: 128 if (channel < MIN_CH_5G_BAND || channel > MAX_CH_5G_BAND) { 129 return false; 130 } 131 break; 132 133 case BAND_6GHZ: 134 if (channel < MIN_CH_6G_BAND || channel > MAX_CH_6G_BAND) { 135 return false; 136 } 137 break; 138 default: 139 return false; 140 } 141 return true; 142 } 143 144 /** 145 * SSID for the AP, or null for a framework-determined SSID. 146 */ 147 private final @Nullable String mSsid; 148 149 /** 150 * BSSID for the AP, or null to use a framework-determined BSSID. 151 */ 152 private final @Nullable MacAddress mBssid; 153 154 /** 155 * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on 156 * the security type. 157 */ 158 private final @Nullable String mPassphrase; 159 160 /** 161 * This is a network that does not broadcast its SSID, so an 162 * SSID-specific probe request must be used for scans. 163 */ 164 private final boolean mHiddenSsid; 165 166 /** 167 * The operating band of the AP. 168 * One or combination of the following band type: 169 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 170 */ 171 private final @BandType int mBand; 172 173 /** 174 * The operating channel of the AP. 175 */ 176 private final int mChannel; 177 178 /** 179 * The maximim allowed number of clients that can associate to the AP. 180 */ 181 private final int mMaxNumberOfClients; 182 183 /** 184 * The operating security type of the AP. 185 * One of the following security types: 186 * {@link #SECURITY_TYPE_OPEN}, 187 * {@link #SECURITY_TYPE_WPA2_PSK}, 188 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 189 * {@link #SECURITY_TYPE_WPA3_SAE} 190 */ 191 private final @SecurityType int mSecurityType; 192 193 /** 194 * The flag to indicate client need to authorize by user 195 * when client is connecting to AP. 196 */ 197 private final boolean mClientControlByUser; 198 199 /** 200 * The list of blocked client that can't associate to the AP. 201 */ 202 private final List<MacAddress> mBlockedClientList; 203 204 /** 205 * The list of allowed client that can associate to the AP. 206 */ 207 private final List<MacAddress> mAllowedClientList; 208 209 /** 210 * Whether auto shutdown of soft AP is enabled or not. 211 */ 212 private final boolean mAutoShutdownEnabled; 213 214 /** 215 * Delay in milliseconds before shutting down soft AP when 216 * there are no connected devices. 217 */ 218 private final long mShutdownTimeoutMillis; 219 220 /** 221 * THe definition of security type OPEN. 222 */ 223 public static final int SECURITY_TYPE_OPEN = 0; 224 225 /** 226 * The definition of security type WPA2-PSK. 227 */ 228 public static final int SECURITY_TYPE_WPA2_PSK = 1; 229 230 /** 231 * The definition of security type WPA3-SAE Transition mode. 232 */ 233 public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2; 234 235 /** 236 * The definition of security type WPA3-SAE. 237 */ 238 public static final int SECURITY_TYPE_WPA3_SAE = 3; 239 240 /** @hide */ 241 @Retention(RetentionPolicy.SOURCE) 242 @IntDef(prefix = { "SECURITY_TYPE_" }, value = { 243 SECURITY_TYPE_OPEN, 244 SECURITY_TYPE_WPA2_PSK, 245 SECURITY_TYPE_WPA3_SAE_TRANSITION, 246 SECURITY_TYPE_WPA3_SAE, 247 }) 248 public @interface SecurityType {} 249 250 /** Private constructor for Builder and Parcelable implementation. */ SoftApConfiguration(@ullable String ssid, @Nullable MacAddress bssid, @Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel, @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled, long shutdownTimeoutMillis, boolean clientControlByUser, @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList)251 private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid, 252 @Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel, 253 @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled, 254 long shutdownTimeoutMillis, boolean clientControlByUser, 255 @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) { 256 mSsid = ssid; 257 mBssid = bssid; 258 mPassphrase = passphrase; 259 mHiddenSsid = hiddenSsid; 260 mBand = band; 261 mChannel = channel; 262 mSecurityType = securityType; 263 mMaxNumberOfClients = maxNumberOfClients; 264 mAutoShutdownEnabled = shutdownTimeoutEnabled; 265 mShutdownTimeoutMillis = shutdownTimeoutMillis; 266 mClientControlByUser = clientControlByUser; 267 mBlockedClientList = new ArrayList<>(blockedList); 268 mAllowedClientList = new ArrayList<>(allowedList); 269 } 270 271 @Override equals(Object otherObj)272 public boolean equals(Object otherObj) { 273 if (this == otherObj) { 274 return true; 275 } 276 if (!(otherObj instanceof SoftApConfiguration)) { 277 return false; 278 } 279 SoftApConfiguration other = (SoftApConfiguration) otherObj; 280 return Objects.equals(mSsid, other.mSsid) 281 && Objects.equals(mBssid, other.mBssid) 282 && Objects.equals(mPassphrase, other.mPassphrase) 283 && mHiddenSsid == other.mHiddenSsid 284 && mBand == other.mBand 285 && mChannel == other.mChannel 286 && mSecurityType == other.mSecurityType 287 && mMaxNumberOfClients == other.mMaxNumberOfClients 288 && mAutoShutdownEnabled == other.mAutoShutdownEnabled 289 && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis 290 && mClientControlByUser == other.mClientControlByUser 291 && Objects.equals(mBlockedClientList, other.mBlockedClientList) 292 && Objects.equals(mAllowedClientList, other.mAllowedClientList); 293 } 294 295 @Override hashCode()296 public int hashCode() { 297 return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid, 298 mBand, mChannel, mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled, 299 mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, 300 mAllowedClientList); 301 } 302 303 @Override toString()304 public String toString() { 305 StringBuilder sbuf = new StringBuilder(); 306 sbuf.append("ssid=").append(mSsid); 307 if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString()); 308 sbuf.append(" \n Passphrase =").append( 309 TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>"); 310 sbuf.append(" \n HiddenSsid =").append(mHiddenSsid); 311 sbuf.append(" \n Band =").append(mBand); 312 sbuf.append(" \n Channel =").append(mChannel); 313 sbuf.append(" \n SecurityType=").append(getSecurityType()); 314 sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients); 315 sbuf.append(" \n AutoShutdownEnabled=").append(mAutoShutdownEnabled); 316 sbuf.append(" \n ShutdownTimeoutMillis=").append(mShutdownTimeoutMillis); 317 sbuf.append(" \n ClientControlByUser=").append(mClientControlByUser); 318 sbuf.append(" \n BlockedClientList=").append(mBlockedClientList); 319 sbuf.append(" \n AllowedClientList=").append(mAllowedClientList); 320 return sbuf.toString(); 321 } 322 323 @Override writeToParcel(@onNull Parcel dest, int flags)324 public void writeToParcel(@NonNull Parcel dest, int flags) { 325 dest.writeString(mSsid); 326 dest.writeParcelable(mBssid, flags); 327 dest.writeString(mPassphrase); 328 dest.writeBoolean(mHiddenSsid); 329 dest.writeInt(mBand); 330 dest.writeInt(mChannel); 331 dest.writeInt(mSecurityType); 332 dest.writeInt(mMaxNumberOfClients); 333 dest.writeBoolean(mAutoShutdownEnabled); 334 dest.writeLong(mShutdownTimeoutMillis); 335 dest.writeBoolean(mClientControlByUser); 336 dest.writeTypedList(mBlockedClientList); 337 dest.writeTypedList(mAllowedClientList); 338 } 339 340 @Override describeContents()341 public int describeContents() { 342 return 0; 343 } 344 345 @NonNull 346 public static final Creator<SoftApConfiguration> CREATOR = new Creator<SoftApConfiguration>() { 347 @Override 348 public SoftApConfiguration createFromParcel(Parcel in) { 349 return new SoftApConfiguration( 350 in.readString(), 351 in.readParcelable(MacAddress.class.getClassLoader()), 352 in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(), 353 in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(), 354 in.createTypedArrayList(MacAddress.CREATOR), 355 in.createTypedArrayList(MacAddress.CREATOR)); 356 } 357 358 @Override 359 public SoftApConfiguration[] newArray(int size) { 360 return new SoftApConfiguration[size]; 361 } 362 }; 363 364 /** 365 * Return String set to be the SSID for the AP. 366 * {@link Builder#setSsid(String)}. 367 */ 368 @Nullable getSsid()369 public String getSsid() { 370 return mSsid; 371 } 372 373 /** 374 * Returns MAC address set to be BSSID for the AP. 375 * {@link Builder#setBssid(MacAddress)}. 376 */ 377 @Nullable getBssid()378 public MacAddress getBssid() { 379 return mBssid; 380 } 381 382 /** 383 * Returns String set to be passphrase for current AP. 384 * {@link Builder#setPassphrase(String, int)}. 385 */ 386 @Nullable getPassphrase()387 public String getPassphrase() { 388 return mPassphrase; 389 } 390 391 /** 392 * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or 393 * not (false: broadcasts its SSID) for the AP. 394 * {@link Builder#setHiddenSsid(boolean)}. 395 */ isHiddenSsid()396 public boolean isHiddenSsid() { 397 return mHiddenSsid; 398 } 399 400 /** 401 * Returns band type set to be the band for the AP. 402 * 403 * One or combination of the following band type: 404 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 405 * 406 * {@link Builder#setBand(int)}. 407 * 408 * @hide 409 */ 410 @SystemApi getBand()411 public @BandType int getBand() { 412 return mBand; 413 } 414 415 /** 416 * Returns Integer set to be the channel for the AP. 417 * {@link Builder#setChannel(int)}. 418 * 419 * @hide 420 */ 421 @SystemApi getChannel()422 public int getChannel() { 423 return mChannel; 424 } 425 426 /** 427 * Get security type params which depends on which security passphrase to set. 428 * 429 * @return One of: 430 * {@link #SECURITY_TYPE_OPEN}, 431 * {@link #SECURITY_TYPE_WPA2_PSK}, 432 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 433 * {@link #SECURITY_TYPE_WPA3_SAE} 434 */ getSecurityType()435 public @SecurityType int getSecurityType() { 436 return mSecurityType; 437 } 438 439 /** 440 * Returns the maximum number of clients that can associate to the AP. 441 * {@link Builder#setMaxNumberOfClients(int)}. 442 * 443 * @hide 444 */ 445 @SystemApi getMaxNumberOfClients()446 public int getMaxNumberOfClients() { 447 return mMaxNumberOfClients; 448 } 449 450 /** 451 * Returns whether auto shutdown is enabled or not. 452 * The Soft AP will shutdown when there are no devices associated to it for 453 * the timeout duration. See {@link Builder#setAutoShutdownEnabled(boolean)}. 454 * 455 * @hide 456 */ 457 @SystemApi isAutoShutdownEnabled()458 public boolean isAutoShutdownEnabled() { 459 return mAutoShutdownEnabled; 460 } 461 462 /** 463 * Returns the shutdown timeout in milliseconds. 464 * The Soft AP will shutdown when there are no devices associated to it for 465 * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(long)}. 466 * 467 * @hide 468 */ 469 @SystemApi getShutdownTimeoutMillis()470 public long getShutdownTimeoutMillis() { 471 return mShutdownTimeoutMillis; 472 } 473 474 /** 475 * Returns a flag indicating whether clients need to be pre-approved by the user. 476 * (true: authorization required) or not (false: not required). 477 * {@link Builder#setClientControlByUserEnabled(Boolean)}. 478 * 479 * @hide 480 */ 481 @SystemApi isClientControlByUserEnabled()482 public boolean isClientControlByUserEnabled() { 483 return mClientControlByUser; 484 } 485 486 /** 487 * Returns List of clients which aren't allowed to associate to the AP. 488 * 489 * Clients are configured using {@link Builder#setBlockedClientList(List)} 490 * 491 * @hide 492 */ 493 @NonNull 494 @SystemApi getBlockedClientList()495 public List<MacAddress> getBlockedClientList() { 496 return mBlockedClientList; 497 } 498 499 /** 500 * List of clients which are allowed to associate to the AP. 501 * Clients are configured using {@link Builder#setAllowedClientList(List)} 502 * 503 * @hide 504 */ 505 @NonNull 506 @SystemApi getAllowedClientList()507 public List<MacAddress> getAllowedClientList() { 508 return mAllowedClientList; 509 } 510 511 /** 512 * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}. 513 * Note that SoftApConfiguration may contain configuration which is cannot be represented 514 * by the legacy WifiConfiguration, in such cases a null will be returned. 515 * 516 * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports 517 * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li> 518 * 519 * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports 520 * NONE, WPA2_PSK, so conversion is limited to these security type.</li> 521 * @hide 522 */ 523 @Nullable 524 @SystemApi toWifiConfiguration()525 public WifiConfiguration toWifiConfiguration() { 526 WifiConfiguration wifiConfig = new WifiConfiguration(); 527 wifiConfig.SSID = mSsid; 528 wifiConfig.preSharedKey = mPassphrase; 529 wifiConfig.hiddenSSID = mHiddenSsid; 530 wifiConfig.apChannel = mChannel; 531 switch (mSecurityType) { 532 case SECURITY_TYPE_OPEN: 533 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 534 break; 535 case SECURITY_TYPE_WPA2_PSK: 536 case SECURITY_TYPE_WPA3_SAE_TRANSITION: 537 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK); 538 break; 539 default: 540 Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType); 541 return null; 542 } 543 544 switch (mBand) { 545 case BAND_2GHZ: 546 wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ; 547 break; 548 case BAND_5GHZ: 549 wifiConfig.apBand = WifiConfiguration.AP_BAND_5GHZ; 550 break; 551 case BAND_2GHZ | BAND_5GHZ: 552 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 553 break; 554 case BAND_ANY: 555 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 556 break; 557 default: 558 Log.e(TAG, "Convert fail, unsupported band setting :" + mBand); 559 return null; 560 } 561 return wifiConfig; 562 } 563 564 /** 565 * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a 566 * Soft AP. 567 * 568 * All fields are optional. By default, SSID and BSSID are automatically chosen by the 569 * framework, and an open network is created. 570 * 571 * @hide 572 */ 573 @SystemApi 574 public static final class Builder { 575 private String mSsid; 576 private MacAddress mBssid; 577 private String mPassphrase; 578 private boolean mHiddenSsid; 579 private int mBand; 580 private int mChannel; 581 private int mMaxNumberOfClients; 582 private int mSecurityType; 583 private boolean mAutoShutdownEnabled; 584 private long mShutdownTimeoutMillis; 585 private boolean mClientControlByUser; 586 private List<MacAddress> mBlockedClientList; 587 private List<MacAddress> mAllowedClientList; 588 589 /** 590 * Constructs a Builder with default values (see {@link Builder}). 591 */ Builder()592 public Builder() { 593 mSsid = null; 594 mBssid = null; 595 mPassphrase = null; 596 mHiddenSsid = false; 597 mBand = BAND_2GHZ; 598 mChannel = 0; 599 mMaxNumberOfClients = 0; 600 mSecurityType = SECURITY_TYPE_OPEN; 601 mAutoShutdownEnabled = true; // enabled by default. 602 mShutdownTimeoutMillis = 0; 603 mClientControlByUser = false; 604 mBlockedClientList = new ArrayList<>(); 605 mAllowedClientList = new ArrayList<>(); 606 } 607 608 /** 609 * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance. 610 */ Builder(@onNull SoftApConfiguration other)611 public Builder(@NonNull SoftApConfiguration other) { 612 Objects.requireNonNull(other); 613 614 mSsid = other.mSsid; 615 mBssid = other.mBssid; 616 mPassphrase = other.mPassphrase; 617 mHiddenSsid = other.mHiddenSsid; 618 mBand = other.mBand; 619 mChannel = other.mChannel; 620 mMaxNumberOfClients = other.mMaxNumberOfClients; 621 mSecurityType = other.mSecurityType; 622 mAutoShutdownEnabled = other.mAutoShutdownEnabled; 623 mShutdownTimeoutMillis = other.mShutdownTimeoutMillis; 624 mClientControlByUser = other.mClientControlByUser; 625 mBlockedClientList = new ArrayList<>(other.mBlockedClientList); 626 mAllowedClientList = new ArrayList<>(other.mAllowedClientList); 627 } 628 629 /** 630 * Builds the {@link SoftApConfiguration}. 631 * 632 * @return A new {@link SoftApConfiguration}, as configured by previous method calls. 633 */ 634 @NonNull build()635 public SoftApConfiguration build() { 636 for (MacAddress client : mAllowedClientList) { 637 if (mBlockedClientList.contains(client)) { 638 throw new IllegalArgumentException("A MacAddress exist in both client list"); 639 } 640 } 641 return new SoftApConfiguration(mSsid, mBssid, mPassphrase, 642 mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients, 643 mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser, 644 mBlockedClientList, mAllowedClientList); 645 } 646 647 /** 648 * Specifies an SSID for the AP. 649 * <p> 650 * Null SSID only support when configure a local-only hotspot. 651 * <p> 652 * <li>If not set, defaults to null.</li> 653 * 654 * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically 655 * chosen by the framework. 656 * @return Builder for chaining. 657 * @throws IllegalArgumentException when the SSID is empty or not valid Unicode. 658 */ 659 @NonNull setSsid(@ullable String ssid)660 public Builder setSsid(@Nullable String ssid) { 661 if (ssid != null) { 662 Preconditions.checkStringNotEmpty(ssid); 663 Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid)); 664 } 665 mSsid = ssid; 666 return this; 667 } 668 669 /** 670 * Specifies a BSSID for the AP. 671 * <p> 672 * <li>If not set, defaults to null.</li> 673 * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is 674 * responsible for avoiding collisions. 675 * @return Builder for chaining. 676 * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC 677 * address. 678 */ 679 @NonNull setBssid(@ullable MacAddress bssid)680 public Builder setBssid(@Nullable MacAddress bssid) { 681 if (bssid != null) { 682 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS)); 683 Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS)); 684 } 685 mBssid = bssid; 686 return this; 687 } 688 689 /** 690 * Specifies that this AP should use specific security type with the given ASCII passphrase. 691 * 692 * @param securityType One of the following security types: 693 * {@link #SECURITY_TYPE_OPEN}, 694 * {@link #SECURITY_TYPE_WPA2_PSK}, 695 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 696 * {@link #SECURITY_TYPE_WPA3_SAE}. 697 * @param passphrase The passphrase to use for sepcific {@code securityType} configuration 698 * or null with {@link #SECURITY_TYPE_OPEN}. 699 * 700 * @return Builder for chaining. 701 * @throws IllegalArgumentException when the passphrase length is invalid and 702 * {@code securityType} is not {@link #SECURITY_TYPE_OPEN} 703 * or non-null passphrase and {@code securityType} is 704 * {@link #SECURITY_TYPE_OPEN}. 705 */ 706 @NonNull setPassphrase(@ullable String passphrase, @SecurityType int securityType)707 public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) { 708 if (securityType == SECURITY_TYPE_OPEN) { 709 if (passphrase != null) { 710 throw new IllegalArgumentException( 711 "passphrase should be null when security type is open"); 712 } 713 } else { 714 Preconditions.checkStringNotEmpty(passphrase); 715 final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); 716 if (!asciiEncoder.canEncode(passphrase)) { 717 throw new IllegalArgumentException("passphrase not ASCII encodable"); 718 } 719 if (securityType == SECURITY_TYPE_WPA2_PSK 720 || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) { 721 if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) { 722 throw new IllegalArgumentException( 723 "Password size must be at least " + PSK_MIN_LEN 724 + " and no more than " + PSK_MAX_LEN 725 + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode"); 726 } 727 } 728 } 729 mSecurityType = securityType; 730 mPassphrase = passphrase; 731 return this; 732 } 733 734 /** 735 * Specifies whether the AP is hidden (doesn't broadcast its SSID) or 736 * not (broadcasts its SSID). 737 * <p> 738 * <li>If not set, defaults to false (i.e not a hidden network).</li> 739 * 740 * @param hiddenSsid true for a hidden SSID, false otherwise. 741 * @return Builder for chaining. 742 */ 743 @NonNull setHiddenSsid(boolean hiddenSsid)744 public Builder setHiddenSsid(boolean hiddenSsid) { 745 mHiddenSsid = hiddenSsid; 746 return this; 747 } 748 749 /** 750 * Specifies the band for the AP. 751 * <p> 752 * <li>If not set, defaults to {@link #BAND_2GHZ}.</li> 753 * 754 * @param band One or combination of the following band type: 755 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 756 * @return Builder for chaining. 757 */ 758 @NonNull setBand(@andType int band)759 public Builder setBand(@BandType int band) { 760 if (!isBandValid(band)) { 761 throw new IllegalArgumentException("Invalid band type"); 762 } 763 mBand = band; 764 // Since band preference is specified, no specific channel is selected. 765 mChannel = 0; 766 return this; 767 } 768 769 /** 770 * Specifies the channel and associated band for the AP. 771 * 772 * The channel which AP resides on. Valid channels are country dependent. 773 * <p> 774 * The default for the channel is a the special value 0 to have the framework 775 * auto-select a valid channel from the band configured with 776 * {@link #setBand(int)}. 777 * 778 * The channel auto selection will offload to driver when 779 * {@link SoftApCapability#areFeaturesSupported( 780 * SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD)} 781 * return true. Driver will auto select best channel which based on environment 782 * interference to get best performance. Check {@link SoftApCapability} to get more detail. 783 * 784 * Note, since 6GHz band use the same channel numbering of 2.4GHz and 5GHZ bands, 785 * the caller needs to pass the band containing the selected channel. 786 * 787 * <p> 788 * <li>If not set, defaults to 0.</li> 789 * @param channel operating channel of the AP. 790 * @param band containing this channel. 791 * @return Builder for chaining. 792 */ 793 @NonNull setChannel(int channel, @BandType int band)794 public Builder setChannel(int channel, @BandType int band) { 795 if (!isChannelBandPairValid(channel, band)) { 796 throw new IllegalArgumentException("Invalid band type"); 797 } 798 mBand = band; 799 mChannel = channel; 800 return this; 801 } 802 803 /** 804 * Specifies the maximum number of clients that can associate to the AP. 805 * 806 * The maximum number of clients (STAs) which can associate to the AP. 807 * The AP will reject association from any clients above this number. 808 * Specify a value of 0 to have the framework automatically use the maximum number 809 * which the device can support (based on hardware and carrier constraints). 810 * <p> 811 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 812 * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients 813 * which the device supports (based on hardware and carrier constraints). 814 * 815 * <p> 816 * <li>If not set, defaults to 0.</li> 817 * 818 * This method requires hardware support. If the method is used to set a 819 * non-zero {@code maxNumberOfClients} value then 820 * {@link WifiManager#startTetheredHotspot} will report error code 821 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 822 * 823 * <p> 824 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 825 * {@link SoftApCapability#areFeaturesSupported(int)} 826 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether 827 * or not this feature is supported. 828 * 829 * @param maxNumberOfClients maximum client number of the AP. 830 * @return Builder for chaining. 831 */ 832 @NonNull setMaxNumberOfClients(@ntRangefrom = 0) int maxNumberOfClients)833 public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) { 834 if (maxNumberOfClients < 0) { 835 throw new IllegalArgumentException("maxNumberOfClients should be not negative"); 836 } 837 mMaxNumberOfClients = maxNumberOfClients; 838 return this; 839 } 840 841 /** 842 * Specifies whether auto shutdown is enabled or not. 843 * The Soft AP will shut down when there are no devices connected to it for 844 * the timeout duration. 845 * 846 * <p> 847 * <li>If not set, defaults to true</li> 848 * 849 * @param enable true to enable, false to disable. 850 * @return Builder for chaining. 851 * 852 * @see #setShutdownTimeoutMillis(long) 853 */ 854 @NonNull setAutoShutdownEnabled(boolean enable)855 public Builder setAutoShutdownEnabled(boolean enable) { 856 mAutoShutdownEnabled = enable; 857 return this; 858 } 859 860 /** 861 * Specifies the shutdown timeout in milliseconds. 862 * The Soft AP will shut down when there are no devices connected to it for 863 * the timeout duration. 864 * 865 * Specify a value of 0 to have the framework automatically use default timeout 866 * setting which defined in {@link R.integer.config_wifi_framework_soft_ap_timeout_delay} 867 * 868 * <p> 869 * <li>If not set, defaults to 0</li> 870 * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is 871 * set to true</li> 872 * 873 * @param timeoutMillis milliseconds of the timeout delay. 874 * @return Builder for chaining. 875 * 876 * @see #setAutoShutdownEnabled(boolean) 877 */ 878 @NonNull setShutdownTimeoutMillis(@ntRangefrom = 0) long timeoutMillis)879 public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) { 880 if (timeoutMillis < 0) { 881 throw new IllegalArgumentException("Invalid timeout value"); 882 } 883 mShutdownTimeoutMillis = timeoutMillis; 884 return this; 885 } 886 887 /** 888 * Configure the Soft AP to require manual user control of client association. 889 * If disabled (the default) then any client which isn't in the blocked list 890 * {@link #getBlockedClientList()} can associate to this Soft AP using the 891 * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier, 892 * or user limited - using {@link #setMaxNumberOfClients(int)}). 893 * 894 * If manual user control is enabled then clients will be accepted, rejected, or require 895 * a user approval based on the configuration provided by 896 * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}. 897 * 898 * <p> 899 * This method requires hardware support. Hardware support can be determined using 900 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 901 * {@link SoftApCapability#areFeaturesSupported(int)} 902 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 903 * 904 * <p> 905 * If the method is called on a device without hardware support then starting the soft AP 906 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 907 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 908 * 909 * <p> 910 * <li>If not set, defaults to false (i.e The authoriztion is not required).</li> 911 * 912 * @param enabled true for enabling the control by user, false otherwise. 913 * @return Builder for chaining. 914 */ 915 @NonNull setClientControlByUserEnabled(boolean enabled)916 public Builder setClientControlByUserEnabled(boolean enabled) { 917 mClientControlByUser = enabled; 918 return this; 919 } 920 921 922 /** 923 * This method together with {@link setClientControlByUserEnabled(boolean)} control client 924 * connections to the AP. If client control by user is disabled using the above method then 925 * this API has no effect and clients are allowed to associate to the AP (within limit of 926 * max number of clients). 927 * 928 * If client control by user is enabled then this API configures the list of clients 929 * which are explicitly allowed. These are auto-accepted. 930 * 931 * All other clients which attempt to associate, whose MAC addresses are on neither list, 932 * are: 933 * <ul> 934 * <li>Rejected</li> 935 * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)} 936 * is issued (which allows the user to add them to the allowed client list if desired).<li> 937 * </ul> 938 * 939 * @param allowedClientList list of clients which are allowed to associate to the AP 940 * without user pre-approval. 941 * @return Builder for chaining. 942 */ 943 @NonNull setAllowedClientList(@onNull List<MacAddress> allowedClientList)944 public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) { 945 mAllowedClientList = new ArrayList<>(allowedClientList); 946 return this; 947 } 948 949 /** 950 * This API configures the list of clients which are blocked and cannot associate 951 * to the Soft AP. 952 * 953 * <p> 954 * This method requires hardware support. Hardware support can be determined using 955 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 956 * {@link SoftApCapability#areFeaturesSupported(int)} 957 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 958 * 959 * <p> 960 * If the method is called on a device without hardware support then starting the soft AP 961 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 962 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 963 * 964 * @param blockedClientList list of clients which are not allowed to associate to the AP. 965 * @return Builder for chaining. 966 */ 967 @NonNull setBlockedClientList(@onNull List<MacAddress> blockedClientList)968 public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) { 969 mBlockedClientList = new ArrayList<>(blockedClientList); 970 return this; 971 } 972 } 973 } 974