Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Q Wifi connection via WifiNetworkSpecifier lose connection immediately after connection established

I'm currently trying to connect to a wifi network. I used the below code.

        WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
                .setSsid(ssid)
                .setBssid(MacAddress.fromString(bssid))
                .setWpa2Passphrase(password)
                .build();

        NetworkRequest request = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setNetworkSpecifier(specifier)
                .build();

        ConnectivityManager manager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);

        manager.requestNetwork(request, new ConnectivityManager.NetworkCallback() {

            @Override
            public void onAvailable(@NonNull Network network) {
                ConnectivityManager.setProcessDefaultNetwork(network);
                super.onAvailable(network);
                NetworkInfo info = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                if (info != null && info.isConnectedOrConnecting()) {
                    if (!emitter.isDisposed()) {
                        emitter.onSuccess(true);
                    }
                } else {
                    if (!emitter.isDisposed()) {
                        emitter.onError(new RuntimeException("OS Disconnected"));
                    }
                }

            }

            @Override
            public void onUnavailable() {
                super.onUnavailable();
                if (!emitter.isDisposed()) {
                    emitter.onError(new RuntimeException("Could not connect Wifi"));
                }
            }
        });
    });

issue: the above code works well with Pixel phone and Nokia but on Oneplus devices, I get toast connection success toast and immediately after this wifi gets disconnected. wifi Symbol is visible very briefly in the status bar. In the next Moment, Wifi-Symbol is gone and the system Dialog is visible again, to connect to the wifi.

Have given below the permissions, and location permission is granted and it is enabled in the device also.

 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

When I debug the Callback it is going through the methods in this Order:

  1. onAvailable()
  2. onCapabilitiesChanged()
  3. onBlockedStatusChanged (blocked: false)
  4. onCapabilitiesChanged()
  5. onLost()

I have already referred these Android Q, programmatically connect to different WiFi AP for internet
WiFi Network Connection keeps disconnecting on Android Q Wifi Network Request Api connection issue in android 10 (Q) Android Q, WifiNetworkSpecifier loosing Wifi immediately after connection is established

and I could not able to find a solution.

Is there anything I'm missing in network request that causes disconnection. or any other solution appreciated.

Thank you.

like image 776
Jayanth Avatar asked Mar 12 '20 18:03

Jayanth


4 Answers

This issue still doesn't seem to be fixed as of September 2020 on certain devices, Oneplus 6, Nokia phones etc seem to be exhibiting this success connection loop. In the meantime if you have a iOT device your app is trying to auto connect and it fails you can try this in the onFail(), to dismiss the connection dialog and take your users gracefully to the wifi page to manually connect.

        connectivityManager.bindProcessToNetwork(null);
        connectivityManager.unregisterNetworkCallback(networkCallback);
        AlertDialog.Builder alert = new AlertDialog.Builder(...);
        alert.setTitle(...);
        alert.setMessage(...);
        alert.setPositiveButton("OK",
          new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
              Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
              intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
              context.startActivity(intent);
            }
          });
        alert.show();
      }
like image 70
rampency Avatar answered Oct 17 '22 09:10

rampency


Late to the conversation but, have you tried calling connectivityManager.bindProcessToNetwork(network) whenever you find an available network?

Here's an example of what I mean based on your question's code:

WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
                .setSsid(ssid)
                .setBssid(MacAddress.fromString(bssid))
                .setWpa2Passphrase(password)
                .build();

        NetworkRequest request = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setNetworkSpecifier(specifier)
                .build();

        ConnectivityManager manager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);

        manager.requestNetwork(request, new ConnectivityManager.NetworkCallback() {

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

                // This is the new line of code
                ConnectivityManager.bindProcessToNetwork(network);

                NetworkInfo info = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                if (info != null && info.isConnectedOrConnecting()) {
                    if (!emitter.isDisposed()) {
                        emitter.onSuccess(true);
                    }
                } else {
                    if (!emitter.isDisposed()) {
                        emitter.onError(new RuntimeException("OS Disconnected"));
                    }
                }

            }
...
}
like image 33
Ivan Garza Avatar answered Oct 17 '22 11:10

Ivan Garza


If you are trying to connect to a network that does not provide access to the internet, instead of

NetworkRequest request = new NetworkRequest.Builder()
 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
 .setNetworkSpecifier(specifier)
 .build();

try

NetworkRequest request = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setNetworkSpecifier(specifier)
.build()

Apparently, internet capability is required by default.

The documentation (see https://developer.android.com/reference/android/net/wifi/WifiNetworkSpecifier.Builder#build()) says

Create a specifier object used to request a local Wi-Fi network. The generated NetworkSpecifier should be used in NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier) when building the NetworkRequest. These specifiers can only be used to request a local wifi network (i.e no internet capability). So, the device will not switch it's default route to wifi if there are other transports (cellular for example) available.

I don't really understand this paragraph, but it talks about the device switching back to the default route, what would cause a disconnection from your target network.

The example that is provided there includes the line

.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)

I copied the example and it worked for me. Never tried to make the connection without the line above.

However, I only had tried to connect to a network with internet connection. To my surprise, when I tried to connect to one without it, in spite of the documentation, the connection fails.

like image 25
jesjf Avatar answered Oct 17 '22 10:10

jesjf


I have been tracking & researching this a lot. All my findings along with my current most optimal solution can be found here

But more specific to your question is the following info taken from the link

As stated here by Google, some OEM Roms are not 'holding on to the request' and therefore the connection is dropping instantly. OnePlus have fixed this problem in some of their later models but not all. This bug will continuously exist for certain phone models on certain Android builds, therefore a successful fallback (i.e. a manual connection with no network disruption) is required. No known workaround is available

  • removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) wont help keep the connection on a OnePlus as stated here

  • setting the Bssid wont help keep the connection on a OnePlus as stated here

  • google cannot help, they have stated it is out of their hands here

  • OnePlus forum posts confirming it working for some models (but not all) after an update, see here, here & here

like image 39
LethalMaus Avatar answered Oct 17 '22 10:10

LethalMaus