TO connect to WiFi AP needed to implement followed steps:
Scan WiFi
To be sure that you have appropriate AP. Bear in mind that you must provide password to secured AP. Suppose you know witch AP you prefer and now we are going to other step:
Create new profile
We need must support information about:
What type AP should be:
Open spot,
WEP,
WPA,
(or WPA2), with shared-key authentication,
WPA2-Enterprise (RADIUS Server authentication)
Priority - Priority determines the preference given to a network
by wpa_supplicant when choosing an access point with which to
associate (I set default 1000)
SSID - AP Name
Password - if it's secured AP.
Here is a snippets method demonstrating the technique:
I used single enum TEncMode encMode
for switch statement
....
WifiConfiguration wc = new WifiConfiguration();
wc.allowedAuthAlgorithms.clear();
wc.allowedGroupCiphers.clear();
wc.allowedKeyManagement.clear();
wc.allowedPairwiseCiphers.clear();
wc.allowedProtocols.clear();
switch (encMode) {
case ENC_WEP:
// If password is empty, it should be left untouched
if (!TextUtils.isEmpty(pswd)) {
wc.wepKeys[0] = TextUtil.convertToQuotedString(pswd);
}
wc.wepTxKeyIndex = 0;
wc.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
wc.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
wc.allowedKeyManagement.set(KeyMgmt.NONE);
wc.allowedGroupCiphers.set(GroupCipher.WEP40);
wc.allowedGroupCiphers.set(GroupCipher.WEP104);
break;
case ENC_WPA:
case ENC_WPA2:
wc.allowedGroupCiphers.set(GroupCipher.TKIP);
wc.allowedGroupCiphers.set(GroupCipher.CCMP);
wc.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
wc.allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
wc.allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
wc.allowedProtocols.set(Protocol.RSN);
wc.allowedProtocols.set(Protocol.WPA);
// If password is empty, it should be left untouched
if (!TextUtils.isEmpty(pswd)) {
if (pswd.length() == 64) {
// Goes unquoted as hex
wc.preSharedKey = pswd;
} else {
// Goes quoted as ASCII
wc.preSharedKey = TextUtil.convertToQuotedString(pswd);
}
}
break;
// case ENC_WPA2_ENTERPRISE:
....
// break;
default:
wc.allowedKeyManagement.set(KeyMgmt.NONE);
break;
}
// This is must be quoted according to the documentation
// http://developer.android.com/reference/android/net/wifi/WifiConfiguration.html#SSID
wc.SSID = TextUtil.convertToQuotedString(ssid.toString());
wc.hiddenSSID = false;
wc.priority = prior;
wc.BSSID = null;
wc.status = WifiConfiguration.Status.ENABLED;
For now we configured new AP according to our requst. Now lets create it:
Create new AP only
....
int res = -1;
WifiManager m_WifiManager = (WifiManager)m_context.getSystemService(Context.WIFI_SERVICE);
....
/** If profile exists, do nothing */
if(ifConnectionProfileExists(ssid) == true){
Log.i(Constants.TAG, "createConnectionProfile :: " + "CREATE_PROFILE ssid=" + ssid + " exists");
}
else{
res = m_WifiManager.addNetwork(wc);
Log.i(Constants.TAG, "createConnectionProfile :: " + " CREATE_PROFILE ssid=" + ssid + " dosn't exist, addNetwork ... res = " + res);
// Don't make to AP high priority to connect
//m_WifiManager.enableNetwork(res, false);
m_WifiManager.saveConfiguration();
if(res != -1){
// profile created
}
else{
// failed to add profile
}
}
if you skip this implementation, after turn WiFi off your created AP will dissapear
m_WifiManager.saveConfiguration();
So far so good, we can wait for android to connect to our new AP or we can do it by ourselves
Create and connect to AP
int res = -1;
/** If profile exists, do nothing */
if(ifConnectionProfileExists(ssid) == true){
res = getNetIdBySSID(ssid);
}
else{
res = m_WifiManager.addNetwork(wc);
}
// Don't make to AP high priority to connect
boolean b = m_WifiManager.enableNetwork(res, true);
if(b == true){
fixSupplicant();
m_WifiManager.saveConfiguration();
// start connect to AP
}
else{
// failed
}
....
private void fixSupplicant() {
final SupplicantState state = m_WifiManager.getConnectionInfo().getSupplicantState();
boolean isReconnectDone = false;
if ((state == SupplicantState.SCANNING)
|| (state == SupplicantState.DISCONNECTED)
|| (state == SupplicantState.DORMANT)) {
isReconnectDone = m_WifiManager.reconnect();;
}
}
private boolean ifConnectionProfileExists(String ssid){
List<WifiConfiguration> apProfiles = m_WifiManager.getConfiguredNetworks();
// remove profile if exists:
for (int i = 0; i < apProfiles.size(); i++) {
final WifiConfiguration ap = apProfiles.get(i);
if ((ap.SSID != null)) {
// try to find by SSID
if (TextUtils.equals(ap.SSID), ssid) {
return true;
}
}
}
return false;
}
Enum TEncMode
/**
* Represents encryption types modes of access points
*/
public enum TEncMode {
/**
* No encryption (open spot)
*/
ENC_NONE(0),
/*
* General encryption
*/
ENC_UNKNOWN(1),
/**
* WEP
*/
ENC_WEP(2),
/**
* WPA
*/
ENC_WPA(3),
/**
* WPA (or WPA2), with shared-key authentication
*/
ENC_WPA2(4),
/**
* WPA2-Enterprise (RADIUS Server authentication).
*/
ENC_WPA2_ENTERPRISE(5)
;
public static TEncMode
FromIntToEnum(
int value ) throws Exception
{
for ( TEncMode c : TEncMode.values() ) {
if ( c.mId == value ) {
return c;
}
}
throw new AgException( new StringBuilder("Illegal TEncMode: ").append(value).toString() );
}
public int
FromEnumToInt() {
return mId;
}
private TEncMode( int id ){
mId = id;
}
private int mId;
}
That's all. For sure you can listen on WiFi state changed to catch CONNECTED
event. Because we don't know how long it will take to device to connect to your AP. But we disabled all other APs and enabled new one. After we can get HTTP response for example from google to be sure that our AP has internet.
Asked me to add this method:
/**
* Surround the given string in quotes.
*
* @param string The text to surround in quotes.
* @return string wrapped with quotes.
*/
static public String convertToQuotedString(String string){
if (string==null) {
string = "";
}
empty(workBuffer);
workBuffer.append("\"");
workBuffer.append(string);
workBuffer.append("\"");
return workBuffer.toString();
}