Home » Android » android – Oreo Wifi Connectivity

android – Oreo Wifi Connectivity

Posted by: admin May 14, 2020 Leave a comment

Questions:

I am working on an IoT app in which there is an on boarding process where the user connects to an access point, which has not internet connectivity, configure the device and then connects to his home Wifi network.

Android 8 devices have been causing some problems, disconnecting from the access point and reconnecting to a previously configured network. I am assuming this is related to the connectivity update which was introduced in Android 8, from section Seamless Connectivity in this link:

On compatible devices, automatic activation of Wi-Fi when a high
quality saved network is nearby.

My question is how to disable this behaviour as I need to stay connected to the access point, without internet connectivity, and finish the on Boarding process.

How to&Answers:

I had the same issue. What I did is adding a step to the boarding process where I invite the user to go to there settings, add manually this network with no data and accept the popup shown by the system.

I have not found a real solution yet.
However, I’ve seen an app called eWeLink where they manage to do it, but it is not an open source project.

Answer:

I am currently facing the same issue right now for the newer phone with Android 8.+. I am using WifiManager call bindProcessToNetwork here this will allows data traffic go through the wifi with no internet access,

here how I connect my phone to the access point

//Method to connect to WIFI Network
public boolean connectTo(String networkSSID, String key) {
    WifiConfiguration config = new WifiConfiguration();
    WifiInfo info = wifi.getConnectionInfo(); //get WifiInfo
    int id = info.getNetworkId(); //get id of currently connected network

    config.SSID = "\"" + networkSSID + "\"";
    if (key.isEmpty()) {
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    }
    int netID = wifi.addNetwork(config);

    int tempConfigId = getExistingNetworkId(config.SSID);

    if (tempConfigId != -1) {
        netID = tempConfigId;
    }

    boolean disconnect = wifi.disconnect();
    wifi.disableNetwork(id); //disable current network
    boolean enabled = wifi.enableNetwork(netID, true);
    boolean connected = wifi.reconnect();

if (((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M))
                    || ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
                            && !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M))) {

                final ConnectivityManager manager = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkRequest.Builder builder;
                builder = new NetworkRequest.Builder();
                //set the transport type do WIFI
                builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);

                manager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
                    @Override
                    public void onAvailable(Network network) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            manager.bindProcessToNetwork(network);
                        } else {
                            ConnectivityManager.setProcessDefaultNetwork(network);
                        }
                        try {
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        manager.unregisterNetworkCallback(this);
                    }
                });
            }

after connecting to the access point created by the device, it will constantly drop off from it.

Answer:

Just wanted to add a bit to the discussion. I’ve been using bindProcessToNetwork for a while and it does fix the loss of WiFi when connected to one without a network as described by Shawn Chen. This is a heavy handed solution that makes it difficult to use Mobile network at the same time. However, the routing layer is rather broken on Android somewhere around 6 where they started forcing request to mobile even though the routing table indicates the wifi device.

Anyway, you can actually bind at a socket level which I describe below. This may help when the process has been bound to the WiFi network and you still want to use mobile. Instead of looking up WiFi (which is what I was experimenting with instead of binding the process), you look up the mobile ‘Network’ object and build a socket to it.

What we need is something that indicates to android not to drop the WiFi connection.

HttpUrlConnection doesn’t allow you to get the socket so you can use okhttp to do it at the per-connection level. I’m using 2.7.5 of OkHttp but it is very similar for the 3+ version of OkHttp.

You get the current networks then process each to find WiFi network.

Network[] networks = connectivityManager.getAllNetworks();

Then you build the url like:

String url = "http://someurl";
HttpUrlConnection uconn = new OkUrlFactory( new OkHttpClient().setSocketFactory(network.getSocketFactory())).open(url)

This all works fine for a few connections and sometimes it works for the series of connections I used. Android is using the knowledge that activity is happening over the network but any pauses and it jumps back to using mobile. Android 9 wifi is just flawed and haven’t figured out how to make it sticky using the socket solution. There may be one.

Answer:

I had same issue. This is how I fix this issue in Android 8+ devices.
1. Since Android 8+ devices auto switch between WiFI and Cellular devices. I removed below code. i.e. Code to force move to wifi.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    NetworkRequest.Builder request = new NetworkRequest.Builder();
    Log.i("forceCellularConnection","request WIFI enable");
    request.addCapability(NetworkCapabilities.TRANSPORT_WIFI);
    connectivityManager.requestNetwork(request.build(), new ConnectivityManager.NetworkCallback() {
          @Override
          public void onAvailable(Network network) {
               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                      connectivityManager.setProcessDefaultNetwork(network);

                      connectivityManager.bindProcessToNetwork(network);
                }
           }
     });

}
  1. Also added below code to forget wifi connection before we make new connection. It takes some time for device to disconnect WiFI. So I added delay before connecting to new WIFI SSID.

    this.wifiManager.disableNetwork(configuration.networkId);
    this.wifiManager.removeNetwork(configuration.networkId);
    this.wifiManager.saveConfiguration(); // Not needed in API level 26 and above
    

Workaround which I tried and helped me making connection work are below: In my case also I have to connect WiFi which doesn’t have internet on it. Its a peer to peer connection.

  1. I Made 2-3 attempts for connection

    new CountDownTimer(16000, 2000) {
    
  2. Also I have written below broadcast receiver to check the state of WiFI. And then made the connection.

    private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() 
    {
        @Override
        public void onReceive(Context context, Intent intent) {
    
            final String action = intent.getAction();
    
            Log.d("WifiReceiver", ">>>>SUPPLICANT_STATE_CHANGED_ACTION<<<<<<");
            SupplicantState supl_state = ((SupplicantState) intent
                    .getParcelableExtra(WifiManager.EXTRA_NEW_STATE));
            switch (supl_state) {
            case ASSOCIATED:
                Log.i("SupplicantState", "ASSOCIATED");
                // authMsg = "ASSOCIATED";
                break;
            case ASSOCIATING:
                // authMsg = "ASSOCIATING";
                Log.i("SupplicantState", "ASSOCIATING");
                break;
            case AUTHENTICATING:
                // authMsg = "AUTHENTICATING";
                Log.i("SupplicantState", "Authenticating...");
                break;
            case COMPLETED:
                authMsg = "CONNECTED";
                Log.i("SupplicantState", "Connected");
                 final ConnectivityManager connection_manager =
                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    
                NetworkRequest.Builder request = new NetworkRequest.Builder();
                request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
    
                connection_manager.registerNetworkCallback(request.build(), new ConnectivityManager.NetworkCallback() {
    
                    @Override
                    public void onAvailable(Network network) {
                        ConnectivityManager.setProcessDefaultNetwork(network);
                    }
                });
                break;
            case DISCONNECTED: