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