WifiNative.java revision e2639d782eef1365a98dbd2639be23a6dd06e691
1842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka/* 2842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * Copyright (C) 2008 The Android Open Source Project 3842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * 4842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 5842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * you may not use this file except in compliance with the License. 6842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * You may obtain a copy of the License at 7842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * 8842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * 10842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 11842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 12842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * See the License for the specific language governing permissions and 14842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * limitations under the License. 15842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka */ 16842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 17842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokapackage android.net.wifi; 18842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 19842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport android.net.wifi.p2p.WifiP2pConfig; 20842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport android.net.wifi.p2p.WifiP2pGroup; 21842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport android.net.wifi.p2p.WifiP2pDevice; 22842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport android.text.TextUtils; 23842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 24842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport android.net.wifi.p2p.nsd.WifiP2pServiceRequest; 25842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport android.util.Log; 26842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 27842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport java.io.InputStream; 28842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport java.lang.Process; 29842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport java.util.ArrayList; 30842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokaimport java.util.List; 31842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 32842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka/** 33842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * Native calls for bring up/shut down of the supplicant daemon and for 34842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * sending requests to the supplicant daemon 35842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * 36842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * waitForEvent() is called on the monitor thread for events. All other methods 37842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * must be serialized from the framework. 38842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * 39842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * {@hide} 40842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka */ 41842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaokapublic class WifiNative { 42842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 43842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private static final boolean DBG = false; 44842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private final String mTAG; 45842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private static final int DEFAULT_GROUP_OWNER_INTENT = 7; 46842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 47842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 48842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 49842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 50842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 51842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka String mInterface = ""; 52842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 53842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public native static boolean loadDriver(); 54842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 55842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public native static boolean isDriverLoaded(); 56842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 57842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public native static boolean unloadDriver(); 58842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 59842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public native static boolean startSupplicant(boolean p2pSupported); 60842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 61842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka /* Sends a kill signal to supplicant. To be used when we have lost connection 62842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka or when the supplicant is hung */ 63842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public native static boolean killSupplicant(); 64842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 65842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private native boolean connectToSupplicant(String iface); 66842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 67842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private native void closeSupplicantConnection(String iface); 68842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 69842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka /** 70842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * Wait for the supplicant to send an event, returning the event string. 71842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka * @return the event string sent by the supplicant. 72842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka */ 73842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private native String waitForEvent(String iface); 74842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 75842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private native boolean doBooleanCommand(String iface, String command); 76842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 77842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private native int doIntCommand(String iface, String command); 78842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 79842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private native String doStringCommand(String iface, String command); 80842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 81842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public WifiNative(String iface) { 82842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka mInterface = iface; 83842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka mTAG = "WifiNative-" + iface; 84842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 85842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 86842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public boolean connectToSupplicant() { 87842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka return connectToSupplicant(mInterface); 88842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 89842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 90842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public void closeSupplicantConnection() { 91842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka closeSupplicantConnection(mInterface); 92842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 93842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 94842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public String waitForEvent() { 95842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka return waitForEvent(mInterface); 96842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 97842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 98842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private boolean doBooleanCommand(String command) { 99842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka if (DBG) Log.d(mTAG, "doBoolean: " + command); 100842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka return doBooleanCommand(mInterface, command); 101842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 102842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 103842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private int doIntCommand(String command) { 104842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka if (DBG) Log.d(mTAG, "doInt: " + command); 105842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka return doIntCommand(mInterface, command); 106842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 107842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 108842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka private String doStringCommand(String command) { 109842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka if (DBG) Log.d(mTAG, "doString: " + command); 110842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka return doStringCommand(mInterface, command); 111842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 112842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 113842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public boolean ping() { 114842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka String pong = doStringCommand("PING"); 115842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka return (pong != null && pong.equals("PONG")); 116842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 117842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 118842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka public boolean scan() { 119842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka return doBooleanCommand("SCAN"); 120842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka } 121842b3d411592847be496590608d298bc17cf70b2Tadashi G. Takaoka 122 public boolean setScanMode(boolean setActive) { 123 if (setActive) { 124 return doBooleanCommand("DRIVER SCAN-ACTIVE"); 125 } else { 126 return doBooleanCommand("DRIVER SCAN-PASSIVE"); 127 } 128 } 129 130 /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. 131 * 132 * Note that underneath we use a harsh-sounding "terminate" supplicant command 133 * for a graceful stop and a mild-sounding "stop" interface 134 * to kill the process 135 */ 136 public boolean stopSupplicant() { 137 return doBooleanCommand("TERMINATE"); 138 } 139 140 public String listNetworks() { 141 return doStringCommand("LIST_NETWORKS"); 142 } 143 144 public int addNetwork() { 145 return doIntCommand("ADD_NETWORK"); 146 } 147 148 public boolean setNetworkVariable(int netId, String name, String value) { 149 if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false; 150 return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value); 151 } 152 153 public String getNetworkVariable(int netId, String name) { 154 if (TextUtils.isEmpty(name)) return null; 155 return doStringCommand("GET_NETWORK " + netId + " " + name); 156 } 157 158 public boolean removeNetwork(int netId) { 159 return doBooleanCommand("REMOVE_NETWORK " + netId); 160 } 161 162 public boolean enableNetwork(int netId, boolean disableOthers) { 163 if (disableOthers) { 164 return doBooleanCommand("SELECT_NETWORK " + netId); 165 } else { 166 return doBooleanCommand("ENABLE_NETWORK " + netId); 167 } 168 } 169 170 public boolean disableNetwork(int netId) { 171 return doBooleanCommand("DISABLE_NETWORK " + netId); 172 } 173 174 public boolean reconnect() { 175 return doBooleanCommand("RECONNECT"); 176 } 177 178 public boolean reassociate() { 179 return doBooleanCommand("REASSOCIATE"); 180 } 181 182 public boolean disconnect() { 183 return doBooleanCommand("DISCONNECT"); 184 } 185 186 public String status() { 187 return doStringCommand("STATUS"); 188 } 189 190 public String getMacAddress() { 191 //Macaddr = XX.XX.XX.XX.XX.XX 192 String ret = doStringCommand("DRIVER MACADDR"); 193 if (!TextUtils.isEmpty(ret)) { 194 String[] tokens = ret.split(" = "); 195 if (tokens.length == 2) return tokens[1]; 196 } 197 return null; 198 } 199 200 public String scanResults() { 201 return doStringCommand("SCAN_RESULTS"); 202 } 203 204 public boolean startDriver() { 205 return doBooleanCommand("DRIVER START"); 206 } 207 208 public boolean stopDriver() { 209 return doBooleanCommand("DRIVER STOP"); 210 } 211 212 213 /** 214 * Start filtering out Multicast V4 packets 215 * @return {@code true} if the operation succeeded, {@code false} otherwise 216 * 217 * Multicast filtering rules work as follows: 218 * 219 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 220 * a power optimized mode (typically when screen goes off). 221 * 222 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 223 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 224 * 225 * DRIVER RXFILTER-ADD Num 226 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 227 * 228 * and DRIVER RXFILTER-START 229 * In order to stop the usage of these rules, we do 230 * 231 * DRIVER RXFILTER-STOP 232 * DRIVER RXFILTER-REMOVE Num 233 * where Num is as described for RXFILTER-ADD 234 * 235 * The SETSUSPENDOPT driver command overrides the filtering rules 236 */ 237 public boolean startFilteringMulticastV4Packets() { 238 return doBooleanCommand("DRIVER RXFILTER-STOP") 239 && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") 240 && doBooleanCommand("DRIVER RXFILTER-START"); 241 } 242 243 /** 244 * Stop filtering out Multicast V4 packets. 245 * @return {@code true} if the operation succeeded, {@code false} otherwise 246 */ 247 public boolean stopFilteringMulticastV4Packets() { 248 return doBooleanCommand("DRIVER RXFILTER-STOP") 249 && doBooleanCommand("DRIVER RXFILTER-ADD 2") 250 && doBooleanCommand("DRIVER RXFILTER-START"); 251 } 252 253 /** 254 * Start filtering out Multicast V6 packets 255 * @return {@code true} if the operation succeeded, {@code false} otherwise 256 */ 257 public boolean startFilteringMulticastV6Packets() { 258 return doBooleanCommand("DRIVER RXFILTER-STOP") 259 && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") 260 && doBooleanCommand("DRIVER RXFILTER-START"); 261 } 262 263 /** 264 * Stop filtering out Multicast V6 packets. 265 * @return {@code true} if the operation succeeded, {@code false} otherwise 266 */ 267 public boolean stopFilteringMulticastV6Packets() { 268 return doBooleanCommand("DRIVER RXFILTER-STOP") 269 && doBooleanCommand("DRIVER RXFILTER-ADD 3") 270 && doBooleanCommand("DRIVER RXFILTER-START"); 271 } 272 273 public int getBand() { 274 String ret = doStringCommand("DRIVER GETBAND"); 275 if (!TextUtils.isEmpty(ret)) { 276 //reply is "BAND X" where X is the band 277 String[] tokens = ret.split(" "); 278 try { 279 if (tokens.length == 2) return Integer.parseInt(tokens[1]); 280 } catch (NumberFormatException e) { 281 return -1; 282 } 283 } 284 return -1; 285 } 286 287 public boolean setBand(int band) { 288 return doBooleanCommand("DRIVER SETBAND " + band); 289 } 290 291 /** 292 * Sets the bluetooth coexistence mode. 293 * 294 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 295 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 296 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 297 * @return Whether the mode was successfully set. 298 */ 299 public boolean setBluetoothCoexistenceMode(int mode) { 300 return doBooleanCommand("DRIVER BTCOEXMODE " + mode); 301 } 302 303 /** 304 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 305 * some of the low-level scan parameters used by the driver are changed to 306 * reduce interference with A2DP streaming. 307 * 308 * @param isSet whether to enable or disable this mode 309 * @return {@code true} if the command succeeded, {@code false} otherwise. 310 */ 311 public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { 312 if (setCoexScanMode) { 313 return doBooleanCommand("DRIVER BTCOEXSCAN-START"); 314 } else { 315 return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); 316 } 317 } 318 319 public boolean saveConfig() { 320 // Make sure we never write out a value for AP_SCAN other than 1 321 return doBooleanCommand("AP_SCAN 1") && doBooleanCommand("SAVE_CONFIG"); 322 } 323 324 public boolean setScanResultHandling(int mode) { 325 return doBooleanCommand("AP_SCAN " + mode); 326 } 327 328 public boolean addToBlacklist(String bssid) { 329 if (TextUtils.isEmpty(bssid)) return false; 330 return doBooleanCommand("BLACKLIST " + bssid); 331 } 332 333 public boolean clearBlacklist() { 334 return doBooleanCommand("BLACKLIST clear"); 335 } 336 337 public boolean setSuspendOptimizations(boolean enabled) { 338 if (enabled) { 339 return doBooleanCommand("DRIVER SETSUSPENDMODE 1"); 340 } else { 341 return doBooleanCommand("DRIVER SETSUSPENDMODE 0"); 342 } 343 } 344 345 public boolean setCountryCode(String countryCode) { 346 return doBooleanCommand("DRIVER COUNTRY " + countryCode); 347 } 348 349 public void enableBackgroundScan(boolean enable) { 350 if (enable) { 351 doBooleanCommand("SET pno 1"); 352 } else { 353 doBooleanCommand("SET pno 0"); 354 } 355 } 356 357 public void setScanInterval(int scanInterval) { 358 doBooleanCommand("SCAN_INTERVAL " + scanInterval); 359 } 360 361 /** Example output: 362 * RSSI=-65 363 * LINKSPEED=48 364 * NOISE=9999 365 * FREQUENCY=0 366 */ 367 public String signalPoll() { 368 return doStringCommand("SIGNAL_POLL"); 369 } 370 371 public boolean startWpsPbc(String bssid) { 372 if (TextUtils.isEmpty(bssid)) { 373 return doBooleanCommand("WPS_PBC"); 374 } else { 375 return doBooleanCommand("WPS_PBC " + bssid); 376 } 377 } 378 379 public boolean startWpsPbc(String iface, String bssid) { 380 if (TextUtils.isEmpty(bssid)) { 381 return doBooleanCommand("WPS_PBC interface=" + iface); 382 } else { 383 return doBooleanCommand("WPS_PBC interface=" + iface + " " + bssid); 384 } 385 } 386 387 public boolean startWpsPinKeypad(String pin) { 388 if (TextUtils.isEmpty(pin)) return false; 389 return doBooleanCommand("WPS_PIN any " + pin); 390 } 391 392 public boolean startWpsPinKeypad(String iface, String pin) { 393 if (TextUtils.isEmpty(pin)) return false; 394 return doBooleanCommand("WPS_PIN interface=" + iface + " any " + pin); 395 } 396 397 398 public String startWpsPinDisplay(String bssid) { 399 if (TextUtils.isEmpty(bssid)) { 400 return doStringCommand("WPS_PIN any"); 401 } else { 402 return doStringCommand("WPS_PIN " + bssid); 403 } 404 } 405 406 public String startWpsPinDisplay(String iface, String bssid) { 407 if (TextUtils.isEmpty(bssid)) { 408 return doStringCommand("WPS_PIN interface=" + iface + " any"); 409 } else { 410 return doStringCommand("WPS_PIN interface=" + iface + " " + bssid); 411 } 412 } 413 414 /* Configures an access point connection */ 415 public boolean startWpsRegistrar(String bssid, String pin) { 416 if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false; 417 return doBooleanCommand("WPS_REG " + bssid + " " + pin); 418 } 419 420 public boolean cancelWps() { 421 return doBooleanCommand("WPS_CANCEL"); 422 } 423 424 public boolean setPersistentReconnect(boolean enabled) { 425 int value = (enabled == true) ? 1 : 0; 426 return doBooleanCommand("SET persistent_reconnect " + value); 427 } 428 429 public boolean setDeviceName(String name) { 430 return doBooleanCommand("SET device_name " + name); 431 } 432 433 public boolean setDeviceType(String type) { 434 return doBooleanCommand("SET device_type " + type); 435 } 436 437 public boolean setConfigMethods(String cfg) { 438 return doBooleanCommand("SET config_methods " + cfg); 439 } 440 441 public boolean setP2pSsidPostfix(String postfix) { 442 return doBooleanCommand("SET p2p_ssid_postfix " + postfix); 443 } 444 445 public boolean setP2pGroupIdle(String iface, int time) { 446 return doBooleanCommand("SET interface=" + iface + " p2p_group_idle " + time); 447 } 448 449 public void setPowerSave(boolean enabled) { 450 if (enabled) { 451 doBooleanCommand("SET ps 1"); 452 } else { 453 doBooleanCommand("SET ps 0"); 454 } 455 } 456 457 public boolean setP2pPowerSave(String iface, boolean enabled) { 458 if (enabled) { 459 return doBooleanCommand("P2P_SET interface=" + iface + " ps 1"); 460 } else { 461 return doBooleanCommand("P2P_SET interface=" + iface + " ps 0"); 462 } 463 } 464 465 /** 466 * "sta" prioritizes STA connection over P2P and "p2p" prioritizes 467 * P2P connection over STA 468 */ 469 public boolean setConcurrencyPriority(String s) { 470 return doBooleanCommand("P2P_SET conc_priority " + s); 471 } 472 473 public boolean p2pFind() { 474 return doBooleanCommand("P2P_FIND"); 475 } 476 477 public boolean p2pFind(int timeout) { 478 if (timeout <= 0) { 479 return p2pFind(); 480 } 481 return doBooleanCommand("P2P_FIND " + timeout); 482 } 483 484 public boolean p2pStopFind() { 485 return doBooleanCommand("P2P_STOP_FIND"); 486 } 487 488 public boolean p2pListen() { 489 return doBooleanCommand("P2P_LISTEN"); 490 } 491 492 public boolean p2pListen(int timeout) { 493 if (timeout <= 0) { 494 return p2pListen(); 495 } 496 return doBooleanCommand("P2P_LISTEN " + timeout); 497 } 498 499 public boolean p2pFlush() { 500 return doBooleanCommand("P2P_FLUSH"); 501 } 502 503 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 504 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 505 public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 506 if (config == null) return null; 507 List<String> args = new ArrayList<String>(); 508 WpsInfo wps = config.wps; 509 args.add(config.deviceAddress); 510 511 switch (wps.setup) { 512 case WpsInfo.PBC: 513 args.add("pbc"); 514 break; 515 case WpsInfo.DISPLAY: 516 if (TextUtils.isEmpty(wps.pin)) { 517 args.add("pin"); 518 } else { 519 args.add(wps.pin); 520 } 521 args.add("display"); 522 break; 523 case WpsInfo.KEYPAD: 524 args.add(wps.pin); 525 args.add("keypad"); 526 break; 527 case WpsInfo.LABEL: 528 args.add(wps.pin); 529 args.add("label"); 530 default: 531 break; 532 } 533 534 //TODO: Add persist behavior once the supplicant interaction is fixed for both 535 // group and client scenarios 536 /* Persist unless there is an explicit request to not do so*/ 537 //if (config.persist != WifiP2pConfig.Persist.NO) args.add("persistent"); 538 539 if (joinExistingGroup) args.add("join"); 540 541 //TODO: This can be adapted based on device plugged in state and 542 //device battery state 543 int groupOwnerIntent = config.groupOwnerIntent; 544 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 545 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; 546 } 547 args.add("go_intent=" + groupOwnerIntent); 548 549 String command = "P2P_CONNECT "; 550 for (String s : args) command += s + " "; 551 552 return doStringCommand(command); 553 } 554 555 public boolean p2pCancelConnect() { 556 return doBooleanCommand("P2P_CANCEL"); 557 } 558 559 public boolean p2pProvisionDiscovery(WifiP2pConfig config) { 560 if (config == null) return false; 561 562 switch (config.wps.setup) { 563 case WpsInfo.PBC: 564 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); 565 case WpsInfo.DISPLAY: 566 //We are doing display, so provision discovery is keypad 567 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); 568 case WpsInfo.KEYPAD: 569 //We are doing keypad, so provision discovery is display 570 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); 571 default: 572 break; 573 } 574 return false; 575 } 576 577 public boolean p2pGroupAdd() { 578 return doBooleanCommand("P2P_GROUP_ADD"); 579 } 580 581 public boolean p2pGroupRemove(String iface) { 582 if (TextUtils.isEmpty(iface)) return false; 583 return doBooleanCommand("P2P_GROUP_REMOVE " + iface); 584 } 585 586 public boolean p2pReject(String deviceAddress) { 587 return doBooleanCommand("P2P_REJECT " + deviceAddress); 588 } 589 590 /* Invite a peer to a group */ 591 public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 592 if (TextUtils.isEmpty(deviceAddress)) return false; 593 594 if (group == null) { 595 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 596 } else { 597 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 598 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 599 } 600 } 601 602 /* Reinvoke a persistent connection */ 603 public boolean p2pReinvoke(int netId, String deviceAddress) { 604 if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false; 605 606 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 607 } 608 609 610 public String p2pGetDeviceAddress() { 611 String status = status(); 612 if (status == null) return ""; 613 614 String[] tokens = status.split("\n"); 615 for (String token : tokens) { 616 if (token.startsWith("p2p_device_address=")) { 617 String[] nameValue = token.split("="); 618 if (nameValue.length != 2) break; 619 return nameValue[1]; 620 } 621 } 622 return ""; 623 } 624 625 public boolean isGroupOwner(String deviceAddress) { 626 /* BSS returns details only for a GO */ 627 String bssInfo = doStringCommand("BSS p2p_dev_addr=" + deviceAddress); 628 if (TextUtils.isEmpty(bssInfo)) return false; 629 return true; 630 } 631 632 public String p2pPeer(String deviceAddress) { 633 return doStringCommand("P2P_PEER " + deviceAddress); 634 } 635 636 public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) { 637 /* 638 * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump> 639 * P2P_SERVICE_ADD upnp <version hex> <service> 640 * 641 * e.g) 642 * [Bonjour] 643 * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) 644 * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027 645 * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) 646 * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 647 * 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 648 * 649 * [UPnP] 650 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 651 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice 652 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp 653 * -org:device:InternetGatewayDevice:1 654 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp 655 * -org:service:ContentDirectory:2 656 */ 657 for (String s : servInfo.getSupplicantQueryList()) { 658 String command = "P2P_SERVICE_ADD"; 659 command += (" " + s); 660 if (!doBooleanCommand(command)) { 661 return false; 662 } 663 } 664 return true; 665 } 666 667 public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) { 668 /* 669 * P2P_SERVICE_DEL bonjour <query hexdump> 670 * P2P_SERVICE_DEL upnp <version hex> <service> 671 */ 672 for (String s : servInfo.getSupplicantQueryList()) { 673 String command = "P2P_SERVICE_DEL "; 674 675 String[] data = s.split(" "); 676 if (data.length < 2) { 677 return false; 678 } 679 if ("upnp".equals(data[0])) { 680 command += s; 681 } else if ("bonjour".equals(data[0])) { 682 command += data[0]; 683 command += (" " + data[1]); 684 } else { 685 return false; 686 } 687 if (!doBooleanCommand(command)) { 688 return false; 689 } 690 } 691 return true; 692 } 693 694 public boolean p2pServiceFlush() { 695 return doBooleanCommand("P2P_SERVICE_FLUSH"); 696 } 697 698 public String p2pServDiscReq(String addr, String query) { 699 String command = "P2P_SERV_DISC_REQ"; 700 command += (" " + addr); 701 command += (" " + query); 702 703 return doStringCommand(command); 704 } 705 706 public boolean p2pServDiscCancelReq(String id) { 707 return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id); 708 } 709} 710