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