• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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