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