• 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.Nullable;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 /**
32  * A class representing a Wi-Fi P2p group. A p2p group consists of a single group
33  * owner and one or more clients. In the case of a group with only two devices, one
34  * will be the group owner and the other will be a group client.
35  *
36  * {@see WifiP2pManager}
37  */
38 public class WifiP2pGroup implements Parcelable {
39 
40     /**
41      * The temporary network id.
42      * @see #getNetworkId()
43      */
44     public static final int NETWORK_ID_TEMPORARY = -1;
45 
46     /**
47      * The temporary network id.
48      *
49      * @hide
50      */
51     @UnsupportedAppUsage
52     public static final int TEMPORARY_NET_ID = NETWORK_ID_TEMPORARY;
53 
54     /**
55      * The persistent network id.
56      * If a matching persistent profile is found, use it.
57      * Otherwise, create a new persistent profile.
58      * @see #getNetworkId()
59      */
60     public static final int NETWORK_ID_PERSISTENT = -2;
61 
62     /** The network name */
63     private String mNetworkName;
64 
65     /** Group owner */
66     private WifiP2pDevice mOwner;
67 
68     /** Device is group owner */
69     private boolean mIsGroupOwner;
70 
71     /** Group clients */
72     private List<WifiP2pDevice> mClients = new ArrayList<WifiP2pDevice>();
73 
74     /** The passphrase used for WPA2-PSK */
75     private String mPassphrase;
76 
77     private String mInterface;
78 
79     /** The network ID in wpa_supplicant */
80     private int mNetId;
81 
82     /** The frequency (in MHz) used by this group */
83     private int mFrequency;
84 
85     /** P2P group started string pattern */
86     private static final Pattern groupStartedPattern = Pattern.compile(
87         "ssid=\"(.+)\" " +
88         "freq=(\\d+) " +
89         "(?:psk=)?([0-9a-fA-F]{64})?" +
90         "(?:passphrase=)?(?:\"(.{0,63})\")? " +
91         "go_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})" +
92         " ?(\\[PERSISTENT\\])?"
93     );
94 
WifiP2pGroup()95     public WifiP2pGroup() {
96     }
97 
98     /**
99      * @param supplicantEvent formats supported include
100      *
101      *  P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
102      *  [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|
103      *  passphrase="fKG4jMe3"] go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT]
104      *
105      *  P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED
106      *
107      *  P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13
108      *  bssid=fa:7b:7a:42:82:13 unknown-network
109      *
110      *  P2P-INVITATION-RECEIVED sa=b8:f9:34:2a:c7:9d persistent=0
111      *
112      *  Note: The events formats can be looked up in the wpa_supplicant code
113      *  @hide
114      */
115     @UnsupportedAppUsage
WifiP2pGroup(String supplicantEvent)116     public WifiP2pGroup(String supplicantEvent) throws IllegalArgumentException {
117 
118         String[] tokens = supplicantEvent.split(" ");
119 
120         if (tokens.length < 3) {
121             throw new IllegalArgumentException("Malformed supplicant event");
122         }
123 
124         if (tokens[0].startsWith("P2P-GROUP")) {
125             mInterface = tokens[1];
126             mIsGroupOwner = tokens[2].equals("GO");
127 
128             Matcher match = groupStartedPattern.matcher(supplicantEvent);
129             if (!match.find()) {
130                 return;
131             }
132 
133             mNetworkName = match.group(1);
134             // It throws NumberFormatException if the string cannot be parsed as an integer.
135             mFrequency = Integer.parseInt(match.group(2));
136             // psk is unused right now
137             //String psk = match.group(3);
138             mPassphrase = match.group(4);
139             mOwner = new WifiP2pDevice(match.group(5));
140             if (match.group(6) != null) {
141                 mNetId = NETWORK_ID_PERSISTENT;
142             } else {
143                 mNetId = NETWORK_ID_TEMPORARY;
144             }
145         } else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
146             String sa = null;
147             mNetId = NETWORK_ID_PERSISTENT;
148             for (String token : tokens) {
149                 String[] nameValue = token.split("=");
150                 if (nameValue.length != 2) continue;
151 
152                 if (nameValue[0].equals("sa")) {
153                     sa = nameValue[1];
154 
155                     // set source address into the client list.
156                     WifiP2pDevice dev = new WifiP2pDevice();
157                     dev.deviceAddress = nameValue[1];
158                     mClients.add(dev);
159                     continue;
160                 }
161 
162                 if (nameValue[0].equals("go_dev_addr")) {
163                     mOwner = new WifiP2pDevice(nameValue[1]);
164                     continue;
165                 }
166 
167                 if (nameValue[0].equals("persistent")) {
168                     mNetId = Integer.parseInt(nameValue[1]);
169                     continue;
170                 }
171             }
172         } else {
173             throw new IllegalArgumentException("Malformed supplicant event");
174         }
175     }
176 
177     /** @hide */
setNetworkName(String networkName)178     public void setNetworkName(String networkName) {
179         mNetworkName = networkName;
180     }
181 
182     /**
183      * Get the network name (SSID) of the group. Legacy Wi-Fi clients will discover
184      * the p2p group using the network name.
185      */
getNetworkName()186     public String getNetworkName() {
187         return mNetworkName;
188     }
189 
190     /** @hide */
191     @UnsupportedAppUsage
setIsGroupOwner(boolean isGo)192     public void setIsGroupOwner(boolean isGo) {
193         mIsGroupOwner = isGo;
194     }
195 
196     /** Check whether this device is the group owner of the created p2p group */
isGroupOwner()197     public boolean isGroupOwner() {
198         return mIsGroupOwner;
199     }
200 
201     /** @hide */
setOwner(WifiP2pDevice device)202     public void setOwner(WifiP2pDevice device) {
203         mOwner = device;
204     }
205 
206     /** Get the details of the group owner as a {@link WifiP2pDevice} object */
getOwner()207     public WifiP2pDevice getOwner() {
208         return mOwner;
209     }
210 
211     /** @hide */
addClient(String address)212     public void addClient(String address) {
213         addClient(new WifiP2pDevice(address));
214     }
215 
216     /** @hide */
addClient(WifiP2pDevice device)217     public void addClient(WifiP2pDevice device) {
218         for (WifiP2pDevice client : mClients) {
219             if (client.equals(device)) return;
220         }
221         mClients.add(device);
222     }
223 
224     /** @hide */
removeClient(String address)225     public boolean removeClient(String address) {
226         return mClients.remove(new WifiP2pDevice(address));
227     }
228 
229     /** @hide */
removeClient(WifiP2pDevice device)230     public boolean removeClient(WifiP2pDevice device) {
231         return mClients.remove(device);
232     }
233 
234     /** @hide */
235     @UnsupportedAppUsage
isClientListEmpty()236     public boolean isClientListEmpty() {
237         return mClients.size() == 0;
238     }
239 
240     /**
241      * Returns {@code true} if the device is part of the group, {@code false} otherwise.
242      *
243      * @hide
244      */
contains(@ullable WifiP2pDevice device)245     public boolean contains(@Nullable WifiP2pDevice device) {
246         return mOwner.equals(device) || mClients.contains(device);
247     }
248 
249     /** Get the list of clients currently part of the p2p group */
getClientList()250     public Collection<WifiP2pDevice> getClientList() {
251         return Collections.unmodifiableCollection(mClients);
252     }
253 
254     /** @hide */
setPassphrase(String passphrase)255     public void setPassphrase(String passphrase) {
256         mPassphrase = passphrase;
257     }
258 
259     /**
260      * Get the passphrase of the group. This function will return a valid passphrase only
261      * at the group owner. Legacy Wi-Fi clients will need this passphrase alongside
262      * network name obtained from {@link #getNetworkName()} to join the group
263      */
getPassphrase()264     public String getPassphrase() {
265         return mPassphrase;
266     }
267 
268     /** @hide */
269     @UnsupportedAppUsage
setInterface(String intf)270     public void setInterface(String intf) {
271         mInterface = intf;
272     }
273 
274     /** Get the interface name on which the group is created */
getInterface()275     public String getInterface() {
276         return mInterface;
277     }
278 
279     /** The network ID of the P2P group in wpa_supplicant. */
getNetworkId()280     public int getNetworkId() {
281         return mNetId;
282     }
283 
284     /** @hide */
285     @UnsupportedAppUsage
setNetworkId(int netId)286     public void setNetworkId(int netId) {
287         this.mNetId = netId;
288     }
289 
290     /** Get the operating frequency (in MHz) of the p2p group */
getFrequency()291     public int getFrequency() {
292         return mFrequency;
293     }
294 
295     /** @hide */
setFrequency(int freq)296     public void setFrequency(int freq) {
297         this.mFrequency = freq;
298     }
299 
toString()300     public String toString() {
301         StringBuffer sbuf = new StringBuffer();
302         sbuf.append("network: ").append(mNetworkName);
303         sbuf.append("\n isGO: ").append(mIsGroupOwner);
304         sbuf.append("\n GO: ").append(mOwner);
305         for (WifiP2pDevice client : mClients) {
306             sbuf.append("\n Client: ").append(client);
307         }
308         sbuf.append("\n interface: ").append(mInterface);
309         sbuf.append("\n networkId: ").append(mNetId);
310         sbuf.append("\n frequency: ").append(mFrequency);
311         return sbuf.toString();
312     }
313 
314     /** Implement the Parcelable interface */
describeContents()315     public int describeContents() {
316         return 0;
317     }
318 
319     /** copy constructor */
WifiP2pGroup(WifiP2pGroup source)320     public WifiP2pGroup(WifiP2pGroup source) {
321         if (source != null) {
322             mNetworkName = source.getNetworkName();
323             mOwner = new WifiP2pDevice(source.getOwner());
324             mIsGroupOwner = source.mIsGroupOwner;
325             for (WifiP2pDevice d : source.getClientList()) mClients.add(d);
326             mPassphrase = source.getPassphrase();
327             mInterface = source.getInterface();
328             mNetId = source.getNetworkId();
329             mFrequency = source.getFrequency();
330         }
331     }
332 
333     /** Implement the Parcelable interface */
writeToParcel(Parcel dest, int flags)334     public void writeToParcel(Parcel dest, int flags) {
335         dest.writeString(mNetworkName);
336         dest.writeParcelable(mOwner, flags);
337         dest.writeByte(mIsGroupOwner ? (byte) 1: (byte) 0);
338         dest.writeInt(mClients.size());
339         for (WifiP2pDevice client : mClients) {
340             dest.writeParcelable(client, flags);
341         }
342         dest.writeString(mPassphrase);
343         dest.writeString(mInterface);
344         dest.writeInt(mNetId);
345         dest.writeInt(mFrequency);
346     }
347 
348     /** Implement the Parcelable interface */
349     public static final @android.annotation.NonNull Creator<WifiP2pGroup> CREATOR =
350         new Creator<WifiP2pGroup>() {
351             public WifiP2pGroup createFromParcel(Parcel in) {
352                 WifiP2pGroup group = new WifiP2pGroup();
353                 group.setNetworkName(in.readString());
354                 group.setOwner((WifiP2pDevice)in.readParcelable(null));
355                 group.setIsGroupOwner(in.readByte() == (byte)1);
356                 int clientCount = in.readInt();
357                 for (int i=0; i<clientCount; i++) {
358                     group.addClient((WifiP2pDevice) in.readParcelable(null));
359                 }
360                 group.setPassphrase(in.readString());
361                 group.setInterface(in.readString());
362                 group.setNetworkId(in.readInt());
363                 group.setFrequency(in.readInt());
364                 return group;
365             }
366 
367             public WifiP2pGroup[] newArray(int size) {
368                 return new WifiP2pGroup[size];
369             }
370         };
371 }
372