1 /* 2 * Copyright (C) 2018 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 static com.android.internal.util.Preconditions.checkNotNull; 20 21 import android.annotation.FlaggedApi; 22 import android.annotation.IntDef; 23 import android.annotation.IntRange; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.RequiresPermission; 27 import android.annotation.SystemApi; 28 import android.net.MacAddress; 29 import android.net.NetworkCapabilities; 30 import android.net.NetworkRequest; 31 import android.net.wifi.hotspot2.PasspointConfiguration; 32 import android.os.Build; 33 import android.os.Parcel; 34 import android.os.ParcelUuid; 35 import android.os.Parcelable; 36 import android.telephony.SubscriptionInfo; 37 import android.telephony.SubscriptionManager; 38 import android.telephony.TelephonyManager; 39 import android.text.TextUtils; 40 41 import androidx.annotation.RequiresApi; 42 43 import com.android.modules.utils.build.SdkLevel; 44 import com.android.wifi.flags.Flags; 45 46 import java.lang.annotation.Retention; 47 import java.lang.annotation.RetentionPolicy; 48 import java.nio.charset.CharsetEncoder; 49 import java.nio.charset.StandardCharsets; 50 import java.util.List; 51 import java.util.Objects; 52 53 /** 54 * The Network Suggestion object is used to provide a Wi-Fi network for consideration when 55 * auto-connecting to networks. Apps cannot directly create this object, they must use 56 * {@link WifiNetworkSuggestion.Builder#build()} to obtain an instance of this object. 57 *<p> 58 * Apps can provide a list of such networks to the platform using 59 * {@link WifiManager#addNetworkSuggestions(List)}. 60 */ 61 public final class WifiNetworkSuggestion implements Parcelable { 62 /** @hide */ 63 @Retention(RetentionPolicy.SOURCE) 64 @IntDef(prefix = {"RANDOMIZATION_"}, value = { 65 RANDOMIZATION_PERSISTENT, 66 RANDOMIZATION_NON_PERSISTENT}) 67 public @interface MacRandomizationSetting {} 68 /** 69 * Generate a randomized MAC from a secret seed and information from the Wi-Fi configuration 70 * (SSID or Passpoint profile) and reuse it for all connections to this network. The 71 * randomized MAC address for this network will stay the same for each subsequent association 72 * until the device undergoes factory reset. 73 */ 74 public static final int RANDOMIZATION_PERSISTENT = 0; 75 /** 76 * With this option, the randomized MAC address will periodically get re-randomized, and 77 * the randomized MAC address will change if the suggestion is removed and then added back. 78 */ 79 public static final int RANDOMIZATION_NON_PERSISTENT = 1; 80 /** 81 * Builder used to create {@link WifiNetworkSuggestion} objects. 82 */ 83 public static final class Builder { 84 private static final int UNASSIGNED_PRIORITY = -1; 85 86 /** 87 * Set WPA Enterprise type according to certificate security level. 88 * This is for backward compatibility in R. 89 */ 90 private static final int WPA3_ENTERPRISE_AUTO = 0; 91 /** Set WPA Enterprise type to standard mode only. */ 92 private static final int WPA3_ENTERPRISE_STANDARD = 1; 93 /** Set WPA Enterprise type to 192 bit mode only. */ 94 private static final int WPA3_ENTERPRISE_192_BIT = 2; 95 96 /** 97 * SSID of the network. 98 */ 99 private WifiSsid mWifiSsid; 100 /** 101 * Optional BSSID within the network. 102 */ 103 private MacAddress mBssid; 104 /** 105 * Whether this is an OWE network or not. 106 */ 107 private boolean mIsEnhancedOpen; 108 /** 109 * Pre-shared key for use with WPA-PSK networks. 110 */ 111 private @Nullable String mWpa2PskPassphrase; 112 /** 113 * Pre-shared key for use with WPA3-SAE networks. 114 */ 115 private @Nullable String mWpa3SaePassphrase; 116 /** 117 * The enterprise configuration details specifying the EAP method, 118 * certificates and other settings associated with the WPA/WPA2-Enterprise networks. 119 */ 120 private @Nullable WifiEnterpriseConfig mWpa2EnterpriseConfig; 121 /** 122 * The enterprise configuration details specifying the EAP method, 123 * certificates and other settings associated with the WPA3-Enterprise networks. 124 */ 125 private @Nullable WifiEnterpriseConfig mWpa3EnterpriseConfig; 126 /** 127 * Indicate what type this WPA3-Enterprise network is. 128 */ 129 private int mWpa3EnterpriseType = WPA3_ENTERPRISE_AUTO; 130 /** 131 * The passpoint config for use with Hotspot 2.0 network 132 */ 133 private @Nullable PasspointConfiguration mPasspointConfiguration; 134 /** 135 * This is a network that does not broadcast its SSID, so an 136 * SSID-specific probe request must be used for scans. 137 */ 138 private boolean mIsHiddenSSID; 139 /** 140 * Whether app needs to log in to captive portal to obtain Internet access. 141 */ 142 private boolean mIsAppInteractionRequired; 143 /** 144 * Whether user needs to log in to captive portal to obtain Internet access. 145 */ 146 private boolean mIsUserInteractionRequired; 147 /** 148 * Whether this network is metered or not. 149 */ 150 private int mMeteredOverride; 151 /** 152 * Priority of this network among other network suggestions from same priority group 153 * provided by the app. 154 * The higher the number, the higher the priority (i.e value of 0 = lowest priority). 155 */ 156 private int mPriority; 157 /** 158 * Priority group ID, while suggestion priority will only effect inside the priority group. 159 */ 160 private int mPriorityGroup; 161 162 /** 163 * The carrier ID identifies the operator who provides this network configuration. 164 * see {@link TelephonyManager#getSimCarrierId()} 165 */ 166 private int mCarrierId; 167 168 /** 169 * The Subscription ID identifies the SIM card for which this network configuration is 170 * valid. 171 */ 172 private int mSubscriptionId; 173 174 /** 175 * Whether this network is shared credential with user to allow user manually connect. 176 */ 177 private boolean mIsSharedWithUser; 178 179 /** 180 * Whether the setCredentialSharedWithUser have been called. 181 */ 182 private boolean mIsSharedWithUserSet; 183 184 /** 185 * Whether this network is initialized with auto-join enabled (the default) or not. 186 */ 187 private boolean mIsInitialAutojoinEnabled; 188 189 /** 190 * Pre-shared key for use with WAPI-PSK networks. 191 */ 192 private @Nullable String mWapiPskPassphrase; 193 194 /** 195 * The enterprise configuration details specifying the EAP method, 196 * certificates and other settings associated with the WAPI networks. 197 */ 198 private @Nullable WifiEnterpriseConfig mWapiEnterpriseConfig; 199 200 /** 201 * Whether this network will be brought up as untrusted (TRUSTED capability bit removed). 202 */ 203 private boolean mIsNetworkUntrusted; 204 205 /** 206 * Whether this network will be brought up as OEM paid (OEM_PAID capability bit added). 207 */ 208 private boolean mIsNetworkOemPaid; 209 210 /** 211 * Whether this network will be brought up as OEM private (OEM_PRIVATE capability bit 212 * added). 213 */ 214 private boolean mIsNetworkOemPrivate; 215 216 /** 217 * Whether this network is a carrier merged network. 218 */ 219 private boolean mIsCarrierMerged; 220 221 /** 222 * The MAC randomization strategy. 223 */ 224 @MacRandomizationSetting 225 private int mMacRandomizationSetting; 226 227 /** 228 * The SAE Hash-to-Element only mode. 229 */ 230 private boolean mSaeH2eOnlyMode; 231 232 /** 233 * Whether this network will be brought up as restricted 234 */ 235 private boolean mIsNetworkRestricted; 236 237 /** 238 * Whether enable Wi-Fi 7 for this network 239 */ 240 private boolean mIsWifi7Enabled; 241 242 243 /** 244 * The Subscription group UUID identifies the SIM cards for which this network configuration 245 * is valid. 246 */ 247 private ParcelUuid mSubscriptionGroup; 248 Builder()249 public Builder() { 250 mBssid = null; 251 mIsEnhancedOpen = false; 252 mWpa2PskPassphrase = null; 253 mWpa3SaePassphrase = null; 254 mWpa2EnterpriseConfig = null; 255 mWpa3EnterpriseConfig = null; 256 mPasspointConfiguration = null; 257 mIsHiddenSSID = false; 258 mIsAppInteractionRequired = false; 259 mIsUserInteractionRequired = false; 260 mMeteredOverride = WifiConfiguration.METERED_OVERRIDE_NONE; 261 mIsSharedWithUser = true; 262 mIsSharedWithUserSet = false; 263 mIsInitialAutojoinEnabled = true; 264 mPriority = UNASSIGNED_PRIORITY; 265 mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 266 mWapiPskPassphrase = null; 267 mWapiEnterpriseConfig = null; 268 mIsNetworkUntrusted = false; 269 mIsNetworkOemPaid = false; 270 mIsNetworkOemPrivate = false; 271 mIsCarrierMerged = false; 272 mPriorityGroup = 0; 273 mMacRandomizationSetting = RANDOMIZATION_PERSISTENT; 274 mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 275 mSaeH2eOnlyMode = false; 276 mIsNetworkRestricted = false; 277 mSubscriptionGroup = null; 278 mWifiSsid = null; 279 mIsWifi7Enabled = true; 280 } 281 282 /** 283 * Set the unicode SSID for the network. 284 * <p> 285 * <li>Overrides any previous value set using {@link #setSsid(String)}.</li> 286 * 287 * <p> 288 * Note: use {@link #setWifiSsid(WifiSsid)} which supports both unicode and non-unicode 289 * SSID. 290 * 291 * @param ssid The SSID of the network. It must be valid Unicode. 292 * @return Instance of {@link Builder} to enable chaining of the builder method. 293 * @throws IllegalArgumentException if the SSID is not valid unicode. 294 */ setSsid(@onNull String ssid)295 public @NonNull Builder setSsid(@NonNull String ssid) { 296 checkNotNull(ssid); 297 final CharsetEncoder unicodeEncoder = StandardCharsets.UTF_8.newEncoder(); 298 if (!unicodeEncoder.canEncode(ssid)) { 299 throw new IllegalArgumentException("SSID is not a valid unicode string"); 300 } 301 mWifiSsid = WifiSsid.fromUtf8Text(ssid); 302 return this; 303 } 304 305 /** 306 * Set the SSID for the network. {@link WifiSsid} support both unicode and non-unicode SSID. 307 * <p> 308 * <li>Overrides any previous value set using {@link #setWifiSsid(WifiSsid)} 309 * or {@link #setSsid(String)}.</li> 310 * <p> 311 * Note: this method is the superset of the {@link #setSsid(String)} 312 * 313 * @param wifiSsid The SSID of the network, in {@link WifiSsid} format. 314 * @return Instance of {@link Builder} to enable chaining of the builder method. 315 * @throws IllegalArgumentException if the wifiSsid is invalid. 316 */ setWifiSsid(@onNull WifiSsid wifiSsid)317 public @NonNull Builder setWifiSsid(@NonNull WifiSsid wifiSsid) { 318 checkNotNull(wifiSsid); 319 if (wifiSsid.getBytes().length == 0) { 320 throw new IllegalArgumentException("Empty WifiSsid is invalid"); 321 } 322 mWifiSsid = WifiSsid.fromBytes(wifiSsid.getBytes()); 323 return this; 324 } 325 326 /** 327 * Set the BSSID to use for filtering networks from scan results. Will only match network 328 * whose BSSID is identical to the specified value. 329 * <p> 330 * <li Sets a specific BSSID for the network suggestion. If set, only the specified BSSID 331 * with the specified SSID will be considered for connection. 332 * <li>If set, only the specified BSSID with the specified SSID will be considered for 333 * connection.</li> 334 * <li>If not set, all BSSIDs with the specified SSID will be considered for connection. 335 * </li> 336 * <li>Overrides any previous value set using {@link #setBssid(MacAddress)}.</li> 337 * 338 * @param bssid BSSID of the network. 339 * @return Instance of {@link Builder} to enable chaining of the builder method. 340 */ setBssid(@onNull MacAddress bssid)341 public @NonNull Builder setBssid(@NonNull MacAddress bssid) { 342 checkNotNull(bssid); 343 mBssid = MacAddress.fromBytes(bssid.toByteArray()); 344 return this; 345 } 346 347 /** 348 * Specifies whether this represents an Enhanced Open (OWE) network. 349 * 350 * @param isEnhancedOpen {@code true} to indicate that the network used enhanced open, 351 * {@code false} otherwise. 352 * @return Instance of {@link Builder} to enable chaining of the builder method. 353 */ setIsEnhancedOpen(boolean isEnhancedOpen)354 public @NonNull Builder setIsEnhancedOpen(boolean isEnhancedOpen) { 355 mIsEnhancedOpen = isEnhancedOpen; 356 return this; 357 } 358 359 /** 360 * Set the ASCII WPA2 passphrase for this network. Needed for authenticating to 361 * WPA2-PSK networks. 362 * 363 * @param passphrase passphrase of the network. 364 * @return Instance of {@link Builder} to enable chaining of the builder method. 365 * @throws IllegalArgumentException if the passphrase is not ASCII encodable. 366 */ setWpa2Passphrase(@onNull String passphrase)367 public @NonNull Builder setWpa2Passphrase(@NonNull String passphrase) { 368 checkNotNull(passphrase); 369 final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); 370 if (!asciiEncoder.canEncode(passphrase)) { 371 throw new IllegalArgumentException("passphrase not ASCII encodable"); 372 } 373 mWpa2PskPassphrase = passphrase; 374 return this; 375 } 376 377 /** 378 * Set the ASCII WPA3 passphrase for this network. Needed for authenticating to WPA3-SAE 379 * networks. 380 * 381 * @param passphrase passphrase of the network. 382 * @return Instance of {@link Builder} to enable chaining of the builder method. 383 * @throws IllegalArgumentException if the passphrase is not ASCII encodable. 384 */ setWpa3Passphrase(@onNull String passphrase)385 public @NonNull Builder setWpa3Passphrase(@NonNull String passphrase) { 386 checkNotNull(passphrase); 387 final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); 388 if (!asciiEncoder.canEncode(passphrase)) { 389 throw new IllegalArgumentException("passphrase not ASCII encodable"); 390 } 391 mWpa3SaePassphrase = passphrase; 392 return this; 393 } 394 395 /** 396 * Set the associated enterprise configuration for this network. Needed for authenticating 397 * to WPA2 enterprise networks. See {@link WifiEnterpriseConfig} for description. 398 * 399 * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. 400 * @return Instance of {@link Builder} to enable chaining of the builder method. 401 * @throws IllegalArgumentException If configuration uses server certificate but validation 402 * is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()} 403 */ setWpa2EnterpriseConfig( @onNull WifiEnterpriseConfig enterpriseConfig)404 public @NonNull Builder setWpa2EnterpriseConfig( 405 @NonNull WifiEnterpriseConfig enterpriseConfig) { 406 checkNotNull(enterpriseConfig); 407 if (enterpriseConfig.isEapMethodServerCertUsed() 408 && !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) { 409 throw new IllegalArgumentException("Enterprise configuration mandates server " 410 + "certificate but validation is not enabled."); 411 } 412 mWpa2EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); 413 return this; 414 } 415 416 /** 417 * Set the associated enterprise configuration for this network. Needed for authenticating 418 * to WPA3-Enterprise networks (standard and 192-bit security). See 419 * {@link WifiEnterpriseConfig} for description. For 192-bit security networks, both the 420 * client and CA certificates must be provided, and must be of type of either 421 * sha384WithRSAEncryption (OID 1.2.840.113549.1.1.12) or ecdsa-with-SHA384 422 * (OID 1.2.840.10045.4.3.3). 423 * 424 * @deprecated use {@link #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)} or 425 * {@link #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)} to specify 426 * WPA3-Enterprise type explicitly. 427 * 428 * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. 429 * @return Instance of {@link Builder} to enable chaining of the builder method. 430 * @throws IllegalArgumentException If configuration uses server certificate but validation 431 * is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()} 432 */ 433 @Deprecated setWpa3EnterpriseConfig( @onNull WifiEnterpriseConfig enterpriseConfig)434 public @NonNull Builder setWpa3EnterpriseConfig( 435 @NonNull WifiEnterpriseConfig enterpriseConfig) { 436 checkNotNull(enterpriseConfig); 437 if (enterpriseConfig.isEapMethodServerCertUsed() 438 && !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) { 439 throw new IllegalArgumentException("Enterprise configuration mandates server " 440 + "certificate but validation is not enabled."); 441 } 442 mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); 443 return this; 444 } 445 446 /** 447 * Set the associated enterprise configuration for this network. Needed for authenticating 448 * to WPA3-Enterprise standard networks. See {@link WifiEnterpriseConfig} for description. 449 * For WPA3-Enterprise in 192-bit security mode networks, 450 * see {@link #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)} for description. 451 * 452 * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. 453 * @return Instance of {@link Builder} to enable chaining of the builder method. 454 * @throws IllegalArgumentException If configuration uses server certificate but validation 455 * is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()} 456 */ setWpa3EnterpriseStandardModeConfig( @onNull WifiEnterpriseConfig enterpriseConfig)457 public @NonNull Builder setWpa3EnterpriseStandardModeConfig( 458 @NonNull WifiEnterpriseConfig enterpriseConfig) { 459 checkNotNull(enterpriseConfig); 460 if (enterpriseConfig.isEapMethodServerCertUsed() 461 && !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) { 462 throw new IllegalArgumentException("Enterprise configuration mandates server " 463 + "certificate but validation is not enabled."); 464 } 465 mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); 466 mWpa3EnterpriseType = WPA3_ENTERPRISE_STANDARD; 467 return this; 468 } 469 470 /** 471 * Set the associated enterprise configuration for this network. Needed for authenticating 472 * to WPA3-Enterprise in 192-bit security mode networks. See {@link WifiEnterpriseConfig} 473 * for description. Both the client and CA certificates must be provided, 474 * and must be of type of either sha384WithRSAEncryption with key length of 3072bit or 475 * more (OID 1.2.840.113549.1.1.12), or ecdsa-with-SHA384 with key length of 384bit or 476 * more (OID 1.2.840.10045.4.3.3). 477 * 478 * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. 479 * @return Instance of {@link Builder} to enable chaining of the builder method. 480 * @throws IllegalArgumentException if the EAP type or certificates do not 481 * meet 192-bit mode requirements. 482 */ setWpa3Enterprise192BitModeConfig( @onNull WifiEnterpriseConfig enterpriseConfig)483 public @NonNull Builder setWpa3Enterprise192BitModeConfig( 484 @NonNull WifiEnterpriseConfig enterpriseConfig) { 485 checkNotNull(enterpriseConfig); 486 if (enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.TLS) { 487 throw new IllegalArgumentException("The 192-bit mode network type must be TLS"); 488 } 489 if (!WifiEnterpriseConfig.isSuiteBCipherCert( 490 enterpriseConfig.getClientCertificate())) { 491 throw new IllegalArgumentException( 492 "The client certificate does not meet 192-bit mode requirements."); 493 } 494 if (!WifiEnterpriseConfig.isSuiteBCipherCert( 495 enterpriseConfig.getCaCertificate())) { 496 throw new IllegalArgumentException( 497 "The CA certificate does not meet 192-bit mode requirements."); 498 } 499 500 mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); 501 mWpa3EnterpriseType = WPA3_ENTERPRISE_192_BIT; 502 return this; 503 } 504 505 /** 506 * Set the associated Passpoint configuration for this network. Needed for authenticating 507 * to Hotspot 2.0 networks. See {@link PasspointConfiguration} for description. 508 * 509 * @param passpointConfig Instance of {@link PasspointConfiguration}. 510 * @return Instance of {@link Builder} to enable chaining of the builder method. 511 * @throws IllegalArgumentException if passpoint configuration is invalid. 512 */ setPasspointConfig( @onNull PasspointConfiguration passpointConfig)513 public @NonNull Builder setPasspointConfig( 514 @NonNull PasspointConfiguration passpointConfig) { 515 checkNotNull(passpointConfig); 516 if (!passpointConfig.validate()) { 517 throw new IllegalArgumentException("Passpoint configuration is invalid"); 518 } 519 mPasspointConfiguration = new PasspointConfiguration(passpointConfig); 520 return this; 521 } 522 523 /** 524 * Set the carrier ID of the network operator. The carrier ID associates a Suggested 525 * network with a specific carrier (and therefore SIM). The carrier ID must be provided 526 * for any network which uses the SIM-based authentication: e.g. EAP-SIM, EAP-AKA, 527 * EAP-AKA', and EAP-PEAP with SIM-based phase 2 authentication. 528 * @param carrierId see {@link TelephonyManager#getSimCarrierId()}. 529 * @return Instance of {@link Builder} to enable chaining of the builder method. 530 * 531 * @hide 532 */ 533 @SystemApi 534 @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) setCarrierId(int carrierId)535 public @NonNull Builder setCarrierId(int carrierId) { 536 mCarrierId = carrierId; 537 return this; 538 } 539 540 /** 541 * Configure the suggestion to only be used with the SIM identified by the subscription 542 * ID specified in this method. The suggested network will only be used by that SIM and 543 * no other SIM - even from the same carrier. 544 * <p> 545 * The caller is restricted to be either of: 546 * <li>A carrier provisioning app (which holds the 547 * {@code android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission). 548 * <li>A carrier-privileged app - which is restricted to only specify a subscription ID 549 * which belong to the same carrier which signed the app, see 550 * {@link TelephonyManager#hasCarrierPrivileges()}. 551 * <p> 552 * Specifying a subscription ID which doesn't match these restriction will cause the 553 * suggestion to be rejected with the error code 554 * {@link WifiManager#STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED}. 555 * 556 * Only one of the {@link #setSubscriptionGroup(ParcelUuid)} and 557 * {@link #setSubscriptionId(int)} should be called for a suggestion. 558 * 559 * @param subscriptionId subscription ID see {@link SubscriptionInfo#getSubscriptionId()} 560 * @return Instance of {@link Builder} to enable chaining of the builder method. 561 * @throws IllegalArgumentException if subscriptionId equals to {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} 562 */ 563 @RequiresApi(Build.VERSION_CODES.S) setSubscriptionId(int subscriptionId)564 public @NonNull Builder setSubscriptionId(int subscriptionId) { 565 if (!SdkLevel.isAtLeastS()) { 566 throw new UnsupportedOperationException(); 567 } 568 if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 569 throw new IllegalArgumentException("Subscription Id is invalid"); 570 } 571 mSubscriptionId = subscriptionId; 572 return this; 573 } 574 575 /** 576 * Configure the suggestion to only be used with the SIMs that belong to the Subscription 577 * Group specified in this method. The suggested network will only be used by the SIM in 578 * this Subscription Group and no other SIMs - even from the same carrier. 579 * <p> 580 * The caller is restricted to be either of: 581 * <li>A carrier provisioning app. 582 * <li>A carrier-privileged app - which is restricted to only specify a subscription ID 583 * which belong to the same carrier which signed the app, see 584 * {@link TelephonyManager#hasCarrierPrivileges()}. 585 * <p> 586 * Specifying a subscription group which doesn't match these restriction will cause the 587 * suggestion to be rejected with the error code 588 * {@link WifiManager#STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED}. 589 * 590 * Only one of the {@link #setSubscriptionGroup(ParcelUuid)} and 591 * {@link #setSubscriptionId(int)} should be called for a suggestion. 592 * 593 * @param groupUuid Subscription group UUID see 594 * {@link SubscriptionManager#createSubscriptionGroup(List)} 595 * @return Instance of {@link Builder} to enable chaining of the builder method. 596 * @throws IllegalArgumentException if group UUID is {@code null}. 597 */ 598 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setSubscriptionGroup(@onNull ParcelUuid groupUuid)599 public @NonNull Builder setSubscriptionGroup(@NonNull ParcelUuid groupUuid) { 600 if (!SdkLevel.isAtLeastT()) { 601 throw new UnsupportedOperationException(); 602 } 603 if (groupUuid == null) { 604 throw new IllegalArgumentException("SubscriptionGroup is invalid"); 605 } 606 mSubscriptionGroup = groupUuid; 607 return this; 608 } 609 610 /** 611 * Suggested networks are considered as part of a pool of all suggested networks and other 612 * networks (e.g. saved networks) - one of which will be selected. 613 * <ul> 614 * <li> Any app can suggest any number of networks. </li> 615 * <li> Priority: only the highest priority (0 being the lowest) currently visible suggested 616 * network or networks (multiple suggested networks may have the same priority) are added to 617 * the network selection pool.</li> 618 * </ul> 619 * <p> 620 * However, this restricts a suggesting app to have a single group of networks which can be 621 * prioritized. In some circumstances multiple groups are useful: for instance, suggesting 622 * networks for 2 different SIMs - each of which may have its own priority order. 623 * <p> 624 * Priority group: creates a separate priority group. Only the highest priority, currently 625 * visible suggested network or networks, within each priority group are included in the 626 * network selection pool. 627 * <p> 628 * Specify an arbitrary integer only used as the priority group. Use with 629 * {@link #setPriority(int)}. 630 * 631 * @param priorityGroup priority group id, if not set default is 0. 632 * @return Instance of {@link Builder} to enable chaining of the builder method. 633 */ setPriorityGroup(@ntRangefrom = 0) int priorityGroup)634 public @NonNull Builder setPriorityGroup(@IntRange(from = 0) int priorityGroup) { 635 mPriorityGroup = priorityGroup; 636 return this; 637 } 638 639 /** 640 * Set the ASCII WAPI passphrase for this network. Needed for authenticating to 641 * WAPI-PSK networks. 642 * 643 * @param passphrase passphrase of the network. 644 * @return Instance of {@link Builder} to enable chaining of the builder method. 645 * @throws IllegalArgumentException if the passphrase is not ASCII encodable. 646 * 647 */ setWapiPassphrase(@onNull String passphrase)648 public @NonNull Builder setWapiPassphrase(@NonNull String passphrase) { 649 checkNotNull(passphrase); 650 final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); 651 if (!asciiEncoder.canEncode(passphrase)) { 652 throw new IllegalArgumentException("passphrase not ASCII encodable"); 653 } 654 mWapiPskPassphrase = passphrase; 655 return this; 656 } 657 658 /** 659 * Set the associated enterprise configuration for this network. Needed for authenticating 660 * to WAPI-CERT networks. See {@link WifiEnterpriseConfig} for description. 661 * 662 * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. 663 * @return Instance of {@link Builder} to enable chaining of the builder method. 664 */ setWapiEnterpriseConfig( @onNull WifiEnterpriseConfig enterpriseConfig)665 public @NonNull Builder setWapiEnterpriseConfig( 666 @NonNull WifiEnterpriseConfig enterpriseConfig) { 667 checkNotNull(enterpriseConfig); 668 mWapiEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); 669 return this; 670 } 671 672 /** 673 * Specifies whether this represents a hidden network. 674 * <p> 675 * <li>If not set, defaults to false (i.e not a hidden network).</li> 676 * 677 * @param isHiddenSsid {@code true} to indicate that the network is hidden, {@code false} 678 * otherwise. 679 * @return Instance of {@link Builder} to enable chaining of the builder method. 680 */ setIsHiddenSsid(boolean isHiddenSsid)681 public @NonNull Builder setIsHiddenSsid(boolean isHiddenSsid) { 682 mIsHiddenSSID = isHiddenSsid; 683 return this; 684 } 685 686 /** 687 * Specifies the MAC randomization method. 688 * <p> 689 * Suggested networks will never use the device (factory) MAC address to associate to the 690 * network - instead they use a locally generated random MAC address. This method controls 691 * the strategy for generating the random MAC address. If not set, defaults to 692 * {@link #RANDOMIZATION_PERSISTENT}. 693 * 694 * @param macRandomizationSetting - one of {@code RANDOMIZATION_*} values 695 * @return Instance of {@link Builder} to enable chaining of the builder method. 696 */ setMacRandomizationSetting( @acRandomizationSetting int macRandomizationSetting)697 public @NonNull Builder setMacRandomizationSetting( 698 @MacRandomizationSetting int macRandomizationSetting) { 699 switch (macRandomizationSetting) { 700 case RANDOMIZATION_PERSISTENT: 701 case RANDOMIZATION_NON_PERSISTENT: 702 mMacRandomizationSetting = macRandomizationSetting; 703 break; 704 default: 705 throw new IllegalArgumentException(); 706 } 707 return this; 708 } 709 710 /** 711 * Specifies whether the app needs to log in to a captive portal to obtain Internet access. 712 * <p> 713 * This will dictate if the directed broadcast 714 * {@link WifiManager#ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} will be sent to the 715 * app after successfully connecting to the network. 716 * Use this for captive portal type networks where the app needs to authenticate the user 717 * before the device can access the network. 718 * <p> 719 * <li>If not set, defaults to false (i.e no app interaction required).</li> 720 * 721 * @param isAppInteractionRequired {@code true} to indicate that app interaction is 722 * required, {@code false} otherwise. 723 * @return Instance of {@link Builder} to enable chaining of the builder method. 724 */ setIsAppInteractionRequired(boolean isAppInteractionRequired)725 public @NonNull Builder setIsAppInteractionRequired(boolean isAppInteractionRequired) { 726 mIsAppInteractionRequired = isAppInteractionRequired; 727 return this; 728 } 729 730 /** 731 * Specifies whether the user needs to log in to a captive portal to obtain Internet access. 732 * <p> 733 * <li>If not set, defaults to false (i.e no user interaction required).</li> 734 * 735 * @param isUserInteractionRequired {@code true} to indicate that user interaction is 736 * required, {@code false} otherwise. 737 * @return Instance of {@link Builder} to enable chaining of the builder method. 738 */ setIsUserInteractionRequired(boolean isUserInteractionRequired)739 public @NonNull Builder setIsUserInteractionRequired(boolean isUserInteractionRequired) { 740 mIsUserInteractionRequired = isUserInteractionRequired; 741 return this; 742 } 743 744 /** 745 * Specify the priority of this network among other network suggestions provided by the same 746 * app and within the same priority group, see {@link #setPriorityGroup(int)}. Priorities 747 * have no impact on suggestions by other apps or suggestions from the same app using a 748 * different priority group. The higher the number, the higher the priority 749 * (i.e value of 0 = lowest priority). If not set, defaults to a lower priority than any 750 * assigned priority. 751 * 752 * @param priority Integer number representing the priority among suggestions by the app. 753 * @return Instance of {@link Builder} to enable chaining of the builder method. 754 * @throws IllegalArgumentException if the priority value is negative. 755 */ setPriority(@ntRangefrom = 0) int priority)756 public @NonNull Builder setPriority(@IntRange(from = 0) int priority) { 757 if (priority < 0) { 758 throw new IllegalArgumentException("Invalid priority value " + priority); 759 } 760 mPriority = priority; 761 return this; 762 } 763 764 /** 765 * Specifies whether this network is metered. 766 * <p> 767 * <li>If not set, defaults to detect automatically.</li> 768 * 769 * @param isMetered {@code true} to indicate that the network is metered, {@code false} 770 * for not metered. 771 * @return Instance of {@link Builder} to enable chaining of the builder method. 772 */ setIsMetered(boolean isMetered)773 public @NonNull Builder setIsMetered(boolean isMetered) { 774 if (isMetered) { 775 mMeteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED; 776 } else { 777 mMeteredOverride = WifiConfiguration.METERED_OVERRIDE_NOT_METERED; 778 } 779 return this; 780 } 781 782 /** 783 * Specifies whether the network credentials provided with this suggestion can be used by 784 * the user to explicitly (manually) connect to this network. If true this network will 785 * appear in the Wi-Fi Picker (in Settings) and the user will be able to select and connect 786 * to it with the provided credentials. If false, the user will need to enter network 787 * credentials and the resulting configuration will become a user saved network. 788 * <p> 789 * <li>Note: Only valid for secure (non-open) networks. 790 * <li>If not set, defaults to true (i.e. allow user to manually connect) for secure 791 * networks and false for open networks.</li> 792 * 793 * @param isShared {@code true} to indicate that the credentials may be used by the user to 794 * manually connect to the network, {@code false} otherwise. 795 * @return Instance of {@link Builder} to enable chaining of the builder method. 796 */ setCredentialSharedWithUser(boolean isShared)797 public @NonNull Builder setCredentialSharedWithUser(boolean isShared) { 798 mIsSharedWithUser = isShared; 799 mIsSharedWithUserSet = true; 800 return this; 801 } 802 803 /** 804 * Specifies whether the suggestion is created with auto-join enabled or disabled. The 805 * user may modify the auto-join configuration of a suggestion directly once the device 806 * associates to the network. 807 * <p> 808 * If auto-join is initialized as disabled the user may still be able to manually connect 809 * to the network. Therefore, disabling auto-join only makes sense if 810 * {@link #setCredentialSharedWithUser(boolean)} is set to true (the default) which 811 * itself implies a secure (non-open) network. 812 * <p> 813 * If not set, defaults to true (i.e. auto-join is initialized as enabled). 814 * 815 * @param enabled true for initializing with auto-join enabled (the default), false to 816 * initializing with auto-join disabled. 817 * @return Instance of {@link Builder} to enable chaining of the builder method. 818 */ setIsInitialAutojoinEnabled(boolean enabled)819 public @NonNull Builder setIsInitialAutojoinEnabled(boolean enabled) { 820 mIsInitialAutojoinEnabled = enabled; 821 return this; 822 } 823 824 /** 825 * Specifies whether the system will bring up the network (if selected) as untrusted. An 826 * untrusted network has its {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} 827 * capability removed. The Wi-Fi network selection process may use this information to 828 * influence priority of the suggested network for Wi-Fi network selection (most likely to 829 * reduce it). The connectivity service may use this information to influence the overall 830 * network configuration of the device. 831 * <p> 832 * <li> These suggestions are only considered for network selection if a 833 * {@link NetworkRequest} without {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} 834 * capability is filed. 835 * <li> An untrusted network's credentials may not be shared with the user using 836 * {@link #setCredentialSharedWithUser(boolean)}.</li> 837 * <li> If not set, defaults to false (i.e. network is trusted).</li> 838 * 839 * @param isUntrusted Boolean indicating whether the network should be brought up untrusted 840 * (if true) or trusted (if false). 841 * @return Instance of {@link Builder} to enable chaining of the builder method. 842 */ setUntrusted(boolean isUntrusted)843 public @NonNull Builder setUntrusted(boolean isUntrusted) { 844 mIsNetworkUntrusted = isUntrusted; 845 return this; 846 } 847 848 /** 849 * Specifies whether the system will bring up the network (if selected) as restricted. A 850 * restricted network has its {@link NetworkCapabilities#NET_CAPABILITY_NOT_RESTRICTED} 851 * capability removed. The Wi-Fi network selection process may use this information to 852 * influence priority of the suggested network for Wi-Fi network selection (most likely to 853 * reduce it). The connectivity service may use this information to influence the overall 854 * network configuration of the device. 855 * <p> 856 * <li> These suggestions are only considered for network selection if a 857 * {@link NetworkRequest} without {@link NetworkCapabilities#NET_CAPABILITY_NOT_RESTRICTED} 858 * capability is filed. 859 * <li> A restricted network's credentials may not be shared with the user using 860 * {@link #setCredentialSharedWithUser(boolean)}.</li> 861 * <li> If not set, defaults to false (i.e. network is unrestricted).</li> 862 * 863 * @param isRestricted Boolean indicating whether the network should be brought up 864 * restricted (if true) or unrestricted (if false). 865 * @return Instance of {@link Builder} to enable chaining of the builder method. 866 */ setRestricted(boolean isRestricted)867 public @NonNull Builder setRestricted(boolean isRestricted) { 868 mIsNetworkRestricted = isRestricted; 869 return this; 870 } 871 872 /** 873 * Sets whether Wi-Fi 7 is enabled for this network. 874 * 875 * @param enabled Enable Wi-Fi 7 if true, otherwise disable Wi-Fi 7 876 * @return Instance of {@link Builder} to enable chaining of the builder method. 877 */ 878 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) setWifi7Enabled(boolean enabled)879 public @NonNull Builder setWifi7Enabled(boolean enabled) { 880 mIsWifi7Enabled = enabled; 881 return this; 882 } 883 /** 884 * Specifies whether the system will bring up the network (if selected) as OEM paid. An 885 * OEM paid network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID} capability 886 * added. 887 * Note: 888 * <li>The connectivity service may use this information to influence the overall 889 * network configuration of the device. This network is typically only available to system 890 * apps. 891 * <li>On devices which do not support concurrent connection (indicated via 892 * {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), Wi-Fi 893 * network selection process may use this information to influence priority of the 894 * suggested network for Wi-Fi network selection (most likely to reduce it). 895 * <li>On devices which support concurrent connections (indicated via 896 * {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), these 897 * OEM paid networks may be brought up as a secondary concurrent connection (primary 898 * connection will be used for networks available to the user and all apps. 899 * <p> 900 * <li> An OEM paid network's credentials may not be shared with the user using 901 * {@link #setCredentialSharedWithUser(boolean)}.</li> 902 * <li> These suggestions are only considered for network selection if a 903 * {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID} 904 * capability is filed. 905 * <li> Each suggestion can have both {@link #setOemPaid(boolean)} and 906 * {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered 907 * for creating either an OEM paid network or OEM private network determined based on 908 * the {@link NetworkRequest} that is active. 909 * <li> If not set, defaults to false (i.e. network is not OEM paid).</li> 910 * 911 * @param isOemPaid Boolean indicating whether the network should be brought up as OEM paid 912 * (if true) or not OEM paid (if false). 913 * @return Instance of {@link Builder} to enable chaining of the builder method. 914 * @hide 915 */ 916 @SystemApi 917 @RequiresApi(Build.VERSION_CODES.S) setOemPaid(boolean isOemPaid)918 public @NonNull Builder setOemPaid(boolean isOemPaid) { 919 if (!SdkLevel.isAtLeastS()) { 920 throw new UnsupportedOperationException(); 921 } 922 mIsNetworkOemPaid = isOemPaid; 923 return this; 924 } 925 926 /** 927 * Specifies whether the system will bring up the network (if selected) as OEM private. An 928 * OEM private network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE} capability 929 * added. 930 * Note: 931 * <li>The connectivity service may use this information to influence the overall 932 * network configuration of the device. This network is typically only available to system 933 * apps. 934 * <li>On devices which do not support concurrent connection (indicated via 935 * {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), Wi-Fi 936 * network selection process may use this information to influence priority of the suggested 937 * network for Wi-Fi network selection (most likely to reduce it). 938 * <li>On devices which support concurrent connections (indicated via 939 * {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), these OEM 940 * private networks may be brought up as a secondary concurrent connection (primary 941 * connection will be used for networks available to the user and all apps. 942 * <p> 943 * <li> An OEM private network's credentials may not be shared with the user using 944 * {@link #setCredentialSharedWithUser(boolean)}.</li> 945 * <li> These suggestions are only considered for network selection if a 946 * {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE} 947 * capability is filed. 948 * <li> Each suggestion can have both {@link #setOemPaid(boolean)} and 949 * {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered 950 * for creating either an OEM paid network or OEM private network determined based on 951 * the {@link NetworkRequest} that is active. 952 * <li> If not set, defaults to false (i.e. network is not OEM private).</li> 953 * 954 * @param isOemPrivate Boolean indicating whether the network should be brought up as OEM 955 * private (if true) or not OEM private (if false). 956 * @return Instance of {@link Builder} to enable chaining of the builder method. 957 * @hide 958 */ 959 @SystemApi 960 @RequiresApi(Build.VERSION_CODES.S) setOemPrivate(boolean isOemPrivate)961 public @NonNull Builder setOemPrivate(boolean isOemPrivate) { 962 if (!SdkLevel.isAtLeastS()) { 963 throw new UnsupportedOperationException(); 964 } 965 mIsNetworkOemPrivate = isOemPrivate; 966 return this; 967 } 968 969 /** 970 * Specifies whether the suggestion represents a carrier merged network. A carrier merged 971 * Wi-Fi network is treated as part of the mobile carrier network. Such configuration may 972 * impact the user interface and data usage accounting. 973 * <p> 974 * Only carriers with the 975 * {@link android.telephony.CarrierConfigManager#KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL} 976 * flag set to {@code true} may use this API. 977 * <p> 978 * <li>A suggestion marked as carrier merged must be metered enterprise network with a valid 979 * subscription Id set. 980 * @see #setIsMetered(boolean) 981 * @see #setSubscriptionId(int) 982 * @see #setWpa2EnterpriseConfig(WifiEnterpriseConfig) 983 * @see #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig) 984 * @see #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig) 985 * @see #setPasspointConfig(PasspointConfiguration) 986 * </li> 987 * <li>If not set, defaults to false (i.e. not a carrier merged network.)</li> 988 * </p> 989 * @param isCarrierMerged Boolean indicating whether the network is treated a carrier 990 * merged network (if true) or non-merged network (if false); 991 * @return Instance of {@link Builder} to enable chaining of the builder method. 992 */ 993 @RequiresApi(Build.VERSION_CODES.S) setCarrierMerged(boolean isCarrierMerged)994 public @NonNull Builder setCarrierMerged(boolean isCarrierMerged) { 995 if (!SdkLevel.isAtLeastS()) { 996 throw new UnsupportedOperationException(); 997 } 998 mIsCarrierMerged = isCarrierMerged; 999 return this; 1000 } 1001 1002 /** 1003 * Specifies whether the suggestion represents an SAE network which only 1004 * accepts Hash-to-Element mode. 1005 * If this is enabled, Hunting & Pecking mode is disabled and only Hash-to-Element 1006 * mode is used for this network. 1007 * This is only valid for an SAE network which is configured using the 1008 * {@link #setWpa3Passphrase}. 1009 * Before calling this API, the application should check Hash-to-Element support using 1010 * {@link WifiManager#isWpa3SaeH2eSupported()}. 1011 * 1012 * @param enable Boolean indicating whether the network only accepts Hash-to-Element mode, 1013 * default is false. 1014 * @return Instance of {@link Builder} to enable chaining of the builder method. 1015 */ 1016 @RequiresApi(Build.VERSION_CODES.S) setIsWpa3SaeH2eOnlyModeEnabled(boolean enable)1017 public @NonNull Builder setIsWpa3SaeH2eOnlyModeEnabled(boolean enable) { 1018 if (!SdkLevel.isAtLeastS()) { 1019 throw new UnsupportedOperationException(); 1020 } 1021 mSaeH2eOnlyMode = enable; 1022 return this; 1023 } 1024 setSecurityParamsInWifiConfiguration( @onNull WifiConfiguration configuration)1025 private void setSecurityParamsInWifiConfiguration( 1026 @NonNull WifiConfiguration configuration) { 1027 if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network. 1028 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); 1029 // WifiConfiguration.preSharedKey needs quotes around ASCII password. 1030 configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\""; 1031 } else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network. 1032 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); 1033 // WifiConfiguration.preSharedKey needs quotes around ASCII password. 1034 configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\""; 1035 if (mSaeH2eOnlyMode) configuration.enableSaeH2eOnlyMode(mSaeH2eOnlyMode); 1036 } else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network 1037 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP); 1038 configuration.enterpriseConfig = mWpa2EnterpriseConfig; 1039 } else if (mWpa3EnterpriseConfig != null) { // WPA3-Enterprise 1040 if (mWpa3EnterpriseType == WPA3_ENTERPRISE_AUTO 1041 && mWpa3EnterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS 1042 && WifiEnterpriseConfig.isSuiteBCipherCert( 1043 mWpa3EnterpriseConfig.getClientCertificate()) 1044 && WifiEnterpriseConfig.isSuiteBCipherCert( 1045 mWpa3EnterpriseConfig.getCaCertificate())) { 1046 // WPA3-Enterprise in 192-bit security mode 1047 configuration.setSecurityParams( 1048 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT); 1049 } else if (mWpa3EnterpriseType == WPA3_ENTERPRISE_192_BIT) { 1050 // WPA3-Enterprise in 192-bit security mode 1051 configuration.setSecurityParams( 1052 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT); 1053 } else { 1054 // WPA3-Enterprise 1055 configuration.setSecurityParams( 1056 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE); 1057 } 1058 configuration.enterpriseConfig = mWpa3EnterpriseConfig; 1059 } else if (mIsEnhancedOpen) { // OWE network 1060 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); 1061 } else if (!TextUtils.isEmpty(mWapiPskPassphrase)) { // WAPI-PSK network. 1062 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_PSK); 1063 // WifiConfiguration.preSharedKey needs quotes around ASCII password. 1064 configuration.preSharedKey = "\"" + mWapiPskPassphrase + "\""; 1065 } else if (mWapiEnterpriseConfig != null) { // WAPI-CERT network 1066 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_CERT); 1067 configuration.enterpriseConfig = mWapiEnterpriseConfig; 1068 } else { // Open network 1069 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); 1070 } 1071 } 1072 1073 /** 1074 * Helper method to build WifiConfiguration object from the builder. 1075 * @return Instance of {@link WifiConfiguration}. 1076 */ buildWifiConfiguration()1077 private WifiConfiguration buildWifiConfiguration() { 1078 final WifiConfiguration wifiConfiguration = new WifiConfiguration(); 1079 // WifiConfiguration.SSID needs quotes around unicode SSID. 1080 wifiConfiguration.SSID = mWifiSsid.toString(); 1081 if (mBssid != null) { 1082 wifiConfiguration.BSSID = mBssid.toString(); 1083 } 1084 1085 setSecurityParamsInWifiConfiguration(wifiConfiguration); 1086 1087 wifiConfiguration.hiddenSSID = mIsHiddenSSID; 1088 wifiConfiguration.priority = mPriority; 1089 wifiConfiguration.meteredOverride = mMeteredOverride; 1090 wifiConfiguration.carrierId = mCarrierId; 1091 wifiConfiguration.trusted = !mIsNetworkUntrusted; 1092 wifiConfiguration.oemPaid = mIsNetworkOemPaid; 1093 wifiConfiguration.oemPrivate = mIsNetworkOemPrivate; 1094 wifiConfiguration.carrierMerged = mIsCarrierMerged; 1095 wifiConfiguration.macRandomizationSetting = 1096 mMacRandomizationSetting == RANDOMIZATION_NON_PERSISTENT 1097 ? WifiConfiguration.RANDOMIZATION_NON_PERSISTENT 1098 : WifiConfiguration.RANDOMIZATION_PERSISTENT; 1099 wifiConfiguration.subscriptionId = mSubscriptionId; 1100 wifiConfiguration.restricted = mIsNetworkRestricted; 1101 wifiConfiguration.setSubscriptionGroup(mSubscriptionGroup); 1102 wifiConfiguration.setWifi7Enabled(mIsWifi7Enabled); 1103 return wifiConfiguration; 1104 } 1105 validateSecurityParams()1106 private void validateSecurityParams() { 1107 int numSecurityTypes = 0; 1108 numSecurityTypes += mIsEnhancedOpen ? 1 : 0; 1109 numSecurityTypes += !TextUtils.isEmpty(mWpa2PskPassphrase) ? 1 : 0; 1110 numSecurityTypes += !TextUtils.isEmpty(mWpa3SaePassphrase) ? 1 : 0; 1111 numSecurityTypes += !TextUtils.isEmpty(mWapiPskPassphrase) ? 1 : 0; 1112 numSecurityTypes += mWpa2EnterpriseConfig != null ? 1 : 0; 1113 numSecurityTypes += mWpa3EnterpriseConfig != null ? 1 : 0; 1114 numSecurityTypes += mWapiEnterpriseConfig != null ? 1 : 0; 1115 numSecurityTypes += mPasspointConfiguration != null ? 1 : 0; 1116 if (numSecurityTypes > 1) { 1117 throw new IllegalStateException("only one of setIsEnhancedOpen, setWpa2Passphrase," 1118 + " setWpa3Passphrase, setWpa2EnterpriseConfig, setWpa3EnterpriseConfig" 1119 + " setWapiPassphrase, setWapiCertSuite, setIsWapiCertSuiteAuto" 1120 + " or setPasspointConfig can be invoked for network suggestion"); 1121 } 1122 } 1123 buildWifiConfigurationForPasspoint()1124 private WifiConfiguration buildWifiConfigurationForPasspoint() { 1125 WifiConfiguration wifiConfiguration = new WifiConfiguration(); 1126 wifiConfiguration.FQDN = mPasspointConfiguration.getHomeSp().getFqdn(); 1127 wifiConfiguration.setPasspointUniqueId(mPasspointConfiguration.getUniqueId()); 1128 wifiConfiguration.priority = mPriority; 1129 wifiConfiguration.meteredOverride = mMeteredOverride; 1130 wifiConfiguration.trusted = !mIsNetworkUntrusted; 1131 wifiConfiguration.oemPaid = mIsNetworkOemPaid; 1132 wifiConfiguration.oemPrivate = mIsNetworkOemPrivate; 1133 wifiConfiguration.carrierMerged = mIsCarrierMerged; 1134 wifiConfiguration.carrierId = mCarrierId; 1135 wifiConfiguration.subscriptionId = mSubscriptionId; 1136 wifiConfiguration.macRandomizationSetting = 1137 mMacRandomizationSetting == RANDOMIZATION_NON_PERSISTENT 1138 ? WifiConfiguration.RANDOMIZATION_NON_PERSISTENT 1139 : WifiConfiguration.RANDOMIZATION_PERSISTENT; 1140 wifiConfiguration.restricted = mIsNetworkRestricted; 1141 wifiConfiguration.setSubscriptionGroup(mSubscriptionGroup); 1142 wifiConfiguration.setWifi7Enabled(mIsWifi7Enabled); 1143 mPasspointConfiguration.setCarrierId(mCarrierId); 1144 mPasspointConfiguration.setSubscriptionId(mSubscriptionId); 1145 mPasspointConfiguration.setSubscriptionGroup(mSubscriptionGroup); 1146 mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride); 1147 mPasspointConfiguration.setOemPrivate(mIsNetworkOemPrivate); 1148 mPasspointConfiguration.setOemPaid(mIsNetworkOemPaid); 1149 mPasspointConfiguration.setCarrierMerged(mIsCarrierMerged); 1150 // MAC randomization should always be enabled for passpoint suggestions regardless of 1151 // the PasspointConfiguration's original setting. 1152 mPasspointConfiguration.setMacRandomizationEnabled(true); 1153 mPasspointConfiguration.setNonPersistentMacRandomizationEnabled( 1154 mMacRandomizationSetting == RANDOMIZATION_NON_PERSISTENT); 1155 return wifiConfiguration; 1156 } 1157 1158 /** 1159 * Create a network suggestion object for use in 1160 * {@link WifiManager#addNetworkSuggestions(List)}. 1161 * 1162 *<p class="note"> 1163 * <b>Note:</b> Apps can set a combination of SSID using {@link #setSsid(String)} and BSSID 1164 * using {@link #setBssid(MacAddress)} to provide more fine grained network suggestions to 1165 * the platform. 1166 * </p> 1167 * 1168 * For example: 1169 * To provide credentials for one open, one WPA2, one WPA3 network with their 1170 * corresponding SSID's and one with Passpoint config: 1171 * 1172 * <pre>{@code 1173 * final WifiNetworkSuggestion suggestion1 = 1174 * new Builder() 1175 * .setSsid("test111111") 1176 * .build(); 1177 * final WifiNetworkSuggestion suggestion2 = 1178 * new Builder() 1179 * .setSsid("test222222") 1180 * .setWpa2Passphrase("test123456") 1181 * .build(); 1182 * final WifiNetworkSuggestion suggestion3 = 1183 * new Builder() 1184 * .setSsid("test333333") 1185 * .setWpa3Passphrase("test6789") 1186 * .build(); 1187 * final PasspointConfiguration passpointConfig= new PasspointConfiguration(); 1188 * // configure passpointConfig to include a valid Passpoint configuration 1189 * final WifiNetworkSuggestion suggestion4 = 1190 * new Builder() 1191 * .setPasspointConfig(passpointConfig) 1192 * .build(); 1193 * final List<WifiNetworkSuggestion> suggestionsList = 1194 * new ArrayList<WifiNetworkSuggestion> { { 1195 * add(suggestion1); 1196 * add(suggestion2); 1197 * add(suggestion3); 1198 * add(suggestion4); 1199 * } }; 1200 * final WifiManager wifiManager = 1201 * context.getSystemService(Context.WIFI_SERVICE); 1202 * wifiManager.addNetworkSuggestions(suggestionsList); 1203 * // ... 1204 * }</pre> 1205 * 1206 * @return Instance of {@link WifiNetworkSuggestion} 1207 * @throws IllegalStateException on invalid params set 1208 * @see WifiNetworkSuggestion 1209 */ build()1210 public @NonNull WifiNetworkSuggestion build() { 1211 validateSecurityParams(); 1212 WifiConfiguration wifiConfiguration; 1213 if (mPasspointConfiguration != null) { 1214 if (mWifiSsid != null) { 1215 throw new IllegalStateException("setSsid should not be invoked for suggestion " 1216 + "with Passpoint configuration"); 1217 } 1218 if (mIsHiddenSSID) { 1219 throw new IllegalStateException("setIsHiddenSsid should not be invoked for " 1220 + "suggestion with Passpoint configuration"); 1221 } 1222 wifiConfiguration = buildWifiConfigurationForPasspoint(); 1223 } else { 1224 if (mWifiSsid == null) { 1225 throw new IllegalStateException("setSsid should be invoked for suggestion"); 1226 } 1227 if (mWifiSsid.getBytes().length == 0) { 1228 throw new IllegalStateException("invalid ssid for suggestion"); 1229 } 1230 if (mBssid != null 1231 && (mBssid.equals(MacAddress.BROADCAST_ADDRESS) 1232 || mBssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS))) { 1233 throw new IllegalStateException("invalid bssid for suggestion"); 1234 } 1235 if (TextUtils.isEmpty(mWpa3SaePassphrase) && mSaeH2eOnlyMode) { 1236 throw new IllegalStateException( 1237 "Hash-to-Element only mode is only allowed for the SAE network"); 1238 } 1239 1240 wifiConfiguration = buildWifiConfiguration(); 1241 if (wifiConfiguration.isOpenNetwork()) { 1242 if (mIsSharedWithUserSet && mIsSharedWithUser) { 1243 throw new IllegalStateException("Open network should not be " 1244 + "setCredentialSharedWithUser to true"); 1245 } 1246 mIsSharedWithUser = false; 1247 } 1248 } 1249 if (!mIsSharedWithUser && !mIsInitialAutojoinEnabled) { 1250 throw new IllegalStateException("Should have not a network with both " 1251 + "setCredentialSharedWithUser and " 1252 + "setIsAutojoinEnabled set to false"); 1253 } 1254 if (mIsNetworkUntrusted || mIsNetworkRestricted) { 1255 if (mIsSharedWithUserSet && mIsSharedWithUser) { 1256 throw new IllegalStateException("Should not be both" 1257 + "setCredentialSharedWithUser and +" 1258 + "setUntrusted or setRestricted to true"); 1259 } 1260 mIsSharedWithUser = false; 1261 } 1262 if (mIsNetworkOemPaid) { 1263 if (mIsSharedWithUserSet && mIsSharedWithUser) { 1264 throw new IllegalStateException("Should not be both" 1265 + "setCredentialSharedWithUser and +" 1266 + "setOemPaid to true"); 1267 } 1268 mIsSharedWithUser = false; 1269 } 1270 if (mIsNetworkOemPrivate) { 1271 if (mIsSharedWithUserSet && mIsSharedWithUser) { 1272 throw new IllegalStateException("Should not be both" 1273 + "setCredentialSharedWithUser and +" 1274 + "setOemPrivate to true"); 1275 } 1276 mIsSharedWithUser = false; 1277 } 1278 if (mIsCarrierMerged) { 1279 if ((mSubscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1280 && mSubscriptionGroup == null) 1281 || mMeteredOverride != WifiConfiguration.METERED_OVERRIDE_METERED 1282 || !isEnterpriseSuggestion()) { 1283 throw new IllegalStateException("A carrier merged network must be a metered, " 1284 + "enterprise network with valid subscription Id"); 1285 } 1286 } 1287 if (mSubscriptionGroup != null 1288 && mSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1289 throw new IllegalStateException("Should not be set both SubscriptionGroup and " 1290 + "SubscriptionId"); 1291 } 1292 return new WifiNetworkSuggestion( 1293 wifiConfiguration, 1294 mPasspointConfiguration, 1295 mIsAppInteractionRequired, 1296 mIsUserInteractionRequired, 1297 mIsSharedWithUser, 1298 mIsInitialAutojoinEnabled, 1299 mPriorityGroup); 1300 } 1301 isEnterpriseSuggestion()1302 private boolean isEnterpriseSuggestion() { 1303 return !(mWpa2EnterpriseConfig == null && mWpa3EnterpriseConfig == null 1304 && mWapiEnterpriseConfig == null && mPasspointConfiguration == null); 1305 } 1306 } 1307 1308 1309 1310 /** 1311 * Network configuration for the provided network. 1312 * @hide 1313 */ 1314 @NonNull 1315 public final WifiConfiguration wifiConfiguration; 1316 1317 /** 1318 * Passpoint configuration for the provided network. 1319 * @hide 1320 */ 1321 @Nullable 1322 public final PasspointConfiguration passpointConfiguration; 1323 1324 /** 1325 * Whether app needs to log in to captive portal to obtain Internet access. 1326 * @hide 1327 */ 1328 public final boolean isAppInteractionRequired; 1329 1330 /** 1331 * Whether user needs to log in to captive portal to obtain Internet access. 1332 * @hide 1333 */ 1334 public final boolean isUserInteractionRequired; 1335 1336 /** 1337 * Whether app share credential with the user, allow user use provided credential to 1338 * connect network manually. 1339 * @hide 1340 */ 1341 public final boolean isUserAllowedToManuallyConnect; 1342 1343 /** 1344 * Whether the suggestion will be initialized as auto-joined or not. 1345 * @hide 1346 */ 1347 public final boolean isInitialAutoJoinEnabled; 1348 1349 /** 1350 * Priority group ID. 1351 * @hide 1352 */ 1353 public final int priorityGroup; 1354 1355 /** @hide */ WifiNetworkSuggestion()1356 public WifiNetworkSuggestion() { 1357 this.wifiConfiguration = new WifiConfiguration(); 1358 this.passpointConfiguration = null; 1359 this.isAppInteractionRequired = false; 1360 this.isUserInteractionRequired = false; 1361 this.isUserAllowedToManuallyConnect = true; 1362 this.isInitialAutoJoinEnabled = true; 1363 this.priorityGroup = 0; 1364 } 1365 1366 /** @hide */ WifiNetworkSuggestion(@onNull WifiConfiguration networkConfiguration, @Nullable PasspointConfiguration passpointConfiguration, boolean isAppInteractionRequired, boolean isUserInteractionRequired, boolean isUserAllowedToManuallyConnect, boolean isInitialAutoJoinEnabled, int priorityGroup)1367 public WifiNetworkSuggestion(@NonNull WifiConfiguration networkConfiguration, 1368 @Nullable PasspointConfiguration passpointConfiguration, 1369 boolean isAppInteractionRequired, 1370 boolean isUserInteractionRequired, 1371 boolean isUserAllowedToManuallyConnect, 1372 boolean isInitialAutoJoinEnabled, int priorityGroup) { 1373 checkNotNull(networkConfiguration); 1374 this.wifiConfiguration = networkConfiguration; 1375 this.passpointConfiguration = passpointConfiguration; 1376 1377 this.isAppInteractionRequired = isAppInteractionRequired; 1378 this.isUserInteractionRequired = isUserInteractionRequired; 1379 this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect; 1380 this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled; 1381 this.priorityGroup = priorityGroup; 1382 } 1383 1384 public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR = 1385 new Creator<WifiNetworkSuggestion>() { 1386 @Override 1387 public WifiNetworkSuggestion createFromParcel(Parcel in) { 1388 return new WifiNetworkSuggestion( 1389 in.readParcelable(null), // wifiConfiguration 1390 in.readParcelable(null), // PasspointConfiguration 1391 in.readBoolean(), // isAppInteractionRequired 1392 in.readBoolean(), // isUserInteractionRequired 1393 in.readBoolean(), // isSharedCredentialWithUser 1394 in.readBoolean(), // isAutojoinEnabled 1395 in.readInt() // priorityGroup 1396 ); 1397 } 1398 1399 @Override 1400 public WifiNetworkSuggestion[] newArray(int size) { 1401 return new WifiNetworkSuggestion[size]; 1402 } 1403 }; 1404 1405 @Override describeContents()1406 public int describeContents() { 1407 return 0; 1408 } 1409 1410 @Override writeToParcel(Parcel dest, int flags)1411 public void writeToParcel(Parcel dest, int flags) { 1412 dest.writeParcelable(wifiConfiguration, flags); 1413 dest.writeParcelable(passpointConfiguration, flags); 1414 dest.writeBoolean(isAppInteractionRequired); 1415 dest.writeBoolean(isUserInteractionRequired); 1416 dest.writeBoolean(isUserAllowedToManuallyConnect); 1417 dest.writeBoolean(isInitialAutoJoinEnabled); 1418 dest.writeInt(priorityGroup); 1419 } 1420 1421 @Override hashCode()1422 public int hashCode() { 1423 return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID, 1424 wifiConfiguration.getDefaultSecurityType(), 1425 wifiConfiguration.getPasspointUniqueId(), 1426 wifiConfiguration.subscriptionId, wifiConfiguration.carrierId, 1427 wifiConfiguration.getSubscriptionGroup()); 1428 } 1429 1430 @Override equals(Object obj)1431 public boolean equals(Object obj) { 1432 if (this == obj) { 1433 return true; 1434 } 1435 if (!(obj instanceof WifiNetworkSuggestion)) { 1436 return false; 1437 } 1438 WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj; 1439 if (this.passpointConfiguration == null ^ lhs.passpointConfiguration == null) { 1440 return false; 1441 } 1442 1443 return TextUtils.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID) 1444 && TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID) 1445 && TextUtils.equals(this.wifiConfiguration.getDefaultSecurityType(), 1446 lhs.wifiConfiguration.getDefaultSecurityType()) 1447 && TextUtils.equals(this.wifiConfiguration.getPasspointUniqueId(), 1448 lhs.wifiConfiguration.getPasspointUniqueId()) 1449 && this.wifiConfiguration.carrierId == lhs.wifiConfiguration.carrierId 1450 && this.wifiConfiguration.subscriptionId == lhs.wifiConfiguration.subscriptionId 1451 && Objects.equals(this.wifiConfiguration.getSubscriptionGroup(), 1452 lhs.wifiConfiguration.getSubscriptionGroup()); 1453 } 1454 1455 @Override toString()1456 public String toString() { 1457 StringBuilder sb = new StringBuilder("WifiNetworkSuggestion[ ") 1458 .append("SSID=").append(wifiConfiguration.SSID) 1459 .append(", BSSID=").append(wifiConfiguration.BSSID) 1460 .append(", FQDN=").append(wifiConfiguration.FQDN) 1461 .append(", SecurityParams="); 1462 wifiConfiguration.getSecurityParamsList().stream() 1463 .forEach(param -> { 1464 sb.append(" "); 1465 sb.append(WifiConfiguration.getSecurityTypeName(param.getSecurityType())); 1466 if (param.isAddedByAutoUpgrade()) sb.append("^"); 1467 }); 1468 sb.append(", isAppInteractionRequired=").append(isAppInteractionRequired) 1469 .append(", isUserInteractionRequired=").append(isUserInteractionRequired) 1470 .append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect) 1471 .append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled) 1472 .append(", isUnTrusted=").append(!wifiConfiguration.trusted) 1473 .append(", isOemPaid=").append(wifiConfiguration.oemPaid) 1474 .append(", isOemPrivate=").append(wifiConfiguration.oemPrivate) 1475 .append(", isCarrierMerged=").append(wifiConfiguration.carrierMerged) 1476 .append(", isHiddenSsid=").append(wifiConfiguration.hiddenSSID) 1477 .append(", priorityGroup=").append(priorityGroup) 1478 .append(", subscriptionId=").append(wifiConfiguration.subscriptionId) 1479 .append(", subscriptionGroup=").append(wifiConfiguration.getSubscriptionGroup()) 1480 .append(", carrierId=").append(wifiConfiguration.carrierId) 1481 .append(", priority=").append(wifiConfiguration.priority) 1482 .append(", meteredness=").append(wifiConfiguration.meteredOverride) 1483 .append(", restricted=").append(wifiConfiguration.restricted) 1484 .append(" ]"); 1485 return sb.toString(); 1486 } 1487 1488 /** 1489 * Get the {@link WifiConfiguration} associated with this Suggestion. 1490 * @hide 1491 */ 1492 @SystemApi 1493 @NonNull getWifiConfiguration()1494 public WifiConfiguration getWifiConfiguration() { 1495 return wifiConfiguration; 1496 } 1497 1498 /** 1499 * Get the BSSID, or null if unset. 1500 * @see Builder#setBssid(MacAddress) 1501 */ 1502 @Nullable getBssid()1503 public MacAddress getBssid() { 1504 if (wifiConfiguration.BSSID == null) { 1505 return null; 1506 } 1507 return MacAddress.fromString(wifiConfiguration.BSSID); 1508 } 1509 1510 /** @see Builder#setCredentialSharedWithUser(boolean) */ isCredentialSharedWithUser()1511 public boolean isCredentialSharedWithUser() { 1512 return isUserAllowedToManuallyConnect; 1513 } 1514 1515 /** @see Builder#setIsAppInteractionRequired(boolean) */ isAppInteractionRequired()1516 public boolean isAppInteractionRequired() { 1517 return isAppInteractionRequired; 1518 } 1519 1520 /** @see Builder#setIsEnhancedOpen(boolean) */ isEnhancedOpen()1521 public boolean isEnhancedOpen() { 1522 return wifiConfiguration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE); 1523 } 1524 1525 /** @see Builder#setIsHiddenSsid(boolean) */ isHiddenSsid()1526 public boolean isHiddenSsid() { 1527 return wifiConfiguration.hiddenSSID; 1528 } 1529 1530 /** @see Builder#setIsInitialAutojoinEnabled(boolean) */ isInitialAutojoinEnabled()1531 public boolean isInitialAutojoinEnabled() { 1532 return isInitialAutoJoinEnabled; 1533 } 1534 1535 /** @see Builder#setIsMetered(boolean) */ isMetered()1536 public boolean isMetered() { 1537 return wifiConfiguration.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED; 1538 } 1539 1540 /** @see Builder#setIsUserInteractionRequired(boolean) */ isUserInteractionRequired()1541 public boolean isUserInteractionRequired() { 1542 return isUserInteractionRequired; 1543 } 1544 1545 /** 1546 * Get the {@link PasspointConfiguration} associated with this Suggestion, or null if this 1547 * Suggestion is not for a Passpoint network. 1548 */ 1549 @Nullable getPasspointConfig()1550 public PasspointConfiguration getPasspointConfig() { 1551 return passpointConfiguration; 1552 } 1553 1554 /** @see Builder#setPriority(int) */ 1555 @IntRange(from = 0) getPriority()1556 public int getPriority() { 1557 return wifiConfiguration.priority; 1558 } 1559 1560 /** 1561 * Return the unicode SSID of the network, or null if this is a Passpoint network or the SSID is 1562 * non-unicode. 1563 * <p> 1564 * Note: use {@link #getWifiSsid()} which supports both unicode and non-unicode SSID. 1565 * @see Builder#setSsid(String) 1566 */ 1567 @Nullable getSsid()1568 public String getSsid() { 1569 if (wifiConfiguration.SSID == null) { 1570 return null; 1571 } 1572 WifiSsid wifiSsid; 1573 try { 1574 wifiSsid = WifiSsid.fromString(wifiConfiguration.SSID); 1575 } catch (IllegalArgumentException e) { 1576 return null; 1577 } 1578 if (wifiSsid.getUtf8Text() == null) { 1579 return null; 1580 } 1581 return wifiSsid.getUtf8Text().toString(); 1582 } 1583 1584 /** 1585 * Return the {@link WifiSsid} of the network, or null if this is a Passpoint network. 1586 * @see Builder#setWifiSsid(WifiSsid) 1587 * @return An object representing the SSID the network. {@code null} for passpoint network. 1588 */ 1589 @Nullable getWifiSsid()1590 public WifiSsid getWifiSsid() { 1591 if (wifiConfiguration.SSID == null) { 1592 return null; 1593 } 1594 WifiSsid wifiSsid; 1595 try { 1596 wifiSsid = WifiSsid.fromString(wifiConfiguration.SSID); 1597 } catch (IllegalArgumentException e) { 1598 throw new IllegalStateException("Invalid SSID in the network suggestion"); 1599 } 1600 return wifiSsid; 1601 } 1602 1603 /** @see Builder#setUntrusted(boolean) */ isUntrusted()1604 public boolean isUntrusted() { 1605 return !wifiConfiguration.trusted; 1606 } 1607 1608 /** 1609 * Return if a suggestion is for a restricted network 1610 * @see Builder#setRestricted(boolean) 1611 * @return true if the suggestion is restricted, false otherwise 1612 */ isRestricted()1613 public boolean isRestricted() { 1614 return wifiConfiguration.restricted; 1615 } 1616 1617 /** 1618 * @see Builder#setOemPaid(boolean) 1619 * @hide 1620 */ 1621 @SystemApi 1622 @RequiresApi(Build.VERSION_CODES.S) isOemPaid()1623 public boolean isOemPaid() { 1624 if (!SdkLevel.isAtLeastS()) { 1625 throw new UnsupportedOperationException(); 1626 } 1627 return wifiConfiguration.oemPaid; 1628 } 1629 1630 /** 1631 * @see Builder#setOemPrivate(boolean) 1632 * @hide 1633 */ 1634 @SystemApi 1635 @RequiresApi(Build.VERSION_CODES.S) isOemPrivate()1636 public boolean isOemPrivate() { 1637 if (!SdkLevel.isAtLeastS()) { 1638 throw new UnsupportedOperationException(); 1639 } 1640 return wifiConfiguration.oemPrivate; 1641 } 1642 1643 /** 1644 * @see Builder#setCarrierMerged(boolean) 1645 */ 1646 @RequiresApi(Build.VERSION_CODES.S) isCarrierMerged()1647 public boolean isCarrierMerged() { 1648 if (!SdkLevel.isAtLeastS()) { 1649 throw new UnsupportedOperationException(); 1650 } 1651 return wifiConfiguration.carrierMerged; 1652 } 1653 1654 /** 1655 * Get the WifiEnterpriseConfig, or null if unset. 1656 * @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig) 1657 * @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig) 1658 * @see Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig) 1659 */ 1660 @Nullable getEnterpriseConfig()1661 public WifiEnterpriseConfig getEnterpriseConfig() { 1662 if (!wifiConfiguration.isEnterprise()) { 1663 return null; 1664 } 1665 return wifiConfiguration.enterpriseConfig; 1666 } 1667 1668 /** 1669 * Get the passphrase, or null if unset. 1670 * @see Builder#setWapiPassphrase(String) 1671 * @see Builder#setWpa2Passphrase(String) 1672 * @see Builder#setWpa3Passphrase(String) 1673 */ 1674 @Nullable getPassphrase()1675 public String getPassphrase() { 1676 if (wifiConfiguration.preSharedKey == null) { 1677 return null; 1678 } 1679 return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey); 1680 } 1681 1682 /** 1683 * @see Builder#setPriorityGroup(int) 1684 */ 1685 @IntRange(from = 0) getPriorityGroup()1686 public int getPriorityGroup() { 1687 return priorityGroup; 1688 } 1689 1690 /** 1691 * @see Builder#setSubscriptionId(int) 1692 */ 1693 @RequiresApi(Build.VERSION_CODES.S) getSubscriptionId()1694 public int getSubscriptionId() { 1695 if (!SdkLevel.isAtLeastS()) { 1696 throw new UnsupportedOperationException(); 1697 } 1698 return wifiConfiguration.subscriptionId; 1699 } 1700 1701 /** 1702 * @see Builder#setCarrierId(int) 1703 * @hide 1704 */ 1705 @SystemApi getCarrierId()1706 public int getCarrierId() { 1707 return wifiConfiguration.carrierId; 1708 } 1709 1710 /** 1711 * Get the MAC randomization method. 1712 * @return one of {@code RANDOMIZATION_*} values 1713 * @see Builder#setMacRandomizationSetting(int) 1714 */ getMacRandomizationSetting()1715 public @MacRandomizationSetting int getMacRandomizationSetting() { 1716 return wifiConfiguration.macRandomizationSetting 1717 == WifiConfiguration.RANDOMIZATION_NON_PERSISTENT 1718 ? RANDOMIZATION_NON_PERSISTENT : RANDOMIZATION_PERSISTENT; 1719 } 1720 1721 /** 1722 * Get the subscription Group UUID of the suggestion 1723 * @see Builder#setSubscriptionGroup(ParcelUuid) 1724 * @return Uuid represent a Subscription Group 1725 */ 1726 @RequiresApi(Build.VERSION_CODES.TIRAMISU) getSubscriptionGroup()1727 public @Nullable ParcelUuid getSubscriptionGroup() { 1728 if (!SdkLevel.isAtLeastT()) { 1729 throw new UnsupportedOperationException(); 1730 } 1731 return wifiConfiguration.getSubscriptionGroup(); 1732 } 1733 1734 /** 1735 * See {@link Builder#setWifi7Enabled(boolean)} 1736 */ 1737 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) isWifi7Enabled()1738 public boolean isWifi7Enabled() { 1739 return wifiConfiguration.isWifi7Enabled(); 1740 } 1741 } 1742