diff options
Diffstat (limited to 'wifi/java/android')
-rw-r--r-- | wifi/java/android/net/wifi/SupplicantStateTracker.java | 14 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiConfigStore.java | 603 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiInfo.java | 24 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiManager.java | 7 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiMonitor.java | 40 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiNative.java | 433 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateMachine.java | 277 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiWatchdogStateMachine.java | 2 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WpsStateMachine.java | 20 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pConfig.java | 12 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pDevice.java | 28 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java | 13 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pGroup.java | 6 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java | 161 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pService.java | 696 |
15 files changed, 1448 insertions, 888 deletions
diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/wifi/java/android/net/wifi/SupplicantStateTracker.java index cbd284c..104a02d 100644 --- a/wifi/java/android/net/wifi/SupplicantStateTracker.java +++ b/wifi/java/android/net/wifi/SupplicantStateTracker.java @@ -39,6 +39,7 @@ class SupplicantStateTracker extends StateMachine { private static final boolean DBG = false; private WifiStateMachine mWifiStateMachine; + private WifiConfigStore mWifiConfigStore; private int mAuthenticationFailuresCount = 0; /* Indicates authentication failure in supplicant broadcast. * TODO: enhance auth failure reporting to include notification @@ -62,11 +63,12 @@ class SupplicantStateTracker extends StateMachine { private State mCompletedState = new CompletedState(); private State mDormantState = new DormantState(); - public SupplicantStateTracker(Context context, WifiStateMachine wsm, Handler target) { - super(TAG, target.getLooper()); + public SupplicantStateTracker(Context c, WifiStateMachine wsm, WifiConfigStore wcs, Handler t) { + super(TAG, t.getLooper()); - mContext = context; + mContext = c; mWifiStateMachine = wsm; + mWifiConfigStore = wcs; addState(mDefaultState); addState(mUninitializedState, mDefaultState); addState(mInactiveState, mDefaultState); @@ -85,11 +87,11 @@ class SupplicantStateTracker extends StateMachine { private void handleNetworkConnectionFailure(int netId) { /* If other networks disabled during connection, enable them */ if (mNetworksDisabledDuringConnect) { - WifiConfigStore.enableAllNetworks(); + mWifiConfigStore.enableAllNetworks(); mNetworksDisabledDuringConnect = false; } /* Disable failed network */ - WifiConfigStore.disableNetwork(netId, WifiConfiguration.DISABLED_AUTH_FAILURE); + mWifiConfigStore.disableNetwork(netId, WifiConfiguration.DISABLED_AUTH_FAILURE); } private void transitionOnSupplicantStateChange(StateChangeResult stateChangeResult) { @@ -285,7 +287,7 @@ class SupplicantStateTracker extends StateMachine { /* Reset authentication failure count */ mAuthenticationFailuresCount = 0; if (mNetworksDisabledDuringConnect) { - WifiConfigStore.enableAllNetworks(); + mWifiConfigStore.enableAllNetworks(); mNetworksDisabledDuringConnect = false; } } diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java index 568a485..5dffa60 100644 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ b/wifi/java/android/net/wifi/WifiConfigStore.java @@ -22,6 +22,7 @@ import android.net.DhcpInfoInternal; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; +import android.net.NetworkInfo.DetailedState; import android.net.ProxyProperties; import android.net.RouteInfo; import android.net.wifi.WifiConfiguration.IpAssignment; @@ -31,6 +32,9 @@ import android.net.wifi.WifiConfiguration.Status; import android.net.wifi.NetworkUpdateResult; import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; import android.os.Environment; +import android.os.Message; +import android.os.Handler; +import android.os.HandlerThread; import android.text.TextUtils; import android.util.Log; @@ -50,6 +54,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * This class provides the API to manage configured @@ -98,12 +103,12 @@ import java.util.List; */ class WifiConfigStore { - private static Context sContext; + private Context mContext; private static final String TAG = "WifiConfigStore"; private static final boolean DBG = false; /* configured networks with network id as the key */ - private static HashMap<Integer, WifiConfiguration> sConfiguredNetworks = + private HashMap<Integer, WifiConfiguration> mConfiguredNetworks = new HashMap<Integer, WifiConfiguration>(); /* A network id is a unique identifier for a network configured in the @@ -113,11 +118,11 @@ class WifiConfigStore { * that is generated from SSID and security type of the network. A mapping * from the generated unique id to network id of the network is needed to * map supplicant config to IP configuration. */ - private static HashMap<Integer, Integer> sNetworkIds = + private HashMap<Integer, Integer> mNetworkIds = new HashMap<Integer, Integer>(); /* Tracks the highest priority of configured networks */ - private static int sLastPriority = -1; + private int mLastPriority = -1; private static final String ipConfigFile = Environment.getDataDirectory() + "/misc/wifi/ipconfig.txt"; @@ -136,13 +141,19 @@ class WifiConfigStore { private static final String EXCLUSION_LIST_KEY = "exclusionList"; private static final String EOS = "eos"; + private WifiNative mWifiNative; + + WifiConfigStore(Context c, WifiNative wn) { + mContext = c; + mWifiNative = wn; + } + /** - * Initialize context, fetch the list of configured networks + * Fetch the list of configured networks * and enable all stored networks in supplicant. */ - static void initialize(Context context) { + void initialize() { if (DBG) log("Loading config and enabling all networks"); - sContext = context; loadConfiguredNetworks(); enableAllNetworks(); } @@ -151,12 +162,10 @@ class WifiConfigStore { * Fetch the list of currently configured networks * @return List of networks */ - static List<WifiConfiguration> getConfiguredNetworks() { + List<WifiConfiguration> getConfiguredNetworks() { List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); - synchronized (sConfiguredNetworks) { - for(WifiConfiguration config : sConfiguredNetworks.values()) { - networks.add(new WifiConfiguration(config)); - } + for(WifiConfiguration config : mConfiguredNetworks.values()) { + networks.add(new WifiConfiguration(config)); } return networks; } @@ -165,23 +174,21 @@ class WifiConfigStore { * enable all networks and save config. This will be a no-op if the list * of configured networks indicates all networks as being enabled */ - static void enableAllNetworks() { + void enableAllNetworks() { boolean networkEnabledStateChanged = false; - synchronized (sConfiguredNetworks) { - for(WifiConfiguration config : sConfiguredNetworks.values()) { - if(config != null && config.status == Status.DISABLED) { - if(WifiNative.enableNetworkCommand(config.networkId, false)) { - networkEnabledStateChanged = true; - config.status = Status.ENABLED; - } else { - loge("Enable network failed on " + config.networkId); - } + for(WifiConfiguration config : mConfiguredNetworks.values()) { + if(config != null && config.status == Status.DISABLED) { + if(mWifiNative.enableNetwork(config.networkId, false)) { + networkEnabledStateChanged = true; + config.status = Status.ENABLED; + } else { + loge("Enable network failed on " + config.networkId); } } } if (networkEnabledStateChanged) { - WifiNative.saveConfigCommand(); + mWifiNative.saveConfig(); sendConfiguredNetworksChangedBroadcast(); } } @@ -198,7 +205,7 @@ class WifiConfigStore { * @param config The configuration details in WifiConfiguration * @return the networkId now associated with the specified configuration */ - static int selectNetwork(WifiConfiguration config) { + int selectNetwork(WifiConfiguration config) { if (config != null) { NetworkUpdateResult result = addOrUpdateNetworkNative(config); int netId = result.getNetworkId(); @@ -223,27 +230,25 @@ class WifiConfigStore { * * @param netId network to select for connection */ - static void selectNetwork(int netId) { + void selectNetwork(int netId) { // Reset the priority of each network at start or if it goes too high. - if (sLastPriority == -1 || sLastPriority > 1000000) { - synchronized (sConfiguredNetworks) { - for(WifiConfiguration config : sConfiguredNetworks.values()) { - if (config.networkId != INVALID_NETWORK_ID) { - config.priority = 0; - addOrUpdateNetworkNative(config); - } + if (mLastPriority == -1 || mLastPriority > 1000000) { + for(WifiConfiguration config : mConfiguredNetworks.values()) { + if (config.networkId != INVALID_NETWORK_ID) { + config.priority = 0; + addOrUpdateNetworkNative(config); } } - sLastPriority = 0; + mLastPriority = 0; } // Set to the highest priority and save the configuration. WifiConfiguration config = new WifiConfiguration(); config.networkId = netId; - config.priority = ++sLastPriority; + config.priority = ++mLastPriority; addOrUpdateNetworkNative(config); - WifiNative.saveConfigCommand(); + mWifiNative.saveConfig(); /* Enable the given network while disabling all other networks */ enableNetworkWithoutBroadcast(netId, true); @@ -257,36 +262,50 @@ class WifiConfigStore { * * @param config WifiConfiguration to be saved */ - static NetworkUpdateResult saveNetwork(WifiConfiguration config) { + NetworkUpdateResult saveNetwork(WifiConfiguration config) { boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); NetworkUpdateResult result = addOrUpdateNetworkNative(config); int netId = result.getNetworkId(); /* enable a new network */ if (newNetwork && netId != INVALID_NETWORK_ID) { - WifiNative.enableNetworkCommand(netId, false); - synchronized (sConfiguredNetworks) { - sConfiguredNetworks.get(netId).status = Status.ENABLED; - } + mWifiNative.enableNetwork(netId, false); + mConfiguredNetworks.get(netId).status = Status.ENABLED; } - WifiNative.saveConfigCommand(); + mWifiNative.saveConfig(); sendConfiguredNetworksChangedBroadcast(); return result; } + void updateStatus(int netId, DetailedState state) { + if (netId != INVALID_NETWORK_ID) { + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config == null) return; + switch (state) { + case CONNECTED: + config.status = Status.CURRENT; + break; + case DISCONNECTED: + config.status = Status.ENABLED; + break; + default: + //do nothing, retain the existing state + break; + } + } + } + /** * Forget the specified network and save config * * @param netId network to forget */ - static void forgetNetwork(int netId) { - if (WifiNative.removeNetworkCommand(netId)) { - WifiNative.saveConfigCommand(); - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null) { - sConfiguredNetworks.remove(netId); - sNetworkIds.remove(configKey(config)); - } + void forgetNetwork(int netId) { + if (mWifiNative.removeNetwork(netId)) { + mWifiNative.saveConfig(); + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null) { + mConfiguredNetworks.remove(netId); + mNetworkIds.remove(configKey(config)); } writeIpAndProxyConfigurations(); sendConfiguredNetworksChangedBroadcast(); @@ -303,7 +322,7 @@ class WifiConfigStore { * * @param config wifi configuration to add/update */ - static int addOrUpdateNetwork(WifiConfiguration config) { + int addOrUpdateNetwork(WifiConfiguration config) { NetworkUpdateResult result = addOrUpdateNetworkNative(config); sendConfiguredNetworksChangedBroadcast(); return result.getNetworkId(); @@ -317,15 +336,13 @@ class WifiConfigStore { * * @param netId network to be removed */ - static boolean removeNetwork(int netId) { - boolean ret = WifiNative.removeNetworkCommand(netId); - synchronized (sConfiguredNetworks) { - if (ret) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null) { - sConfiguredNetworks.remove(netId); - sNetworkIds.remove(configKey(config)); - } + boolean removeNetwork(int netId) { + boolean ret = mWifiNative.removeNetwork(netId); + if (ret) { + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null) { + mConfiguredNetworks.remove(netId); + mNetworkIds.remove(configKey(config)); } } sendConfiguredNetworksChangedBroadcast(); @@ -340,19 +357,17 @@ class WifiConfigStore { * * @param netId network to be removed */ - static boolean enableNetwork(int netId, boolean disableOthers) { + boolean enableNetwork(int netId, boolean disableOthers) { boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); sendConfiguredNetworksChangedBroadcast(); return ret; } - static boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { - boolean ret = WifiNative.enableNetworkCommand(netId, disableOthers); + boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { + boolean ret = mWifiNative.enableNetwork(netId, disableOthers); - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null) config.status = Status.ENABLED; - } + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null) config.status = Status.ENABLED; if (disableOthers) { markAllNetworksDisabledExcept(netId); @@ -364,7 +379,7 @@ class WifiConfigStore { * Disable a network. Note that there is no saveConfig operation. * @param netId network to be disabled */ - static boolean disableNetwork(int netId) { + boolean disableNetwork(int netId) { return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON); } @@ -373,15 +388,13 @@ class WifiConfigStore { * @param netId network to be disabled * @param reason reason code network was disabled */ - static boolean disableNetwork(int netId, int reason) { - boolean ret = WifiNative.disableNetworkCommand(netId); - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - /* Only change the reason if the network was not previously disabled */ - if (config != null && config.status != Status.DISABLED) { - config.status = Status.DISABLED; - config.disableReason = reason; - } + boolean disableNetwork(int netId, int reason) { + boolean ret = mWifiNative.disableNetwork(netId); + WifiConfiguration config = mConfiguredNetworks.get(netId); + /* Only change the reason if the network was not previously disabled */ + if (config != null && config.status != Status.DISABLED) { + config.status = Status.DISABLED; + config.disableReason = reason; } sendConfiguredNetworksChangedBroadcast(); return ret; @@ -390,17 +403,17 @@ class WifiConfigStore { /** * Save the configured networks in supplicant to disk */ - static boolean saveConfig() { - return WifiNative.saveConfigCommand(); + boolean saveConfig() { + return mWifiNative.saveConfig(); } /** * Start WPS pin method configuration with pin obtained * from the access point */ - static WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { + WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { WpsResult result = new WpsResult(); - if (WifiNative.startWpsWithPinFromAccessPointCommand(config.BSSID, config.pin)) { + if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { /* WPS leaves all networks disabled */ markAllNetworksDisabled(); result.status = WpsResult.Status.SUCCESS; @@ -416,9 +429,9 @@ class WifiConfigStore { * from the device * @return WpsResult indicating status and pin */ - static WpsResult startWpsWithPinFromDevice(WpsInfo config) { + WpsResult startWpsWithPinFromDevice(WpsInfo config) { WpsResult result = new WpsResult(); - result.pin = WifiNative.startWpsWithPinFromDeviceCommand(config.BSSID); + result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); /* WPS leaves all networks disabled */ if (!TextUtils.isEmpty(result.pin)) { markAllNetworksDisabled(); @@ -433,9 +446,9 @@ class WifiConfigStore { /** * Start WPS push button configuration */ - static WpsResult startWpsPbc(WpsInfo config) { + WpsResult startWpsPbc(WpsInfo config) { WpsResult result = new WpsResult(); - if (WifiNative.startWpsPbcCommand(config.BSSID)) { + if (mWifiNative.startWpsPbc(config.BSSID)) { /* WPS leaves all networks disabled */ markAllNetworksDisabled(); result.status = WpsResult.Status.SUCCESS; @@ -449,11 +462,9 @@ class WifiConfigStore { /** * Fetch the link properties for a given network id */ - static LinkProperties getLinkProperties(int netId) { - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null) return new LinkProperties(config.linkProperties); - } + LinkProperties getLinkProperties(int netId) { + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null) return new LinkProperties(config.linkProperties); return null; } @@ -464,7 +475,7 @@ class WifiConfigStore { * that, we should remove handling DhcpInfo and move * to using LinkProperties */ - static DhcpInfoInternal getIpConfiguration(int netId) { + DhcpInfoInternal getIpConfiguration(int netId) { DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); LinkProperties linkProperties = getLinkProperties(netId); @@ -490,33 +501,29 @@ class WifiConfigStore { /** * set IP configuration for a given network id */ - static void setIpConfiguration(int netId, DhcpInfoInternal dhcpInfo) { + void setIpConfiguration(int netId, DhcpInfoInternal dhcpInfo) { LinkProperties linkProperties = dhcpInfo.makeLinkProperties(); - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null) { - // add old proxy details - if(config.linkProperties != null) { - linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); - } - config.linkProperties = linkProperties; + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null) { + // add old proxy details + if(config.linkProperties != null) { + linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); } + config.linkProperties = linkProperties; } } /** * clear IP configuration for a given network id */ - static void clearIpConfiguration(int netId) { - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null && config.linkProperties != null) { - // Clear everything except proxy - ProxyProperties proxy = config.linkProperties.getHttpProxy(); - config.linkProperties.clear(); - config.linkProperties.setHttpProxy(proxy); - } + void clearIpConfiguration(int netId) { + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null && config.linkProperties != null) { + // Clear everything except proxy + ProxyProperties proxy = config.linkProperties.getHttpProxy(); + config.linkProperties.clear(); + config.linkProperties.setHttpProxy(proxy); } } @@ -524,7 +531,7 @@ class WifiConfigStore { /** * Fetch the proxy properties for a given network id */ - static ProxyProperties getProxyProperties(int netId) { + ProxyProperties getProxyProperties(int netId) { LinkProperties linkProperties = getLinkProperties(netId); if (linkProperties != null) { return new ProxyProperties(linkProperties.getHttpProxy()); @@ -535,107 +542,137 @@ class WifiConfigStore { /** * Return if the specified network is using static IP */ - static boolean isUsingStaticIp(int netId) { - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null && config.ipAssignment == IpAssignment.STATIC) { - return true; - } + boolean isUsingStaticIp(int netId) { + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null && config.ipAssignment == IpAssignment.STATIC) { + return true; } return false; } - private static void sendConfiguredNetworksChangedBroadcast() { + private void sendConfiguredNetworksChangedBroadcast() { Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - sContext.sendBroadcast(intent); + mContext.sendBroadcast(intent); } - static void loadConfiguredNetworks() { - String listStr = WifiNative.listNetworksCommand(); - sLastPriority = 0; + void loadConfiguredNetworks() { + String listStr = mWifiNative.listNetworks(); + mLastPriority = 0; - synchronized (sConfiguredNetworks) { - sConfiguredNetworks.clear(); - sNetworkIds.clear(); + mConfiguredNetworks.clear(); + mNetworkIds.clear(); - if (listStr == null) - return; + if (listStr == null) + return; - String[] lines = listStr.split("\n"); - // Skip the first line, which is a header - for (int i = 1; i < lines.length; i++) { - String[] result = lines[i].split("\t"); - // network-id | ssid | bssid | flags - WifiConfiguration config = new WifiConfiguration(); - try { - config.networkId = Integer.parseInt(result[0]); - } catch(NumberFormatException e) { - continue; - } - if (result.length > 3) { - if (result[3].indexOf("[CURRENT]") != -1) - config.status = WifiConfiguration.Status.CURRENT; - else if (result[3].indexOf("[DISABLED]") != -1) - config.status = WifiConfiguration.Status.DISABLED; - else - config.status = WifiConfiguration.Status.ENABLED; - } else { + String[] lines = listStr.split("\n"); + // Skip the first line, which is a header + for (int i = 1; i < lines.length; i++) { + String[] result = lines[i].split("\t"); + // network-id | ssid | bssid | flags + WifiConfiguration config = new WifiConfiguration(); + try { + config.networkId = Integer.parseInt(result[0]); + } catch(NumberFormatException e) { + continue; + } + if (result.length > 3) { + if (result[3].indexOf("[CURRENT]") != -1) + config.status = WifiConfiguration.Status.CURRENT; + else if (result[3].indexOf("[DISABLED]") != -1) + config.status = WifiConfiguration.Status.DISABLED; + else config.status = WifiConfiguration.Status.ENABLED; - } - readNetworkVariables(config); - if (config.priority > sLastPriority) { - sLastPriority = config.priority; - } - sConfiguredNetworks.put(config.networkId, config); - sNetworkIds.put(configKey(config), config.networkId); + } else { + config.status = WifiConfiguration.Status.ENABLED; + } + readNetworkVariables(config); + if (config.priority > mLastPriority) { + mLastPriority = config.priority; } + mConfiguredNetworks.put(config.networkId, config); + mNetworkIds.put(configKey(config), config.networkId); } + readIpAndProxyConfigurations(); sendConfiguredNetworksChangedBroadcast(); } - static void updateIpAndProxyFromWpsConfig(int netId, WpsInfo wpsConfig) { - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get(netId); - if (config != null) { - config.ipAssignment = wpsConfig.ipAssignment; - config.proxySettings = wpsConfig.proxySettings; - config.linkProperties = wpsConfig.linkProperties; - writeIpAndProxyConfigurations(); - } + void updateIpAndProxyFromWpsConfig(int netId, WpsInfo wpsConfig) { + WifiConfiguration config = mConfiguredNetworks.get(netId); + if (config != null) { + config.ipAssignment = wpsConfig.ipAssignment; + config.proxySettings = wpsConfig.proxySettings; + config.linkProperties = wpsConfig.linkProperties; + writeIpAndProxyConfigurations(); } } /* Mark all networks except specified netId as disabled */ - private static void markAllNetworksDisabledExcept(int netId) { - synchronized (sConfiguredNetworks) { - for(WifiConfiguration config : sConfiguredNetworks.values()) { - if(config != null && config.networkId != netId) { - if (config.status != Status.DISABLED) { - config.status = Status.DISABLED; - config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; - } + private void markAllNetworksDisabledExcept(int netId) { + for(WifiConfiguration config : mConfiguredNetworks.values()) { + if(config != null && config.networkId != netId) { + if (config.status != Status.DISABLED) { + config.status = Status.DISABLED; + config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; } } } } - private static void markAllNetworksDisabled() { + private void markAllNetworksDisabled() { markAllNetworksDisabledExcept(INVALID_NETWORK_ID); } - private static void writeIpAndProxyConfigurations() { + private void writeIpAndProxyConfigurations() { - DataOutputStream out = null; - try { - out = new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(ipConfigFile))); + /* Make a copy */ + List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); + for(WifiConfiguration config : mConfiguredNetworks.values()) { + networks.add(new WifiConfiguration(config)); + } + + DelayedDiskWrite.write(networks); + } - out.writeInt(IPCONFIG_FILE_VERSION); + private static class DelayedDiskWrite { - synchronized (sConfiguredNetworks) { - for(WifiConfiguration config : sConfiguredNetworks.values()) { + private static HandlerThread sDiskWriteHandlerThread; + private static Handler sDiskWriteHandler; + /* Tracks multiple writes on the same thread */ + private static int sWriteSequence = 0; + private static final String TAG = "DelayedDiskWrite"; + + static void write (final List<WifiConfiguration> networks) { + + /* Do a delayed write to disk on a seperate handler thread */ + synchronized (DelayedDiskWrite.class) { + if (++sWriteSequence == 1) { + sDiskWriteHandlerThread = new HandlerThread("WifiConfigThread"); + sDiskWriteHandlerThread.start(); + sDiskWriteHandler = new Handler(sDiskWriteHandlerThread.getLooper()); + } + } + + sDiskWriteHandler.post(new Runnable() { + @Override + public void run() { + onWriteCalled(networks); + } + }); + } + + private static void onWriteCalled(List<WifiConfiguration> networks) { + + DataOutputStream out = null; + try { + out = new DataOutputStream(new BufferedOutputStream( + new FileOutputStream(ipConfigFile))); + + out.writeInt(IPCONFIG_FILE_VERSION); + + for(WifiConfiguration config : networks) { boolean writeToFile = false; try { @@ -708,7 +745,7 @@ class WifiConfigStore { /* Ignore */ break; default: - loge("Ignore invalid proxy settings while writing"); + loge("Ignthisore invalid proxy settings while writing"); break; } if (writeToFile) { @@ -720,20 +757,33 @@ class WifiConfigStore { } out.writeUTF(EOS); } - } - } catch (IOException e) { - loge("Error writing data file"); - } finally { - if (out != null) { - try { - out.close(); - } catch (Exception e) {} + } catch (IOException e) { + loge("Error writing data file"); + } finally { + if (out != null) { + try { + out.close(); + } catch (Exception e) {} + } + + //Quit if no more writes sent + synchronized (DelayedDiskWrite.class) { + if (--sWriteSequence == 0) { + sDiskWriteHandler.getLooper().quit(); + sDiskWriteHandler = null; + sDiskWriteHandlerThread = null; + } + } } } + + private static void loge(String s) { + Log.e(TAG, s); + } } - private static void readIpAndProxyConfigurations() { + private void readIpAndProxyConfigurations() { DataInputStream in = null; try { @@ -806,44 +856,42 @@ class WifiConfigStore { } while (true); if (id != -1) { - synchronized (sConfiguredNetworks) { - WifiConfiguration config = sConfiguredNetworks.get( - sNetworkIds.get(id)); + WifiConfiguration config = mConfiguredNetworks.get( + mNetworkIds.get(id)); - if (config == null) { - loge("configuration found for missing network, ignored"); - } else { - config.linkProperties = linkProperties; - switch (ipAssignment) { - case STATIC: - case DHCP: - config.ipAssignment = ipAssignment; - break; - case UNASSIGNED: - //Ignore - break; - default: - loge("Ignore invalid ip assignment while reading"); - break; - } + if (config == null) { + loge("configuration found for missing network, ignored"); + } else { + config.linkProperties = linkProperties; + switch (ipAssignment) { + case STATIC: + case DHCP: + config.ipAssignment = ipAssignment; + break; + case UNASSIGNED: + //Ignore + break; + default: + loge("Ignore invalid ip assignment while reading"); + break; + } - switch (proxySettings) { - case STATIC: - config.proxySettings = proxySettings; - ProxyProperties proxyProperties = - new ProxyProperties(proxyHost, proxyPort, exclusionList); - linkProperties.setHttpProxy(proxyProperties); - break; - case NONE: - config.proxySettings = proxySettings; - break; - case UNASSIGNED: - //Ignore - break; - default: - loge("Ignore invalid proxy settings while reading"); - break; - } + switch (proxySettings) { + case STATIC: + config.proxySettings = proxySettings; + ProxyProperties proxyProperties = + new ProxyProperties(proxyHost, proxyPort, exclusionList); + linkProperties.setHttpProxy(proxyProperties); + break; + case NONE: + config.proxySettings = proxySettings; + break; + case UNASSIGNED: + //Ignore + break; + default: + loge("Ignore invalid proxy settings while reading"); + break; } } } else { @@ -862,7 +910,7 @@ class WifiConfigStore { } } - private static NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) { + private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) { /* * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty * network configuration. Otherwise, the networkId should @@ -872,12 +920,12 @@ class WifiConfigStore { boolean newNetwork = false; // networkId of INVALID_NETWORK_ID means we want to create a new network if (netId == INVALID_NETWORK_ID) { - Integer savedNetId = sNetworkIds.get(configKey(config)); + Integer savedNetId = mNetworkIds.get(configKey(config)); if (savedNetId != null) { netId = savedNetId; } else { newNetwork = true; - netId = WifiNative.addNetworkCommand(); + netId = mWifiNative.addNetwork(); if (netId < 0) { loge("Failed to add a network!"); return new NetworkUpdateResult(INVALID_NETWORK_ID); @@ -890,7 +938,7 @@ class WifiConfigStore { setVariables: { if (config.SSID != null && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.ssidVarName, config.SSID)) { @@ -899,7 +947,7 @@ class WifiConfigStore { } if (config.BSSID != null && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.bssidVarName, config.BSSID)) { @@ -910,7 +958,7 @@ class WifiConfigStore { String allowedKeyManagementString = makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); if (config.allowedKeyManagement.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.KeyMgmt.varName, allowedKeyManagementString)) { @@ -922,7 +970,7 @@ class WifiConfigStore { String allowedProtocolsString = makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); if (config.allowedProtocols.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.Protocol.varName, allowedProtocolsString)) { @@ -934,7 +982,7 @@ class WifiConfigStore { String allowedAuthAlgorithmsString = makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); if (config.allowedAuthAlgorithms.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.AuthAlgorithm.varName, allowedAuthAlgorithmsString)) { @@ -947,7 +995,7 @@ class WifiConfigStore { makeString(config.allowedPairwiseCiphers, WifiConfiguration.PairwiseCipher.strings); if (config.allowedPairwiseCiphers.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.PairwiseCipher.varName, allowedPairwiseCiphersString)) { @@ -959,7 +1007,7 @@ class WifiConfigStore { String allowedGroupCiphersString = makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); if (config.allowedGroupCiphers.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.GroupCipher.varName, allowedGroupCiphersString)) { @@ -971,7 +1019,7 @@ class WifiConfigStore { // Prevent client screw-up by passing in a WifiConfiguration we gave it // by preventing "*" as a key. if (config.preSharedKey != null && !config.preSharedKey.equals("*") && - !WifiNative.setNetworkVariableCommand( + !mWifiNative.setNetworkVariable( netId, WifiConfiguration.pskVarName, config.preSharedKey)) { @@ -985,7 +1033,7 @@ class WifiConfigStore { // Prevent client screw-up by passing in a WifiConfiguration we gave it // by preventing "*" as a key. if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { - if (!WifiNative.setNetworkVariableCommand( + if (!mWifiNative.setNetworkVariable( netId, WifiConfiguration.wepKeyVarNames[i], config.wepKeys[i])) { @@ -998,7 +1046,7 @@ class WifiConfigStore { } if (hasSetKey) { - if (!WifiNative.setNetworkVariableCommand( + if (!mWifiNative.setNetworkVariable( netId, WifiConfiguration.wepTxKeyIdxVarName, Integer.toString(config.wepTxKeyIndex))) { @@ -1007,7 +1055,7 @@ class WifiConfigStore { } } - if (!WifiNative.setNetworkVariableCommand( + if (!mWifiNative.setNetworkVariable( netId, WifiConfiguration.priorityVarName, Integer.toString(config.priority))) { @@ -1016,7 +1064,7 @@ class WifiConfigStore { break setVariables; } - if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand( + if (config.hiddenSSID && !mWifiNative.setNetworkVariable( netId, WifiConfiguration.hiddenSSIDVarName, Integer.toString(config.hiddenSSID ? 1 : 0))) { @@ -1033,7 +1081,7 @@ class WifiConfigStore { if (field != config.eap) { value = (value.length() == 0) ? "NULL" : convertToQuotedString(value); } - if (!WifiNative.setNetworkVariableCommand( + if (!mWifiNative.setNetworkVariable( netId, varName, value)) { @@ -1048,42 +1096,37 @@ class WifiConfigStore { if (updateFailed) { if (newNetwork) { - WifiNative.removeNetworkCommand(netId); + mWifiNative.removeNetwork(netId); loge("Failed to set a network variable, removed network: " + netId); } return new NetworkUpdateResult(INVALID_NETWORK_ID); } /* An update of the network variables requires reading them - * back from the supplicant to update sConfiguredNetworks. + * back from the supplicant to update mConfiguredNetworks. * This is because some of the variables (SSID, wep keys & * passphrases) reflect different values when read back than * when written. For example, wep key is stored as * irrespective * of the value sent to the supplicant */ - WifiConfiguration sConfig; - synchronized (sConfiguredNetworks) { - sConfig = sConfiguredNetworks.get(netId); - } - if (sConfig == null) { - sConfig = new WifiConfiguration(); - sConfig.networkId = netId; + WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); + if (currentConfig == null) { + currentConfig = new WifiConfiguration(); + currentConfig.networkId = netId; } - readNetworkVariables(sConfig); + readNetworkVariables(currentConfig); - synchronized (sConfiguredNetworks) { - sConfiguredNetworks.put(netId, sConfig); - sNetworkIds.put(configKey(sConfig), netId); - } + mConfiguredNetworks.put(netId, currentConfig); + mNetworkIds.put(configKey(currentConfig), netId); - NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(sConfig, config); + NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); result.setNetworkId(netId); return result; } /* Compare current and new configuration and write to file on change */ - private static NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( + private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( WifiConfiguration currentConfig, WifiConfiguration newConfig) { boolean ipChanged = false; @@ -1182,7 +1225,7 @@ class WifiConfigStore { return new NetworkUpdateResult(ipChanged, proxyChanged); } - private static void addIpSettingsFromConfig(LinkProperties linkProperties, + private void addIpSettingsFromConfig(LinkProperties linkProperties, WifiConfiguration config) { for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) { linkProperties.addLinkAddress(linkAddr); @@ -1201,7 +1244,7 @@ class WifiConfigStore { * * @param config the {@link WifiConfiguration} object to be filled in. */ - private static void readNetworkVariables(WifiConfiguration config) { + private void readNetworkVariables(WifiConfiguration config) { int netId = config.networkId; if (netId < 0) @@ -1214,21 +1257,21 @@ class WifiConfigStore { */ String value; - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName); + value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); if (!TextUtils.isEmpty(value)) { config.SSID = value; } else { config.SSID = null; } - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName); + value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); if (!TextUtils.isEmpty(value)) { config.BSSID = value; } else { config.BSSID = null; } - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName); + value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); config.priority = -1; if (!TextUtils.isEmpty(value)) { try { @@ -1237,7 +1280,7 @@ class WifiConfigStore { } } - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName); + value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); config.hiddenSSID = false; if (!TextUtils.isEmpty(value)) { try { @@ -1246,7 +1289,7 @@ class WifiConfigStore { } } - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName); + value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); config.wepTxKeyIndex = -1; if (!TextUtils.isEmpty(value)) { try { @@ -1256,7 +1299,7 @@ class WifiConfigStore { } for (int i = 0; i < 4; i++) { - value = WifiNative.getNetworkVariableCommand(netId, + value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepKeyVarNames[i]); if (!TextUtils.isEmpty(value)) { config.wepKeys[i] = value; @@ -1265,14 +1308,14 @@ class WifiConfigStore { } } - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName); + value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); if (!TextUtils.isEmpty(value)) { config.preSharedKey = value; } else { config.preSharedKey = null; } - value = WifiNative.getNetworkVariableCommand(config.networkId, + value = mWifiNative.getNetworkVariable(config.networkId, WifiConfiguration.Protocol.varName); if (!TextUtils.isEmpty(value)) { String vals[] = value.split(" "); @@ -1285,7 +1328,7 @@ class WifiConfigStore { } } - value = WifiNative.getNetworkVariableCommand(config.networkId, + value = mWifiNative.getNetworkVariable(config.networkId, WifiConfiguration.KeyMgmt.varName); if (!TextUtils.isEmpty(value)) { String vals[] = value.split(" "); @@ -1298,7 +1341,7 @@ class WifiConfigStore { } } - value = WifiNative.getNetworkVariableCommand(config.networkId, + value = mWifiNative.getNetworkVariable(config.networkId, WifiConfiguration.AuthAlgorithm.varName); if (!TextUtils.isEmpty(value)) { String vals[] = value.split(" "); @@ -1311,7 +1354,7 @@ class WifiConfigStore { } } - value = WifiNative.getNetworkVariableCommand(config.networkId, + value = mWifiNative.getNetworkVariable(config.networkId, WifiConfiguration.PairwiseCipher.varName); if (!TextUtils.isEmpty(value)) { String vals[] = value.split(" "); @@ -1324,7 +1367,7 @@ class WifiConfigStore { } } - value = WifiNative.getNetworkVariableCommand(config.networkId, + value = mWifiNative.getNetworkVariable(config.networkId, WifiConfiguration.GroupCipher.varName); if (!TextUtils.isEmpty(value)) { String vals[] = value.split(" "); @@ -1339,7 +1382,7 @@ class WifiConfigStore { for (WifiConfiguration.EnterpriseField field : config.enterpriseFields) { - value = WifiNative.getNetworkVariableCommand(netId, + value = mWifiNative.getNetworkVariable(netId, field.varName()); if (!TextUtils.isEmpty(value)) { if (field != config.eap) value = removeDoubleQuotes(value); @@ -1348,16 +1391,16 @@ class WifiConfigStore { } } - private static String removeDoubleQuotes(String string) { + private String removeDoubleQuotes(String string) { if (string.length() <= 2) return ""; return string.substring(1, string.length() - 1); } - private static String convertToQuotedString(String string) { + private String convertToQuotedString(String string) { return "\"" + string + "\""; } - private static String makeString(BitSet set, String[] strings) { + private String makeString(BitSet set, String[] strings) { StringBuffer buf = new StringBuffer(); int nextSetBit = -1; @@ -1377,7 +1420,7 @@ class WifiConfigStore { return buf.toString(); } - private static int lookupString(String string, String[] strings) { + private int lookupString(String string, String[] strings) { int size = strings.length; string = string.replace('-', '_'); @@ -1412,10 +1455,10 @@ class WifiConfigStore { return key.hashCode(); } - static String dump() { + String dump() { StringBuffer sb = new StringBuffer(); String LS = System.getProperty("line.separator"); - sb.append("sLastPriority ").append(sLastPriority).append(LS); + sb.append("mLastPriority ").append(mLastPriority).append(LS); sb.append("Configured networks ").append(LS); for (WifiConfiguration conf : getConfiguredNetworks()) { sb.append(conf).append(LS); @@ -1423,15 +1466,15 @@ class WifiConfigStore { return sb.toString(); } - public static String getConfigFile() { + public String getConfigFile() { return ipConfigFile; } - private static void loge(String s) { + private void loge(String s) { Log.e(TAG, s); } - private static void log(String s) { + private void log(String s) { Log.d(TAG, s); } } diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index d5b404e..7bb927b 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -70,7 +70,6 @@ public class WifiInfo implements Parcelable { private InetAddress mIpAddress; private String mMacAddress; - private boolean mExplicitConnect; WifiInfo() { mSSID = null; @@ -80,7 +79,6 @@ public class WifiInfo implements Parcelable { mRssi = -9999; mLinkSpeed = -1; mHiddenSSID = false; - mExplicitConnect = false; } /** @@ -98,7 +96,6 @@ public class WifiInfo implements Parcelable { mLinkSpeed = source.mLinkSpeed; mIpAddress = source.mIpAddress; mMacAddress = source.mMacAddress; - mExplicitConnect = source.mExplicitConnect; } } @@ -175,22 +172,6 @@ public class WifiInfo implements Parcelable { mNetworkId = id; } - - /** - * @hide - */ - public boolean isExplicitConnect() { - return mExplicitConnect; - } - - /** - * @hide - */ - public void setExplicitConnect(boolean explicitConnect) { - this.mExplicitConnect = explicitConnect; - } - - /** * Each configured network has a unique small integer ID, used to identify * the network when performing operations on the supplicant. This method @@ -279,8 +260,7 @@ public class WifiInfo implements Parcelable { append(mSupplicantState == null ? none : mSupplicantState). append(", RSSI: ").append(mRssi). append(", Link speed: ").append(mLinkSpeed). - append(", Net ID: ").append(mNetworkId). - append(", Explicit connect: ").append(mExplicitConnect); + append(", Net ID: ").append(mNetworkId); return sb.toString(); } @@ -304,7 +284,6 @@ public class WifiInfo implements Parcelable { dest.writeString(getSSID()); dest.writeString(mBSSID); dest.writeString(mMacAddress); - dest.writeByte(mExplicitConnect ? (byte)1 : (byte)0); mSupplicantState.writeToParcel(dest, flags); } @@ -324,7 +303,6 @@ public class WifiInfo implements Parcelable { info.setSSID(in.readString()); info.mBSSID = in.readString(); info.mMacAddress = in.readString(); - info.mExplicitConnect = in.readByte() == 1 ? true : false; info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); return info; } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 40ac2a0..1a0e0da 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -413,6 +413,13 @@ public class WifiManager { private static final int MAX_RSSI = -55; /** + * Number of RSSI levels used in the framework to initiate + * {@link #RSSI_CHANGED_ACTION} broadcast + * @hide + */ + public static final int RSSI_LEVELS = 5; + + /** * Auto settings in the driver. The driver could choose to operate on both * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band. * @hide diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java index 2ccc8a2..bbb74d1 100644 --- a/wifi/java/android/net/wifi/WifiMonitor.java +++ b/wifi/java/android/net/wifi/WifiMonitor.java @@ -20,6 +20,7 @@ import android.net.NetworkInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pGroup; +import android.net.wifi.p2p.WifiP2pProvDiscEvent; import android.net.wifi.StateChangeResult; import android.os.Message; import android.util.Log; @@ -181,6 +182,10 @@ public class WifiMonitor { pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 group_capab=0x0 */ private static final String P2P_PROV_DISC_PBC_REQ_STR = "P2P-PROV-DISC-PBC-REQ"; + + /* P2P-PROV-DISC-PBC-RESP 02:12:47:f2:5a:36 */ + private static final String P2P_PROV_DISC_PBC_RSP_STR = "P2P-PROV-DISC-PBC-RESP"; + /* P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 group_capab=0x0 */ @@ -191,12 +196,13 @@ public class WifiMonitor { private static final String P2P_PROV_DISC_SHOW_PIN_STR = "P2P-PROV-DISC-SHOW-PIN"; private static final String HOST_AP_EVENT_PREFIX_STR = "AP"; - /* AP-STA-CONNECTED 42:fc:89:a8:96:09 */ + /* AP-STA-CONNECTED 42:fc:89:a8:96:09 dev_addr=02:90:4c:a0:92:54 */ private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED"; /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */ private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED"; private final StateMachine mStateMachine; + private final WifiNative mWifiNative; /* Supplicant events reported to a state machine */ private static final int BASE = Protocol.BASE_WIFI_MONITOR; @@ -233,8 +239,9 @@ public class WifiMonitor { public static final int P2P_INVITATION_RECEIVED_EVENT = BASE + 31; public static final int P2P_INVITATION_RESULT_EVENT = BASE + 32; public static final int P2P_PROV_DISC_PBC_REQ_EVENT = BASE + 33; - public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 34; - public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 35; + public static final int P2P_PROV_DISC_PBC_RSP_EVENT = BASE + 34; + public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 35; + public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 36; /* hostap events */ public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41; @@ -260,8 +267,9 @@ public class WifiMonitor { */ private static final int MAX_RECV_ERRORS = 10; - public WifiMonitor(StateMachine wifiStateMachine) { + public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) { mStateMachine = wifiStateMachine; + mWifiNative = wifiNative; } public void startMonitoring() { @@ -286,7 +294,7 @@ public class WifiMonitor { //noinspection InfiniteLoopStatement for (;;) { - String eventStr = WifiNative.waitForEvent(); + String eventStr = mWifiNative.waitForEvent(); // Skip logging the common but mostly uninteresting scan-results event if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) { @@ -400,7 +408,7 @@ public class WifiMonitor { int connectTries = 0; while (true) { - if (WifiNative.connectToSupplicant()) { + if (mWifiNative.connectToSupplicant()) { return true; } if (connectTries++ < 5) { @@ -480,10 +488,16 @@ public class WifiMonitor { mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, nameValue[1]); } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) { mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT, - new WifiP2pDevice(dataString)); + new WifiP2pProvDiscEvent(dataString)); + } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) { + mStateMachine.sendMessage(P2P_PROV_DISC_PBC_RSP_EVENT, + new WifiP2pProvDiscEvent(dataString)); } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) { mStateMachine.sendMessage(P2P_PROV_DISC_ENTER_PIN_EVENT, - new WifiP2pDevice(dataString)); + new WifiP2pProvDiscEvent(dataString)); + } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) { + mStateMachine.sendMessage(P2P_PROV_DISC_SHOW_PIN_EVENT, + new WifiP2pProvDiscEvent(dataString)); } } @@ -492,9 +506,17 @@ public class WifiMonitor { */ private void handleHostApEvents(String dataString) { String[] tokens = dataString.split(" "); + /* AP-STA-CONNECTED 42:fc:89:a8:96:09 dev_addr=02:90:4c:a0:92:54 */ if (tokens[0].equals(AP_STA_CONNECTED_STR)) { - mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, tokens[1]); + String[] nameValue = tokens[2].split("="); + if (nameValue.length != 2) return; + WifiP2pDevice device = new WifiP2pDevice(); + device.interfaceAddress = tokens[1]; + device.deviceAddress = nameValue[1]; + mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, device); + /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */ } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) { + //TODO: fix this once wpa_supplicant reports this consistently mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, tokens[1]); } } diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 6ff1bc2..48a785c 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -19,6 +19,8 @@ package android.net.wifi; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pDevice; +import android.os.SystemProperties; +import android.text.TextUtils; import android.util.Log; import java.io.InputStream; @@ -27,30 +29,23 @@ import java.util.ArrayList; import java.util.List; /** - * Native calls for sending requests to the supplicant daemon, and for - * receiving asynchronous events. All methods of the form "xxxxCommand()" - * must be single-threaded, to avoid requests and responses initiated - * from multiple threads from being intermingled. - * <p/> - * Note that methods whose names are not of the form "xxxCommand()" do - * not talk to the supplicant daemon. - * Also, note that all WifiNative calls should happen in the - * WifiStateTracker class except for waitForEvent() call which is - * on a separate monitor channel for WifiMonitor + * Native calls for bring up/shut down of the supplicant daemon and for + * sending requests to the supplicant daemon * - * TODO: clean up the API and move the functionality from JNI to here. We should - * be able to get everything done with doBooleanCommand, doIntCommand and - * doStringCommand native commands + * waitForEvent() is called on the monitor thread for events. All other methods + * must be serialized from the framework. * * {@hide} */ public class WifiNative { + private static final int DEFAULT_GROUP_OWNER_INTENT = 7; + static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; - public native static String getErrorString(int errorCode); + String mInterface = ""; public native static boolean loadDriver(); @@ -62,92 +57,252 @@ public class WifiNative { public native static boolean startP2pSupplicant(); - /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. - * - * Note that underneath we use a harsh-sounding "terminate" supplicant command - * for a graceful stop and a mild-sounding "stop" interface - * to kill the process - */ - public native static boolean stopSupplicant(); - /* Sends a kill signal to supplicant. To be used when we have lost connection or when the supplicant is hung */ public native static boolean killSupplicant(); - public native static boolean connectToSupplicant(); + private native boolean connectToSupplicant(String iface); - public native static void closeSupplicantConnection(); + private native void closeSupplicantConnection(String iface); - public native static boolean pingCommand(); + /** + * Wait for the supplicant to send an event, returning the event string. + * @return the event string sent by the supplicant. + */ + private native String waitForEvent(String iface); - public native static boolean scanCommand(boolean forceActive); + private native boolean doBooleanCommand(String iface, String command); - public native static boolean setScanModeCommand(boolean setActive); + private native int doIntCommand(String iface, String command); - public native static String listNetworksCommand(); + private native String doStringCommand(String iface, String command); - public native static int addNetworkCommand(); + public WifiNative(String iface) { + mInterface = iface; + } - public native static boolean setNetworkVariableCommand(int netId, String name, String value); + public boolean connectToSupplicant() { + return connectToSupplicant(mInterface); + } - public native static String getNetworkVariableCommand(int netId, String name); + public void closeSupplicantConnection() { + closeSupplicantConnection(mInterface); + } - public native static boolean removeNetworkCommand(int netId); + public String waitForEvent() { + return waitForEvent(mInterface); + } - public native static boolean enableNetworkCommand(int netId, boolean disableOthers); + private boolean doBooleanCommand(String command) { + return doBooleanCommand(mInterface, command); + } - public native static boolean disableNetworkCommand(int netId); + private int doIntCommand(String command) { + return doIntCommand(mInterface, command); + } - public native static boolean reconnectCommand(); + private String doStringCommand(String command) { + return doStringCommand(mInterface, command); + } - public native static boolean reassociateCommand(); + public boolean ping() { + String pong = doStringCommand("PING"); + return (pong != null && pong.equals("PONG")); + } - public native static boolean disconnectCommand(); + public boolean scan() { + return doBooleanCommand("SCAN"); + } - public native static String statusCommand(); + public boolean setScanMode(boolean setActive) { + if (setActive) { + return doBooleanCommand("DRIVER SCAN-ACTIVE"); + } else { + return doBooleanCommand("DRIVER SCAN-PASSIVE"); + } + } - public native static String getMacAddressCommand(); + /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. + * + * Note that underneath we use a harsh-sounding "terminate" supplicant command + * for a graceful stop and a mild-sounding "stop" interface + * to kill the process + */ + public boolean stopSupplicant() { + return doBooleanCommand("TERMINATE"); + } - public native static String scanResultsCommand(); + public String listNetworks() { + return doStringCommand("LIST_NETWORKS"); + } - public native static boolean startDriverCommand(); + public int addNetwork() { + return doIntCommand("ADD_NETWORK"); + } - public native static boolean stopDriverCommand(); + public boolean setNetworkVariable(int netId, String name, String value) { + if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false; + return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value); + } + + public String getNetworkVariable(int netId, String name) { + if (TextUtils.isEmpty(name)) return null; + return doStringCommand("GET_NETWORK " + netId + " " + name); + } + + public boolean removeNetwork(int netId) { + return doBooleanCommand("REMOVE_NETWORK " + netId); + } + + public boolean enableNetwork(int netId, boolean disableOthers) { + if (disableOthers) { + return doBooleanCommand("SELECT_NETWORK " + netId); + } else { + return doBooleanCommand("ENABLE_NETWORK " + netId); + } + } + + public boolean disableNetwork(int netId) { + return doBooleanCommand("DISABLE_NETWORK " + netId); + } + + public boolean reconnect() { + return doBooleanCommand("RECONNECT"); + } + + public boolean reassociate() { + return doBooleanCommand("REASSOCIATE"); + } + + public boolean disconnect() { + return doBooleanCommand("DISCONNECT"); + } + + public String status() { + return doStringCommand("STATUS"); + } + + public String getMacAddress() { + //Macaddr = XX.XX.XX.XX.XX.XX + String ret = doStringCommand("DRIVER MACADDR"); + if (!TextUtils.isEmpty(ret)) { + String[] tokens = ret.split(" = "); + if (tokens.length == 2) return tokens[1]; + } + return null; + } + + public String scanResults() { + return doStringCommand("SCAN_RESULTS"); + } + + public boolean startDriver() { + return doBooleanCommand("DRIVER START"); + } + + public boolean stopDriver() { + return doBooleanCommand("DRIVER STOP"); + } /** * Start filtering out Multicast V4 packets * @return {@code true} if the operation succeeded, {@code false} otherwise + * + * Multicast filtering rules work as follows: + * + * The driver can filter multicast (v4 and/or v6) and broadcast packets when in + * a power optimized mode (typically when screen goes off). + * + * In order to prevent the driver from filtering the multicast/broadcast packets, we have to + * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective + * + * DRIVER RXFILTER-ADD Num + * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 + * + * and DRIVER RXFILTER-START + * In order to stop the usage of these rules, we do + * + * DRIVER RXFILTER-STOP + * DRIVER RXFILTER-REMOVE Num + * where Num is as described for RXFILTER-ADD + * + * The SETSUSPENDOPT driver command overrides the filtering rules */ - public native static boolean startFilteringMulticastV4Packets(); + public boolean startFilteringMulticastV4Packets() { + return doBooleanCommand("DRIVER RXFILTER-STOP") + && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") + && doBooleanCommand("DRIVER RXFILTER-START"); + } /** * Stop filtering out Multicast V4 packets. * @return {@code true} if the operation succeeded, {@code false} otherwise */ - public native static boolean stopFilteringMulticastV4Packets(); + public boolean stopFilteringMulticastV4Packets() { + return doBooleanCommand("DRIVER RXFILTER-STOP") + && doBooleanCommand("DRIVER RXFILTER-ADD 2") + && doBooleanCommand("DRIVER RXFILTER-START"); + } /** * Start filtering out Multicast V6 packets * @return {@code true} if the operation succeeded, {@code false} otherwise */ - public native static boolean startFilteringMulticastV6Packets(); + public boolean startFilteringMulticastV6Packets() { + return doBooleanCommand("DRIVER RXFILTER-STOP") + && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") + && doBooleanCommand("DRIVER RXFILTER-START"); + } /** * Stop filtering out Multicast V6 packets. * @return {@code true} if the operation succeeded, {@code false} otherwise */ - public native static boolean stopFilteringMulticastV6Packets(); + public boolean stopFilteringMulticastV6Packets() { + return doBooleanCommand("DRIVER RXFILTER-STOP") + && doBooleanCommand("DRIVER RXFILTER-ADD 3") + && doBooleanCommand("DRIVER RXFILTER-START"); + } - public native static boolean setPowerModeCommand(int mode); + public int getPowerMode() { + String ret = doStringCommand("DRIVER GETPOWER"); + if (!TextUtils.isEmpty(ret)) { + // reply comes back in the form "powermode = XX" where XX is the + // number we're interested in. + String[] tokens = ret.split(" = "); + try { + if (tokens.length == 2) return Integer.parseInt(tokens[1]); + } catch (NumberFormatException e) { + return -1; + } + } + return -1; + } - public native static int getBandCommand(); + public boolean setPowerMode(int mode) { + return doBooleanCommand("DRIVER POWERMODE " + mode); + } - public native static boolean setBandCommand(int band); + public int getBand() { + String ret = doStringCommand("DRIVER GETBAND"); + if (!TextUtils.isEmpty(ret)) { + //reply is "BAND X" where X is the band + String[] tokens = ret.split(" "); + try { + if (tokens.length == 2) return Integer.parseInt(tokens[1]); + } catch (NumberFormatException e) { + return -1; + } + } + return -1; + } - public native static int getPowerModeCommand(); + public boolean setBand(int band) { + return doBooleanCommand("DRIVER SETBAND " + band); + } - /** + /** * Sets the bluetooth coexistence mode. * * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, @@ -155,7 +310,9 @@ public class WifiNative { * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. * @return Whether the mode was successfully set. */ - public native static boolean setBluetoothCoexistenceModeCommand(int mode); + public boolean setBluetoothCoexistenceMode(int mode) { + return doBooleanCommand("DRIVER BTCOEXMODE " + mode); + } /** * Enable or disable Bluetooth coexistence scan mode. When this mode is on, @@ -165,43 +322,57 @@ public class WifiNative { * @param isSet whether to enable or disable this mode * @return {@code true} if the command succeeded, {@code false} otherwise. */ - public native static boolean setBluetoothCoexistenceScanModeCommand(boolean setCoexScanMode); - - public native static boolean saveConfigCommand(); - - public native static boolean reloadConfigCommand(); - - public native static boolean setScanResultHandlingCommand(int mode); - - public native static boolean addToBlacklistCommand(String bssid); - - public native static boolean clearBlacklistCommand(); - - public native static boolean startWpsPbcCommand(String bssid); - - public native static boolean startWpsWithPinFromAccessPointCommand(String bssid, String apPin); - - public native static String startWpsWithPinFromDeviceCommand(String bssid); + public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { + if (setCoexScanMode) { + return doBooleanCommand("DRIVER BTCOEXSCAN-START"); + } else { + return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); + } + } - public native static boolean setSuspendOptimizationsCommand(boolean enabled); + public boolean saveConfig() { + // Make sure we never write out a value for AP_SCAN other than 1 + return doBooleanCommand("AP_SCAN 1") && doBooleanCommand("SAVE_CONFIG"); + } - public native static boolean setCountryCodeCommand(String countryCode); + public boolean setScanResultHandling(int mode) { + return doBooleanCommand("AP_SCAN " + mode); + } - /** - * Wait for the supplicant to send an event, returning the event string. - * @return the event string sent by the supplicant. - */ - public native static String waitForEvent(); + public boolean addToBlacklist(String bssid) { + if (TextUtils.isEmpty(bssid)) return false; + return doBooleanCommand("BLACKLIST " + bssid); + } - public native static void enableBackgroundScanCommand(boolean enable); + public boolean clearBlacklist() { + return doBooleanCommand("BLACKLIST clear"); + } - public native static void setScanIntervalCommand(int scanInterval); + public boolean setSuspendOptimizations(boolean enabled) { + if (enabled) { + return doBooleanCommand("DRIVER SETSUSPENDOPT 0"); + } else { + return doBooleanCommand("DRIVER SETSUSPENDOPT 1"); + } + } - private native static boolean doBooleanCommand(String command); + public boolean setCountryCode(String countryCode) { + return doBooleanCommand("DRIVER COUNTRY " + countryCode); + } - private native static int doIntCommand(String command); + public void enableBackgroundScan(boolean enable) { + //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml + //and will need an update if the names are changed + if (enable) { + doBooleanCommand("DRIVER BGSCAN-START"); + } else { + doBooleanCommand("DRIVER BGSCAN-STOP"); + } + } - private native static String doStringCommand(String command); + public void setScanInterval(int scanInterval) { + doBooleanCommand("SCAN_INTERVAL " + scanInterval); + } /** Example output: * RSSI=-65 @@ -209,60 +380,81 @@ public class WifiNative { * NOISE=9999 * FREQUENCY=0 */ - public static String signalPoll() { + public String signalPoll() { return doStringCommand("SIGNAL_POLL"); } - public static boolean wpsPbc() { + public boolean startWpsPbc() { return doBooleanCommand("WPS_PBC"); } - public static boolean wpsPin(String pin) { + public boolean startWpsPbc(String bssid) { + return doBooleanCommand("WPS_PBC " + bssid); + } + + public boolean startWpsPinKeypad(String pin) { return doBooleanCommand("WPS_PIN any " + pin); } - public static boolean setPersistentReconnect(boolean enabled) { + public String startWpsPinDisplay(String bssid) { + return doStringCommand("WPS_PIN " + bssid); + } + + /* Configures an access point connection */ + public boolean startWpsRegistrar(String bssid, String pin) { + return doBooleanCommand("WPS_REG " + bssid + " " + pin); + } + + public boolean setPersistentReconnect(boolean enabled) { int value = (enabled == true) ? 1 : 0; - return WifiNative.doBooleanCommand("SET persistent_reconnect " + value); + return doBooleanCommand("SET persistent_reconnect " + value); + } + + public boolean setDeviceName(String name) { + return doBooleanCommand("SET device_name " + name); + } + + public boolean setDeviceType(String type) { + return doBooleanCommand("SET device_type " + type); } - public static boolean setDeviceName(String name) { - return WifiNative.doBooleanCommand("SET device_name " + name); + public boolean setConfigMethods(String cfg) { + return doBooleanCommand("SET config_methods " + cfg); } - public static boolean setDeviceType(String type) { - return WifiNative.doBooleanCommand("SET device_type " + type); + public boolean setP2pSsidPostfix(String postfix) { + return doBooleanCommand("SET p2p_ssid_postfix " + postfix); } - public static boolean p2pFind() { + public boolean p2pFind() { return doBooleanCommand("P2P_FIND"); } - public static boolean p2pFind(int timeout) { + public boolean p2pFind(int timeout) { if (timeout <= 0) { return p2pFind(); } return doBooleanCommand("P2P_FIND " + timeout); } - public static boolean p2pListen() { + public boolean p2pListen() { return doBooleanCommand("P2P_LISTEN"); } - public static boolean p2pListen(int timeout) { + public boolean p2pListen(int timeout) { if (timeout <= 0) { return p2pListen(); } return doBooleanCommand("P2P_LISTEN " + timeout); } - public static boolean p2pFlush() { + public boolean p2pFlush() { return doBooleanCommand("P2P_FLUSH"); } /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ - public static String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { + public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { if (config == null) return null; List<String> args = new ArrayList<String>(); WpsInfo wps = config.wps; @@ -273,8 +465,11 @@ public class WifiNative { args.add("pbc"); break; case WpsInfo.DISPLAY: - //TODO: pass the pin back for display - args.add("pin"); + if (TextUtils.isEmpty(wps.pin)) { + args.add("pin"); + } else { + args.add(wps.pin); + } args.add("display"); break; case WpsInfo.KEYPAD: @@ -295,9 +490,11 @@ public class WifiNative { if (joinExistingGroup) args.add("join"); + //TODO: This can be adapted based on device plugged in state and + //device battery state int groupOwnerIntent = config.groupOwnerIntent; if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { - groupOwnerIntent = 3; //default value + groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; } args.add("go_intent=" + groupOwnerIntent); @@ -307,25 +504,43 @@ public class WifiNative { return doStringCommand(command); } - public static boolean p2pCancelConnect() { + public boolean p2pCancelConnect() { return doBooleanCommand("P2P_CANCEL"); } - public static boolean p2pGroupAdd() { + public boolean p2pProvisionDiscovery(WifiP2pConfig config) { + if (config == null) return false; + + switch (config.wps.setup) { + case WpsInfo.PBC: + return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); + case WpsInfo.DISPLAY: + //We are doing display, so provision discovery is keypad + return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); + case WpsInfo.KEYPAD: + //We are doing keypad, so provision discovery is display + return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); + default: + break; + } + return false; + } + + public boolean p2pGroupAdd() { return doBooleanCommand("P2P_GROUP_ADD"); } - public static boolean p2pGroupRemove(String iface) { + public boolean p2pGroupRemove(String iface) { if (iface == null) return false; return doBooleanCommand("P2P_GROUP_REMOVE " + iface); } - public static boolean p2pReject(String deviceAddress) { + public boolean p2pReject(String deviceAddress) { return doBooleanCommand("P2P_REJECT " + deviceAddress); } /* Invite a peer to a group */ - public static boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { + public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { if (deviceAddress == null) return false; if (group == null) { @@ -337,14 +552,14 @@ public class WifiNative { } /* Reinvoke a persistent connection */ - public static boolean p2pReinvoke(int netId, String deviceAddress) { + public boolean p2pReinvoke(int netId, String deviceAddress) { if (deviceAddress == null || netId < 0) return false; return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); } - public static String p2pGetInterfaceAddress(String deviceAddress) { + public String p2pGetInterfaceAddress(String deviceAddress) { if (deviceAddress == null) return null; // "p2p_peer deviceAddress" returns a multi-line result containing @@ -364,8 +579,8 @@ public class WifiNative { return null; } - public static String p2pGetDeviceAddress() { - String status = statusCommand(); + public String p2pGetDeviceAddress() { + String status = status(); if (status == null) return ""; String[] tokens = status.split("\n"); @@ -379,7 +594,7 @@ public class WifiNative { return ""; } - public static String p2pPeer(String deviceAddress) { + public String p2pPeer(String deviceAddress) { return doStringCommand("P2P_PEER " + deviceAddress); } } diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 4539c6b..b8b7c0e 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -113,6 +113,8 @@ public class WifiStateMachine extends StateMachine { private static final String SOFTAP_IFACE = "wl0.1"; private WifiMonitor mWifiMonitor; + private WifiNative mWifiNative; + private WifiConfigStore mWifiConfigStore; private INetworkManagementService mNwService; private ConnectivityManager mCm; @@ -135,6 +137,8 @@ public class WifiStateMachine extends StateMachine { private int mReconnectCount = 0; private boolean mIsScanMode = false; private boolean mScanResultIsPending = false; + /* Tracks if the current scan settings are active */ + private boolean mSetScanActive = false; private boolean mBluetoothConnectionActive = false; @@ -276,6 +280,8 @@ public class WifiStateMachine extends StateMachine { static final int CMD_CLEAR_BLACKLIST = BASE + 58; /* Save configuration */ static final int CMD_SAVE_CONFIG = BASE + 59; + /* Get configured networks*/ + static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 60; /* Supplicant commands after driver start*/ /* Initiate a scan */ @@ -537,11 +543,6 @@ public class WifiStateMachine extends StateMachine { private final WorkSource mLastRunningWifiUids = new WorkSource(); private final IBatteryStats mBatteryStats; - private boolean mNextWifiActionExplicit = false; - private int mLastExplicitNetworkId; - private long mLastNetworkChoiceTime; - private static final long EXPLICIT_CONNECT_ALLOWED_DELAY_MS = 2 * 60 * 1000; - public WifiStateMachine(Context context, String wlanInterface) { super(TAG); @@ -555,11 +556,14 @@ public class WifiStateMachine extends StateMachine { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNwService = INetworkManagementService.Stub.asInterface(b); - mWifiMonitor = new WifiMonitor(this); + mWifiNative = new WifiNative(mInterfaceName); + mWifiConfigStore = new WifiConfigStore(context, mWifiNative); + mWifiMonitor = new WifiMonitor(this, mWifiNative); mDhcpInfoInternal = new DhcpInfoInternal(); mWifiInfo = new WifiInfo(); - mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler()); - mWpsStateMachine = new WpsStateMachine(context, this, getHandler()); + mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, + getHandler()); + mWpsStateMachine = new WpsStateMachine(context, this, mWifiConfigStore, getHandler()); mLinkProperties = new LinkProperties(); WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( @@ -852,8 +856,11 @@ public class WifiStateMachine extends StateMachine { return result; } - public List<WifiConfiguration> syncGetConfiguredNetworks() { - return WifiConfigStore.getConfiguredNetworks(); + public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { + Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); + List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; + resultMsg.recycle(); + return result; } /** @@ -1039,7 +1046,7 @@ public class WifiStateMachine extends StateMachine { * Returns the wifi configuration file */ public String getConfigFile() { - return WifiConfigStore.getConfigFile(); + return mWifiConfigStore.getConfigFile(); } /** @@ -1113,9 +1120,9 @@ public class WifiStateMachine extends StateMachine { sb.append("mReconnectCount ").append(mReconnectCount).append(LS); sb.append("mIsScanMode ").append(mIsScanMode).append(LS); sb.append("Supplicant status").append(LS) - .append(WifiNative.statusCommand()).append(LS).append(LS); + .append(mWifiNative.status()).append(LS).append(LS); - sb.append(WifiConfigStore.dump()); + sb.append(mWifiConfigStore.dump()); return sb.toString(); } @@ -1146,9 +1153,9 @@ public class WifiStateMachine extends StateMachine { ifcg = mNwService.getInterfaceConfig(intf); if (ifcg != null) { /* IP/netmask: 192.168.43.1/255.255.255.0 */ - ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress( - "192.168.43.1"), 24); - ifcg.interfaceFlags = "[up]"; + ifcg.setLinkAddress(new LinkAddress( + NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); + ifcg.setInterfaceUp(); mNwService.setInterfaceConfig(intf, ifcg); } @@ -1180,8 +1187,8 @@ public class WifiStateMachine extends StateMachine { try { ifcg = mNwService.getInterfaceConfig(mInterfaceName); if (ifcg != null) { - ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress( - "0.0.0.0"), 0); + ifcg.setLinkAddress( + new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); mNwService.setInterfaceConfig(mInterfaceName, ifcg); } } catch (Exception e) { @@ -1408,7 +1415,7 @@ public class WifiStateMachine extends StateMachine { } private String fetchSSID() { - String status = WifiNative.statusCommand(); + String status = mWifiNative.status(); if (status == null) { return null; } @@ -1431,7 +1438,7 @@ public class WifiStateMachine extends StateMachine { int newRssi = -1; int newLinkSpeed = -1; - String signalPoll = WifiNative.signalPoll(); + String signalPoll = mWifiNative.signalPoll(); if (signalPoll != null) { String[] lines = signalPoll.split("\n"); @@ -1462,14 +1469,11 @@ public class WifiStateMachine extends StateMachine { * be displayed in the status bar, and only send the * broadcast if that much more coarse-grained number * changes. This cuts down greatly on the number of - * broadcasts, at the cost of not mWifiInforming others + * broadcasts, at the cost of not informing others * interested in RSSI of all the changes in signal * level. */ - // TODO: The second arg to the call below needs to be a symbol somewhere, but - // it's actually the size of an array of icons that's private - // to StatusBar Policy. - int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4); + int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); if (newSignalLevel != mLastSignalLevel) { sendRssiChangeBroadcast(newRssi); } @@ -1484,28 +1488,28 @@ public class WifiStateMachine extends StateMachine { } private void setHighPerfModeEnabledNative(boolean enable) { - if(!WifiNative.setSuspendOptimizationsCommand(!enable)) { + if(!mWifiNative.setSuspendOptimizations(!enable)) { loge("set suspend optimizations failed!"); } if (enable) { - if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) { + if (!mWifiNative.setPowerMode(POWER_MODE_ACTIVE)) { loge("set power mode active failed!"); } } else { - if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) { + if (!mWifiNative.setPowerMode(POWER_MODE_AUTO)) { loge("set power mode auto failed!"); } } } private void configureLinkProperties() { - if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { - mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId); + if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { + mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId); } else { synchronized (mDhcpInfoInternal) { mLinkProperties = mDhcpInfoInternal.makeLinkProperties(); } - mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId)); + mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); } mLinkProperties.setInterfaceName(mInterfaceName); if (DBG) { @@ -1648,17 +1652,18 @@ public class WifiStateMachine extends StateMachine { mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); mWifiInfo.setRssi(MIN_RSSI); mWifiInfo.setLinkSpeed(-1); - mWifiInfo.setExplicitConnect(false); - /* send event to CM & network change broadcast */ setNetworkDetailedState(DetailedState.DISCONNECTED); + mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); + + /* send event to CM & network change broadcast */ sendNetworkStateChangeBroadcast(mLastBssid); /* Clear network properties */ mLinkProperties.clear(); /* Clear IP settings if the network used DHCP */ - if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { - WifiConfigStore.clearIpConfiguration(mLastNetworkId); + if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { + mWifiConfigStore.clearIpConfiguration(mLastNetworkId); } mLastBssid= null; @@ -1684,29 +1689,29 @@ public class WifiStateMachine extends StateMachine { * coexistence would interrupt that connection. */ // Disable the coexistence mode - WifiNative.setBluetoothCoexistenceModeCommand( - WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); + mWifiNative.setBluetoothCoexistenceMode( + mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); } - mPowerMode = WifiNative.getPowerModeCommand(); + mPowerMode = mWifiNative.getPowerMode(); if (mPowerMode < 0) { // Handle the case where supplicant driver does not support // getPowerModeCommand. mPowerMode = WifiStateMachine.POWER_MODE_AUTO; } if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) { - WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE); + mWifiNative.setPowerMode(WifiStateMachine.POWER_MODE_ACTIVE); } } void handlePostDhcpSetup() { /* restore power mode */ - WifiNative.setPowerModeCommand(mPowerMode); + mWifiNative.setPowerMode(mPowerMode); // Set the coexistence mode back to its default value - WifiNative.setBluetoothCoexistenceModeCommand( - WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); + mWifiNative.setBluetoothCoexistenceMode( + mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); } private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) { @@ -1715,13 +1720,13 @@ public class WifiStateMachine extends StateMachine { } mLastSignalLevel = -1; // force update of signal strength mReconnectCount = 0; //Reset IP failure tracking - WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal); + mWifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal); InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress); mWifiInfo.setInetAddress(addr); if (getNetworkDetailedState() == DetailedState.CONNECTED) { //DHCP renewal in connected state LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties(); - linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId)); + linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); linkProperties.setInterfaceName(mInterfaceName); if (!linkProperties.equals(mLinkProperties)) { if (DBG) { @@ -1734,6 +1739,7 @@ public class WifiStateMachine extends StateMachine { } else { configureLinkProperties(); setNetworkDetailedState(DetailedState.CONNECTED); + mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); sendNetworkStateChangeBroadcast(mLastBssid); } } @@ -1749,7 +1755,7 @@ public class WifiStateMachine extends StateMachine { if (++mReconnectCount > getMaxDhcpRetries()) { loge("Failed " + mReconnectCount + " times, Disabling " + mLastNetworkId); - WifiConfigStore.disableNetwork(mLastNetworkId, + mWifiConfigStore.disableNetwork(mLastNetworkId, WifiConfiguration.DISABLED_DHCP_FAILURE); mReconnectCount = 0; } @@ -1757,8 +1763,8 @@ public class WifiStateMachine extends StateMachine { /* DHCP times out after about 30 seconds, we do a * disconnect and an immediate reconnect to try again */ - WifiNative.disconnectCommand(); - WifiNative.reconnectCommand(); + mWifiNative.disconnect(); + mWifiNative.reconnect(); } /* Current design is to not set the config on a running hostapd but instead @@ -1824,6 +1830,10 @@ public class WifiStateMachine extends StateMachine { case CMD_SAVE_CONFIG: mReplyChannel.replyToMessage(message, message.what, FAILURE); break; + case CMD_GET_CONFIGURED_NETWORKS: + mReplyChannel.replyToMessage(message, message.what, + mWifiConfigStore.getConfiguredNetworks()); + break; case CMD_ENABLE_RSSI_POLL: mEnableRssiPolling = (message.arg1 == 1); break; @@ -1909,7 +1919,7 @@ public class WifiStateMachine extends StateMachine { // 50021 wifi_state_changed (custom|1|5) EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - if (WifiNative.isDriverLoaded()) { + if (mWifiNative.isDriverLoaded()) { transitionTo(mDriverLoadedState); } else { @@ -1962,7 +1972,7 @@ public class WifiStateMachine extends StateMachine { break; } - if(WifiNative.loadDriver()) { + if(mWifiNative.loadDriver()) { if (DBG) log("Driver load successful"); sendMessage(CMD_LOAD_DRIVER_SUCCESS); } else { @@ -2050,7 +2060,7 @@ public class WifiStateMachine extends StateMachine { loge("Unable to change interface settings: " + ie); } - if(WifiNative.startSupplicant()) { + if(mWifiNative.startSupplicant()) { if (DBG) log("Supplicant start successful"); mWifiMonitor.startMonitoring(); transitionTo(mSupplicantStartingState); @@ -2082,7 +2092,7 @@ public class WifiStateMachine extends StateMachine { public void run() { if (DBG) log(getName() + message.toString() + "\n"); mWakeLock.acquire(); - if(WifiNative.unloadDriver()) { + if(mWifiNative.unloadDriver()) { if (DBG) log("Driver unload successful"); sendMessage(CMD_UNLOAD_DRIVER_SUCCESS); @@ -2213,9 +2223,9 @@ public class WifiStateMachine extends StateMachine { mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; mLastSignalLevel = -1; - mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand()); + mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); - WifiConfigStore.initialize(mContext); + mWifiConfigStore.initialize(); sendSupplicantConnectionChangedBroadcast(true); transitionTo(mDriverStartedState); @@ -2223,7 +2233,7 @@ public class WifiStateMachine extends StateMachine { case WifiMonitor.SUP_DISCONNECTION_EVENT: if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { loge("Failed to setup control channel, restart supplicant"); - WifiNative.killSupplicant(); + mWifiNative.killSupplicant(); transitionTo(mDriverLoadedState); sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); } else { @@ -2272,7 +2282,7 @@ public class WifiStateMachine extends StateMachine { long supplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(), Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, mDefaultSupplicantScanIntervalMs); - WifiNative.setScanIntervalCommand((int)supplicantScanIntervalMs / 1000); + mWifiNative.setScanInterval((int)supplicantScanIntervalMs / 1000); } @Override public boolean processMessage(Message message) { @@ -2285,8 +2295,8 @@ public class WifiStateMachine extends StateMachine { break; case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ loge("Connection lost, restart supplicant"); - WifiNative.killSupplicant(); - WifiNative.closeSupplicantConnection(); + mWifiNative.killSupplicant(); + mWifiNative.closeSupplicantConnection(); mNetworkInfo.setIsAvailable(false); handleNetworkDisconnect(); sendSupplicantConnectionChangedBroadcast(false); @@ -2297,46 +2307,46 @@ public class WifiStateMachine extends StateMachine { break; case WifiMonitor.SCAN_RESULTS_EVENT: eventLoggingEnabled = false; - setScanResults(WifiNative.scanResultsCommand()); + setScanResults(mWifiNative.scanResults()); sendScanResultsAvailableBroadcast(); mScanResultIsPending = false; break; case CMD_PING_SUPPLICANT: - boolean ok = WifiNative.pingCommand(); + boolean ok = mWifiNative.ping(); mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); break; case CMD_ADD_OR_UPDATE_NETWORK: config = (WifiConfiguration) message.obj; mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, - WifiConfigStore.addOrUpdateNetwork(config)); + mWifiConfigStore.addOrUpdateNetwork(config)); break; case CMD_REMOVE_NETWORK: - ok = WifiConfigStore.removeNetwork(message.arg1); + ok = mWifiConfigStore.removeNetwork(message.arg1); mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); break; case CMD_ENABLE_NETWORK: - ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); + ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); break; case CMD_ENABLE_ALL_NETWORKS: long time = android.os.SystemClock.elapsedRealtime(); if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { - WifiConfigStore.enableAllNetworks(); + mWifiConfigStore.enableAllNetworks(); mLastEnableAllNetworksTime = time; } break; case CMD_DISABLE_NETWORK: - ok = WifiConfigStore.disableNetwork(message.arg1, message.arg2); + ok = mWifiConfigStore.disableNetwork(message.arg1, message.arg2); mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); break; case CMD_BLACKLIST_NETWORK: - WifiNative.addToBlacklistCommand((String)message.obj); + mWifiNative.addToBlacklist((String)message.obj); break; case CMD_CLEAR_BLACKLIST: - WifiNative.clearBlacklistCommand(); + mWifiNative.clearBlacklist(); break; case CMD_SAVE_CONFIG: - ok = WifiConfigStore.saveConfig(); + ok = mWifiConfigStore.saveConfig(); mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); // Inform the backup manager about a data change @@ -2360,10 +2370,10 @@ public class WifiStateMachine extends StateMachine { break; case CMD_SAVE_NETWORK: config = (WifiConfiguration) message.obj; - WifiConfigStore.saveNetwork(config); + mWifiConfigStore.saveNetwork(config); break; case CMD_FORGET_NETWORK: - WifiConfigStore.forgetNetwork(message.arg1); + mWifiConfigStore.forgetNetwork(message.arg1); break; default: return NOT_HANDLED; @@ -2386,7 +2396,7 @@ public class WifiStateMachine extends StateMachine { if (DBG) log(getName() + "\n"); EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); if (DBG) log("stopping supplicant"); - if (!WifiNative.stopSupplicant()) { + if (!mWifiNative.stopSupplicant()) { loge("Failed to stop supplicant"); } @@ -2413,15 +2423,15 @@ public class WifiStateMachine extends StateMachine { /* Socket connection can be lost when we do a graceful shutdown * or when the driver is hung. Ensure supplicant is stopped here. */ - WifiNative.killSupplicant(); - WifiNative.closeSupplicantConnection(); + mWifiNative.killSupplicant(); + mWifiNative.closeSupplicantConnection(); transitionTo(mDriverLoadedState); break; case CMD_STOP_SUPPLICANT_FAILED: if (message.arg1 == mSupplicantStopFailureToken) { loge("Timed out on a supplicant stop, kill and proceed"); - WifiNative.killSupplicant(); - WifiNative.closeSupplicantConnection(); + mWifiNative.killSupplicant(); + mWifiNative.closeSupplicantConnection(); transitionTo(mDriverLoadedState); } break; @@ -2512,7 +2522,7 @@ public class WifiStateMachine extends StateMachine { * When this mode is on, some of the low-level scan parameters used by the * driver are changed to reduce interference with bluetooth */ - WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive); + mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); /* set country code */ setCountryCode(); /* set frequency band of operation */ @@ -2521,22 +2531,26 @@ public class WifiStateMachine extends StateMachine { setNetworkDetailedState(DetailedState.DISCONNECTED); /* Remove any filtering on Multicast v6 at start */ - WifiNative.stopFilteringMulticastV6Packets(); + mWifiNative.stopFilteringMulticastV6Packets(); /* Reset Multicast v4 filtering state */ if (mFilteringMulticastV4Packets.get()) { - WifiNative.startFilteringMulticastV4Packets(); + mWifiNative.startFilteringMulticastV4Packets(); } else { - WifiNative.stopFilteringMulticastV4Packets(); + mWifiNative.stopFilteringMulticastV4Packets(); } if (mIsScanMode) { - WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); - WifiNative.disconnectCommand(); + mWifiNative.setScanResultHandling(SCAN_ONLY_MODE); + mWifiNative.disconnect(); transitionTo(mScanModeState); } else { - WifiNative.setScanResultHandlingCommand(CONNECT_MODE); - WifiNative.reconnectCommand(); + mWifiNative.setScanResultHandling(CONNECT_MODE); + mWifiNative.reconnect(); + // Status pulls in the current supplicant state and network connection state + // events over the monitor connection. This helps framework sync up with + // current supplicant state + mWifiNative.status(); transitionTo(mDisconnectedState); } } @@ -2546,15 +2560,19 @@ public class WifiStateMachine extends StateMachine { boolean eventLoggingEnabled = true; switch(message.what) { case CMD_SET_SCAN_TYPE: - if (message.arg1 == SCAN_ACTIVE) { - WifiNative.setScanModeCommand(true); - } else { - WifiNative.setScanModeCommand(false); - } + mSetScanActive = (message.arg1 == SCAN_ACTIVE); + mWifiNative.setScanMode(mSetScanActive); break; case CMD_START_SCAN: eventLoggingEnabled = false; - WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); + boolean forceActive = (message.arg1 == SCAN_ACTIVE); + if (forceActive && !mSetScanActive) { + mWifiNative.setScanMode(forceActive); + } + mWifiNative.scan(); + if (forceActive && !mSetScanActive) { + mWifiNative.setScanMode(mSetScanActive); + } mScanResultIsPending = true; break; case CMD_SET_HIGH_PERF_MODE: @@ -2563,14 +2581,14 @@ public class WifiStateMachine extends StateMachine { case CMD_SET_COUNTRY_CODE: String country = (String) message.obj; if (DBG) log("set country code " + country); - if (!WifiNative.setCountryCodeCommand(country.toUpperCase())) { + if (!mWifiNative.setCountryCode(country.toUpperCase())) { loge("Failed to set country code " + country); } break; case CMD_SET_FREQUENCY_BAND: int band = message.arg1; if (DBG) log("set frequency band " + band); - if (WifiNative.setBandCommand(band)) { + if (mWifiNative.setBand(band)) { mFrequencyBand.set(band); //Fetch the latest scan results when frequency band is set startScan(true); @@ -2581,7 +2599,7 @@ public class WifiStateMachine extends StateMachine { case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: mBluetoothConnectionActive = (message.arg1 != BluetoothAdapter.STATE_DISCONNECTED); - WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive); + mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); break; case CMD_STOP_DRIVER: int mode = message.arg1; @@ -2614,28 +2632,28 @@ public class WifiStateMachine extends StateMachine { case CMD_DELAYED_STOP_DRIVER: if (message.arg1 != mDelayedStopCounter) break; if (getCurrentState() != mDisconnectedState) { - WifiNative.disconnectCommand(); + mWifiNative.disconnect(); handleNetworkDisconnect(); } mWakeLock.acquire(); - WifiNative.stopDriverCommand(); + mWifiNative.stopDriver(); transitionTo(mDriverStoppingState); mWakeLock.release(); break; case CMD_START_PACKET_FILTERING: if (message.arg1 == MULTICAST_V6) { - WifiNative.startFilteringMulticastV6Packets(); + mWifiNative.startFilteringMulticastV6Packets(); } else if (message.arg1 == MULTICAST_V4) { - WifiNative.startFilteringMulticastV4Packets(); + mWifiNative.startFilteringMulticastV4Packets(); } else { loge("Illegal arugments to CMD_START_PACKET_FILTERING"); } break; case CMD_STOP_PACKET_FILTERING: if (message.arg1 == MULTICAST_V6) { - WifiNative.stopFilteringMulticastV6Packets(); + mWifiNative.stopFilteringMulticastV6Packets(); } else if (message.arg1 == MULTICAST_V4) { - WifiNative.stopFilteringMulticastV4Packets(); + mWifiNative.stopFilteringMulticastV4Packets(); } else { loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); } @@ -2717,7 +2735,7 @@ public class WifiStateMachine extends StateMachine { break; case CMD_START_DRIVER: mWakeLock.acquire(); - WifiNative.startDriverCommand(); + mWifiNative.startDriver(); mWakeLock.release(); transitionTo(mDriverStartingState); break; @@ -2744,8 +2762,8 @@ public class WifiStateMachine extends StateMachine { /* Ignore */ return HANDLED; } else { - WifiNative.setScanResultHandlingCommand(message.arg1); - WifiNative.reconnectCommand(); + mWifiNative.setScanResultHandling(message.arg1); + mWifiNative.reconnect(); mIsScanMode = false; transitionTo(mDisconnectedState); } @@ -2812,13 +2830,13 @@ public class WifiStateMachine extends StateMachine { break; /* Do a redundant disconnect without transition */ case CMD_DISCONNECT: - WifiNative.disconnectCommand(); + mWifiNative.disconnect(); break; case CMD_RECONNECT: - WifiNative.reconnectCommand(); + mWifiNative.reconnect(); break; case CMD_REASSOCIATE: - WifiNative.reassociateCommand(); + mWifiNative.reassociate(); break; case CMD_CONNECT_NETWORK: int netId = message.arg1; @@ -2832,19 +2850,15 @@ public class WifiStateMachine extends StateMachine { * a connection to the enabled network. */ if (config != null) { - netId = WifiConfigStore.selectNetwork(config); + netId = mWifiConfigStore.selectNetwork(config); } else { - WifiConfigStore.selectNetwork(netId); + mWifiConfigStore.selectNetwork(netId); } /* The state tracker handles enabling networks upon completion/failure */ mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK); - WifiNative.reconnectCommand(); - mLastExplicitNetworkId = netId; - mLastNetworkChoiceTime = SystemClock.elapsedRealtime(); - mNextWifiActionExplicit = true; - if (DBG) log("Setting wifi connect explicit for netid " + netId); + mWifiNative.reconnect(); /* Expect a disconnection from the old connection */ transitionTo(mDisconnectingState); break; @@ -2854,7 +2868,7 @@ public class WifiStateMachine extends StateMachine { break; case WifiMonitor.SCAN_RESULTS_EVENT: /* Set the scan setting back to "connect" mode */ - WifiNative.setScanResultHandlingCommand(CONNECT_MODE); + mWifiNative.setScanResultHandling(CONNECT_MODE); /* Handle scan results */ return NOT_HANDLED; case WifiMonitor.NETWORK_CONNECTION_EVENT: @@ -2866,13 +2880,6 @@ public class WifiStateMachine extends StateMachine { mWifiInfo.setSSID(fetchSSID()); mWifiInfo.setBSSID(mLastBssid); mWifiInfo.setNetworkId(mLastNetworkId); - if (mNextWifiActionExplicit && - mWifiInfo.getNetworkId() == mLastExplicitNetworkId && - SystemClock.elapsedRealtime() < mLastNetworkChoiceTime + - EXPLICIT_CONNECT_ALLOWED_DELAY_MS) { - mWifiInfo.setExplicitConnect(true); - } - mNextWifiActionExplicit = false; /* send event to CM & network change broadcast */ setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); sendNetworkStateChangeBroadcast(mLastBssid); @@ -2906,18 +2913,18 @@ public class WifiStateMachine extends StateMachine { loge("Failed to enable IPv6: " + e); } - if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { + if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { //start DHCP mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( mContext, WifiStateMachine.this, mInterfaceName); mDhcpStateMachine.registerForPreDhcpNotification(); mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); } else { - DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration( + DhcpInfoInternal dhcpInfoInternal = mWifiConfigStore.getIpConfiguration( mLastNetworkId); InterfaceConfiguration ifcg = new InterfaceConfiguration(); - ifcg.addr = dhcpInfoInternal.makeLinkAddress(); - ifcg.interfaceFlags = "[up]"; + ifcg.setLinkAddress(dhcpInfoInternal.makeLinkAddress()); + ifcg.setInterfaceUp(); try { mNwService.setInterfaceConfig(mInterfaceName, ifcg); if (DBG) log("Static IP configuration succeeded"); @@ -2959,7 +2966,7 @@ public class WifiStateMachine extends StateMachine { transitionTo(mDisconnectingState); break; case CMD_DISCONNECT: - WifiNative.disconnectCommand(); + mWifiNative.disconnect(); transitionTo(mDisconnectingState); break; /* Ignore connection to same network */ @@ -3026,7 +3033,7 @@ public class WifiStateMachine extends StateMachine { } break; case CMD_DISCONNECT: - WifiNative.disconnectCommand(); + mWifiNative.disconnect(); transitionTo(mDisconnectingState); break; case CMD_SET_SCAN_MODE: @@ -3042,7 +3049,7 @@ public class WifiStateMachine extends StateMachine { * When scan results are received, the mode is switched * back to CONNECT_MODE. */ - WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); + mWifiNative.setScanResultHandling(SCAN_ONLY_MODE); /* Have the parent state handle the rest */ return NOT_HANDLED; /* Ignore connection to same network */ @@ -3054,7 +3061,7 @@ public class WifiStateMachine extends StateMachine { return NOT_HANDLED; case CMD_SAVE_NETWORK: WifiConfiguration config = (WifiConfiguration) message.obj; - NetworkUpdateResult result = WifiConfigStore.saveNetwork(config); + NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); if (mWifiInfo.getNetworkId() == result.getNetworkId()) { if (result.hasIpChanged()) { log("Reconfiguring IP on connection"); @@ -3110,7 +3117,7 @@ public class WifiStateMachine extends StateMachine { * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit */ if (mScanResultIsPending) { - WifiNative.setScanResultHandlingCommand(CONNECT_MODE); + mWifiNative.setScanResultHandling(CONNECT_MODE); } } } @@ -3191,7 +3198,7 @@ public class WifiStateMachine extends StateMachine { * cleared */ if (!mScanResultIsPending) { - WifiNative.enableBackgroundScanCommand(true); + mWifiNative.enableBackgroundScan(true); } } else { setScanAlarm(true); @@ -3203,9 +3210,9 @@ public class WifiStateMachine extends StateMachine { switch (message.what) { case CMD_SET_SCAN_MODE: if (message.arg1 == SCAN_ONLY_MODE) { - WifiNative.setScanResultHandlingCommand(message.arg1); + mWifiNative.setScanResultHandling(message.arg1); //Supplicant disconnect to prevent further connects - WifiNative.disconnectCommand(); + mWifiNative.disconnect(); mIsScanMode = true; transitionTo(mScanModeState); } @@ -3213,10 +3220,10 @@ public class WifiStateMachine extends StateMachine { case CMD_ENABLE_BACKGROUND_SCAN: mEnableBackgroundScan = (message.arg1 == 1); if (mEnableBackgroundScan) { - WifiNative.enableBackgroundScanCommand(true); + mWifiNative.enableBackgroundScan(true); setScanAlarm(false); } else { - WifiNative.enableBackgroundScanCommand(false); + mWifiNative.enableBackgroundScan(false); setScanAlarm(true); } break; @@ -3231,14 +3238,14 @@ public class WifiStateMachine extends StateMachine { case CMD_START_SCAN: /* Disable background scan temporarily during a regular scan */ if (mEnableBackgroundScan) { - WifiNative.enableBackgroundScanCommand(false); + mWifiNative.enableBackgroundScan(false); } /* Handled in parent state */ return NOT_HANDLED; case WifiMonitor.SCAN_RESULTS_EVENT: /* Re-enable background scan when a pending scan result is received */ if (mEnableBackgroundScan && mScanResultIsPending) { - WifiNative.enableBackgroundScanCommand(true); + mWifiNative.enableBackgroundScan(true); } /* Handled in parent state */ return NOT_HANDLED; @@ -3253,7 +3260,7 @@ public class WifiStateMachine extends StateMachine { public void exit() { /* No need for a background scan upon exit from a disconnected state */ if (mEnableBackgroundScan) { - WifiNative.enableBackgroundScanCommand(false); + mWifiNative.enableBackgroundScan(false); } setScanAlarm(false); } diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java index b27c60f..0ca3852 100644 --- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java +++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java @@ -1030,7 +1030,7 @@ public class WifiWatchdogStateMachine extends StateMachine { mHasConnectedWifiManager = true; } mWifiManager.disableNetwork(networkId, WifiConfiguration.DISABLED_DNS_FAILURE); - if (mShowDisabledNotification && mConnectionInfo.isExplicitConnect()) { + if (mShowDisabledNotification) { setDisabledNetworkNotificationVisible(true); } transitionTo(mNotConnectedState); diff --git a/wifi/java/android/net/wifi/WpsStateMachine.java b/wifi/java/android/net/wifi/WpsStateMachine.java index c14a8db..441a3b0 100644 --- a/wifi/java/android/net/wifi/WpsStateMachine.java +++ b/wifi/java/android/net/wifi/WpsStateMachine.java @@ -52,6 +52,7 @@ class WpsStateMachine extends StateMachine { private static final boolean DBG = false; private WifiStateMachine mWifiStateMachine; + private WifiConfigStore mWifiConfigStore; private WpsInfo mWpsInfo; @@ -62,11 +63,12 @@ class WpsStateMachine extends StateMachine { private State mInactiveState = new InactiveState(); private State mActiveState = new ActiveState(); - public WpsStateMachine(Context context, WifiStateMachine wsm, Handler target) { - super(TAG, target.getLooper()); + public WpsStateMachine(Context context, WifiStateMachine wsm, WifiConfigStore wcs, Handler t) { + super(TAG, t.getLooper()); mContext = context; mWifiStateMachine = wsm; + mWifiConfigStore = wcs; addState(mDefaultState); addState(mInactiveState, mDefaultState); addState(mActiveState, mDefaultState); @@ -97,13 +99,13 @@ class WpsStateMachine extends StateMachine { WpsResult result; switch (mWpsInfo.setup) { case WpsInfo.PBC: - result = WifiConfigStore.startWpsPbc(mWpsInfo); + result = mWifiConfigStore.startWpsPbc(mWpsInfo); break; case WpsInfo.KEYPAD: - result = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsInfo); + result = mWifiConfigStore.startWpsWithPinFromAccessPoint(mWpsInfo); break; case WpsInfo.DISPLAY: - result = WifiConfigStore.startWpsWithPinFromDevice(mWpsInfo); + result = mWifiConfigStore.startWpsWithPinFromDevice(mWpsInfo); break; default: result = new WpsResult(Status.FAILURE); @@ -151,9 +153,9 @@ class WpsStateMachine extends StateMachine { * and the configuration list needs to be reloaded from the supplicant. */ Log.d(TAG, "WPS set up successful"); - WifiConfigStore.enableAllNetworks(); - WifiConfigStore.loadConfiguredNetworks(); - WifiConfigStore.updateIpAndProxyFromWpsConfig( + mWifiConfigStore.enableAllNetworks(); + mWifiConfigStore.loadConfiguredNetworks(); + mWifiConfigStore.updateIpAndProxyFromWpsConfig( stateChangeResult.networkId, mWpsInfo); mWifiStateMachine.sendMessage(WifiStateMachine.WPS_COMPLETED_EVENT); transitionTo(mInactiveState); @@ -161,7 +163,7 @@ class WpsStateMachine extends StateMachine { case INACTIVE: /* A failed WPS connection */ Log.d(TAG, "WPS set up failed, enabling other networks"); - WifiConfigStore.enableAllNetworks(); + mWifiConfigStore.enableAllNetworks(); mWifiStateMachine.sendMessage(WifiStateMachine.WPS_COMPLETED_EVENT); transitionTo(mInactiveState); break; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java index e0c1b13..6aea090 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java @@ -84,19 +84,19 @@ public class WifiP2pConfig implements Parcelable { } catch (NumberFormatException e) { devPasswdId = 0; } - //As defined in wps/wps_defs.h + //Based on definitions in wps/wps_defs.h switch (devPasswdId) { - case 0x00: - wps.setup = WpsInfo.LABEL; - break; + //DEV_PW_USER_SPECIFIED = 0x0001, case 0x01: - wps.setup = WpsInfo.KEYPAD; + wps.setup = WpsInfo.DISPLAY; break; + //DEV_PW_PUSHBUTTON = 0x0004, case 0x04: wps.setup = WpsInfo.PBC; break; + //DEV_PW_REGISTRAR_SPECIFIED = 0x0005 case 0x05: - wps.setup = WpsInfo.DISPLAY; + wps.setup = WpsInfo.KEYPAD; break; default: wps.setup = WpsInfo.PBC; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java index 1b0c301..7471a2d 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java @@ -34,12 +34,12 @@ public class WifiP2pDevice implements Parcelable { /** * The device name is a user friendly string to identify a Wi-Fi p2p device */ - public String deviceName; + public String deviceName = ""; /** * The device MAC address uniquely identifies a Wi-Fi p2p device */ - public String deviceAddress; + public String deviceAddress = ""; /** * interfaceAddress @@ -130,23 +130,11 @@ public class WifiP2pDevice implements Parcelable { * * fa:7b:7a:42:02:13 * - * P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 - * pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 - * group_capab=0x0 - * - * P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 - * pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 - * group_capab=0x0 - * - * P2P-PROV-DISC-SHOW-PIN 42:fc:89:e1:e2:27 44490607 p2p_dev_addr=42:fc:89:e1:e2:27 - * pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 - * group_capab=0x0 - * * Note: The events formats can be looked up in the wpa_supplicant code * @hide */ public WifiP2pDevice(String string) throws IllegalArgumentException { - String[] tokens = string.split(" "); + String[] tokens = string.split("[ \n]"); if (tokens.length < 1) { throw new IllegalArgumentException("Malformed supplicant event"); @@ -160,7 +148,13 @@ public class WifiP2pDevice implements Parcelable { for (String token : tokens) { String[] nameValue = token.split("="); - if (nameValue.length != 2) continue; + if (nameValue.length != 2) { + //mac address without key is device address + if (token.matches("(([0-9a-f]{2}:){5}[0-9a-f]{2})")) { + deviceAddress = token; + } + continue; + } if (nameValue[0].equals("p2p_dev_addr")) { deviceAddress = nameValue[1]; @@ -172,7 +166,7 @@ public class WifiP2pDevice implements Parcelable { continue; } - if (nameValue[0].equals("name")) { + if (nameValue[0].equals("name") || nameValue[0].equals("device_name")) { deviceName = trimQuotes(nameValue[1]); continue; } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java index 9ce2545..cbb4e81 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java @@ -80,6 +80,19 @@ public class WifiP2pDeviceList implements Parcelable { } /** @hide */ + public void updateInterfaceAddress(WifiP2pDevice device) { + for (WifiP2pDevice d : mDevices) { + //Found, update interface address + if (d.equals(device)) { + d.interfaceAddress = device.interfaceAddress; + return; + } + } + //Not found, add a new one + mDevices.add(device); + } + + /** @hide */ public boolean remove(WifiP2pDevice device) { if (device == null) return false; return mDevices.remove(device); diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java index 9473993..e141aba 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java @@ -172,6 +172,12 @@ public class WifiP2pGroup implements Parcelable { return mClients.size() == 0; } + /** @hide Returns {@code true} if the device is part of the group */ + public boolean contains(WifiP2pDevice device) { + if (mOwner.equals(device) || mClients.contains(device)) return true; + return false; + } + /** Get the list of clients currently part of the p2p group */ public Collection<WifiP2pDevice> getClientList() { return Collections.unmodifiableCollection(mClients); diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java b/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java new file mode 100644 index 0000000..f70abe8 --- /dev/null +++ b/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.p2p; + +import android.os.Parcelable; +import android.os.Parcel; +import android.util.Log; + +/** + * A class representing a Wi-Fi p2p provisional discovery request/response + * See {@link #WifiP2pProvDiscEvent} for supported types + * + * @hide + */ +public class WifiP2pProvDiscEvent { + + private static final String TAG = "WifiP2pProvDiscEvent"; + + public static final int PBC_REQ = 1; + public static final int PBC_RSP = 2; + public static final int ENTER_PIN = 3; + public static final int SHOW_PIN = 4; + + /* One of PBC_REQ, PBC_RSP, ENTER_PIN or SHOW_PIN */ + public int event; + + public WifiP2pDevice device; + + /* Valid when event = SHOW_PIN */ + public String pin; + + public WifiP2pProvDiscEvent() { + device = new WifiP2pDevice(); + } + + /** + * @param string formats supported include + * + * P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 + * pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 + * group_capab=0x0 + * + * P2P-PROV-DISC-PBC-RESP 02:12:47:f2:5a:36 + * + * P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 + * pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 + * group_capab=0x0 + * + * P2P-PROV-DISC-SHOW-PIN 42:fc:89:e1:e2:27 44490607 p2p_dev_addr=42:fc:89:e1:e2:27 + * pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 + * group_capab=0x0 + * + * Note: The events formats can be looked up in the wpa_supplicant code + * @hide + */ + public WifiP2pProvDiscEvent(String string) throws IllegalArgumentException { + String[] tokens = string.split(" "); + + if (tokens.length < 2) { + throw new IllegalArgumentException("Malformed event " + string); + } + + if (tokens[0].endsWith("PBC-REQ")) event = PBC_REQ; + else if (tokens[0].endsWith("PBC-RESP")) event = PBC_RSP; + else if (tokens[0].endsWith("ENTER-PIN")) event = ENTER_PIN; + else if (tokens[0].endsWith("SHOW-PIN")) event = SHOW_PIN; + else throw new IllegalArgumentException("Malformed event " + string); + + device = new WifiP2pDevice(); + + for (String token : tokens) { + String[] nameValue = token.split("="); + if (nameValue.length != 2) { + //mac address without key is device address + if (token.matches("(([0-9a-f]{2}:){5}[0-9a-f]{2})")) { + device.deviceAddress = token; + } else if (token.matches("[0-9]+")) { + pin = token; + } else { + //ignore; + } + continue; + } + + if (nameValue[0].equals("p2p_dev_addr")) { + device.deviceAddress = nameValue[1]; + continue; + } + + if (nameValue[0].equals("pri_dev_type")) { + device.primaryDeviceType = nameValue[1]; + continue; + } + + if (nameValue[0].equals("name")) { + device.deviceName = trimQuotes(nameValue[1]); + continue; + } + + if (nameValue[0].equals("config_methods")) { + device.wpsConfigMethodsSupported = parseHex(nameValue[1]); + continue; + } + + if (nameValue[0].equals("dev_capab")) { + device.deviceCapability = parseHex(nameValue[1]); + continue; + } + + if (nameValue[0].equals("group_capab")) { + device.groupCapability = parseHex(nameValue[1]); + continue; + } + } + } + + public String toString() { + StringBuffer sbuf = new StringBuffer(); + sbuf.append(device); + sbuf.append("\n event: ").append(event); + sbuf.append("\n pin: ").append(pin); + return sbuf.toString(); + } + + private String trimQuotes(String str) { + str = str.trim(); + if (str.startsWith("'") && str.endsWith("'")) { + return str.substring(1, str.length()-1); + } + return str; + } + + //supported formats: 0x1abc, 0X1abc, 1abc + private int parseHex(String hexString) { + int num = 0; + if (hexString.startsWith("0x") || hexString.startsWith("0X")) { + hexString = hexString.substring(2); + } + + try { + num = Integer.parseInt(hexString, 16); + } catch(NumberFormatException e) { + Log.e(TAG, "Failed to parse hex string " + hexString); + } + return num; + } +} diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index 6bb22a4..69cbb5c 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -52,11 +52,14 @@ import android.os.Messenger; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; +import android.text.TextUtils; import android.util.Slog; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; import android.widget.EditText; +import android.widget.TextView; import com.android.internal.R; import com.android.internal.telephony.TelephonyIntents; @@ -81,7 +84,7 @@ import java.util.Collection; */ public class WifiP2pService extends IWifiP2pManager.Stub { private static final String TAG = "WifiP2pService"; - private static final boolean DBG = false; + private static final boolean DBG = true; private static final String NETWORKTYPE = "WIFI_P2P"; private Context mContext; @@ -100,9 +103,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub { private AsyncChannel mReplyChannel = new AsyncChannel(); private AsyncChannel mWifiChannel; + private static final Boolean JOIN_GROUP = true; + private static final Boolean FORM_GROUP = false; + /* Two minutes comes from the wpa_supplicant setting */ - private static final int GROUP_NEGOTIATION_WAIT_TIME_MS = 120 * 1000; - private static int mGroupNegotiationTimeoutIndex = 0; + private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000; + private static int mGroupCreatingTimeoutIndex = 0; /** * Delay between restarts upon failure to setup connection with supplicant @@ -123,30 +129,23 @@ public class WifiP2pService extends IWifiP2pManager.Stub { /* Message sent to WifiStateMachine to indicate Wi-Fi client/hotspot operation can proceed */ public static final int WIFI_ENABLE_PROCEED = BASE + 2; - /* Delayed message to timeout of group negotiation */ - public static final int GROUP_NEGOTIATION_TIMED_OUT = BASE + 3; + /* Delayed message to timeout group creation */ + public static final int GROUP_CREATING_TIMED_OUT = BASE + 3; /* User accepted to disable Wi-Fi in order to enable p2p */ private static final int WIFI_DISABLE_USER_ACCEPT = BASE + 4; /* User rejected to disable Wi-Fi in order to enable p2p */ private static final int WIFI_DISABLE_USER_REJECT = BASE + 5; - /* User accepted a group negotiation request */ - private static final int GROUP_NEGOTIATION_USER_ACCEPT = BASE + 6; - /* User rejected a group negotiation request */ - private static final int GROUP_NEGOTIATION_USER_REJECT = BASE + 7; - - /* User accepted a group invitation request */ - private static final int GROUP_INVITATION_USER_ACCEPT = BASE + 8; - /* User rejected a group invitation request */ - private static final int GROUP_INVITATION_USER_REJECT = BASE + 9; + /* User accepted a peer request */ + private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 6; + /* User rejected a peer request */ + private static final int PEER_CONNECTION_USER_REJECT = BASE + 7; /* Airplane mode changed */ - private static final int AIRPLANE_MODE_CHANGED = BASE + 10; + private static final int AIRPLANE_MODE_CHANGED = BASE + 8; /* Emergency callback mode */ - private static final int EMERGENCY_CALLBACK_MODE = BASE + 11; - private static final int WPS_PBC = BASE + 12; - private static final int WPS_PIN = BASE + 13; + private static final int EMERGENCY_CALLBACK_MODE = BASE + 9; private final boolean mP2pSupported; @@ -167,7 +166,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public WifiP2pService(Context context) { mContext = context; - mInterface = SystemProperties.get("wifi.interface", "wlan0"); + //STOPSHIP: fix this + mInterface = "p2p0"; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, ""); mP2pSupported = mContext.getPackageManager().hasSystemFeature( @@ -270,24 +270,24 @@ public class WifiP2pService extends IWifiP2pManager.Stub { private P2pEnabledState mP2pEnabledState = new P2pEnabledState(); // Inactive is when p2p is enabled with no connectivity private InactiveState mInactiveState = new InactiveState(); - private UserAuthorizingGroupNegotiationState mUserAuthorizingGroupNegotiationState - = new UserAuthorizingGroupNegotiationState(); - private UserAuthorizingGroupInvitationState mUserAuthorizingGroupInvitationState - = new UserAuthorizingGroupInvitationState(); + private GroupCreatingState mGroupCreatingState = new GroupCreatingState(); + private UserAuthorizingInvitationState mUserAuthorizingInvitationState + = new UserAuthorizingInvitationState(); + private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState(); private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState(); + private GroupCreatedState mGroupCreatedState = new GroupCreatedState(); + private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState(); - private WifiMonitor mWifiMonitor = new WifiMonitor(this); + private WifiNative mWifiNative = new WifiNative(mInterface); + private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative); private WifiP2pDeviceList mPeers = new WifiP2pDeviceList(); private WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo(); private WifiP2pGroup mGroup; - // Saved WifiP2pConfig from GO negotiation request - private WifiP2pConfig mSavedGoNegotiationConfig; - - // Saved WifiP2pConfig from connect request - private WifiP2pConfig mSavedConnectConfig; + // Saved WifiP2pConfig for a peer connection + private WifiP2pConfig mSavedPeerConfig; // Saved WifiP2pGroup from invitation request private WifiP2pGroup mSavedP2pGroup; @@ -304,10 +304,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub { addState(mP2pEnablingState, mDefaultState); addState(mP2pEnabledState, mDefaultState); addState(mInactiveState, mP2pEnabledState); - addState(mUserAuthorizingGroupNegotiationState, mInactiveState); - addState(mUserAuthorizingGroupInvitationState, mInactiveState); - addState(mGroupNegotiationState, mP2pEnabledState); + addState(mGroupCreatingState, mP2pEnabledState); + addState(mUserAuthorizingInvitationState, mGroupCreatingState); + addState(mProvisionDiscoveryState, mGroupCreatingState); + addState(mGroupNegotiationState, mGroupCreatingState); addState(mGroupCreatedState, mP2pEnabledState); + addState(mUserAuthorizingJoinState, mGroupCreatedState); if (p2pSupported) { setInitialState(mP2pDisabledState); @@ -393,13 +395,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub { sendMessage(WifiP2pManager.DISABLE_P2P); break; // Ignore + case WifiMonitor.P2P_INVITATION_RESULT_EVENT: case WIFI_DISABLE_USER_ACCEPT: case WIFI_DISABLE_USER_REJECT: - case GROUP_NEGOTIATION_USER_ACCEPT: - case GROUP_NEGOTIATION_USER_REJECT: - case GROUP_INVITATION_USER_ACCEPT: - case GROUP_INVITATION_USER_REJECT: - case GROUP_NEGOTIATION_TIMED_OUT: + case PEER_CONNECTION_USER_ACCEPT: + case PEER_CONNECTION_USER_REJECT: + case GROUP_CREATING_TIMED_OUT: break; default: loge("Unhandled message " + message); @@ -457,9 +458,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public void enter() { if (DBG) logd(getName()); logd("stopping supplicant"); - if (!WifiNative.stopSupplicant()) { + if (!mWifiNative.stopSupplicant()) { loge("Failed to stop supplicant, issue kill"); - WifiNative.killSupplicant(); + mWifiNative.killSupplicant(); } } @@ -469,7 +470,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { switch (message.what) { case WifiMonitor.SUP_DISCONNECTION_EVENT: logd("Supplicant connection lost"); - WifiNative.closeSupplicantConnection(); + mWifiNative.closeSupplicantConnection(); transitionTo(mP2pDisabledState); break; case WifiP2pManager.ENABLE_P2P: @@ -595,7 +596,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { if (DBG) Slog.w(TAG, "Unable to bring down wlan interface: " + e); } - if (WifiNative.startP2pSupplicant()) { + if (mWifiNative.startP2pSupplicant()) { mWifiMonitor.startMonitoring(); transitionTo(mP2pEnablingState); } else { @@ -631,7 +632,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { case WifiMonitor.SUP_DISCONNECTION_EVENT: if (++mP2pRestartCount <= P2P_RESTART_TRIES) { loge("Failed to start p2p, retry"); - WifiNative.killSupplicant(); + mWifiNative.killSupplicant(); sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS); } else { loge("Failed " + mP2pRestartCount + " times to start p2p, quit "); @@ -674,7 +675,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { break; case WifiP2pManager.DISCOVER_PEERS: int timeout = message.arg1; - if (WifiNative.p2pFind(timeout)) { + if (mWifiNative.p2pFind(timeout)) { replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED); } else { replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, @@ -691,53 +692,14 @@ public class WifiP2pService extends IWifiP2pManager.Stub { device = (WifiP2pDevice) message.obj; if (mPeers.remove(device)) sendP2pPeersChangedBroadcast(); break; - case WifiP2pManager.CONNECT: - if (DBG) logd(getName() + " sending connect"); - mSavedConnectConfig = (WifiP2pConfig) message.obj; - mPersistGroup = false; - int netId = configuredNetworkId(mSavedConnectConfig.deviceAddress); - if (netId >= 0) { - //TODO: if failure, remove config and do a regular p2pConnect() - WifiNative.p2pReinvoke(netId, mSavedConnectConfig.deviceAddress); - } else { - boolean join = false; - if (isGroupOwner(mSavedConnectConfig.deviceAddress)) join = true; - String pin = WifiNative.p2pConnect(mSavedConnectConfig, join); - try { - Integer.parseInt(pin); - notifyWpsPin(pin, mSavedConnectConfig.deviceAddress); - } catch (NumberFormatException ignore) { - // do nothing if p2pConnect did not return a pin - } - } - updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.INVITED); - sendP2pPeersChangedBroadcast(); - replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); - transitionTo(mGroupNegotiationState); - break; - case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant died */ + case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant died */ loge("Connection lost, restart p2p"); - WifiNative.killSupplicant(); - WifiNative.closeSupplicantConnection(); + mWifiNative.killSupplicant(); + mWifiNative.closeSupplicantConnection(); if (mPeers.clear()) sendP2pPeersChangedBroadcast(); transitionTo(mP2pDisabledState); sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS); break; - case WifiMonitor.P2P_GROUP_STARTED_EVENT: - mGroup = (WifiP2pGroup) message.obj; - if (DBG) logd(getName() + " group started"); - if (mGroup.isGroupOwner()) { - startDhcpServer(mGroup.getInterface()); - } else { - mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext, - P2pStateMachine.this, mGroup.getInterface()); - mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); - WifiP2pDevice groupOwner = mGroup.getOwner(); - updateDeviceStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED); - sendP2pPeersChangedBroadcast(); - } - transitionTo(mGroupCreatedState); - break; default: return NOT_HANDLED; } @@ -757,21 +719,88 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public void enter() { if (DBG) logd(getName()); //Start listening every time we get inactive - WifiNative.p2pListen(); + mWifiNative.p2pListen(); } @Override public boolean processMessage(Message message) { if (DBG) logd(getName() + message.toString()); switch (message.what) { + case WifiP2pManager.CONNECT: + if (DBG) logd(getName() + " sending connect"); + mSavedPeerConfig = (WifiP2pConfig) message.obj; + String updatedPeerDetails = mWifiNative.p2pPeer(mSavedPeerConfig.deviceAddress); + mPeers.update(new WifiP2pDevice(updatedPeerDetails)); + mPersistGroup = false; + int netId = configuredNetworkId(mSavedPeerConfig.deviceAddress); + if (netId >= 0) { + //TODO: if failure, remove config and do a regular p2pConnect() + mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress); + } else { + //If peer is a GO, we do not need to send provisional discovery, + //the supplicant takes care of it. + if (isGroupOwner(mSavedPeerConfig.deviceAddress)) { + p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP); + transitionTo(mGroupNegotiationState); + } else { + transitionTo(mProvisionDiscoveryState); + } + } + updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); + sendP2pPeersChangedBroadcast(); + replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); + break; case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT: - mSavedGoNegotiationConfig = (WifiP2pConfig) message.obj; - notifyP2pGoNegotationRequest(mSavedGoNegotiationConfig); - transitionTo(mUserAuthorizingGroupNegotiationState); + mSavedPeerConfig = (WifiP2pConfig) message.obj; + transitionTo(mUserAuthorizingInvitationState); + break; + case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: + WifiP2pGroup group = (WifiP2pGroup) message.obj; + WifiP2pDevice owner = group.getOwner(); + + if (owner == null) { + if (DBG) loge("Ignored invitation from null owner"); + break; + } + + mSavedPeerConfig = new WifiP2pConfig(); + mSavedPeerConfig.deviceAddress = group.getOwner().deviceAddress; + + //Check if we have the owner in peer list and use appropriate + //wps method. Default is to use PBC. + if ((owner = getDeviceFromPeerList(owner.deviceAddress)) != null) { + if (owner.wpsPbcSupported()) { + mSavedPeerConfig.wps.setup = WpsInfo.PBC; + } else if (owner.wpsKeypadSupported()) { + mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; + } else if (owner.wpsDisplaySupported()) { + mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; + } + } + transitionTo(mUserAuthorizingInvitationState); + break; + case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: + case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: + case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: + WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj; + mSavedPeerConfig = new WifiP2pConfig(); + mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress; + if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) { + mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; + if (DBG) logd("Keypad prov disc request"); + } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) { + mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; + mSavedPeerConfig.wps.pin = provDisc.pin; + if (DBG) logd("Display prov disc request"); + } else { + mSavedPeerConfig.wps.setup = WpsInfo.PBC; + if (DBG) logd("PBC prov disc request"); + } + transitionTo(mUserAuthorizingInvitationState); break; case WifiP2pManager.CREATE_GROUP: mPersistGroup = true; - if (WifiNative.p2pGroupAdd()) { + if (mWifiNative.p2pGroupAdd()) { replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED); } else { replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, @@ -779,40 +808,46 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } transitionTo(mGroupNegotiationState); break; - case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: - WifiP2pGroup group = (WifiP2pGroup) message.obj; - notifyP2pInvitationReceived(group); - transitionTo(mUserAuthorizingGroupInvitationState); - break; - default: + default: return NOT_HANDLED; } return HANDLED; } } - class UserAuthorizingGroupNegotiationState extends State { + class GroupCreatingState extends State { @Override public void enter() { if (DBG) logd(getName()); + sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT, + ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS); } @Override public boolean processMessage(Message message) { if (DBG) logd(getName() + message.toString()); switch (message.what) { - case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT: - case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: - //Ignore additional connection requests + case GROUP_CREATING_TIMED_OUT: + if (mGroupCreatingTimeoutIndex == message.arg1) { + if (DBG) logd("Group negotiation timed out"); + updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.FAILED); + mSavedPeerConfig = null; + sendP2pPeersChangedBroadcast(); + transitionTo(mInactiveState); + } break; - case GROUP_NEGOTIATION_USER_ACCEPT: - sendMessage(WifiP2pManager.CONNECT, mSavedGoNegotiationConfig); - mSavedGoNegotiationConfig = null; + case WifiP2pManager.DISCOVER_PEERS: + /* Discovery will break negotiation */ + replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, + WifiP2pManager.BUSY); break; - case GROUP_NEGOTIATION_USER_REJECT: - if (DBG) logd("User rejected incoming negotiation request"); - mSavedGoNegotiationConfig = null; - transitionTo(mInactiveState); + case WifiP2pManager.CANCEL_CONNECT: + if (mWifiNative.p2pCancelConnect()) { + replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED); + } else { + replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, + WifiP2pManager.ERROR); + } break; default: return NOT_HANDLED; @@ -821,30 +856,31 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } } - class UserAuthorizingGroupInvitationState extends State { + class UserAuthorizingInvitationState extends State { @Override public void enter() { if (DBG) logd(getName()); + notifyInvitationReceived(); } @Override public boolean processMessage(Message message) { if (DBG) logd(getName() + message.toString()); switch (message.what) { - case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT: - case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: - //Ignore additional connection requests - break; - case GROUP_INVITATION_USER_ACCEPT: - if (DBG) logd(getName() + " connect to invited group"); - WifiP2pConfig config = new WifiP2pConfig(); - config.deviceAddress = mSavedP2pGroup.getOwner().deviceAddress; - sendMessage(WifiP2pManager.CONNECT, config); - mSavedP2pGroup = null; - break; - case GROUP_INVITATION_USER_REJECT: - if (DBG) logd("User rejected incoming invitation request"); - mSavedP2pGroup = null; + case PEER_CONNECTION_USER_ACCEPT: + //TODO: handle persistence + if (isGroupOwner(mSavedPeerConfig.deviceAddress)) { + p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP); + } else { + p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP); + } + updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); + sendP2pPeersChangedBroadcast(); + transitionTo(mGroupNegotiationState); + break; + case PEER_CONNECTION_USER_REJECT: + if (DBG) logd("User rejected invitation " + mSavedPeerConfig); + mSavedPeerConfig = null; transitionTo(mInactiveState); break; default: @@ -852,15 +888,77 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public void exit() { + //TODO: dismiss dialog if not already done + } } + class ProvisionDiscoveryState extends State { + @Override + public void enter() { + if (DBG) logd(getName()); + mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig); + } + + @Override + public boolean processMessage(Message message) { + if (DBG) logd(getName() + message.toString()); + WifiP2pProvDiscEvent provDisc; + WifiP2pDevice device; + switch (message.what) { + case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT: + provDisc = (WifiP2pProvDiscEvent) message.obj; + device = provDisc.device; + if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; + + if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { + if (DBG) logd("Found a match " + mSavedPeerConfig); + mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP); + transitionTo(mGroupNegotiationState); + } + break; + case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: + provDisc = (WifiP2pProvDiscEvent) message.obj; + device = provDisc.device; + if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; + + if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) { + if (DBG) logd("Found a match " + mSavedPeerConfig); + /* we already have the pin */ + if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) { + mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP); + transitionTo(mGroupNegotiationState); + } else { + transitionTo(mUserAuthorizingInvitationState); + } + } + break; + case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: + provDisc = (WifiP2pProvDiscEvent) message.obj; + device = provDisc.device; + if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; + + if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) { + if (DBG) logd("Found a match " + mSavedPeerConfig); + mSavedPeerConfig.wps.pin = provDisc.pin; + mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP); + notifyInvitationSent(provDisc.pin, device.deviceAddress); + transitionTo(mGroupNegotiationState); + } + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + } class GroupNegotiationState extends State { @Override public void enter() { if (DBG) logd(getName()); - sendMessageDelayed(obtainMessage(GROUP_NEGOTIATION_TIMED_OUT, - ++mGroupNegotiationTimeoutIndex, 0), GROUP_NEGOTIATION_WAIT_TIME_MS); } @Override @@ -873,36 +971,30 @@ public class WifiP2pService extends IWifiP2pManager.Stub { case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: if (DBG) logd(getName() + " go success"); break; + case WifiMonitor.P2P_GROUP_STARTED_EVENT: + mGroup = (WifiP2pGroup) message.obj; + if (DBG) logd(getName() + " group started"); + if (mGroup.isGroupOwner()) { + startDhcpServer(mGroup.getInterface()); + } else { + mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext, + P2pStateMachine.this, mGroup.getInterface()); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); + WifiP2pDevice groupOwner = mGroup.getOwner(); + updateDeviceStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED); + sendP2pPeersChangedBroadcast(); + } + mSavedPeerConfig = null; + transitionTo(mGroupCreatedState); + break; case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: if (DBG) logd(getName() + " go failure"); - updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.FAILED); - mSavedConnectConfig = null; + updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.FAILED); + mSavedPeerConfig = null; sendP2pPeersChangedBroadcast(); transitionTo(mInactiveState); break; - case GROUP_NEGOTIATION_TIMED_OUT: - if (mGroupNegotiationTimeoutIndex == message.arg1) { - if (DBG) logd("Group negotiation timed out"); - updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.FAILED); - mSavedConnectConfig = null; - sendP2pPeersChangedBroadcast(); - transitionTo(mInactiveState); - } - break; - case WifiP2pManager.DISCOVER_PEERS: - /* Discovery will break negotiation */ - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.CANCEL_CONNECT: - if (WifiNative.p2pCancelConnect()) { - replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, - WifiP2pManager.ERROR); - } - break; default: return NOT_HANDLED; } @@ -910,6 +1002,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } } + + class GroupCreatedState extends State { @Override public void enter() { @@ -930,20 +1024,22 @@ public class WifiP2pService extends IWifiP2pManager.Stub { if (DBG) logd(getName() + message.toString()); switch (message.what) { case WifiMonitor.AP_STA_CONNECTED_EVENT: - //After a GO setup, STA connected event comes with interface address - String interfaceAddress = (String) message.obj; - String deviceAddress = getDeviceAddress(interfaceAddress); + WifiP2pDevice device = (WifiP2pDevice) message.obj; + String deviceAddress = device.deviceAddress; if (deviceAddress != null) { mGroup.addClient(deviceAddress); + mPeers.updateInterfaceAddress(device); updateDeviceStatus(deviceAddress, WifiP2pDevice.CONNECTED); if (DBG) logd(getName() + " ap sta connected"); sendP2pPeersChangedBroadcast(); } else { - loge("Connect on unknown device address : " + interfaceAddress); + loge("Connect on null device address, ignore"); } break; case WifiMonitor.AP_STA_DISCONNECTED_EVENT: - interfaceAddress = (String) message.obj; + //TODO: the disconnection event is still inconsistent and reports + //interface address. Fix this after wpa_supplicant is fixed. + String interfaceAddress = (String) message.obj; deviceAddress = getDeviceAddress(interfaceAddress); if (deviceAddress != null) { updateDeviceStatus(deviceAddress, WifiP2pDevice.AVAILABLE); @@ -951,7 +1047,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { if (DBG) logd("Removed client " + deviceAddress); if (!mPersistGroup && mGroup.isClientListEmpty()) { Slog.d(TAG, "Client list empty, remove non-persistent p2p group"); - WifiNative.p2pGroupRemove(mGroup.getInterface()); + mWifiNative.p2pGroupRemove(mGroup.getInterface()); } } else { if (DBG) logd("Failed to remove client " + deviceAddress); @@ -962,7 +1058,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { sendP2pPeersChangedBroadcast(); if (DBG) loge(getName() + " ap sta disconnected"); } else { - loge("Disconnect on unknown device address : " + interfaceAddress); + loge("Disconnect on unknown interface address : " + interfaceAddress); } break; case DhcpStateMachine.CMD_POST_DHCP_ACTION: @@ -973,12 +1069,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub { setWifiP2pInfoOnGroupFormation(dhcpInfo.serverAddress); sendP2pConnectionChangedBroadcast(); } else { - WifiNative.p2pGroupRemove(mGroup.getInterface()); + mWifiNative.p2pGroupRemove(mGroup.getInterface()); } break; case WifiP2pManager.REMOVE_GROUP: if (DBG) loge(getName() + " remove group"); - if (WifiNative.p2pGroupRemove(mGroup.getInterface())) { + if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) { replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); } else { replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, @@ -1010,17 +1106,14 @@ public class WifiP2pService extends IWifiP2pManager.Stub { transitionTo(mInactiveState); break; case WifiMonitor.P2P_DEVICE_LOST_EVENT: - WifiP2pDevice device = (WifiP2pDevice) message.obj; - if (device.equals(mGroup.getOwner())) { - logd("Lost the group owner, killing p2p connection"); - WifiNative.p2pGroupRemove(mGroup.getInterface()); - } else if (mGroup.removeClient(device)) { - if (!mPersistGroup && mGroup.isClientListEmpty()) { - Slog.d(TAG, "Client list empty, removing a non-persistent p2p group"); - WifiNative.p2pGroupRemove(mGroup.getInterface()); - } + device = (WifiP2pDevice) message.obj; + //Device loss for a connected device indicates it is not in discovery any more + if (mGroup.contains(device)) { + if (DBG) logd("Lost " + device +" , do nothing"); + return HANDLED; } - return NOT_HANDLED; // Do the regular device lost handling + // Do the regular device lost handling + return NOT_HANDLED; case WifiP2pManager.DISABLE_P2P: sendMessage(WifiP2pManager.REMOVE_GROUP); deferMessage(message); @@ -1028,7 +1121,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { case WifiP2pManager.CONNECT: WifiP2pConfig config = (WifiP2pConfig) message.obj; logd("Inviting device : " + config.deviceAddress); - if (WifiNative.p2pInvite(mGroup, config.deviceAddress)) { + if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) { updateDeviceStatus(config.deviceAddress, WifiP2pDevice.INVITED); sendP2pPeersChangedBroadcast(); replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); @@ -1038,24 +1131,25 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } // TODO: figure out updating the status to declined when invitation is rejected break; - case WifiMonitor.P2P_INVITATION_RESULT_EVENT: - logd("===> INVITATION RESULT EVENT : " + message.obj); - break; case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: - notifyP2pProvDiscPbcRequest((WifiP2pDevice) message.obj); - break; case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: - notifyP2pProvDiscPinRequest((WifiP2pDevice) message.obj); + case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: + WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj; + mSavedPeerConfig = new WifiP2pConfig(); + mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress; + if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) { + mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; + } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) { + mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; + mSavedPeerConfig.wps.pin = provDisc.pin; + } else { + mSavedPeerConfig.wps.setup = WpsInfo.PBC; + } + transitionTo(mUserAuthorizingJoinState); break; case WifiMonitor.P2P_GROUP_STARTED_EVENT: Slog.e(TAG, "Duplicate group creation event notice, ignore"); break; - case WPS_PBC: - WifiNative.wpsPbc(); - break; - case WPS_PIN: - WifiNative.wpsPin((String) message.obj); - break; default: return NOT_HANDLED; } @@ -1070,6 +1164,48 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } } + class UserAuthorizingJoinState extends State { + @Override + public void enter() { + if (DBG) logd(getName()); + notifyInvitationReceived(); + } + + @Override + public boolean processMessage(Message message) { + if (DBG) logd(getName() + message.toString()); + switch (message.what) { + case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: + case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: + case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: + //Ignore more client requests + break; + case PEER_CONNECTION_USER_ACCEPT: + if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { + mWifiNative.startWpsPbc(); + } else { + mWifiNative.startWpsPinKeypad(mSavedPeerConfig.wps.pin); + } + mSavedPeerConfig = null; + transitionTo(mGroupCreatedState); + break; + case PEER_CONNECTION_USER_REJECT: + if (DBG) logd("User rejected incoming request"); + mSavedPeerConfig = null; + transitionTo(mGroupCreatedState); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + + @Override + public void exit() { + //TODO: dismiss dialog if not already done + } + } + private void sendP2pStateChangedBroadcast(boolean enabled) { final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); @@ -1110,9 +1246,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub { InterfaceConfiguration ifcg = null; try { ifcg = mNwService.getInterfaceConfig(intf); - ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress( - SERVER_ADDRESS), 24); - ifcg.interfaceFlags = "[up]"; + ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress( + SERVER_ADDRESS), 24)); + ifcg.setInterfaceUp(); mNwService.setInterfaceConfig(intf, ifcg); /* This starts the dnsmasq server */ mNwService.startTethering(DHCP_RANGE); @@ -1146,140 +1282,80 @@ public class WifiP2pService extends IWifiP2pManager.Stub { dialog.show(); } - private void notifyWpsPin(String pin, String peerAddress) { + private void addRowToDialog(ViewGroup group, int stringId, String value) { Resources r = Resources.getSystem(); - AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) - .setMessage(r.getString(R.string.wifi_p2p_pin_display_message, pin, peerAddress)) - .setPositiveButton(r.getString(R.string.ok), null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); + View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row, + group, false); + ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId)); + ((TextView) row.findViewById(R.id.value)).setText(value); + group.addView(row); } - private void notifyP2pGoNegotationRequest(WifiP2pConfig config) { + private void notifyInvitationSent(String pin, String peerAddress) { Resources r = Resources.getSystem(); - WpsInfo wps = config.wps; - final View textEntryView = LayoutInflater.from(mContext) - .inflate(R.layout.wifi_p2p_go_negotiation_request_alert, null); - final EditText pin = (EditText) textEntryView .findViewById(R.id.wifi_p2p_wps_pin); - - AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) - .setView(textEntryView) - .setPositiveButton(r.getString(R.string.ok), new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (DBG) logd(getName() + " connect " + pin.getText()); - if (pin.getVisibility() == View.GONE) { - mSavedGoNegotiationConfig.wps.setup = WpsInfo.PBC; - } else { - mSavedGoNegotiationConfig.wps.setup = WpsInfo.KEYPAD; - mSavedGoNegotiationConfig.wps.pin = pin.getText().toString(); - } - sendMessage(GROUP_NEGOTIATION_USER_ACCEPT); - } - }) - .setNegativeButton(r.getString(R.string.cancel), new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (DBG) logd(getName() + " ignore connect"); - sendMessage(GROUP_NEGOTIATION_USER_REJECT); - } - }) - .create(); - - if (wps.setup == WpsInfo.PBC) { - pin.setVisibility(View.GONE); - dialog.setMessage(r.getString(R.string.wifi_p2p_pbc_go_negotiation_request_message, - config.deviceAddress)); - } else { - dialog.setMessage(r.getString(R.string.wifi_p2p_pin_go_negotiation_request_message, - config.deviceAddress)); - } - - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - } - - private void notifyP2pProvDiscPbcRequest(WifiP2pDevice peer) { - Resources r = Resources.getSystem(); final View textEntryView = LayoutInflater.from(mContext) - .inflate(R.layout.wifi_p2p_go_negotiation_request_alert, null); - final EditText pin = (EditText) textEntryView .findViewById(R.id.wifi_p2p_wps_pin); + .inflate(R.layout.wifi_p2p_dialog, null); + + ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); + addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress)); + addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin); AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) + .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title)) .setView(textEntryView) - .setPositiveButton(r.getString(R.string.ok), new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (DBG) logd(getName() + " wps_pbc"); - sendMessage(WPS_PBC); - } - }) - .setNegativeButton(r.getString(R.string.cancel), null) + .setPositiveButton(r.getString(R.string.ok), null) .create(); - - pin.setVisibility(View.GONE); - dialog.setMessage(r.getString(R.string.wifi_p2p_pbc_go_negotiation_request_message, - peer.deviceAddress)); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); dialog.show(); } - private void notifyP2pProvDiscPinRequest(WifiP2pDevice peer) { + private void notifyInvitationReceived() { Resources r = Resources.getSystem(); + final WpsInfo wps = mSavedPeerConfig.wps; final View textEntryView = LayoutInflater.from(mContext) - .inflate(R.layout.wifi_p2p_go_negotiation_request_alert, null); - final EditText pin = (EditText) textEntryView .findViewById(R.id.wifi_p2p_wps_pin); - - AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) - .setView(textEntryView) - .setPositiveButton(r.getString(R.string.ok), new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (DBG) logd(getName() + " wps_pin"); - sendMessage(WPS_PIN, pin.getText().toString()); - } - }) - .setNegativeButton(r.getString(R.string.cancel), null) - .create(); + .inflate(R.layout.wifi_p2p_dialog, null); - dialog.setMessage(r.getString(R.string.wifi_p2p_pin_go_negotiation_request_message, - peer.deviceAddress)); + ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); + addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName( + mSavedPeerConfig.deviceAddress)); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - } - - private void notifyP2pInvitationReceived(WifiP2pGroup group) { - mSavedP2pGroup = group; - Resources r = Resources.getSystem(); - final View textEntryView = LayoutInflater.from(mContext) - .inflate(R.layout.wifi_p2p_go_negotiation_request_alert, null); - final EditText pin = (EditText) textEntryView .findViewById(R.id.wifi_p2p_wps_pin); + final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin); AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) + .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title)) .setView(textEntryView) - .setPositiveButton(r.getString(R.string.ok), new OnClickListener() { + .setPositiveButton(r.getString(R.string.accept), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { - sendMessage(GROUP_INVITATION_USER_ACCEPT); + if (wps.setup == WpsInfo.KEYPAD) { + mSavedPeerConfig.wps.pin = pin.getText().toString(); + } + if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig); + sendMessage(PEER_CONNECTION_USER_ACCEPT); } }) - .setNegativeButton(r.getString(R.string.cancel), new OnClickListener() { + .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - if (DBG) logd(getName() + " ignore invite"); - sendMessage(GROUP_INVITATION_USER_REJECT); + if (DBG) logd(getName() + " ignore connect"); + sendMessage(PEER_CONNECTION_USER_REJECT); } }) .create(); - pin.setVisibility(View.GONE); - dialog.setMessage(r.getString(R.string.wifi_p2p_pbc_go_negotiation_request_message, - group.getOwner().deviceAddress)); + //make the enter pin area or the display pin area visible + switch (wps.setup) { + case WpsInfo.KEYPAD: + if (DBG) logd("Enter pin section visible"); + textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE); + break; + case WpsInfo.DISPLAY: + if (DBG) logd("Shown pin section visible"); + addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin); + break; + default: + break; + } dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); dialog.show(); @@ -1319,21 +1395,55 @@ public class WifiP2pService extends IWifiP2pManager.Stub { mWifiP2pInfo.groupOwnerAddress = null; } + private String getDeviceName(String deviceAddress) { + for (WifiP2pDevice d : mPeers.getDeviceList()) { + if (d.deviceAddress.equals(deviceAddress)) { + return d.deviceName; + } + } + //Treat the address as name if there is no match + return deviceAddress; + } + private String getDeviceAddress(String interfaceAddress) { for (WifiP2pDevice d : mPeers.getDeviceList()) { - if (interfaceAddress.equals(WifiNative.p2pGetInterfaceAddress(d.deviceAddress))) { + if (interfaceAddress.equals(d.interfaceAddress)) { return d.deviceAddress; } } return null; } - private void initializeP2pSettings() { - WifiNative.setPersistentReconnect(true); - WifiNative.setDeviceName(mThisDevice.deviceName); - WifiNative.setDeviceType(mThisDevice.primaryDeviceType); + private WifiP2pDevice getDeviceFromPeerList(String deviceAddress) { + for (WifiP2pDevice d : mPeers.getDeviceList()) { + if (d.deviceAddress.equals(deviceAddress)) { + return d; + } + } + return null; + } + + private void p2pConnectWithPinDisplay(WifiP2pConfig config, boolean join) { + String pin = mWifiNative.p2pConnect(config, join); + try { + Integer.parseInt(pin); + notifyInvitationSent(pin, config.deviceAddress); + } catch (NumberFormatException ignore) { + // do nothing if p2pConnect did not return a pin + } + } - mThisDevice.deviceAddress = WifiNative.p2pGetDeviceAddress(); + private void initializeP2pSettings() { + mWifiNative.setPersistentReconnect(true); + mWifiNative.setDeviceName(mThisDevice.deviceName); + //DIRECT-XY-DEVICENAME (XY is randomly generated) + mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); + mWifiNative.setDeviceType(mThisDevice.primaryDeviceType); + //The supplicant default is to support everything, but a bug necessitates + //the framework to specify this explicitly + mWifiNative.setConfigMethods("keypad display push_button"); + + mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress(); updateThisDevice(WifiP2pDevice.AVAILABLE); if (DBG) Slog.d(TAG, "DeviceAddress: " + mThisDevice.deviceAddress); } |