WifiP2pDevice.java revision 1f6d8706918ddb277cad5fc8a006cc56ea7dbf69
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; 21import android.util.Log; 22 23import java.util.regex.Pattern; 24import java.util.regex.Matcher; 25 26/** 27 * A class representing a Wi-Fi p2p device 28 * 29 * {@see WifiP2pManager} 30 */ 31public class WifiP2pDevice implements Parcelable { 32 33 private static final String TAG = "WifiP2pDevice"; 34 35 /** 36 * The device name is a user friendly string to identify a Wi-Fi p2p device 37 */ 38 public String deviceName = ""; 39 40 /** 41 * The device MAC address uniquely identifies a Wi-Fi p2p device 42 */ 43 public String deviceAddress = ""; 44 45 /** 46 * Primary device type identifies the type of device. For example, an application 47 * could filter the devices discovered to only display printers if the purpose is to 48 * enable a printing action from the user. See the Wi-Fi Direct technical specification 49 * for the full list of standard device types supported. 50 */ 51 public String primaryDeviceType; 52 53 /** 54 * Secondary device type is an optional attribute that can be provided by a device in 55 * addition to the primary device type. 56 */ 57 public String secondaryDeviceType; 58 59 60 // These definitions match the ones in wpa_supplicant 61 /* WPS config methods supported */ 62 private static final int WPS_CONFIG_DISPLAY = 0x0008; 63 private static final int WPS_CONFIG_PUSHBUTTON = 0x0080; 64 private static final int WPS_CONFIG_KEYPAD = 0x0100; 65 66 /* Device Capability bitmap */ 67 private static final int DEVICE_CAPAB_SERVICE_DISCOVERY = 1; 68 private static final int DEVICE_CAPAB_CLIENT_DISCOVERABILITY = 1<<1; 69 private static final int DEVICE_CAPAB_CONCURRENT_OPER = 1<<2; 70 private static final int DEVICE_CAPAB_INFRA_MANAGED = 1<<3; 71 private static final int DEVICE_CAPAB_DEVICE_LIMIT = 1<<4; 72 private static final int DEVICE_CAPAB_INVITATION_PROCEDURE = 1<<5; 73 74 /* Group Capability bitmap */ 75 private static final int GROUP_CAPAB_GROUP_OWNER = 1; 76 private static final int GROUP_CAPAB_PERSISTENT_GROUP = 1<<1; 77 private static final int GROUP_CAPAB_GROUP_LIMIT = 1<<2; 78 private static final int GROUP_CAPAB_INTRA_BSS_DIST = 1<<3; 79 private static final int GROUP_CAPAB_CROSS_CONN = 1<<4; 80 private static final int GROUP_CAPAB_PERSISTENT_RECONN = 1<<5; 81 private static final int GROUP_CAPAB_GROUP_FORMATION = 1<<6; 82 83 /** 84 * WPS config methods supported 85 * @hide 86 */ 87 public int wpsConfigMethodsSupported; 88 89 /** 90 * Device capability 91 * @hide 92 */ 93 public int deviceCapability; 94 95 /** 96 * Group capability 97 * @hide 98 */ 99 public int groupCapability; 100 101 public static final int CONNECTED = 0; 102 public static final int INVITED = 1; 103 public static final int FAILED = 2; 104 public static final int AVAILABLE = 3; 105 public static final int UNAVAILABLE = 4; 106 107 /** Device connection status */ 108 public int status = UNAVAILABLE; 109 110 /** @hide */ 111 public WifiP2pWfdInfo wfdInfo; 112 113 /** Detailed device string pattern with WFD info 114 * Example: 115 * P2P-DEVICE-FOUND 00:18:6b:de:a3:6e p2p_dev_addr=00:18:6b:de:a3:6e 116 * pri_dev_type=1-0050F204-1 name='DWD-300-DEA36E' config_methods=0x188 117 * dev_capab=0x21 group_capab=0x9 118 */ 119 private static final Pattern detailedDevicePattern = Pattern.compile( 120 "((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) " + 121 "(\\d+ )?" + 122 "p2p_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) " + 123 "pri_dev_type=(\\d+-[0-9a-fA-F]+-\\d+) " + 124 "name='(.*)' " + 125 "config_methods=(0x[0-9a-fA-F]+) " + 126 "dev_capab=(0x[0-9a-fA-F]+) " + 127 "group_capab=(0x[0-9a-fA-F]+)" + 128 "( wfd_dev_info=000006([0-9a-fA-F]+))?" 129 ); 130 131 /** 2 token device address pattern 132 * Example: 133 * P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13 134 * AP-STA-DISCONNECTED 42:fc:89:a8:96:09 135 */ 136 private static final Pattern twoTokenPattern = Pattern.compile( 137 "(p2p_dev_addr=)?((?:[0-9a-f]{2}:){5}[0-9a-f]{2})" 138 ); 139 140 /** 3 token device address pattern 141 * Example: 142 * AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=fa:7b:7a:42:02:13 143 * AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=fa:7b:7a:42:02:13 144 */ 145 private static final Pattern threeTokenPattern = Pattern.compile( 146 "(?:[0-9a-f]{2}:){5}[0-9a-f]{2} p2p_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})" 147 ); 148 149 150 public WifiP2pDevice() { 151 } 152 153 /** 154 * @param string formats supported include 155 * P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13 156 * pri_dev_type=1-0050F204-1 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27 157 * group_capab=0x0 wfd_dev_info=000006015d022a0032 158 * 159 * P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13 160 * 161 * AP-STA-CONNECTED 42:fc:89:a8:96:09 [p2p_dev_addr=02:90:4c:a0:92:54] 162 * 163 * AP-STA-DISCONNECTED 42:fc:89:a8:96:09 [p2p_dev_addr=02:90:4c:a0:92:54] 164 * 165 * fa:7b:7a:42:02:13 166 * 167 * Note: The events formats can be looked up in the wpa_supplicant code 168 * @hide 169 */ 170 public WifiP2pDevice(String string) throws IllegalArgumentException { 171 String[] tokens = string.split("[ \n]"); 172 Matcher match; 173 174 if (tokens.length < 1) { 175 throw new IllegalArgumentException("Malformed supplicant event"); 176 } 177 178 switch (tokens.length) { 179 case 1: 180 /* Just a device address */ 181 deviceAddress = string; 182 return; 183 case 2: 184 match = twoTokenPattern.matcher(string); 185 if (!match.find()) { 186 throw new IllegalArgumentException("Malformed supplicant event"); 187 } 188 deviceAddress = match.group(2); 189 return; 190 case 3: 191 match = threeTokenPattern.matcher(string); 192 if (!match.find()) { 193 throw new IllegalArgumentException("Malformed supplicant event"); 194 } 195 deviceAddress = match.group(1); 196 return; 197 default: 198 match = detailedDevicePattern.matcher(string); 199 if (!match.find()) { 200 throw new IllegalArgumentException("Malformed supplicant event"); 201 } 202 203 deviceAddress = match.group(3); 204 primaryDeviceType = match.group(4); 205 deviceName = match.group(5); 206 wpsConfigMethodsSupported = parseHex(match.group(6)); 207 deviceCapability = parseHex(match.group(7)); 208 groupCapability = parseHex(match.group(8)); 209 if (match.group(9) != null) { 210 String str = match.group(10); 211 wfdInfo = new WifiP2pWfdInfo(parseHex(str.substring(0,4)), 212 parseHex(str.substring(4,8)), 213 parseHex(str.substring(8,12))); 214 } 215 break; 216 } 217 218 if (tokens[0].startsWith("P2P-DEVICE-FOUND")) { 219 status = AVAILABLE; 220 } 221 } 222 223 /** Returns true if WPS push button configuration is supported */ 224 public boolean wpsPbcSupported() { 225 return (wpsConfigMethodsSupported & WPS_CONFIG_PUSHBUTTON) != 0; 226 } 227 228 /** Returns true if WPS keypad configuration is supported */ 229 public boolean wpsKeypadSupported() { 230 return (wpsConfigMethodsSupported & WPS_CONFIG_KEYPAD) != 0; 231 } 232 233 /** Returns true if WPS display configuration is supported */ 234 public boolean wpsDisplaySupported() { 235 return (wpsConfigMethodsSupported & WPS_CONFIG_DISPLAY) != 0; 236 } 237 238 /** Returns true if the device is capable of service discovery */ 239 public boolean isServiceDiscoveryCapable() { 240 return (deviceCapability & DEVICE_CAPAB_SERVICE_DISCOVERY) != 0; 241 } 242 243 /** Returns true if the device is capable of invitation {@hide}*/ 244 public boolean isInvitationCapable() { 245 return (deviceCapability & DEVICE_CAPAB_INVITATION_PROCEDURE) != 0; 246 } 247 248 /** Returns true if the device reaches the limit. {@hide}*/ 249 public boolean isDeviceLimit() { 250 return (deviceCapability & DEVICE_CAPAB_DEVICE_LIMIT) != 0; 251 } 252 253 /** Returns true if the device is a group owner */ 254 public boolean isGroupOwner() { 255 return (groupCapability & GROUP_CAPAB_GROUP_OWNER) != 0; 256 } 257 258 /** Returns true if the group reaches the limit. {@hide}*/ 259 public boolean isGroupLimit() { 260 return (groupCapability & GROUP_CAPAB_GROUP_LIMIT) != 0; 261 } 262 263 @Override 264 public boolean equals(Object obj) { 265 if (this == obj) return true; 266 if (!(obj instanceof WifiP2pDevice)) return false; 267 268 WifiP2pDevice other = (WifiP2pDevice) obj; 269 if (other == null || other.deviceAddress == null) { 270 return (deviceAddress == null); 271 } 272 return other.deviceAddress.equals(deviceAddress); 273 } 274 275 public String toString() { 276 StringBuffer sbuf = new StringBuffer(); 277 sbuf.append("Device: ").append(deviceName); 278 sbuf.append("\n deviceAddress: ").append(deviceAddress); 279 sbuf.append("\n primary type: ").append(primaryDeviceType); 280 sbuf.append("\n secondary type: ").append(secondaryDeviceType); 281 sbuf.append("\n wps: ").append(wpsConfigMethodsSupported); 282 sbuf.append("\n grpcapab: ").append(groupCapability); 283 sbuf.append("\n devcapab: ").append(deviceCapability); 284 sbuf.append("\n status: ").append(status); 285 sbuf.append("\n wfdInfo: ").append(wfdInfo); 286 return sbuf.toString(); 287 } 288 289 /** Implement the Parcelable interface */ 290 public int describeContents() { 291 return 0; 292 } 293 294 /** copy constructor */ 295 public WifiP2pDevice(WifiP2pDevice source) { 296 if (source != null) { 297 deviceName = source.deviceName; 298 deviceAddress = source.deviceAddress; 299 primaryDeviceType = source.primaryDeviceType; 300 secondaryDeviceType = source.secondaryDeviceType; 301 wpsConfigMethodsSupported = source.wpsConfigMethodsSupported; 302 deviceCapability = source.deviceCapability; 303 groupCapability = source.groupCapability; 304 status = source.status; 305 wfdInfo = source.wfdInfo; 306 } 307 } 308 309 /** Implement the Parcelable interface */ 310 public void writeToParcel(Parcel dest, int flags) { 311 dest.writeString(deviceName); 312 dest.writeString(deviceAddress); 313 dest.writeString(primaryDeviceType); 314 dest.writeString(secondaryDeviceType); 315 dest.writeInt(wpsConfigMethodsSupported); 316 dest.writeInt(deviceCapability); 317 dest.writeInt(groupCapability); 318 dest.writeInt(status); 319 if (wfdInfo != null) { 320 dest.writeInt(1); 321 wfdInfo.writeToParcel(dest, flags); 322 } else { 323 dest.writeInt(0); 324 } 325 } 326 327 /** Implement the Parcelable interface */ 328 public static final Creator<WifiP2pDevice> CREATOR = 329 new Creator<WifiP2pDevice>() { 330 public WifiP2pDevice createFromParcel(Parcel in) { 331 WifiP2pDevice device = new WifiP2pDevice(); 332 device.deviceName = in.readString(); 333 device.deviceAddress = in.readString(); 334 device.primaryDeviceType = in.readString(); 335 device.secondaryDeviceType = in.readString(); 336 device.wpsConfigMethodsSupported = in.readInt(); 337 device.deviceCapability = in.readInt(); 338 device.groupCapability = in.readInt(); 339 device.status = in.readInt(); 340 if (in.readInt() == 1) { 341 device.wfdInfo = WifiP2pWfdInfo.CREATOR.createFromParcel(in); 342 } 343 return device; 344 } 345 346 public WifiP2pDevice[] newArray(int size) { 347 return new WifiP2pDevice[size]; 348 } 349 }; 350 351 //supported formats: 0x1abc, 0X1abc, 1abc 352 private int parseHex(String hexString) { 353 int num = 0; 354 if (hexString.startsWith("0x") || hexString.startsWith("0X")) { 355 hexString = hexString.substring(2); 356 } 357 358 try { 359 num = Integer.parseInt(hexString, 16); 360 } catch(NumberFormatException e) { 361 Log.e(TAG, "Failed to parse hex string " + hexString); 362 } 363 return num; 364 } 365} 366