• Home
  • History
  • Annotate
  • 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.compat.annotation.UnsupportedAppUsage;
24 import android.net.MacAddress;
25 import android.net.wifi.WpsInfo;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.text.TextUtils;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.nio.charset.StandardCharsets;
33 import java.util.regex.PatternSyntaxException;
34 
35 /**
36  * A class representing a Wi-Fi P2p configuration for setting up a connection
37  *
38  * {@see WifiP2pManager}
39  */
40 public class WifiP2pConfig implements Parcelable {
41 
42     /**
43      * The device MAC address uniquely identifies a Wi-Fi p2p device
44      */
45     public String deviceAddress = "";
46 
47     /**
48      * Wi-Fi Protected Setup information
49      */
50     public WpsInfo wps;
51 
52     /** Get the network name of this P2P configuration, or null if unset. */
53     @Nullable
getNetworkName()54     public String getNetworkName() {
55         return networkName;
56     }
57 
58     /** @hide */
59     public String networkName = "";
60 
61     /** Get the passphrase of this P2P configuration, or null if unset. */
62     @Nullable
getPassphrase()63     public String getPassphrase() {
64         return passphrase;
65     }
66 
67     /** @hide */
68     public String passphrase = "";
69 
70     /**
71      * Get the required band for the group owner.
72      * The result will be one of the following:
73      * {@link #GROUP_OWNER_BAND_AUTO},
74      * {@link #GROUP_OWNER_BAND_2GHZ},
75      * {@link #GROUP_OWNER_BAND_5GHZ}
76      */
77     @GroupOperatingBandType
getGroupOwnerBand()78     public int getGroupOwnerBand() {
79         return groupOwnerBand;
80     }
81 
82     /** @hide */
83     @GroupOperatingBandType
84     public int groupOwnerBand = GROUP_OWNER_BAND_AUTO;
85 
86     /** @hide */
87     @IntDef(flag = false, prefix = { "GROUP_OWNER_BAND_" }, value = {
88         GROUP_OWNER_BAND_AUTO,
89         GROUP_OWNER_BAND_2GHZ,
90         GROUP_OWNER_BAND_5GHZ
91     })
92     @Retention(RetentionPolicy.SOURCE)
93     public @interface GroupOperatingBandType {}
94 
95     /**
96      * Allow the system to pick the operating frequency from all supported bands.
97      */
98     public static final int GROUP_OWNER_BAND_AUTO = 0;
99     /**
100      * Allow the system to pick the operating frequency from the 2.4 GHz band.
101      */
102     public static final int GROUP_OWNER_BAND_2GHZ = 1;
103     /**
104      * Allow the system to pick the operating frequency from the 5 GHz band.
105      */
106     public static final int GROUP_OWNER_BAND_5GHZ = 2;
107 
108     /**
109      * The least inclination to be a group owner, to be filled in the field
110      * {@link #groupOwnerIntent}.
111      */
112     public static final int GROUP_OWNER_INTENT_MIN = 0;
113 
114     /**
115      * The most inclination to be a group owner, to be filled in the field
116      * {@link #groupOwnerIntent}.
117      */
118     public static final int GROUP_OWNER_INTENT_MAX = 15;
119 
120     /**
121      * The system can choose an appropriate owner intent value, to be filled in the field
122      * {@link #groupOwnerIntent}.
123      */
124     public static final int GROUP_OWNER_INTENT_AUTO = -1;
125 
126     /**
127      * This is an integer value between {@link #GROUP_OWNER_INTENT_MIN} and
128      * {@link #GROUP_OWNER_INTENT_MAX} where
129      * {@link #GROUP_OWNER_INTENT_MIN} indicates the least inclination to be a group owner and
130      * {@link #GROUP_OWNER_INTENT_MAX} indicates the highest inclination to be a group owner.
131      *
132      * A value of {@link #GROUP_OWNER_INTENT_AUTO} indicates the system can choose an appropriate
133      * value.
134      *
135      * By default this field is set to {@link #GROUP_OWNER_INTENT_AUTO}.
136      */
137     @IntRange(from = 0, to = 15)
138     public int groupOwnerIntent = GROUP_OWNER_INTENT_AUTO;
139 
140     /** @hide */
141     @UnsupportedAppUsage
142     public int netId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
143 
144     /**
145      * Get the network ID of this P2P configuration.
146      * @return either a non-negative network ID, or one of
147      * {@link WifiP2pGroup#NETWORK_ID_PERSISTENT} or {@link WifiP2pGroup#NETWORK_ID_TEMPORARY}.
148      */
getNetworkId()149     public int getNetworkId() {
150         return netId;
151     }
152 
WifiP2pConfig()153     public WifiP2pConfig() {
154         //set defaults
155         wps = new WpsInfo();
156         wps.setup = WpsInfo.PBC;
157     }
158 
159     /** @hide */
invalidate()160     public void invalidate() {
161         deviceAddress = "";
162     }
163 
164     /** P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 {@hide}*/
165     @UnsupportedAppUsage
WifiP2pConfig(String supplicantEvent)166     public WifiP2pConfig(String supplicantEvent) throws IllegalArgumentException {
167         String[] tokens = supplicantEvent.split(" ");
168 
169         if (tokens.length < 2 || !tokens[0].equals("P2P-GO-NEG-REQUEST")) {
170             throw new IllegalArgumentException("Malformed supplicant event");
171         }
172 
173         deviceAddress = tokens[1];
174         wps = new WpsInfo();
175 
176         if (tokens.length > 2) {
177             String[] nameVal = tokens[2].split("=");
178             int devPasswdId;
179             try {
180                 devPasswdId = Integer.parseInt(nameVal[1]);
181             } catch (NumberFormatException e) {
182                 devPasswdId = 0;
183             }
184             //Based on definitions in wps/wps_defs.h
185             switch (devPasswdId) {
186                 //DEV_PW_USER_SPECIFIED = 0x0001,
187                 case 0x01:
188                     wps.setup = WpsInfo.DISPLAY;
189                     break;
190                 //DEV_PW_PUSHBUTTON = 0x0004,
191                 case 0x04:
192                     wps.setup = WpsInfo.PBC;
193                     break;
194                 //DEV_PW_REGISTRAR_SPECIFIED = 0x0005
195                 case 0x05:
196                     wps.setup = WpsInfo.KEYPAD;
197                     break;
198                 default:
199                     wps.setup = WpsInfo.PBC;
200                     break;
201             }
202         }
203     }
204 
toString()205     public String toString() {
206         StringBuffer sbuf = new StringBuffer();
207         sbuf.append("\n address: ").append(deviceAddress);
208         sbuf.append("\n wps: ").append(wps);
209         sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent);
210         sbuf.append("\n persist: ").append(netId);
211         sbuf.append("\n networkName: ").append(networkName);
212         sbuf.append("\n passphrase: ").append(
213                 TextUtils.isEmpty(passphrase) ? "<empty>" : "<non-empty>");
214         sbuf.append("\n groupOwnerBand: ").append(groupOwnerBand);
215         return sbuf.toString();
216     }
217 
218     /** Implement the Parcelable interface */
describeContents()219     public int describeContents() {
220         return 0;
221     }
222 
223     /** copy constructor */
WifiP2pConfig(WifiP2pConfig source)224     public WifiP2pConfig(WifiP2pConfig source) {
225         if (source != null) {
226             deviceAddress = source.deviceAddress;
227             wps = new WpsInfo(source.wps);
228             groupOwnerIntent = source.groupOwnerIntent;
229             netId = source.netId;
230             networkName = source.networkName;
231             passphrase = source.passphrase;
232             groupOwnerBand = source.groupOwnerBand;
233         }
234     }
235 
236     /** Implement the Parcelable interface */
writeToParcel(Parcel dest, int flags)237     public void writeToParcel(Parcel dest, int flags) {
238         dest.writeString(deviceAddress);
239         dest.writeParcelable(wps, flags);
240         dest.writeInt(groupOwnerIntent);
241         dest.writeInt(netId);
242         dest.writeString(networkName);
243         dest.writeString(passphrase);
244         dest.writeInt(groupOwnerBand);
245     }
246 
247     /** Implement the Parcelable interface */
248     public static final @android.annotation.NonNull Creator<WifiP2pConfig> CREATOR =
249         new Creator<WifiP2pConfig>() {
250             public WifiP2pConfig createFromParcel(Parcel in) {
251                 WifiP2pConfig config = new WifiP2pConfig();
252                 config.deviceAddress = in.readString();
253                 config.wps = (WpsInfo) in.readParcelable(null);
254                 config.groupOwnerIntent = in.readInt();
255                 config.netId = in.readInt();
256                 config.networkName = in.readString();
257                 config.passphrase = in.readString();
258                 config.groupOwnerBand = in.readInt();
259                 return config;
260             }
261 
262             public WifiP2pConfig[] newArray(int size) {
263                 return new WifiP2pConfig[size];
264             }
265         };
266 
267     /**
268      * Builder used to build {@link WifiP2pConfig} objects for
269      * creating or joining a group.
270      */
271     public static final class Builder {
272 
273         private static final MacAddress MAC_ANY_ADDRESS =
274                 MacAddress.fromString("02:00:00:00:00:00");
275         /**
276          * Maximum number of bytes allowed for a SSID.
277          */
278         private static final int MAX_SSID_BYTES = 32;
279 
280         private MacAddress mDeviceAddress = MAC_ANY_ADDRESS;
281         private String mNetworkName = "";
282         private String mPassphrase = "";
283         private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
284         private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
285         private int mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
286 
287         /**
288          * Specify the peer's MAC address. If not set, the device will
289          * try to find a peer whose SSID matches the network name as
290          * specified by {@link #setNetworkName(String)}. Specifying null will
291          * reset the peer's MAC address to "02:00:00:00:00:00".
292          * <p>
293          *     Optional. "02:00:00:00:00:00" by default.
294          *
295          * @param deviceAddress the peer's MAC address.
296          * @return The builder to facilitate chaining
297          *         {@code builder.setXXX(..).setXXX(..)}.
298          */
setDeviceAddress(@ullable MacAddress deviceAddress)299         public @NonNull Builder setDeviceAddress(@Nullable MacAddress deviceAddress) {
300             if (deviceAddress == null) {
301                 mDeviceAddress = MAC_ANY_ADDRESS;
302             } else {
303                 mDeviceAddress = deviceAddress;
304             }
305             return this;
306         }
307 
308         /**
309          * Specify the network name, a.k.a. group name,
310          * for creating or joining a group.
311          * <p>
312          * A network name shall begin with "DIRECT-xy". x and y are selected
313          * from the following character set: upper case letters, lower case
314          * letters and numbers. Any byte values allowed for an SSID according to
315          * IEEE802.11-2012 [1] may be included after the string "DIRECT-xy"
316          * (including none).
317          * <p>
318          *     Must be called - an empty network name or an network name
319          *     not conforming to the P2P Group ID naming rule is not valid.
320          *
321          * @param networkName network name of a group.
322          * @return The builder to facilitate chaining
323          *         {@code builder.setXXX(..).setXXX(..)}.
324          */
setNetworkName(@onNull String networkName)325         public @NonNull Builder setNetworkName(@NonNull String networkName) {
326             if (TextUtils.isEmpty(networkName)) {
327                 throw new IllegalArgumentException(
328                         "network name must be non-empty.");
329             }
330             if (networkName.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
331                 throw new IllegalArgumentException(
332                         "network name exceeds " + MAX_SSID_BYTES + " bytes.");
333             }
334             try {
335                 if (!networkName.matches("^DIRECT-[a-zA-Z0-9]{2}.*")) {
336                     throw new IllegalArgumentException(
337                             "network name must starts with the prefix DIRECT-xy.");
338                 }
339             } catch (PatternSyntaxException e) {
340                 // can never happen (fixed pattern)
341             }
342             mNetworkName = networkName;
343             return this;
344         }
345 
346         /**
347          * Specify the passphrase for creating or joining a group.
348          * <p>
349          * The passphrase must be an ASCII string whose length is between 8
350          * and 63.
351          * <p>
352          *     Must be called - an empty passphrase is not valid.
353          *
354          * @param passphrase the passphrase of a group.
355          * @return The builder to facilitate chaining
356          *         {@code builder.setXXX(..).setXXX(..)}.
357          */
setPassphrase(@onNull String passphrase)358         public @NonNull Builder setPassphrase(@NonNull String passphrase) {
359             if (TextUtils.isEmpty(passphrase)) {
360                 throw new IllegalArgumentException(
361                         "passphrase must be non-empty.");
362             }
363             if (passphrase.length() < 8 || passphrase.length() > 63) {
364                 throw new IllegalArgumentException(
365                         "The length of a passphrase must be between 8 and 63.");
366             }
367             mPassphrase = passphrase;
368             return this;
369         }
370 
371         /**
372          * Specify the band to use for creating the group or joining the group. The band should
373          * be {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ} or
374          * {@link #GROUP_OWNER_BAND_AUTO}.
375          * <p>
376          * When creating a group as Group Owner using {@link
377          * WifiP2pManager#createGroup(WifiP2pManager.Channel,
378          * WifiP2pConfig, WifiP2pManager.ActionListener)},
379          * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to pick the operating
380          * frequency from all supported bands.
381          * Specifying {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ}
382          * only allows the system to pick the operating frequency in the specified band.
383          * If the Group Owner cannot create a group in the specified band, the operation will fail.
384          * <p>
385          * When joining a group as Group Client using {@link
386          * WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
387          * WifiP2pManager.ActionListener)},
388          * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to scan all supported
389          * frequencies to find the desired group. Specifying {@link #GROUP_OWNER_BAND_2GHZ} or
390          * {@link #GROUP_OWNER_BAND_5GHZ} only allows the system to scan the specified band.
391          * <p>
392          *     {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
393          *     mutually exclusive. Setting operating band and frequency both is invalid.
394          * <p>
395          *     Optional. {@link #GROUP_OWNER_BAND_AUTO} by default.
396          *
397          * @param band the operating band of the group.
398          *             This should be one of {@link #GROUP_OWNER_BAND_AUTO},
399          *             {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ}.
400          * @return The builder to facilitate chaining
401          *         {@code builder.setXXX(..).setXXX(..)}.
402          */
setGroupOperatingBand(@roupOperatingBandType int band)403         public @NonNull Builder setGroupOperatingBand(@GroupOperatingBandType int band) {
404             switch (band) {
405                 case GROUP_OWNER_BAND_AUTO:
406                 case GROUP_OWNER_BAND_2GHZ:
407                 case GROUP_OWNER_BAND_5GHZ:
408                     mGroupOperatingBand = band;
409                     break;
410                 default:
411                     throw new IllegalArgumentException(
412                         "Invalid constant for the group operating band!");
413             }
414             return this;
415         }
416 
417         /**
418          * Specify the frequency, in MHz, to use for creating the group or joining the group.
419          * <p>
420          * When creating a group as Group Owner using {@link WifiP2pManager#createGroup(
421          * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
422          * specifying a frequency only allows the system to pick the specified frequency.
423          * If the Group Owner cannot create a group at the specified frequency,
424          * the operation will fail.
425          * When not specifying a frequency, it allows the system to pick operating frequency
426          * from all supported bands.
427          * <p>
428          * When joining a group as Group Client using {@link WifiP2pManager#connect(
429          * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
430          * specifying a frequency only allows the system to scan the specified frequency.
431          * If the frequency is not supported or invalid, the operation will fail.
432          * When not specifying a frequency, it allows the system to scan all supported
433          * frequencies to find the desired group.
434          * <p>
435          *     {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
436          *     mutually exclusive. Setting operating band and frequency both is invalid.
437          * <p>
438          *     Optional. 0 by default.
439          *
440          * @param frequency the operating frequency of the group.
441          * @return The builder to facilitate chaining
442          *         {@code builder.setXXX(..).setXXX(..)}.
443          */
setGroupOperatingFrequency(int frequency)444         public @NonNull Builder setGroupOperatingFrequency(int frequency) {
445             if (frequency < 0) {
446                 throw new IllegalArgumentException(
447                     "Invalid group operating frequency!");
448             }
449             mGroupOperatingFrequency = frequency;
450             return this;
451         }
452 
453         /**
454          * Specify that the group configuration be persisted (i.e. saved).
455          * By default the group configuration will not be saved.
456          * <p>
457          *     Optional. false by default.
458          *
459          * @param persistent is this group persistent group.
460          * @return The builder to facilitate chaining
461          *         {@code builder.setXXX(..).setXXX(..)}.
462          */
enablePersistentMode(boolean persistent)463         public @NonNull Builder enablePersistentMode(boolean persistent) {
464             if (persistent) {
465                 mNetId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
466             } else {
467                 mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
468             }
469             return this;
470         }
471 
472         /**
473          * Build {@link WifiP2pConfig} given the current requests made on the builder.
474          * @return {@link WifiP2pConfig} constructed based on builder method calls.
475          */
build()476         public @NonNull WifiP2pConfig build() {
477             if (TextUtils.isEmpty(mNetworkName)) {
478                 throw new IllegalStateException(
479                         "network name must be non-empty.");
480             }
481             if (TextUtils.isEmpty(mPassphrase)) {
482                 throw new IllegalStateException(
483                         "passphrase must be non-empty.");
484             }
485 
486             if (mGroupOperatingFrequency > 0 && mGroupOperatingBand > 0) {
487                 throw new IllegalStateException(
488                         "Preferred frequency and band are mutually exclusive.");
489             }
490 
491             WifiP2pConfig config = new WifiP2pConfig();
492             config.deviceAddress = mDeviceAddress.toString();
493             config.networkName = mNetworkName;
494             config.passphrase = mPassphrase;
495             config.groupOwnerBand = GROUP_OWNER_BAND_AUTO;
496             if (mGroupOperatingFrequency > 0) {
497                 config.groupOwnerBand = mGroupOperatingFrequency;
498             } else if (mGroupOperatingBand > 0) {
499                 config.groupOwnerBand = mGroupOperatingBand;
500             }
501             config.netId = mNetId;
502             return config;
503         }
504     }
505 }
506