Android Question Connect to wifi without internet

Michael Wenning

Member
Licensed User
I have a project with ESP8266 as a Access Point with Wifi connection. It has no internet connectivity.
Most mobile phones work good. I have problems with never Sony mobiles (Android 8.1 and 9.0).
They connect to the ESP8226, detect there is no internet connectivity and disconnect. I have found Erels solution for this in
https://www.b4x.com/android/forum/threads/mqtt-chat-network-error.90892/

It's based on:
... cm.InitializeStatic("android.net.ConnectivityManager").RunMethod("setProcessDefaultNetwork", Array(Network))

from: https://developer.android.com/reference/android/net/ConnectivityManager
i found this for never Android version:

static boolean setProcessDefaultNetwork(Network Network)
This method was deprecated in API level 23.
This function can throw IllegalStateException.
Use bindProcessToNetwork(Network) instead. bindProcessToNetwork Is a direct replacement.


1. Can someone please help me to implement this (always got error messages)?

2. Is there a better solution? What can i do?

Thank's a lot for your help and best regards from germany
Michael
 

Computersmith64

Well-Known Member
Licensed User
You can try any of the functions in this class:

B4X:
Sub Class_Globals
   
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
   
End Sub
Public Sub isWifiConnected() As Boolean
    Dim jo As JavaObject = Me
    Dim r As Reflector
    'Return jo.RunMethod("isNetworkConnected", Array(r.GetContext))
    Return jo.RunMethod("isConnected", Array(r.GetContext))
End Sub
#if JAVA
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.Build;
import android.net.Network;
import android.net.NetworkInfo;
import android.net.NetworkCapabilities;
//import anywheresoftware.b4a.BA;
//Pretty much a straight rip from https://stackoverflow.com/a/53078141
public boolean isNetworkConnected(Context context) {
    final ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (cm != null) {
        if (Build.VERSION.SDK_INT < 23) {
           //BA.Log("Build SDK < 23");
            NetworkInfo ni = cm.getActiveNetworkInfo();
            if (ni != null) {
                return (ni.isConnected() && (ni.getType() == ConnectivityManager.TYPE_WIFI));
            }
        } else {
           //BA.Log("Build SDK >= 23");
            Network n = cm.getActiveNetwork();
            if (n != null) {
                final NetworkCapabilities nc = cm.getNetworkCapabilities(n);
                return (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
            }
        }
    }
    return false;
}
public boolean getConnectivityStatus(Context context) {
    final ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    //connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo info = connManager.getActiveNetworkInfo();
    if (info != null)
        return info.isConnected(); // WIFI connected
    else
        return false; // no info object implies no connectivity
}
 public static boolean isConnected(Context context){
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            Network[] activeNetworks = cm.getAllNetworks();
            for (Network n: activeNetworks) {
                NetworkInfo nInfo = cm.getNetworkInfo(n);
                if(nInfo.isConnected())
                    return true;
            }
        } else {
            NetworkInfo[] info = cm.getAllNetworkInfo();
            if (info != null)
                for (NetworkInfo anInfo : info)
                    if (anInfo.getState() == NetworkInfo.State.CONNECTED) {
                        return true;
                    }
        }
        return false;
    }
#End If
However assuming you are using the MLWiFi (SimpleWifi) library, you will still have a problem with Android 9 devices in that you will never get the WiFi to return a connected state if there is no internet connection - per this thread -> Simple Wifi (MLWifi) not working correctly with Android 9

- Colin.
 

Michael Wenning

Member
Licensed User
Thank's for reply Colin.

The phone definitely connects to the ESP8266 wifi. It detects that there is no internet connectivity
and cuts connection. My app tries again and again...
I have found Erels solution for Android < 23.
It forces the phone after the wifi connection
to stay in the wifi, no matter if the internet connection exists or not.

Sub PreferWifiRouting As ResumableSub
Dim p As Phone
If p.SdkVersion >= 21 Then
Dim ctxt As JavaObject
ctxt.InitializeContext
Dim builder As JavaObject
builder.InitializeNewInstance("android.net.NetworkRequest.Builder", Null)
Dim manager As JavaObject = ctxt.RunMethod("getSystemService", Array("connectivity"))
builder.RunMethod("addTransportType", Array(1)) 'NetworkCapabilities.TRANSPORT_WIFI
Dim event As JavaObject
event.InitializeNewInstance(Application.PackageName & ".main$NetworkCallback", Null)
manager.RunMethod("requestNetwork", Array(builder.RunMethod("build", Null), event))
Wait For network_available (Network As Object)
Log("Network found.")
Dim cm As JavaObject
Return cm.InitializeStatic("android.net.ConnectivityManager").RunMethod("setProcessDefaultNetwork", Array(Network))
End If
Return False
End Sub

#if Java
public static class NetworkCallback extends android.net.ConnectivityManager.NetworkCallback {
public void onAvailable(android.net.Network network) {
processBA.raiseEventFromUI(null, "network_available", network);
}
}
#End If

The new method for Android > 23 is bindProcessToNetwork(Network).

But i don't know to implement. Please help.

Best regards
Michael
 

Computersmith64

Well-Known Member
Licensed User
Sorry - I misread your post. Maybe if you post the code that you've tried & the errors you're getting it might help someone come up with an answer.

- Colin.
 

Michael Wenning

Member
Licensed User
Good idea!

Here is the code:

B4X:
Private Sub PreferWifiRouting  As ResumableSub
    'Dim p As Phone
    'If p.SdkVersion >= 22 Then
    If Starter.wifi.APIversion >= 22 Then
        Dim ctxt As JavaObject
        ' MW 29.03.2019
        Log("PreferWifiRouting Start")
        ctxt.InitializeContext
        Dim builder As JavaObject
        builder.InitializeNewInstance("android.net.NetworkRequest.Builder", Null)
        Dim manager As JavaObject = ctxt.RunMethod("getSystemService", Array("connectivity"))
        builder.RunMethod("addTransportType", Array(1)) 'NetworkCapabilities.TRANSPORT_WIFI
        Dim event As JavaObject
        
        event.InitializeNewInstance(Application.PackageName & ".wificonnect$NetworkCallback", Null)
        
        manager.RunMethod("requestNetwork", Array(builder.RunMethod("build", Null), event))
        Wait For network_available (Network As Object)
        ' MW 29.03.2019
        Log("PreferWifiRouting Network found.")
        
        Dim cm As JavaObject
        
        ' Up to API 22
        
        '' Return cm.InitializeStatic("android.net.ConnectivityManager").RunMethod("setProcessDefaultNetwork", Array(Network))
        
        ' static boolean    setProcessDefaultNetwork(Network Network)
        ' This method was deprecated in API level 23.
        ' This function can throw IllegalStateException.
        ' Use bindProcessToNetwork(Network) instead. bindProcessToNetwork Is a direct replacement.
    
        Return  cm.InitializeStatic("android.net.ConnectivityManager").RunMethod("bindProcessToNetwork", Array(Network))
    
    End If
    Return False
End Sub


#if Java

public static class NetworkCallback extends android.net.ConnectivityManager.NetworkCallback {
    public void onAvailable(android.net.Network network) {
         processBA.raiseEventFromUI(null, "network_available", network);
  }
}

#End If
Here is the error log:

...
Wartezeit [mSek] für Disconnect Versuche: 10
StartConnectToAP: MyBike14313210 ist ein auf dem Handy gespeicherter Access Point!
PreferWifiRouting Start
*** Service (receiver) Create ***
BroadcastReceiver has been initialized.
** Service (receiver) Start **
TimerCheckTimeOutForConnection_Tick!Zeit: 03/30/2019 12:46:23
TimerCheckTimeOutForConnection_Tick!Zeit: 03/30/2019 12:46:24
TimerCheckTimeOutForConnection_Tick!Zeit: 03/30/2019 12:46:25
TimerCheckTimeOutForConnection_Tick!Zeit: 03/30/2019 12:46:26
PreferWifiRouting Network found.
Error occurred on line: 372 (WifiConnect)
java.lang.IllegalArgumentException: Expected receiver of type android.net.ConnectivityManager, but got java.lang.Class<android.net.ConnectivityManager>
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:131)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:176)
at anywheresoftware.b4a.shell.DebugResumableSub$RemoteResumableSub.resume(DebugResumableSub.java:22)
at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:250)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:137)
at anywheresoftware.b4a.BA$1.run(BA.java:335)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)


line 372 is: Return cm.InitializeStatic("android.net.ConnectivityManager").RunMethod("bindProcessToNetwork", Array(Network))

Is someone able to help me?

Thank's a lot and regards
Michael
 

Michael Wenning

Member
Licensed User
The code with "setProcessDefaultNetwork" runs well whithout errors but it doesn't bring any improvement.
The Sony mobiles connect to the ESP8226, detect there is no internet connectivity and disconnect.
So i want to try out the newer possibility with "bindProcessToNetwork".
The problem is that my Java knowledge is not sufficient for the implementation.

Is someone able to help me?

Thank's a lot and regards
Michael
 

Michael Wenning

Member
Licensed User
Hello,
i helped myself and here is the code sample for interested:

B4X:
'  Service Modul

Sub Process_Globals
  Private nativeMe As JavaObject
End Sub

Sub Service_Create
  nativeMe.InitializeContext
End Sub


' MW 07.04.2019
Public Sub PreferWifiRoutingJava(SollSsid As String) As Int
   
    Dim intErfolg As Int = nativeMe.RunMethod("BindProcessToNetwork", Array (SollSsid))
   
    'Sleep(0)
#If DEBUG      
    Log ("PreferWifiRoutingJava Sub Ergebnis: " & intErfolg)
#End if  
   
    Return intErfolg
   
End Sub

#If Java


 import android.os.Build;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.NetworkRequest;
 import android.os.SystemClock;
 import android.net.wifi.WifiConfiguration;
 import java.util.List;
 import android.content.Context;
 import android.content.Intent;
 import android.content.BroadcastReceiver;
 import android.content.IntentFilter;
 import anywheresoftware.b4a.BA;


public String CheckAktuelleSsid () {
        String AktSsid;
        AktSsid ="";
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiInfo;
        wifiInfo = wifiManager.getConnectionInfo();
        if (wifiInfo.getSupplicantState() == SupplicantState.COMPLETED) {
            AktSsid = wifiInfo.getSSID();
            // Ausgabe Logc
           // Log.i(TAG, "Check SSID: " + AktSsid);
        }
        return AktSsid;
    }

   
public int BindProcessToNetwork (final String networkSSID ) {
       
        //String AktuelleSsid;
        intZustand = -99;
       
        // AktuelleSsid ="";
       
        // „Lollipop“    5.0[81]    21        
        if (android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.LOLLIPOP){
         
           final ConnectivityManager manager =(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
           // ConnectivityManager manager =(ConnectivityManager) 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) {
                       int intZustandCb = 0;
                    boolean connected = false;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        connected = manager.bindProcessToNetwork(null);
                         
                        final String AktuelleSsid = CheckAktuelleSsid();
                        // BA.Log("bindProcessToNetwork AktuelleSsid: " + AktuelleSsid);
                        // BA.Log("bindProcessToNetwork networkSSID: " + networkSSID);
                       
                           if (AktuelleSsid.contains(networkSSID)) {
                       
                            manager.bindProcessToNetwork(network);
                            if (connected) {
                                // Log.i(TAG, "bindProcessToNetwork OK: " + network.toString());
                                BA.Log("bindProcessToNetwork OK: " + network.toString());
                                intZustandCb = 1;
                            }
                            else {
                                //Log.i(TAG, "bindProcessToNetwork NOK: " + network.toString());
                                BA.Log("bindProcessToNetwork NOK: " + network.toString());
                                intZustandCb = 2;
                            }
                        }
                    } else {
                        //This method was deprecated in API level 23
                        connected = ConnectivityManager.setProcessDefaultNetwork(network);
                        if (connected) {
                            //Log.i(TAG, "setProcessDefaultNetwork OK: " + network.toString());
                            BA.Log("setProcessDefaultNetwork OK: " + network.toString());
                            intZustandCb = 3;
                        }
                        else {
                            //Log.i(TAG, "setProcessDefaultNetwork NOK: " + network.toString());
                            BA.Log("setProcessDefaultNetwork NOK: " + network.toString());
                            intZustandCb = 4;
                        }
                    }
                    try {
                        //Do a callback Or something Else To alert your code that it's ok to send the message through socket now
                    } catch (Exception e) {
                        e.printStackTrace();
                        intZustandCb = -11;
                    }
                    manager.unregisterNetworkCallback(this);
                   // Log.i(TAG, "unregisterNetworkCallback");
                   //BA.Log("Ende mit unregisterNetworkCallback");
                   intZustandCb += 10;
                   //BA.Log("Callback Zustand Callback: " + String.valueOf(intZustandCb));
                   intZustand = intZustandCb;
                }
            });
           
        }
       
        // BA.Log("Zustand Aussen vorher: " + String.valueOf(intZustand));
       
        int i = 0;
               
        do {
            SystemClock.sleep(1);
            i++;
            //BA.Log("Zaehler i: " + String.valueOf(i));
            if (i > 200){
              intZustand = -1;
              break;
            }
        } while (intZustand < - 1);
       
        BA.Log("Zaehler i: " + String.valueOf(i));
        //BA.Log("Zustand Aussen Nachher: " + String.valueOf(intZustand));
       
        // MkGestartet = false;
       
        return intZustand;
               
    } // Ende von: Public void BindProcessToNetwork...
   
 
#End If
Best regards from Germany
Michael
 
Top