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