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 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK); 537 break; 538 default: 539 Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType); 540 return null; 541 } 542 543 switch (mBand) { 544 case BAND_2GHZ: 545 wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ; 546 break; 547 case BAND_5GHZ: 548 wifiConfig.apBand = WifiConfiguration.AP_BAND_5GHZ; 549 break; 550 case BAND_2GHZ | BAND_5GHZ: 551 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 552 break; 553 case BAND_ANY: 554 wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; 555 break; 556 default: 557 Log.e(TAG, "Convert fail, unsupported band setting :" + mBand); 558 return null; 559 } 560 return wifiConfig; 561 } 562 563 /** 564 * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a 565 * Soft AP. 566 * 567 * All fields are optional. By default, SSID and BSSID are automatically chosen by the 568 * framework, and an open network is created. 569 * 570 * @hide 571 */ 572 @SystemApi 573 public static final class Builder { 574 private String mSsid; 575 private MacAddress mBssid; 576 private String mPassphrase; 577 private boolean mHiddenSsid; 578 private int mBand; 579 private int mChannel; 580 private int mMaxNumberOfClients; 581 private int mSecurityType; 582 private boolean mAutoShutdownEnabled; 583 private long mShutdownTimeoutMillis; 584 private boolean mClientControlByUser; 585 private List<MacAddress> mBlockedClientList; 586 private List<MacAddress> mAllowedClientList; 587 588 /** 589 * Constructs a Builder with default values (see {@link Builder}). 590 */ Builder()591 public Builder() { 592 mSsid = null; 593 mBssid = null; 594 mPassphrase = null; 595 mHiddenSsid = false; 596 mBand = BAND_2GHZ; 597 mChannel = 0; 598 mMaxNumberOfClients = 0; 599 mSecurityType = SECURITY_TYPE_OPEN; 600 mAutoShutdownEnabled = true; // enabled by default. 601 mShutdownTimeoutMillis = 0; 602 mClientControlByUser = false; 603 mBlockedClientList = new ArrayList<>(); 604 mAllowedClientList = new ArrayList<>(); 605 } 606 607 /** 608 * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance. 609 */ Builder(@onNull SoftApConfiguration other)610 public Builder(@NonNull SoftApConfiguration other) { 611 Objects.requireNonNull(other); 612 613 mSsid = other.mSsid; 614 mBssid = other.mBssid; 615 mPassphrase = other.mPassphrase; 616 mHiddenSsid = other.mHiddenSsid; 617 mBand = other.mBand; 618 mChannel = other.mChannel; 619 mMaxNumberOfClients = other.mMaxNumberOfClients; 620 mSecurityType = other.mSecurityType; 621 mAutoShutdownEnabled = other.mAutoShutdownEnabled; 622 mShutdownTimeoutMillis = other.mShutdownTimeoutMillis; 623 mClientControlByUser = other.mClientControlByUser; 624 mBlockedClientList = new ArrayList<>(other.mBlockedClientList); 625 mAllowedClientList = new ArrayList<>(other.mAllowedClientList); 626 } 627 628 /** 629 * Builds the {@link SoftApConfiguration}. 630 * 631 * @return A new {@link SoftApConfiguration}, as configured by previous method calls. 632 */ 633 @NonNull build()634 public SoftApConfiguration build() { 635 for (MacAddress client : mAllowedClientList) { 636 if (mBlockedClientList.contains(client)) { 637 throw new IllegalArgumentException("A MacAddress exist in both client list"); 638 } 639 } 640 return new SoftApConfiguration(mSsid, mBssid, mPassphrase, 641 mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients, 642 mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser, 643 mBlockedClientList, mAllowedClientList); 644 } 645 646 /** 647 * Specifies an SSID for the AP. 648 * <p> 649 * Null SSID only support when configure a local-only hotspot. 650 * <p> 651 * <li>If not set, defaults to null.</li> 652 * 653 * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically 654 * chosen by the framework. 655 * @return Builder for chaining. 656 * @throws IllegalArgumentException when the SSID is empty or not valid Unicode. 657 */ 658 @NonNull setSsid(@ullable String ssid)659 public Builder setSsid(@Nullable String ssid) { 660 if (ssid != null) { 661 Preconditions.checkStringNotEmpty(ssid); 662 Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid)); 663 } 664 mSsid = ssid; 665 return this; 666 } 667 668 /** 669 * Specifies a BSSID for the AP. 670 * <p> 671 * <li>If not set, defaults to null.</li> 672 * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is 673 * responsible for avoiding collisions. 674 * @return Builder for chaining. 675 * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC 676 * address. 677 */ 678 @NonNull setBssid(@ullable MacAddress bssid)679 public Builder setBssid(@Nullable MacAddress bssid) { 680 if (bssid != null) { 681 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS)); 682 Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS)); 683 } 684 mBssid = bssid; 685 return this; 686 } 687 688 /** 689 * Specifies that this AP should use specific security type with the given ASCII passphrase. 690 * 691 * @param securityType One of the following security types: 692 * {@link #SECURITY_TYPE_OPEN}, 693 * {@link #SECURITY_TYPE_WPA2_PSK}, 694 * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}, 695 * {@link #SECURITY_TYPE_WPA3_SAE}. 696 * @param passphrase The passphrase to use for sepcific {@code securityType} configuration 697 * or null with {@link #SECURITY_TYPE_OPEN}. 698 * 699 * @return Builder for chaining. 700 * @throws IllegalArgumentException when the passphrase length is invalid and 701 * {@code securityType} is not {@link #SECURITY_TYPE_OPEN} 702 * or non-null passphrase and {@code securityType} is 703 * {@link #SECURITY_TYPE_OPEN}. 704 */ 705 @NonNull setPassphrase(@ullable String passphrase, @SecurityType int securityType)706 public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) { 707 if (securityType == SECURITY_TYPE_OPEN) { 708 if (passphrase != null) { 709 throw new IllegalArgumentException( 710 "passphrase should be null when security type is open"); 711 } 712 } else { 713 Preconditions.checkStringNotEmpty(passphrase); 714 final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); 715 if (!asciiEncoder.canEncode(passphrase)) { 716 throw new IllegalArgumentException("passphrase not ASCII encodable"); 717 } 718 if (securityType == SECURITY_TYPE_WPA2_PSK 719 || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) { 720 if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) { 721 throw new IllegalArgumentException( 722 "Password size must be at least " + PSK_MIN_LEN 723 + " and no more than " + PSK_MAX_LEN 724 + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode"); 725 } 726 } 727 } 728 mSecurityType = securityType; 729 mPassphrase = passphrase; 730 return this; 731 } 732 733 /** 734 * Specifies whether the AP is hidden (doesn't broadcast its SSID) or 735 * not (broadcasts its SSID). 736 * <p> 737 * <li>If not set, defaults to false (i.e not a hidden network).</li> 738 * 739 * @param hiddenSsid true for a hidden SSID, false otherwise. 740 * @return Builder for chaining. 741 */ 742 @NonNull setHiddenSsid(boolean hiddenSsid)743 public Builder setHiddenSsid(boolean hiddenSsid) { 744 mHiddenSsid = hiddenSsid; 745 return this; 746 } 747 748 /** 749 * Specifies the band for the AP. 750 * <p> 751 * <li>If not set, defaults to {@link #BAND_2GHZ}.</li> 752 * 753 * @param band One or combination of the following band type: 754 * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. 755 * @return Builder for chaining. 756 */ 757 @NonNull setBand(@andType int band)758 public Builder setBand(@BandType int band) { 759 if (!isBandValid(band)) { 760 throw new IllegalArgumentException("Invalid band type"); 761 } 762 mBand = band; 763 // Since band preference is specified, no specific channel is selected. 764 mChannel = 0; 765 return this; 766 } 767 768 /** 769 * Specifies the channel and associated band for the AP. 770 * 771 * The channel which AP resides on. Valid channels are country dependent. 772 * <p> 773 * The default for the channel is a the special value 0 to have the framework 774 * auto-select a valid channel from the band configured with 775 * {@link #setBand(int)}. 776 * 777 * The channel auto selection will offload to driver when 778 * {@link SoftApCapability#areFeaturesSupported( 779 * SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD)} 780 * return true. Driver will auto select best channel which based on environment 781 * interference to get best performance. Check {@link SoftApCapability} to get more detail. 782 * 783 * Note, since 6GHz band use the same channel numbering of 2.4GHz and 5GHZ bands, 784 * the caller needs to pass the band containing the selected channel. 785 * 786 * <p> 787 * <li>If not set, defaults to 0.</li> 788 * @param channel operating channel of the AP. 789 * @param band containing this channel. 790 * @return Builder for chaining. 791 */ 792 @NonNull setChannel(int channel, @BandType int band)793 public Builder setChannel(int channel, @BandType int band) { 794 if (!isChannelBandPairValid(channel, band)) { 795 throw new IllegalArgumentException("Invalid band type"); 796 } 797 mBand = band; 798 mChannel = channel; 799 return this; 800 } 801 802 /** 803 * Specifies the maximum number of clients that can associate to the AP. 804 * 805 * The maximum number of clients (STAs) which can associate to the AP. 806 * The AP will reject association from any clients above this number. 807 * Specify a value of 0 to have the framework automatically use the maximum number 808 * which the device can support (based on hardware and carrier constraints). 809 * <p> 810 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 811 * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients 812 * which the device supports (based on hardware and carrier constraints). 813 * 814 * <p> 815 * <li>If not set, defaults to 0.</li> 816 * 817 * This method requires hardware support. If the method is used to set a 818 * non-zero {@code maxNumberOfClients} value then 819 * {@link WifiManager#startTetheredHotspot} will report error code 820 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 821 * 822 * <p> 823 * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 824 * {@link SoftApCapability#areFeaturesSupported(int)} 825 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether 826 * or not this feature is supported. 827 * 828 * @param maxNumberOfClients maximum client number of the AP. 829 * @return Builder for chaining. 830 */ 831 @NonNull setMaxNumberOfClients(@ntRangefrom = 0) int maxNumberOfClients)832 public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) { 833 if (maxNumberOfClients < 0) { 834 throw new IllegalArgumentException("maxNumberOfClients should be not negative"); 835 } 836 mMaxNumberOfClients = maxNumberOfClients; 837 return this; 838 } 839 840 /** 841 * Specifies whether auto shutdown is enabled or not. 842 * The Soft AP will shut down when there are no devices connected to it for 843 * the timeout duration. 844 * 845 * <p> 846 * <li>If not set, defaults to true</li> 847 * 848 * @param enable true to enable, false to disable. 849 * @return Builder for chaining. 850 * 851 * @see #setShutdownTimeoutMillis(long) 852 */ 853 @NonNull setAutoShutdownEnabled(boolean enable)854 public Builder setAutoShutdownEnabled(boolean enable) { 855 mAutoShutdownEnabled = enable; 856 return this; 857 } 858 859 /** 860 * Specifies the shutdown timeout in milliseconds. 861 * The Soft AP will shut down when there are no devices connected to it for 862 * the timeout duration. 863 * 864 * Specify a value of 0 to have the framework automatically use default timeout 865 * setting which defined in {@link R.integer.config_wifi_framework_soft_ap_timeout_delay} 866 * 867 * <p> 868 * <li>If not set, defaults to 0</li> 869 * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is 870 * set to true</li> 871 * 872 * @param timeoutMillis milliseconds of the timeout delay. 873 * @return Builder for chaining. 874 * 875 * @see #setAutoShutdownEnabled(boolean) 876 */ 877 @NonNull setShutdownTimeoutMillis(@ntRangefrom = 0) long timeoutMillis)878 public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) { 879 if (timeoutMillis < 0) { 880 throw new IllegalArgumentException("Invalid timeout value"); 881 } 882 mShutdownTimeoutMillis = timeoutMillis; 883 return this; 884 } 885 886 /** 887 * Configure the Soft AP to require manual user control of client association. 888 * If disabled (the default) then any client which isn't in the blocked list 889 * {@link #getBlockedClientList()} can associate to this Soft AP using the 890 * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier, 891 * or user limited - using {@link #setMaxNumberOfClients(int)}). 892 * 893 * If manual user control is enabled then clients will be accepted, rejected, or require 894 * a user approval based on the configuration provided by 895 * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}. 896 * 897 * <p> 898 * This method requires hardware support. Hardware support can be determined using 899 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 900 * {@link SoftApCapability#areFeaturesSupported(int)} 901 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 902 * 903 * <p> 904 * If the method is called on a device without hardware support then starting the soft AP 905 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 906 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 907 * 908 * <p> 909 * <li>If not set, defaults to false (i.e The authoriztion is not required).</li> 910 * 911 * @param enabled true for enabling the control by user, false otherwise. 912 * @return Builder for chaining. 913 */ 914 @NonNull setClientControlByUserEnabled(boolean enabled)915 public Builder setClientControlByUserEnabled(boolean enabled) { 916 mClientControlByUser = enabled; 917 return this; 918 } 919 920 921 /** 922 * This method together with {@link setClientControlByUserEnabled(boolean)} control client 923 * connections to the AP. If client control by user is disabled using the above method then 924 * this API has no effect and clients are allowed to associate to the AP (within limit of 925 * max number of clients). 926 * 927 * If client control by user is enabled then this API configures the list of clients 928 * which are explicitly allowed. These are auto-accepted. 929 * 930 * All other clients which attempt to associate, whose MAC addresses are on neither list, 931 * are: 932 * <ul> 933 * <li>Rejected</li> 934 * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)} 935 * is issued (which allows the user to add them to the allowed client list if desired).<li> 936 * </ul> 937 * 938 * @param allowedClientList list of clients which are allowed to associate to the AP 939 * without user pre-approval. 940 * @return Builder for chaining. 941 */ 942 @NonNull setAllowedClientList(@onNull List<MacAddress> allowedClientList)943 public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) { 944 mAllowedClientList = new ArrayList<>(allowedClientList); 945 return this; 946 } 947 948 /** 949 * This API configures the list of clients which are blocked and cannot associate 950 * to the Soft AP. 951 * 952 * <p> 953 * This method requires hardware support. Hardware support can be determined using 954 * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and 955 * {@link SoftApCapability#areFeaturesSupported(int)} 956 * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} 957 * 958 * <p> 959 * If the method is called on a device without hardware support then starting the soft AP 960 * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with 961 * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. 962 * 963 * @param blockedClientList list of clients which are not allowed to associate to the AP. 964 * @return Builder for chaining. 965 */ 966 @NonNull setBlockedClientList(@onNull List<MacAddress> blockedClientList)967 public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) { 968 mBlockedClientList = new ArrayList<>(blockedClientList); 969 return this; 970 } 971 } 972 } 973