Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Oreo Wifi Connectivity

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.

like image 697
Digital Da Avatar asked Mar 19 '18 12:03

Digital Da


People also ask

How to completely forget a WiFi network on Android?

For Android (general instruction using Google Marshmallow): Open Settings on your device, and tap on the WiFI icon to access WiFi network options. Tap and hold the WiFi network you want to delete, then select Forget Network from the menu that appears.

How do I connect to WiFi using cellular?

To do this, swipe down on your notification bar and check that the mobile data toggle is switched on. Or go into “Settings,” tap “Connections,” and “Data Usage” and make sure that mobile data is switched on. Step 2: Connect to a Wi-Fi network. Tap “Settings,” then “Connections”, then “Wi-Fi” and flip the switch on.


4 Answers

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:
    
like image 54
Nasir Khan Avatar answered Oct 16 '22 07:10

Nasir Khan


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.

like image 41
adc Avatar answered Oct 16 '22 07:10

adc


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.

like image 36
Shawn Chen Avatar answered Oct 16 '22 07:10

Shawn Chen


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.

like image 43
Bruce Avatar answered Oct 16 '22 06:10

Bruce