I'm trying to connect to a WiFi (open network) which couldn't have Internet access and I having some problems with this.
When the Wifi has internet, my code work 100% for all devices. But, when the Wifi has no internet, some devices doesn't respond my code (below) correctly.
List<WifiConfiguration> wifiConfigurations = wifiManager.getConfiguredNetworks();
int i = -1;
for (WifiConfiguration iWifiConfig : wifiConfigurations) {
String wifiConfigSSID = iWifiConfig.SSID.replace("\"", "");
if (SSID_REGISTERED.equals(wifiConfigSSID)) {
i = iWifiConfig.networkId;
}
}
wifiManager.disconnect();
//I already tried call "Thread.sleep(5000);" here.
wifiManager.enableNetwork(i, true);
//I already tried call "Thread.sleep(5000);" here.
wifiManager.reconnect();
//I already tried call "Thread.sleep(5000);" here.
I noticed I'm having problems in devices that show a confirmation dialog for Wifi without internet (Dialog Wifi without Internet Confirmation). In those devices, the reconnect doesn't return error, and the phone show that is connected at the Wifi, but I can't reach my server in the lan network.
For all other devices, that doesn't have this dialog confirmation, my code work 100%.
Related
I am currently working on an app which connects to an communication pod through wifi (no internet) but my app also needs cellular connection for internet access.
I tried achieving it by adding transport network capabilities TRANSPORT_CELLULAR, but it worked only for devices with wifi assistant(switches between wifi and cellular data as the network strength),
isn't there anyway to achieve it simultaneously which works for every device?
Example will be good.
mConnectivityManager = (ConnectivityManager)mLoginActivity.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder request = new NetworkRequest.Builder();
request.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
request.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mConnectivityManager.registerNetworkCallback (request.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
mConnectivityManager.bindProcessToNetwork(network);
}
});
I have a deployed app that is failing on Android 9. Part of its function is to configure a module over an Access Point network to allow that that module to connect to the users home network.
I have code that detects and connects to the correct WIFI network, but when I attempt to open a socket to the device, it fails - only on Android 9 and only if mobile data is enabled. If I manually disable mobile data on the device everything runs fine.
Socket open() {
Socket sock = new Socket(Proxy.NO_PROXY);
try {
sock.bind(new InetSocketAddress(localIpAddress(), 50000));
} catch (IOException e) {
activity.logContent("Warning: Failed to bind socket : " + e.toString());
}
try {
sock.connect(new InetSocketAddress("192.168.17.1", 5555), (int)5000);
} catch (IOException e) {
// This catch fires when Mobile Data is on.
activity.logContent("Connected to " + activity.mWifiManager.getConnectionInfo().getSSID());
activity.logContent("Couldn't open socket : " + e.toString());
}
return sock;
}
I have tried this with and without the Proxy.NO_PROXY and with and without the bind() call. If the bind call is missing the error implies that the socket is attempting to connect over the cell network. (Note: activity.logContent() is an on-screen log so it is easier to see what is happening when not connected to a debugger).
Any ideas what is going wrong?
After a few days of imprecations I believe I have come to the identification of the problem and therefore to the solution:
The problem occurs due to some changes in the version of android (I presume to be 9.0 even if other changes had occurred on API 21), in particular on the creation of the socket, if the system detects that there is a "better" network (access to internet, high signal, etc, etc) socket creation refers to that network and no longer to the wifi network you would like.
I looked for ways to force the creation of the socket on the wifi network (which is the network I want) and the only way I found is this:
Simply put instead of:
Socket sock = new Socket ();
Do:
ConnectivityManager connectivity = (ConnectivityManager) MyApp.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null)
{
for (Network network : connectivity.getAllNetworks())
{
NetworkInfo networkInfo = connectivity.getNetworkInfo(network);
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI)
{
if (networkInfo.isConnected())
{
Socket sock = network.getSocketFactory().createSocket();
}
}
}
}
Practically browse the networks present in the device and when you find your active wifi you do nothing but take advantage of this function to get the right socket for sure:
getSocketFactory().createSocket()
Now you have the working socket!
In my case it now works perfectly, if someone finds better solutions, it is welcome, but for now it is the only way I have found to make everything work as in the previous version of android.
In Android 9 there a security config about network: Android security config
Adding your domain in network_security_config might solve your problem. I had this in my network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">119.xxx.xxx.xxx</domain>
</domain-config>
</network-security-config>
I am not sure about the exact reason of why this is happening. However, when you are turning on your mobile data and you are only connected to the internet using your mobile data (considering your wifi is turned off), it gets the IP address from the cellular network which is no more connected in your home network. Hence, this is trivial to expect such timeout scenarios, because, it cannot reach the private IP addresses of your home network starting with 192.168.....
Now my confusion is that even if the mobile data is turned on, and both wifi and mobile data is turned on at the same time, the device should connect to the wifi as a default behavior.
Hence I would like to suggest you check the following.
Android 9 (Pie) introduces special Wifi preference, which prevents connecting to public networks automatically. You might consider checking the settings.
Please check the IP address of your device and check if it has some IP address starting with 192.168..... If not, then definitely, you are getting your IP address from your cellular network and hence it cannot reach your private IP addresses of the home network.
We have an app we are making that needs to switch to cellular for some requests even when WiFi is connected.
According to the ConnectionManager documentation these following methods are now deprecated, but is not so clear on what to use instead.
public void useMobileNetworkMode(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.setNetworkPreference(ConnectivityManager.TYPE_MOBILE);
}
public void useDefaultNetworkMode(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.setNetworkPreference(ConnectivityManager.DEFAULT_NETWORK_PREFERENCE);
}
Do these methods still work in android 5/6? and if anyone has info or something to replace these methods with I would be very grateful!
Ok little bit more on the problem :)
I have managed to investigate ConnectivityManager and can see the networks using :
Network networkToUse = null;
Network[] networks;
networks = cm.getAllNetworks();
for (Network network : networks) {
NetworkInfo ni = cm.getNetworkInfo(network);
Log.e("NETWORKINFO", ni.getType() + " " + ni.getExtraInfo());
if (ni.getType()== ConnectivityManager.TYPE_WIFI) {
Log.e("NETWORKINFO", "isWifi");
if (ni.isConnected()) {
Log.e("NETWORKINFO", "and is connected");
if (networkToUse == null) {
networkToUse = network;
}
}
}
if (ni.getType()== ConnectivityManager.TYPE_MOBILE) {
Log.e("NETWORKINFO", "HasMobile");
if (ni.isConnected()) {
Log.e("NETWORKINFO", "and is connected");
networkToUse = network;
}
}
}
It is here I kind of get stuck because I can't logically see a way of telling the app to use one of these networks when performing a HttpsURLConnection from URL.openLink();.
UPDATE:
I have just noticed that the mobile one disappears shortly after WiFi connects. There is a moment where I get both but not for long.
I have also tried this:
final ConnectivityManager connection_manager =
(ConnectivityManager)httpsClient.getCheckoutController().getCheckout().getCurrentActivity().getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder request = new NetworkRequest.Builder();
request.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
connection_manager.registerNetworkCallback(request.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
Log.e("NETWORKINFO", "FOUND A CELLULAR NETWORK " + connection_manager.getNetworkInfo(network));
}
});
request = new NetworkRequest.Builder();
request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
connection_manager.registerNetworkCallback(request.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
Log.e("NETWORKINFO", "FOUND A WIFI NETWORK "+connection_manager.getNetworkInfo(network));
}
});
but as with the "list" of networks" in previous try I only ever 1 callback, even if mobile data is on as well.
UPDATE;
Ok I seem to see mobile sometimes using above method. but it seems to create API level spaghetti hell. It sometimes also takes a very long time for the mobile callback to fire. I wonder if this is because it has to wake up the cellular modem and wait for it's handshake or something?
UPDATE;
I had another possible suggestion using Sockets (something I have little experience with..)
Does anyone know if it is possible to build a CELLULAR SSL connection socket to do https requests using HttpsURLConnection.getSocketFactory() and SSLSocket ?
Any info would be very welcome in this week long quest :D
UPDATE:
Found a good and categorical answer from someone at google:
How to stay connected through mobile network after WIFI is connected on Android?
However after implementation, i get a network callback for the mobile but when i open URL connection and perform a request it seems to get stuck for ages (about 4 minutes) before i get the response.
I have a Huawei 5.0.1 phone, which is the highest i have available. Obviously this is not good. However it is not tested on 5.1 galaxy S6 and works.. so could be the phone.
According to the Android documentation it is no longer working in Android version 5 and above.
This method was deprecated in API level 21.
Functionality has been removed as it no longer makes sense, with many more >than two networks - we'd need an array to express preference. Instead we >use dynamic network properties of the networks to describe their >precedence.
Found a good and categorical answer from someone at google: How to stay connected through mobile network after WIFI is connected on Android?
(Link is in edited info above)
However after implementation, i get a network callback for the mobile but when i open URL connection and perform a request it seems to get stuck for ages (about 4 minutes) before i get the response.
I have a Huawei 5.0.1 phone, which is the highest i have available. Obviously this is not good. However it is not tested on 5.1 galaxy S6 and works.. so could be the phone.
I need to detect the local IP address and subnet mask on the WiFi network, on an Android device (in order to proper calculate the UDP broadcast address strictly for the local subnet).
When the device is connected to an Access Point, the following is properly working:
// Only works when NOT tethering
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcp = wifi.getDhcpInfo();
if (dhcp == null)
throw new IOException("No DHCPInfo on WiFi side.");
foo(dhcp.ipAddress, dhcp.netmask);
But it doesn't work when it's the android device providing an Access Point though tethering: DhcpInfo seem to contain info set by the DCHP server when the Android device is a client of it, not when it's the Android device itself providing the DHCP service. When in tethering, the most promising solution I could find is:
// No way to get subnet mask
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
if (info == null)
throw new IOException("No connection info on WiFi side.");
foo(info.getIpAddress(), info.??? /* netmask*/ );
EDIT: WRONG, in my tests even this only works when NOT tethering. While tethering the IP is always 0.
But there's nothing like WifiInfo.getNetMask(), how can I get the subnet mask in that case? (This absence strikes me as really strange, since there's a plethora of other info there. Am I missing something obvious?)
Also, ideally I'd like a solution that doesn't need to discriminate if the Android device is providing tethering, and just get the local IP address and subnet mask, on the WiFi network, in any case, both when the Android device is providing or a client of an Access Point.
Even standard Java (i.e. not Android-specific) NetworkInterface.getNetworkInterfaces(), don't seem to have a way to get the subnet mask (apart from not allowing to discriminate which corresponds to the WiFi). What am I missing?
Best solution I found at the moment:
It baffles me how info/interface about tethering is so cumbersome/hidden to get, and yet not taken into consideration when you get info from WifiManager, or ConnectivityManager for the Wifi type: it all works only when NOT in tethering. I'm actually lost to that branch of investigation.
Best solution I found at the moment is using standard Java NetworkInterface.getNetworkInterfaces(), instead of any Android API.
Experimentally, Android seems smart enough to set to null broadcast for network interfaces to the external mobile network. It actually makes lot of sense since Android silently drop UDP broadcasts involving external mobile network.
// This works both in tethering and when connected to an Access Point
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements())
{
NetworkInterface networkInterface = interfaces.nextElement();
if (networkInterface.isLoopback())
continue; // Don't want to broadcast to the loopback interface
for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses())
{
InetAddress broadcast = interfaceAddress.getBroadcast();
// InetAddress ip = interfaceAddress.getAddress();
// interfaceAddress.getNetworkPrefixLength() is another way to express subnet mask
// Android seems smart enough to set to null broadcast to
// the external mobile network. It makes sense since Android
// silently drop UDP broadcasts involving external mobile network.
if (broadcast == null)
continue;
... // Use the broadcast
}
}
As for subnet mask, the result from getNetworkPrefixLength() can be coerced into a subnet mask. I used getBroadcast() directly since that was my ultimate goal.
No special permissions seem to be needed for this code (no ACCESS_WIFI_STATE nor NETWORK, just INTERNET).
Primary reference for the code snippet: http://enigma2eureka.blogspot.it/2009/08/finding-your-ip-v4-broadcast-address.html
I would like to connect to WiFi network programmatically.
Here is my code:
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(true);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + ssid + "\"";
config.preSharedKey = "\""+ key +"\"";
int netId = wifiManager.addNetwork(config);
wifiManager.saveConfiguration();
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
When I have wifi enabled on my phone, it works as expected, but the problem is, when wifi is disabled. In this case the only result is enabling wifi adapter, but not connecting to the network. It seems like enabling takes to long so it won't get connected. Another strange thing to me is that wifiManager.getConfiguredNetworks() returns null. Do you know how to fix that?
Thank you
It seems like enabling takes to long so it won't get connected.
Yes. This is because enabling of the network is done async, it happens in parallel, and doesn't occur immediately. Here are two possible solutions to your problem:
1) This is the easiest solution, but not the best. Loop as described by another user checking for the scan results to come in. However, you should add a sleep of some sort between every cycle of the loop. I.E. you want to wait for 1ms, so as to not eat up all the CPU resources. I am not sure how to do this in Android off the top of my head. There is another problem with this method. If u are in the GUI thread, you will block all GUI events this way, as you wait for the connection to be established.
2) This is the proper solution. You can register for broadcast events after the network connection has been established. Then you will get an event when it finishes. From this event you can finish performing whatever operations are needed.
Sorry for the rushed answer. I am not an Android pro, so I can't explain the details as to how to do this off the top of my head, but I thought I would at least point you in the right direction.
Actually if you connect WiFi more than one time it will solve your issue.
One other thing I see if my WiFi is enabled and I connect to a specific WiFi network then it's working.
One other thing when I switch from mobile network to a specific WiFi network then it gives an unstable connection ..for this problem I connect WiFi through a specific WiFi network and then forget the network after a 3 second delay I again connect. Then it works properly.
I use this code for connecting to WiFi.
And for delay and for got WiFi network I use this code... .......
{
wifi(SSID,PASS);
final Handler handler = new Handler();
handler.postDelayed(
new Runnable()
{
Override public void run() { forgot(); }
}, 3000);
final Handler handler1 = new Handler();
handler1.postDelayed(
new Runnable()
{
Override public void run() {wifi(SSID,PASS); }
}, 3000);
}