Reputation: 7833
I have a requirement to scan list of unknown SSID and login that access point with a few predefined password. If success, then continue next task. If failed, then try to login next SSID.
I try to register as many as I can to see which one is working:
receiverWifi = new WifiReceiver();
registerReceiver(receiverWifi, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
registerReceiver(receiverWifi, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
registerReceiver(receiverWifi, new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
registerReceiver(receiverWifi, new IntentFilter(WifiManager.NETWORK_IDS_CHANGED_ACTION));
registerReceiver(receiverWifi, new IntentFilter(WifiManager.ACTION_PICK_WIFI_NETWORK));
registerReceiver(receiverWifi, new IntentFilter(WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE));
registerReceiver(receiverWifi, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
registerReceiver(receiverWifi, new IntentFilter(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION));
I connect ssid with password like this:
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = String.format("\"%s\"", ssid);
wifiConfig.preSharedKey = String.format("\"%s\"", password);
netId = mainWifi.addNetwork(wifiConfig);
if (netId != -1) {
if (mainWifi.disconnect())
if (mainWifi.enableNetwork(netId, true))
if (mainWifi.reconnect()) {
}
}
And it did flow to connected:
class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
} else if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
networkInfo.isConnected()) {
WifiInfo wifiInfo = mainWifi.getConnectionInfo();
ssid = wifiInfo.getSSID();
//able to know Wifi connected to ssid here
}
} else if (intent.getAction().equalsIgnoreCase(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
}
}
}
But how do I figure out if password failed with this SSID ? I want to know if password failed, then the code will try next SSID. But which action should I use to know the password attempt was failed ? Currently I noticed only android.net.wifi.STATE_CHANGE
action keep receiving but it doesn't means password failed.
Upvotes: 0
Views: 1538
Reputation: 7833
WifiManager.ERROR_AUTHENTICATING
is not always appear, so I end up with this:
class WifiReceiverResult extends BroadcastReceiver {
boolean assoc = false;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
SupplicantState supl_state = ((SupplicantState)intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE));
switch (supl_state) {
case ASSOCIATED:
assoc = true;
break;
case FOUR_WAY_HANDSHAKE: //need this because ASSOCIATED sometimes skipped
assoc = true;
break;
case DISCONNECTED:
if (assoc) {
assoc = false;
//... try next SSID
}
break;
...
Due to DISCONNECTED
only valid if ASSOCIATED
OR FOUR_WAY_HANDSHAKE
appear once, so I put a assoc
variable as safe guard. It's of course not 100% accurate to reflect "invalid password" but I have no other better choice.
[UPDATE] keep in mind that the above is not the final code, you should also handle timeout and maximum attempts of DISCONNECTED, otherwise it might only success after few minutes(it's unacceptable in my requirement, I better try next SSID and then retry the whole list of SSID again) or repeat the stage SCANNING...DISCONNECTED infinitely.
This is what I do:
Handler myHandler = new Handler(Looper.getMainLooper());
Runnable runner = new Runnable() {
@Override
public void run() {
if (isTimeout) {
//Network idle timeout 15 seconds, do scanning next again
List<WifiConfiguration> list = mainWifi.getConfiguredNetworks(); //here might hang for 20 seconds !
for( WifiConfiguration i : list ) {
mainWifi.removeNetwork(i.networkId);
mainWifi.saveConfiguration();
}
connectAPWithTimeout();
}
}
};
...
void connectAPWithTimeout() {
if (runner != null) {
myHandler.removeCallbacks(runner);
}
myHandler.postDelayed(runner, 15000);
isTimeout = true;
try {
receiverWifiR.connectToAP(); //my custom method to connect to next ssid hotspot
} catch (NullPointerException e) {
}
}
...
class WifiReceiverResult extends BroadcastReceiver {
int attempt = 0;
...
@Override
public void onReceive(Context context, Intent intent) {
...
case DISCONNECTED:
attempt+=1;
if (assoc || attempt > 2) {
isTimeout = false;
assoc = false;
attempt = 0;
connectAPWithTimeout();
}
break;
And don't forget to remove callback when retry the class or connected before quit the class:
isTimeout = false;
if (runner != null) {
myHandler.removeCallbacks(runner);
}
Upvotes: 2
Reputation: 9425
add BrocastReciver for action "SUPPLICANT_STATE_CHANGED_ACTION" then add bellow code in onRecive
if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
int linkWifiResult = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 123);
if (linkWifiResult == WifiManager.ERROR_AUTHENTICATING) {
Log.i(TAG,"pwd error);
}
}
Upvotes: 1