林果皞
林果皞

Reputation: 7833

Android - how to know SSID failed with password?

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

Answers (2)

林果皞
林果皞

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

Cyrus
Cyrus

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

Related Questions