Search code examples
javaandroidftpwifiandroid-things

Switching between 2 Wifi networks, connecting fails


I'm having trouble switching between 2 networks programmatically on a Raspberry Pi 3 running Android things (but it should be the same as running normal Android).

The first network is coming from a device server as an access point. It runs an FTP server which I need to access through its network. It has a static IP-address in the 192.168.xxx.xxx network that I know, and is secured by WPA2-PSK. I have the SSID and passphrase which I know to be correct. This device is in it's own private network that it makes itself and isn't reachable an external address. The only way to connect to it is by connecting to it's network and FTP'ing to it's static address.

The second network is an open network of which I also know the SSID. This one is preconfigured by another application, so my application can't update the configuration.

The code below is what I have at the moment. The DownloadFilesTask is called in the onCreate of my startscreen.

The configuration of the first network seems to fail, as adding the configuration to the WifiManager returns -1 as networkId as I can see in the log in the last 2 lines before disconnecting and loosing all logging. The 2 lines are:

04-11 11:10:51.258 1332-1349/rocks.androidthings.hellothings D/connecting: SSID1 passphase

04-11 11:10:51.259 411-740/system_process I/addOrUpdateNetwork: uid = 10026 SSID SSID1 nid=-1

After this I get a java.net.socketException: invalid argument or cannot connect assign requested address.

I have been struggling with this for the past few days, so any help would be appreciated.

public String connectToNetwork1() {
    try {
        WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);

        if (!wifiManager.getConnectionInfo().getSSID().equals("\"" + SSID1 + "\"")) {

            WifiConfiguration conf = new WifiConfiguration();
            conf.SSID = "\"" + SSID1 + "\"";

            conf.preSharedKey = "\"" + passphrase + "\"";
            conf.allowedProtocols.set(WifiConfiguration.Protocol.RSN); // For WPA2
            conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            Log.d("connecting", conf.SSID + " " + conf.preSharedKey);

            int networkId = wifiManager.addNetwork(conf);

            Log.d("after connecting", conf.SSID + " " + conf.preSharedKey);
            wifiManager.disconnect();
            Thread t = new Thread(() -> {
                wifiManager.enableNetwork(networkId, true);                 
            });
            t.start();
            t.join();
            wifiManager.reconnect();
            Log.d("re connecting", wifiManager.getConnectionInfo().getSSID());
            return wifiManager.getConnectionInfo().toString();
        } else {
            Log.d("WIFI", "already connected to network1");
            return "already connected to network1";
        }
    } catch (Exception ex) {
        Log.d("ERROR", ex.toString());
    }
    return "nougabollen";
}

public String connectToNetwork2() {
    try {
        WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        if (!wifiManager.getConnectionInfo().getSSID().equals("\"" + SSID2 + "\"")) {

            /*WifiConfiguration conf = new WifiConfiguration();             //
            conf.SSID = "\"" + SSID2 + "\"";                                //
                                                                            //  
            conf.status = WifiConfiguration.Status.ENABLED;                 //
            conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);  // this block is useless since my application can't update this network
                                                                            // since network 2 is configured elsewhere  
            Log.d("connecting", conf.SSID);                                 //
                                                                            //
            int networkId = wifiManager.addNetwork(conf);*/                 //
            int networkId = -2;
            List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
            for(WifiConfiguration wc : configs){
                if(wc.SSID.equals("\"" + SSID2 + "\"")){
                    networkId = wc.networkId;
                }
            }
            int finalNetworkId = networkId;
            wifiManager.disconnect();
            Thread t = new Thread(() -> {
                wifiManager.enableNetwork(finalNetworkId, true);
            });
            t.start();
            t.join();
            wifiManager.reconnect();
            Log.d("re connecting", wifiManager.getConnectionInfo().getSSID());
            return  "tried networkId: " + networkId + "   " + wifiManager.getConnectionInfo().toString();
        } else {
            Log.d("WIFI", "already connected to network2");
            return "already connected to network2";
        }
    } catch (Exception ex) {
        Log.d("ERROR", ex.toString());
    }
    return "smoutebollen";
}

private class DownloadFilesTask extends AsyncTask<Void, Void, String> {

    @Override
    protected String doInBackground(Void... params) {
        String text = "";
        text += " " + connectToNetwork1();
        text += " " + retrieveFile();
        text += " " + connectToNetwork2();
        Log.d("text", text);
        return text;
    }

    protected void onPostExecute(String text) {
        test.setText(text);
    }
}

The code that I use to retrieve the file is (using apache.commons.net):

public static String getDummyFile(){
    FTPClient client = new FTPClient();
    Log.d("ftp","client created");
    InetAddress ip = null;
    try {
        ip = InetAddress.getByName("192.168.242.129"); // this is the address of the device creating the first network
    }
    catch (Exception e){
        Log.d("inetaddres",e.toString());
    }
    try {
        Log.d("inet", ip.getHostAddress());
        int reply = -1; //response


        client.connect(ip);
        Log.d("ftp","client connected");
        reply = client.getReplyCode();
        Log.d("ftp",""+reply);
        client.enterLocalPassiveMode();
        Log.d("ftp","passive mode");

        //check if login is accepted
        /*if (!client.login("anonymous", "")) {
            Log.d("FTP", "error logging in");
        }*/

        //check if bad reponse code
        /*if (!FTPReply.isPositiveCompletion(reply)) {
            client.disconnect();
            Log.d("FTP", "connection refused");
        }*/

        //set file type to binary and enter passive mode, active not supported on android
        client.setFileType(FTP.BINARY_FILE_TYPE);
        Log.d("ftp", "set type to binary");
        client.changeWorkingDirectory("/files");
        Log.d("ftp","changed dir");
        String[] names = client.listNames();
        Log.d("FTP", names[1].toString());
        Log.d("FTP", client.printWorkingDirectory() + "/" + names[1].toString());
        mapFiles(client,"/files","",0);
        return client.printWorkingDirectory() + "/" + names[1].toString();

    } catch (Exception e) {
        Log.d("ftp",e.toString());
        text = e.toString();
    }
    finally {
        try {
            client.disconnect();
        }
        catch (Exception e){

        }
    }
    return text;
}

which gives the exception when trying to connect, since I'm not connected to the network.


Solution

  • So I managed to get it working, the following is my working code. Main differences are setting WPA as protocol, and letting the thread were I connect sleep for 3 seconds after enabling the network.

        public String connectToXs() {
        try {
            WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    
            if (!wifiManager.getConnectionInfo().getSSID().equals("\"ssid\"")) {
    
                WifiConfiguration wc = new WifiConfiguration();
                wc.SSID = "\"ssid\"";
    
                wc.preSharedKey  = "\"key\"";
                wc.status = WifiConfiguration.Status.ENABLED;
                wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
                wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
                wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                wc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                wc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                int res = wifiManager.addNetwork(wc);
                Log.d("WifiPreference", "add Network returned " + res );
                final boolean[] b = new boolean[1];
                Thread t = new Thread(() -> {
                    b[0] = wifiManager.enableNetwork(res, true);
                    wifiManager.setWifiEnabled(true);
                    try {
                        Thread.sleep(3000);
                    }
                    catch (Exception e){
                        Log.d("ERROR",e.toString());
                    }
                });
                t.start();
                t.join();
                Log.d("WifiPreference", "enableNetwork returned " + b[0]);
    
                return wifiManager.getConnectionInfo().toString();
            } else {
                Log.d("WIFI", "already connected");
                return "already connected";
            }
        } catch (Exception ex) {
            Log.d("ERROR", ex.toString());
        }
        return "nougabollen";
    }
    
    public String connectToGuest() {
        try {
            WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            if (!wifiManager.getConnectionInfo().getSSID().equals("\"" + "ssid2" + "\"")) {
    
                //int networkId = wifiManager.addNetwork(conf);
                int networkId = -2;
                List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
                for(WifiConfiguration wc : configs){
                    if(wc.SSID.equals("\"SSID2\"")){
                        networkId = wc.networkId;
                    }
                }
                int finalNetworkId = networkId;
                wifiManager.disconnect();
                Thread t = new Thread(() -> {
                    wifiManager.enableNetwork(finalNetworkId, true);
                    try {
                        Thread.sleep(3000);
                    }
                    catch (Exception e){
                        Log.d("ERROR",e.toString());
                    }
                });
                t.start();
                t.join();
                wifiManager.reconnect();
                Log.d("re connecting", wifiManager.getConnectionInfo().getSSID());
                return  "tried networkId: " + networkId + "   " + wifiManager.getConnectionInfo().toString();
            } else {
                Log.d("WIFI", "already connected");
                return "already connected";
            }
        } catch (Exception ex) {
            Log.d("ERROR", ex.toString());
        }
        return "smoutebollen";
    }