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