Search code examples
androidbroadcastreceiverandroid-broadcastreceiver

Broadcast receiver doesn't catch required case when checking for Wifi connections


I'm building an app, which has two parts. In the first part, the user scans for nearby host spots and gets a list of available networks. This part works fine. The second part, is the one with a problem. In this part, the user chooses a network to connect to and the screen is updated accordingly. I implemented a broadcast receiver to catch when the user connects to the selected network. When the mobile data is turned-off, the broadcast receiver catches the right case and everything works. However, if the mobile data is on, the broadcast receiver doesn't catch the case when the connection to the wifi is happening, though I can see that the phone already connected to the wifi.

Here is my code snippet for the broadcast receiver:

mConnectivityReceiver = new BroadcastReceiver() {
       @Override
       public void onReceive(Context context, Intent intent) {

           new Thread(new Runnable() {
               @Override
               public void run() {

                        final ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
                        final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

                        if(networkInfo != null && networkInfo.isAvailable()){

                            Log.e("connectivityReceiver", "networkInfo type " + networkInfo.getTypeName());
                           switch (networkInfo.getType()){

                               case ConnectivityManager.TYPE_WIFI://When mobile data is on, I never reach this case
                                   updateUI(networkInfo);
                                   break;
                               case ConnectivityManager.TYPE_MOBILE:
                                   //do nothing.
                                   break;
                           }

                        }
                    }

               public void updateUI(final NetworkInfo networkInfo){

                   if(networkInfo.isAvailable() && networkInfo.getExtraInfo()!= null){

                            Log.e("connectivityReceiver","networkInfo extra: " + networkInfo.getExtraInfo());

                            if(networkInfo.getExtraInfo() != null){

                                if(networkInfo.getExtraInfo().contains(selectedNetwork)) {
                                    networks.clear();
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            mAdapter.notifyDataSetChanged();
                                            mDiscoverNetworksBtn.setEnabled(true);
                                            mDiscoverNetworksBtn.setVisibility(View.VISIBLE);
                                            mProgressbar.setVisibility(View.GONE);
                                            mWaitMessage.setVisibility(View.GONE);

                                        }
                                    });

                                    unregisterReceiver(mConnectivityReceiver);
                                }
                                else if(!networkInfo.getExtraInfo().equals("<unknown ssid>")){
                                    Log.e("connectivityReceiver", "Error occurred while trying to connect to " + selectedNetwork);
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(IoTSetupActivity.this, "Error occurred while trying to connect to " + selectedNetwork, Toast.LENGTH_LONG).show();
                                            mProgressbar.setVisibility(View.GONE);
                                            mWaitMessage.setVisibility(View.GONE);
                                            mListview.setVisibility(View.VISIBLE);
                                        }
                                    });
                                }

                            }

                        }

                    }
                }).start();
            }
        };

Here is the code snippet that I use to connect to selected network:

private void connectToNetwork(final Network network){

        final WifiConfiguration conf = new WifiConfiguration();
        conf.SSID = "\"" + network.getNetworkName() + "\"";
conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

            WifiManager wifiManager = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            wifiManager.addNetwork(conf);

            List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
            for(WifiConfiguration i : list){
                if(i.SSID != null && i.SSID.equals(conf.SSID)){

                    registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

                    Log.e("connectToNetwork", "Disconnecting from " + wifiManager.getConnectionInfo().getSSID());
                    boolean isDisconnected = wifiManager.disconnect();
                    Log.v("connectToNetwork", "isDisconnected: " + isDisconnected);

                    boolean isEnabled = wifiManager.enableNetwork(i.networkId, true);
                    Log.v("connectToNetwork", "isEnabled: " + isEnabled);

                    Log.e("connectToNetwork", "Trying to reconnect to " + conf.SSID);
                    boolean isReconnected = wifiManager.reconnect();
                    Log.v("connectToNetwork", "isReconnected: " + isReconnected);

//                    Toast.makeText(IoTSetupActivity.this,"Connected to " + conf.SSID, Toast.LENGTH_LONG).show();
                    break;
                }
            }
}

Edit according to Denis answer:

public class ConnectivityNetworkCallback extends ConnectivityManager.NetworkCallback{

        @Override
        public void onAvailable(android.net.Network network) {
            super.onAvailable(network);

            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
                mConnectivityManager.bindProcessToNetwork(network);
            else
                ConnectivityManager.setProcessDefaultNetwork(network);

            NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
            int connectionType = networkInfo.getType();
            Log.e("networkCallback", "connectionType: " + networkInfo.getTypeName());
            switch(connectionType){

                case ConnectivityManager.TYPE_WIFI:
                    String networkName = networkInfo.getExtraInfo();

                    Log.e("networkCallback","network type wifi, extra: " + networkName);
                    break;
                case ConnectivityManager.TYPE_MOBILE:
                    Log.e("networkCallback","network type mobile, extra:  " + networkInfo.getExtraInfo());
                    break;
            }
        }

Now my problem is when I have both mobile data and Wifi on, and switch between wifi networks, sometimes the first log prints that I'm connected to mobile and doesn't fires again when the devices connects to the new wifi, and sometimes it prints that I'm connected to the new wifi.


Solution

  • First of all wifiManager.reconnect() is not required, when you call enableNetwork(id, true) as this will already try to connect.

    Second, you must ensure, that you haven't previously connected manually to that network via system settings. In this case, your app won't connect to it as it is not permitted to. If you have created a connection manually, you must forget that network first to allow the app to re-create that connection. Afterwards, you will see a small text-hint in the system settings which app created that configuration.

    Third, the broadcast receiver isn't good for this purpose of what you're trying. It has too many cases which are all error-prone. Use the ConnectivityManager.NetworkCallback if you're working on Android 5 and later and listen for onAvailable() calls. This will ensure, that the wifi connection is actually set-up and usable.