1 /* 2 * Copyright (C) 2011 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.p2p; 18 19 import android.annotation.IntDef; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.net.MacAddress; 26 import android.net.wifi.WpsInfo; 27 import android.os.Build; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 import android.text.TextUtils; 31 32 import androidx.annotation.RequiresApi; 33 34 import com.android.modules.utils.build.SdkLevel; 35 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.nio.charset.StandardCharsets; 39 import java.util.regex.PatternSyntaxException; 40 41 /** 42 * A class representing a Wi-Fi P2p configuration for setting up a connection 43 * 44 * {@see WifiP2pManager} 45 */ 46 public class WifiP2pConfig implements Parcelable { 47 48 /** 49 * The device MAC address uniquely identifies a Wi-Fi p2p device 50 */ 51 public String deviceAddress = ""; 52 53 /** 54 * Wi-Fi Protected Setup information 55 */ 56 public WpsInfo wps; 57 58 /** Get the network name of this P2P configuration, or null if unset. */ 59 @Nullable getNetworkName()60 public String getNetworkName() { 61 return networkName; 62 } 63 64 /** @hide */ 65 public String networkName = ""; 66 67 /** Get the passphrase of this P2P configuration, or null if unset. */ 68 @Nullable getPassphrase()69 public String getPassphrase() { 70 return passphrase; 71 } 72 73 /** @hide */ 74 public String passphrase = ""; 75 76 /** 77 * Get the required band for the group owner. 78 * The result will be one of the following: 79 * {@link #GROUP_OWNER_BAND_AUTO}, 80 * {@link #GROUP_OWNER_BAND_2GHZ}, 81 * {@link #GROUP_OWNER_BAND_5GHZ} 82 */ 83 @GroupOperatingBandType getGroupOwnerBand()84 public int getGroupOwnerBand() { 85 return groupOwnerBand; 86 } 87 88 /** @hide */ 89 @GroupOperatingBandType 90 public int groupOwnerBand = GROUP_OWNER_BAND_AUTO; 91 92 /** @hide */ 93 @IntDef(flag = false, prefix = { "GROUP_OWNER_BAND_" }, value = { 94 GROUP_OWNER_BAND_AUTO, 95 GROUP_OWNER_BAND_2GHZ, 96 GROUP_OWNER_BAND_5GHZ 97 }) 98 @Retention(RetentionPolicy.SOURCE) 99 public @interface GroupOperatingBandType {} 100 101 /** 102 * IP provisioning via IPv4 DHCP, when joining a group as a group client. 103 */ 104 public static final int GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP = 0; 105 106 /** 107 * IP provisioning via IPv6 link-local, when joining a group as a group client. 108 */ 109 public static final int GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL = 1; 110 111 /** 112 * Allow the system to pick the operating frequency from all supported bands. 113 */ 114 public static final int GROUP_OWNER_BAND_AUTO = 0; 115 /** 116 * Allow the system to pick the operating frequency from the 2.4 GHz band. 117 */ 118 public static final int GROUP_OWNER_BAND_2GHZ = 1; 119 /** 120 * Allow the system to pick the operating frequency from the 5 GHz band. 121 */ 122 public static final int GROUP_OWNER_BAND_5GHZ = 2; 123 124 /** 125 * The least inclination to be a group owner, to be filled in the field 126 * {@link #groupOwnerIntent}. 127 */ 128 public static final int GROUP_OWNER_INTENT_MIN = 0; 129 130 /** 131 * The most inclination to be a group owner, to be filled in the field 132 * {@link #groupOwnerIntent}. 133 */ 134 public static final int GROUP_OWNER_INTENT_MAX = 15; 135 136 /** 137 * The system can choose an appropriate owner intent value, to be filled in the field 138 * {@link #groupOwnerIntent}. 139 */ 140 public static final int GROUP_OWNER_INTENT_AUTO = -1; 141 142 /** 143 * This is an integer value between {@link #GROUP_OWNER_INTENT_MIN} and 144 * {@link #GROUP_OWNER_INTENT_MAX} where 145 * {@link #GROUP_OWNER_INTENT_MIN} indicates the least inclination to be a group owner and 146 * {@link #GROUP_OWNER_INTENT_MAX} indicates the highest inclination to be a group owner. 147 * 148 * A value of {@link #GROUP_OWNER_INTENT_AUTO} indicates the system can choose an appropriate 149 * value. 150 * 151 * By default this field is set to {@link #GROUP_OWNER_INTENT_AUTO}. 152 */ 153 @IntRange(from = 0, to = 15) 154 public int groupOwnerIntent = GROUP_OWNER_INTENT_AUTO; 155 156 /** @hide */ 157 @IntDef(prefix = { "GROUP_CLIENT_IP_PROVISIONING_MODE_" }, value = { 158 GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP, 159 GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL 160 }) 161 @Retention(RetentionPolicy.SOURCE) 162 public @interface GroupClientIpProvisioningMode {} 163 164 @GroupClientIpProvisioningMode 165 private int mGroupClientIpProvisioningMode = GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP; 166 167 /** 168 * Query whether or not join existing group is enabled/disabled. 169 * @see #setJoinExistingGroup(boolean) 170 * 171 * @return true if configured to trigger the join existing group logic. False otherwise. 172 * @hide 173 */ 174 @SystemApi isJoinExistingGroup()175 public boolean isJoinExistingGroup() { 176 return mJoinExistingGroup; 177 } 178 179 /** 180 * Join an existing group as a client. 181 */ 182 private boolean mJoinExistingGroup = false; 183 184 /** @hide */ 185 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 186 public int netId = WifiP2pGroup.NETWORK_ID_PERSISTENT; 187 188 /** 189 * Get the network ID of this P2P configuration. 190 * @return either a non-negative network ID, or one of 191 * {@link WifiP2pGroup#NETWORK_ID_PERSISTENT} or {@link WifiP2pGroup#NETWORK_ID_TEMPORARY}. 192 */ getNetworkId()193 public int getNetworkId() { 194 return netId; 195 } 196 WifiP2pConfig()197 public WifiP2pConfig() { 198 //set defaults 199 wps = new WpsInfo(); 200 wps.setup = WpsInfo.PBC; 201 } 202 203 /** @hide */ invalidate()204 public void invalidate() { 205 deviceAddress = ""; 206 } 207 208 /** P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 {@hide}*/ 209 @UnsupportedAppUsage WifiP2pConfig(String supplicantEvent)210 public WifiP2pConfig(String supplicantEvent) throws IllegalArgumentException { 211 String[] tokens = supplicantEvent.split(" "); 212 213 if (tokens.length < 2 || !tokens[0].equals("P2P-GO-NEG-REQUEST")) { 214 throw new IllegalArgumentException("Malformed supplicant event"); 215 } 216 217 deviceAddress = tokens[1]; 218 wps = new WpsInfo(); 219 220 if (tokens.length > 2) { 221 String[] nameVal = tokens[2].split("="); 222 int devPasswdId; 223 try { 224 devPasswdId = Integer.parseInt(nameVal[1]); 225 } catch (NumberFormatException e) { 226 devPasswdId = 0; 227 } 228 //Based on definitions in wps/wps_defs.h 229 switch (devPasswdId) { 230 //DEV_PW_USER_SPECIFIED = 0x0001, 231 case 0x01: 232 wps.setup = WpsInfo.DISPLAY; 233 break; 234 //DEV_PW_PUSHBUTTON = 0x0004, 235 case 0x04: 236 wps.setup = WpsInfo.PBC; 237 break; 238 //DEV_PW_REGISTRAR_SPECIFIED = 0x0005 239 case 0x05: 240 wps.setup = WpsInfo.KEYPAD; 241 break; 242 default: 243 wps.setup = WpsInfo.PBC; 244 break; 245 } 246 } 247 } 248 249 /** 250 * Get the IP provisioning mode when joining a group as a group client. 251 * The result will be one of the following: 252 * {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP}, 253 * {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL} 254 */ 255 @GroupClientIpProvisioningMode getGroupClientIpProvisioningMode()256 public int getGroupClientIpProvisioningMode() { 257 return mGroupClientIpProvisioningMode; 258 } 259 toString()260 public String toString() { 261 StringBuffer sbuf = new StringBuffer(); 262 sbuf.append("\n address: ").append(deviceAddress); 263 sbuf.append("\n wps: ").append(wps); 264 sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent); 265 sbuf.append("\n persist: ").append(netId); 266 sbuf.append("\n networkName: ").append(networkName); 267 sbuf.append("\n passphrase: ").append( 268 TextUtils.isEmpty(passphrase) ? "<empty>" : "<non-empty>"); 269 sbuf.append("\n groupOwnerBand: ").append(groupOwnerBand); 270 sbuf.append("\n groupClientIpProvisioningMode: ").append(mGroupClientIpProvisioningMode); 271 sbuf.append("\n joinExistingGroup: ").append(mJoinExistingGroup); 272 return sbuf.toString(); 273 } 274 275 /** Implement the Parcelable interface */ describeContents()276 public int describeContents() { 277 return 0; 278 } 279 280 /** copy constructor */ WifiP2pConfig(WifiP2pConfig source)281 public WifiP2pConfig(WifiP2pConfig source) { 282 if (source != null) { 283 deviceAddress = source.deviceAddress; 284 wps = new WpsInfo(source.wps); 285 groupOwnerIntent = source.groupOwnerIntent; 286 netId = source.netId; 287 networkName = source.networkName; 288 passphrase = source.passphrase; 289 groupOwnerBand = source.groupOwnerBand; 290 mGroupClientIpProvisioningMode = source.mGroupClientIpProvisioningMode; 291 mJoinExistingGroup = source.mJoinExistingGroup; 292 } 293 } 294 295 /** Implement the Parcelable interface */ writeToParcel(Parcel dest, int flags)296 public void writeToParcel(Parcel dest, int flags) { 297 dest.writeString(deviceAddress); 298 dest.writeParcelable(wps, flags); 299 dest.writeInt(groupOwnerIntent); 300 dest.writeInt(netId); 301 dest.writeString(networkName); 302 dest.writeString(passphrase); 303 dest.writeInt(groupOwnerBand); 304 dest.writeInt(mGroupClientIpProvisioningMode); 305 dest.writeBoolean(mJoinExistingGroup); 306 } 307 308 /** Implement the Parcelable interface */ 309 @NonNull 310 public static final Creator<WifiP2pConfig> CREATOR = 311 new Creator<WifiP2pConfig>() { 312 public WifiP2pConfig createFromParcel(Parcel in) { 313 WifiP2pConfig config = new WifiP2pConfig(); 314 config.deviceAddress = in.readString(); 315 config.wps = (WpsInfo) in.readParcelable(null); 316 config.groupOwnerIntent = in.readInt(); 317 config.netId = in.readInt(); 318 config.networkName = in.readString(); 319 config.passphrase = in.readString(); 320 config.groupOwnerBand = in.readInt(); 321 config.mGroupClientIpProvisioningMode = in.readInt(); 322 config.mJoinExistingGroup = in.readBoolean(); 323 return config; 324 } 325 326 public WifiP2pConfig[] newArray(int size) { 327 return new WifiP2pConfig[size]; 328 } 329 }; 330 331 /** 332 * Builder used to build {@link WifiP2pConfig} objects for 333 * creating or joining a group. 334 * 335 * The WifiP2pConfig can be constructed for two use-cases: 336 * <ul> 337 * <li>SSID + Passphrase are known: use {@link #setNetworkName(String)} and 338 * {@link #setPassphrase(String)}.</li> 339 * <li>SSID or Passphrase is unknown, in such a case the MAC address must be known and 340 * specified using {@link #setDeviceAddress(MacAddress)}.</li> 341 * </ul> 342 */ 343 public static final class Builder { 344 345 private static final MacAddress MAC_ANY_ADDRESS = 346 MacAddress.fromString("02:00:00:00:00:00"); 347 /** 348 * Maximum number of bytes allowed for a SSID. 349 */ 350 private static final int MAX_SSID_BYTES = 32; 351 352 private MacAddress mDeviceAddress = MAC_ANY_ADDRESS; 353 private String mNetworkName = ""; 354 private String mPassphrase = ""; 355 private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO; 356 private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO; 357 private int mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY; 358 private int mGroupClientIpProvisioningMode = GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP; 359 private boolean mJoinExistingGroup = false; 360 361 /** 362 * Specify the peer's MAC address. If not set, the device will 363 * try to find a peer whose SSID matches the network name as 364 * specified by {@link #setNetworkName(String)}. Specifying null will 365 * reset the peer's MAC address to "02:00:00:00:00:00". 366 * <p> 367 * Optional. "02:00:00:00:00:00" by default. 368 * 369 * <p> If the network name is not set, the peer's MAC address is mandatory. 370 * 371 * @param deviceAddress the peer's MAC address. 372 * @return The builder to facilitate chaining 373 * {@code builder.setXXX(..).setXXX(..)}. 374 */ 375 @NonNull setDeviceAddress(@ullable MacAddress deviceAddress)376 public Builder setDeviceAddress(@Nullable MacAddress deviceAddress) { 377 if (deviceAddress == null) { 378 mDeviceAddress = MAC_ANY_ADDRESS; 379 } else { 380 mDeviceAddress = deviceAddress; 381 } 382 return this; 383 } 384 385 /** 386 * Specify the network name, a.k.a. group name, 387 * for creating or joining a group. 388 * <p> 389 * A network name shall begin with "DIRECT-xy". x and y are selected 390 * from the following character set: upper case letters, lower case 391 * letters and numbers. Any byte values allowed for an SSID according to 392 * IEEE802.11-2012 [1] may be included after the string "DIRECT-xy" 393 * (including none). 394 * <p> 395 * Must be called - an empty network name or an network name 396 * not conforming to the P2P Group ID naming rule is not valid. 397 * 398 * @param networkName network name of a group. 399 * @return The builder to facilitate chaining 400 * {@code builder.setXXX(..).setXXX(..)}. 401 */ 402 @NonNull setNetworkName(@onNull String networkName)403 public Builder setNetworkName(@NonNull String networkName) { 404 if (TextUtils.isEmpty(networkName)) { 405 throw new IllegalArgumentException( 406 "network name must be non-empty."); 407 } 408 if (networkName.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) { 409 throw new IllegalArgumentException( 410 "network name exceeds " + MAX_SSID_BYTES + " bytes."); 411 } 412 try { 413 if (!networkName.matches("^DIRECT-[a-zA-Z0-9]{2}.*")) { 414 throw new IllegalArgumentException( 415 "network name must starts with the prefix DIRECT-xy."); 416 } 417 } catch (PatternSyntaxException e) { 418 // can never happen (fixed pattern) 419 } 420 mNetworkName = networkName; 421 return this; 422 } 423 424 /** 425 * Specify the passphrase for creating or joining a group. 426 * <p> 427 * The passphrase must be an ASCII string whose length is between 8 428 * and 63. 429 * <p> 430 * Must be called - an empty passphrase is not valid. 431 * 432 * @param passphrase the passphrase of a group. 433 * @return The builder to facilitate chaining 434 * {@code builder.setXXX(..).setXXX(..)}. 435 */ 436 @NonNull setPassphrase(@onNull String passphrase)437 public Builder setPassphrase(@NonNull String passphrase) { 438 if (TextUtils.isEmpty(passphrase)) { 439 throw new IllegalArgumentException( 440 "passphrase must be non-empty."); 441 } 442 if (passphrase.length() < 8 || passphrase.length() > 63) { 443 throw new IllegalArgumentException( 444 "The length of a passphrase must be between 8 and 63."); 445 } 446 mPassphrase = passphrase; 447 return this; 448 } 449 450 /** 451 * Specify the band to use for creating the group or joining the group. The band should 452 * be {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ} or 453 * {@link #GROUP_OWNER_BAND_AUTO}. 454 * <p> 455 * When creating a group as Group Owner using {@link 456 * WifiP2pManager#createGroup(WifiP2pManager.Channel, 457 * WifiP2pConfig, WifiP2pManager.ActionListener)}, 458 * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to pick the operating 459 * frequency from all supported bands. 460 * Specifying {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ} 461 * only allows the system to pick the operating frequency in the specified band. 462 * If the Group Owner cannot create a group in the specified band, the operation will fail. 463 * <p> 464 * When joining a group as Group Client using {@link 465 * WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig, 466 * WifiP2pManager.ActionListener)}, 467 * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to scan all supported 468 * frequencies to find the desired group. Specifying {@link #GROUP_OWNER_BAND_2GHZ} or 469 * {@link #GROUP_OWNER_BAND_5GHZ} only allows the system to scan the specified band. 470 * <p> 471 * {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are 472 * mutually exclusive. Setting operating band and frequency both is invalid. 473 * <p> 474 * Optional. {@link #GROUP_OWNER_BAND_AUTO} by default. 475 * 476 * @param band the operating band of the group. 477 * This should be one of {@link #GROUP_OWNER_BAND_AUTO}, 478 * {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ}. 479 * @return The builder to facilitate chaining 480 * {@code builder.setXXX(..).setXXX(..)}. 481 */ 482 @NonNull setGroupOperatingBand(@roupOperatingBandType int band)483 public Builder setGroupOperatingBand(@GroupOperatingBandType int band) { 484 switch (band) { 485 case GROUP_OWNER_BAND_AUTO: 486 case GROUP_OWNER_BAND_2GHZ: 487 case GROUP_OWNER_BAND_5GHZ: 488 mGroupOperatingBand = band; 489 break; 490 default: 491 throw new IllegalArgumentException( 492 "Invalid constant for the group operating band!"); 493 } 494 return this; 495 } 496 497 /** 498 * Specify the frequency, in MHz, to use for creating the group or joining the group. 499 * <p> 500 * When creating a group as Group Owner using {@link WifiP2pManager#createGroup( 501 * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)}, 502 * specifying a frequency only allows the system to pick the specified frequency. 503 * If the Group Owner cannot create a group at the specified frequency, 504 * the operation will fail. 505 * When not specifying a frequency, it allows the system to pick operating frequency 506 * from all supported bands. 507 * <p> 508 * When joining a group as Group Client using {@link WifiP2pManager#connect( 509 * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)}, 510 * specifying a frequency only allows the system to scan the specified frequency. 511 * If the frequency is not supported or invalid, the operation will fail. 512 * When not specifying a frequency, it allows the system to scan all supported 513 * frequencies to find the desired group. 514 * <p> 515 * {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are 516 * mutually exclusive. Setting operating band and frequency both is invalid. 517 * <p> 518 * Optional. 0 by default. 519 * 520 * @param frequency the operating frequency of the group. 521 * @return The builder to facilitate chaining 522 * {@code builder.setXXX(..).setXXX(..)}. 523 */ 524 @NonNull setGroupOperatingFrequency(int frequency)525 public Builder setGroupOperatingFrequency(int frequency) { 526 if (frequency < 0) { 527 throw new IllegalArgumentException( 528 "Invalid group operating frequency!"); 529 } 530 mGroupOperatingFrequency = frequency; 531 return this; 532 } 533 534 /** 535 * Specify that the group configuration be persisted (i.e. saved). 536 * By default the group configuration will not be saved. 537 * <p> 538 * Optional. false by default. 539 * 540 * @param persistent is this group persistent group. 541 * @return The builder to facilitate chaining 542 * {@code builder.setXXX(..).setXXX(..)}. 543 */ 544 @NonNull enablePersistentMode(boolean persistent)545 public Builder enablePersistentMode(boolean persistent) { 546 if (persistent) { 547 mNetId = WifiP2pGroup.NETWORK_ID_PERSISTENT; 548 } else { 549 mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY; 550 } 551 return this; 552 } 553 554 /** 555 * Specify the IP provisioning mode when joining a group as a group client. The IP 556 * provisioning mode should be {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP} or 557 * {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL}. 558 * <p> 559 * When joining a group as group client using {@link 560 * WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig, 561 * WifiP2pManager.ActionListener)}, 562 * specifying {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP} directs the system to 563 * assign a IPv4 to the group client using DHCP. Specifying 564 * {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL} directs the system to assign 565 * a link-local IPv6 to the group client. 566 * <p> 567 * Optional. {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP} by default. 568 * <p> 569 * 570 * If {@link WifiP2pManager#isGroupOwnerIPv6LinkLocalAddressProvided()} is {@code true} and 571 * {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL} is used then the system will 572 * discover the group owner's IPv6 link-local address and broadcast it using the 573 * {@link WifiP2pManager#EXTRA_WIFI_P2P_INFO} extra of the 574 * {@link WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION} broadcast. Otherwise, if 575 * {@link WifiP2pManager#isGroupOwnerIPv6LinkLocalAddressProvided()} is 576 * {@code false} then the group owner's IPv6 link-local address is not discovered and it is 577 * the responsibility of the caller to obtain it in some other way, e.g. via out-of-band 578 * communication. 579 * 580 * @param groupClientIpProvisioningMode the IP provisioning mode of the group client. 581 * This should be one of {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP}, 582 * {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL}. 583 * @return The builder to facilitate chaining 584 * {@code builder.setXXX(..).setXXX(..)}. 585 * @see WifiP2pManager#isGroupOwnerIPv6LinkLocalAddressProvided() 586 */ 587 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 588 @NonNull setGroupClientIpProvisioningMode( @roupClientIpProvisioningMode int groupClientIpProvisioningMode)589 public Builder setGroupClientIpProvisioningMode( 590 @GroupClientIpProvisioningMode int groupClientIpProvisioningMode) { 591 // Since group client IP provisioning modes use NetworkStack functionalities introduced 592 // in T, hence we need at least T sdk for this to be supported. 593 if (!SdkLevel.isAtLeastT()) { 594 throw new UnsupportedOperationException( 595 "IPv6 link-local provisioning not supported"); 596 } 597 switch (groupClientIpProvisioningMode) { 598 case GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP: 599 case GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL: 600 mGroupClientIpProvisioningMode = groupClientIpProvisioningMode; 601 break; 602 default: 603 throw new IllegalArgumentException( 604 "Invalid constant for the group client IP provisioning mode!"); 605 } 606 return this; 607 } 608 609 /** 610 * Specify that the device wants to join an existing group as client. 611 * Usually group owner sets the group owner capability bit in beacons/probe responses. But 612 * there are deployed devices which don't set the group owner capability bit. 613 * This API is for applications which can get the peer group owner capability via OOB 614 * (out of band) mechanisms and forcefully trigger the join existing group logic. 615 * <p> 616 * Optional. false by default. 617 * 618 * @param join true to forcefully trigger the join existing group logic, false to let 619 * device decide whether to join a group or form a group. 620 * @return The builder to facilitate chaining 621 * {@code builder.setXXX(..).setXXX(..)}. 622 * @hide 623 */ 624 @SystemApi 625 @NonNull setJoinExistingGroup(boolean join)626 public Builder setJoinExistingGroup(boolean join) { 627 mJoinExistingGroup = join; 628 return this; 629 } 630 631 /** 632 * Build {@link WifiP2pConfig} given the current requests made on the builder. 633 * @return {@link WifiP2pConfig} constructed based on builder method calls. 634 */ 635 @NonNull build()636 public WifiP2pConfig build() { 637 if ((TextUtils.isEmpty(mNetworkName) && !TextUtils.isEmpty(mPassphrase)) 638 || (!TextUtils.isEmpty(mNetworkName) && TextUtils.isEmpty(mPassphrase))) { 639 throw new IllegalStateException( 640 "network name and passphrase must be non-empty or empty both."); 641 } 642 if (TextUtils.isEmpty(mNetworkName) 643 && mDeviceAddress.equals(MAC_ANY_ADDRESS)) { 644 throw new IllegalStateException( 645 "peer address must be set if network name and pasphrase are not set."); 646 } 647 648 if (mGroupOperatingFrequency > 0 && mGroupOperatingBand > 0) { 649 throw new IllegalStateException( 650 "Preferred frequency and band are mutually exclusive."); 651 } 652 653 WifiP2pConfig config = new WifiP2pConfig(); 654 config.deviceAddress = mDeviceAddress.toString(); 655 config.networkName = mNetworkName; 656 config.passphrase = mPassphrase; 657 config.groupOwnerBand = GROUP_OWNER_BAND_AUTO; 658 if (mGroupOperatingFrequency > 0) { 659 config.groupOwnerBand = mGroupOperatingFrequency; 660 } else if (mGroupOperatingBand > 0) { 661 config.groupOwnerBand = mGroupOperatingBand; 662 } 663 config.netId = mNetId; 664 config.mGroupClientIpProvisioningMode = mGroupClientIpProvisioningMode; 665 config.mJoinExistingGroup = mJoinExistingGroup; 666 return config; 667 } 668 } 669 } 670