/*
* Wifi Connecter
*
* Copyright (c) 20101 Kevin Yuan (farproc@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**/
package com.farproc.wifi.connecter;
import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;
import java.util.Comparator;
import java.util.List;
public class Wifi {
private static final ConfigurationSecurities ConfigSec = ConfigurationSecurities.newInstance();
private static final String TAG = "Wifi Connecter";
private static final int MAX_PRIORITY = 99999;
/**
* Change the password of an existing configured network and connect to it
*
* @param wifiMgr
* @param config
* @param newPassword
* @return
*/
public static int changePasswordAndConnect(final Context ctx, final WifiManager wifiMgr, final WifiConfiguration config, final String newPassword, final int numOpenNetworksKept) {
ConfigSec.setupSecurity(config, ConfigSec.getWifiConfigurationSecurity(config), newPassword);
final int networkId = wifiMgr.updateNetwork(config);
if (networkId == -1) {
// Update failed.
return -1;
}
// Force the change to apply.
wifiMgr.disconnect();
return connectToConfiguredNetwork(ctx, wifiMgr, config, true);
}
/**
* Configure a network, and connect to it.
*
* @param wifiMgr
* @param scanResult
* @param password Password for secure network or is ignored.
* @return
*/
public static int connectToNewNetwork(final Context ctx, final WifiManager wifiMgr, final ScanResult scanResult, final String password, final int numOpenNetworksKept) {
final String security = ConfigSec.getScanResultSecurity(scanResult);
if (ConfigSec.isOpenNetwork(security)) {
checkForExcessOpenNetworkAndSave(wifiMgr, numOpenNetworksKept);
}
WifiConfiguration config = new WifiConfiguration();
config.SSID = convertToQuotedString(scanResult.SSID);
config.BSSID = scanResult.BSSID;
ConfigSec.setupSecurity(config, security, password);
int id = -1;
try {
id = wifiMgr.addNetwork(config);
} catch (NullPointerException e) {
Log.e(TAG, "Weird!! Really!! What's wrong??", e);
// Weird!! Really!!
// This exception is reported by user to Android Developer Console(https://market.android.com/publish/Home)
}
if (id == -1) {
return -1;
}
if (!wifiMgr.saveConfiguration()) {
return -1;
}
config = getWifiConfiguration(wifiMgr, config, security);
if (config == null) {
return -1;
}
return connectToConfiguredNetwork(ctx, wifiMgr, config, true);
}
/**
* Connect to a configured network.
*
* @param ctx
* @param wifiManager
* @param config
* @param reassociate
* @return
*/
private static int connectToConfiguredNetwork(final Context ctx, final WifiManager wifiMgr, WifiConfiguration config, boolean reassociate) {
final String security = ConfigSec.getWifiConfigurationSecurity(config);
int configId = config.networkId;
int oldPri = config.priority;
// Make it the highest priority.
int newPri = getMaxPriority(wifiMgr) + 1;
if (newPri > MAX_PRIORITY) {
newPri = shiftPriorityAndSave(wifiMgr);
config = getWifiConfiguration(wifiMgr, config, security);
if (config == null) {
return -1;
}
}
// Set highest priority to this configured network
config.priority = newPri;
int networkId = wifiMgr.updateNetwork(config);
if (networkId == -1) {
return -1;
}
// Do not disable others
if (!wifiMgr.enableNetwork(networkId, false)) {
config.priority = oldPri;
return -1;
}
if (!wifiMgr.saveConfiguration()) {
config.priority = oldPri;
return -1;
}
// We have to retrieve the WifiConfiguration after save.
config = getWifiConfiguration(wifiMgr, config, security);
if (config == null) {
return -1;
}
// Disable others, but do not save.
// Just to force the WifiManager to connect to it.
if (!wifiMgr.enableNetwork(config.networkId, true)) {
return -1;
}
final boolean connect = reassociate ? wifiMgr.reassociate() : wifiMgr.reconnect();
if (!connect) {
return -1;
}
return configId;
}
private static void sortByPriority(final List<WifiConfiguration> configurations) {
java.util.Collections.sort(configurations, new Comparator<WifiConfiguration>() {
public int compare(WifiConfiguration object1,
WifiConfiguration object2) {
return object1.priority - object2.priority;
}
});
}
/**
* Ensure no more than numOpenNetworksKept open networks in configuration list.
*
* @param wifiMgr
* @param numOpenNetworksKept
* @return Operation succeed or not.
*/
private static boolean checkForExcessOpenNetworkAndSave(final WifiManager wifiMgr, final int numOpenNetworksKept) {
final List<WifiConfiguration> configurations = wifiMgr.getConfiguredNetworks();
sortByPriority(configurations);
boolean modified = false;
int tempCount = 0;
for (int i = configurations.size() - 1; i >= 0; i--) {
final WifiConfiguration config = configurations.get(i);
if (ConfigSec.isOpenNetwork(ConfigSec.getWifiConfigurationSecurity(config))) {
tempCount++;
if (tempCount >= numOpenNetworksKept) {
modified = true;
wifiMgr.removeNetwork(config.networkId);
}
}
}
return !modified || wifiMgr.saveConfiguration();
}
private static int shiftPriorityAndSave(final WifiManager wifiMgr) {
final List<WifiConfiguration> configurations = wifiMgr.getConfiguredNetworks();
sortByPriority(configurations);
final int size = configurations.size();
for (int i = 0; i < size; i++) {
final WifiConfiguration config = configurations.get(i);
config.priority = i;
wifiMgr.updateNetwork(config);
}
wifiMgr.saveConfiguration();
return size;
}
private static int getMaxPriority(final WifiManager wifiManager) {
final List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
int pri = 0;
for (final WifiConfiguration config : configurations) {
if (config.priority > pri) {
pri = config.priority;
}
}
return pri;
}
public static void cleanPreviousConfiguration(final WifiManager wifiMgr, final ScanResult hotspot, String hotspotSecurity) {
WifiConfiguration config;
do {
config = getWifiConfiguration(wifiMgr, hotspot, null);
if (config != null)
wifiMgr.removeNetwork(config.networkId);
} while (config != null);
}
private static WifiConfiguration getWifiConfiguration(final WifiManager wifiMgr, final ScanResult hotspot, String hotspotSecurity) {
final String ssid = convertToQuotedString(hotspot.SSID);
if (ssid.length() == 0) {
return null;
}
final String bssid = hotspot.BSSID;
if (bssid == null) {
return null;
}
if (hotspotSecurity == null) {
hotspotSecurity = ConfigSec.getScanResultSecurity(hotspot);
}
final List<WifiConfiguration> configurations = wifiMgr.getConfiguredNetworks();
if (configurations == null) {
return null;
}
for (final WifiConfiguration config : configurations) {
if (config.SSID == null || !ssid.equals(config.SSID)) {
continue;
}
if (config.BSSID == null || bssid.equals(config.BSSID)) {
final String configSecurity = ConfigSec.getWifiConfigurationSecurity(config);
if (hotspotSecurity.equals(configSecurity)) {
return config;
}
}
}
return null;
}
private static WifiConfiguration getWifiConfiguration(final WifiManager wifiMgr, final WifiConfiguration configToFind, String security) {
final String ssid = configToFind.SSID;
if (ssid.length() == 0) {
return null;
}
final String bssid = configToFind.BSSID;
if (security == null) {
security = ConfigSec.getWifiConfigurationSecurity(configToFind);
}
final List<WifiConfiguration> configurations = wifiMgr.getConfiguredNetworks();
for (final WifiConfiguration config : configurations) {
if (config.SSID == null || !ssid.equals(config.SSID)) {
continue;
}
if (config.BSSID == null || bssid == null || bssid.equals(config.BSSID)) {
final String configSecurity = ConfigSec.getWifiConfigurationSecurity(config);
if (security.equals(configSecurity)) {
return config;
}
}
}
return null;
}
public static String convertToQuotedString(String string) {
if (TextUtils.isEmpty(string)) {
return "";
}
final int lastPos = string.length() - 1;
if (lastPos > 0 && (string.charAt(0) == '"' && string.charAt(lastPos) == '"')) {
return string;
}
return "\"" + string + "\"";
}
}