Android - Check internet connection through an specific network (WIFI) - android

Basically, what I need is check if my Wifi connection has Internet access. The most effective way I know is with sock.connect() but I need to be sure that the connection will be done through the Wifi network and this is my main issue,
I was searching for a few days about this and there is not a good response to this.
There are a lot of solutions like How do I see if Wi-Fi is connected on Android? but they only check if the device is connected to a router. I need to know if the router as internet access
My best approximation was this:
Socket sock = new Socket();
ConnectivityManager
cm = (ConnectivityManager) mContext.getApplicationContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Network net = cm.getActiveNetwork();
net.bindSocket(sock);
}
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
But this has some limitations. The biggest limitation is that only works for API >= 23.
Also, if I am in China I think that hostname "8.8.8.8" will not work, right?
And finally, cm.getActiveNetwork() will only be the WIFI network if my device is connected to a wifi network, and this is not totally true because it is possible to modify the default active network.
What I need to know is:
Is there any working alternative for API >= 16?
Is there a good hostname that will work fine in China?
Any help will be appreciated,
Thanks in advance!

Yes you have to check with a remote server in order to be sure.
A common way would be like this:
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (isConnected) {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
if (ipAddr.isReachable(5000)) {
// Internet access OK!
}
} catch (Exception e) {
// Error handling...
}
}
Prefer domain names when calling getByName rather than IPs (https://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#getByName(java.lang.String))
If you want to avoid the connectivity manager you can register a BroadcastReceiver for WifiManager.NETWORK_STATE_CHANGED_ACTION events and you will know if you are connected to a WiFi (the current state is received almost immediately).
As regards the region issue I am out of ideas, maybe use NTP servers instead of google (much more innocent servers) or try Baidu!?

Finally, I came to a solution:
public interface Consumer {
void accept(Boolean internet);
}
class InternetCheck extends AsyncTask<Void, Void, Boolean> {
private Consumer mConsumer;
public InternetCheck(Consumer consumer) {
mConsumer = consumer;
execute();
}
#Override
protected Boolean doInBackground(Void... voids) {
Socket socket = null;
try {
WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
socket = new Socket();
socket.setKeepAlive(false);
String localIpAddress = getIpAddress(wifiManager);
socket.bind(new InetSocketAddress(localIpAddress, 0));
socket.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
return true;
}
return false;
} catch (IOException e) {
//unbind();
return false;
}finally {
if(socket != null && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
#Override
protected void onPostExecute(Boolean internet) {
mConsumer.accept(internet);
}
}
public static String getIpAddress(WifiManager wifiManager) {
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return String.format(Locale.getDefault(), "%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
}
I came to a solution after saw this question. With this, I obtained the IP address of my wifi connection and with this, I was able to bind the socket (socket.bind(...)) to the wifi connection and be check if my router had internet access.
I hope this solution helps somebody in the future :)

Related

Android Internet connectivity check better method

According to the Android developer site, Determining and Monitoring the Connectivity Status, we can check there is an active Internet connection. But this is not working if even only Wi-Fi is connected and not Internet available (it notifies there is an Internet connection).
Now I ping a website and check whether Internet connections are available or not. And this method needs some more processing time. Is there a better method for checking Internet connectivity than this to avoid the time delay in ping the address?
Try this:
It's really simple and fast:
public boolean isInternetAvailable(String address, int port, int timeoutMs) {
try {
Socket sock = new Socket();
SocketAddress sockaddr = new InetSocketAddress(address, port);
sock.connect(sockaddr, timeoutMs); // This will block no more than timeoutMs
sock.close();
return true;
} catch (IOException e) { return false; }
}
Then wherever you want to check just use this:
if (isInternetAvailable("8.8.8.8", 53, 1000)) {
// Internet available, do something
} else {
// Internet not available
}
The first problem you should make it clear is what do you mean by whether internet is available?
Not connected to wifi or cellular network;
Connected to a limited wifi: e.g. In a school network, if you connect to school wifi, you can access intranet directly. But you have to log in with school account to access extranet. In this case, if you ping extranet website, you may receive response because some intranet made auto redirect to login page;
Connected to unlimited wifi: you are free to access most websites;
The second problem is what do you want to achieve?
As far as I understand your description, you seems want to test the connection of network and remind user if it fails. So I recommend you just ping your server, which is always fine if you want to exchange data with it.
You wonder whether there is a better way to test connectivity, and the answer is no.
The current TCP/IP network is virtual circuit, packet-switched network, which means there is no a fixed 'path' for the data to run, i.e. not like a telephone, we have a real connection between two users, we can know the connection is lost immediately after circuit is broken. We have to send a packet to the destination, and find no response, then we know, we lose the connection (which is what ping -- ICMP protocol -- does).
In conclusion, we have no better way to test the connectivity to a host other than ping it, that is why heartbeat is used in service management.
Try the following:
public boolean checkOnlineState() {
ConnectivityManager CManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo NInfo = CManager.getActiveNetworkInfo();
if (NInfo != null && NInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
Don't forget the access:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Else:
if (InetAddress.getByName("www.google.com").isReachable(timeout))
{ }
else
{ }
On checking this issue it found that We cannot determine whether an active internet connection is there, by using the method specified in the developer site:
https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html
This will only check whther ther active connection of wifi.
So I found 2 methods which will check whether there is an active internet connection
1.Ping a website using below method
URL url = new URL(myUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
// 30 second time out.
httpURLConnection.setConnectTimeout(30000);
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
isAvailable = true;
}
2.Check the availability of Google DNS using socket
try {
Socket sock = new Socket();
SocketAddress sockaddr = new InetSocketAddress("8.8.8.8", 53);
sock.connect(sockaddr, 1000); // this will block no more than timeoutMs
sock.close();
return true;
}
The second method is little faster than 2nd method (Which suits for my requirement)
Thanks all for the answers and support.
I wanted to comment, but not enough reputation :/
Anyways, an issue with the accepted answer is it doesn't catch a SocketTimeoutException, which I've seen in the wild (Android) that causes crashes.
public boolean isInternetAvailable(String address, int port, int timeoutMs) {
try {
Socket sock = new Socket();
SocketAddress sockaddr = new InetSocketAddress(address, port);
sock.connect(sockaddr, timeoutMs); // This will block no more than timeoutMs
sock.close();
return true;
} catch (IOException e) {
return false;
} catch (SocketTimeoutException e) {
return false;
}
}
//***To verify internet access
public static Boolean isOnline(){
boolean isAvailable = false;
try {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
URL url = new URL("https://stackoverflow.com/");
HttpURLConnection httpURLConnection = null;
httpURLConnection = (HttpURLConnection) url.openConnection();
// 2 second time out.
httpURLConnection.setConnectTimeout(2000);
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
isAvailable = true;
} else {
isAvailable = false;
}
} catch (IOException e) {
e.printStackTrace();
isAvailable = false;
}
if (isAvailable){
return true;
}else {
return false;
}
}
ConnectivityManager will not be able to tell you if you have active connection on WIFI.
The only option to check if we have active Internet connection is to ping the URL. But you don't need to do that with every HTTP request you made from your App.
What you can do:
Use below code to check connectivity
private boolean checkInternetConnection()
{
ConnectivityManager cm = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
// test for connection
if (cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isAvailable()
&& cm.getActiveNetworkInfo().isConnected())
{
return true;
}
else
{
return false;
}
}
And while making rest call using HTTP client set timeout like 10 seconds. If you don't get response in 10 seconds means you donot have active internet connection and exception will be thrown (Mostly you get response within 10 seconds). No need to check active connection by pinging everytime (if you are not making Chat or VOIP app)
Maybe this can help you:
private boolean checkInternetConnection() {
ConnectivityManager cm = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
// Test for connection
if (cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isAvailable()
&& cm.getActiveNetworkInfo().isConnected()) {
return true;
}
else {
return false;
}
}
Try this method, this will help you:
public static boolean isNetworkConnected(Context context)
{
ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null)
{
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected())
{
return true;
}
}
return false;
}
You can try this for check Internet connectivity:
/**
* Check Connectivity of network.
*/
public static boolean isOnline(Context context) {
try {
if (context == null)
return false;
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm != null) {
if (cm.getActiveNetworkInfo() != null) {
return cm.getActiveNetworkInfo().isConnected();
} else {
return false;
}
} else {
return false;
}
}
catch (Exception e) {
Log.error("Exception", e);
return false;
}
}
In your activity you call this function like this.
if(YourClass.isOnline(context))
{
// Do your stuff here.
}
else
{
// Show alert, no Internet connection.
}
Don't forget to add ACCESS_NETWORK_STATE PERMISSION:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Try this if you want to just ping the URL:
public static boolean isPingAvailable(String myUrl) {
boolean isAvailable = false;
try {
URL url = new URL(myUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
// 30 second time out.
httpURLConnection.setConnectTimeout(30000);
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
isAvailable = true;
}
} catch (Exception e) {
isAvailable = false;
e.printStackTrace();
}
return isAvailable;
}

Android fast switch to known wifi network

I am trying to write some code that will disconnect current wifi network (if any) and reconnect to a specific wifi network with known SSID.
I have been following the code used here; How do I connect to a specific Wi-Fi network in Android programmatically?
which works but the connection takes several seconds, upto about 10 seconds.
Specifically, I use the code as follows;
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiConfiguration config;
I obtain the config, whether by creating a new one and setting the SSID and KeyMgmt to NONE and then adding it;
wifiManager.add(config);
or by getting a config that already exists;
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for( WifiConfiguration i : list ) {
if(i.SSID != null && i.SSID.equals("\"" + networkSSID + "\"")) {
config = i;
break;
}
}
Then I call;
wifiManager.disconnect();
wifiManager.enableNetwork(i.networkId, true);
wifiManager.reconnect();
I have a broadcast received checking the wifi state and when i get a connected for my correct SSID i can continue, however, this process takes upto 10 seconds, how can i set up the config or wifimanager to connect to this much quicker?
Thanks
I think this code is help to you..
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.network_test);
context = this;
mUpdate = new UpdateTimeTask();
mHandler = new Handler();
mHandler.post(mUpdate);
}
public Boolean isNetAvailable(Context con) {
try{
connectivityManager = (ConnectivityManager) con.getSystemService(Context.CONNECTIVITY_SERVICE);
wifiInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
mobileInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if(wifiInfo.isConnected() || mobileInfo.isConnected()) {
return true;
}
}catch(Exception e){
e.printStackTrace();
}
return false;
}
private class UpdateTimeTask implements Runnable{
public void run() {
boolean net = isNetAvailable(context);
if(net != false) {
Toast.makeText(getBaseContext(), "network Available", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(getBaseContext(), "network Not Available", Toast.LENGTH_SHORT).show();
}
mHandler.postDelayed(mUpdate, 30000);
}
}
}
Have you tried adding startScan() to your routine to force an immediate rescan for available networks at the time you wish to connect? I imagine forcing that command repeatedly with an alarmManager or something similar is possible, but I would think that has the potential to have an expensive performance/battery impact. If you have a specific trigger, it could be a solution.
See here: http://developer.android.com/reference/android/net/wifi/WifiManager.html#startScan()

How to detect WiFi tethering state

I want to know how to detect state of WiFi tethering. I've seen an article: Android 2.3 wifi hotspot API But it doesn't work! It returns always WIFI_AP_STATE_DISABLED = 1. It doesn't depend on real state of WiFi tethering.
Using reflection:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Method[] wmMethods = wifi.getClass().getDeclaredMethods();
for (Method method: wmMethods) {
if (method.getName().equals("isWifiApEnabled")) {
try {
boolean isWifiAPenabled = method.invoke(wifi);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
As you can see here
In addition to the reflexion, to get the Wifi tethering status update, you can listen to this broadcast Action :
IntentFilter filter = new IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED");
To get all tethering option update :
IntentFilter filter = new IntentFilter("android.net.conn.TETHER_STATE_CHANGED");
Those actions are hidden inside the Android source code
First, you need to get WifiManager:
Context context = ...
final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Then:
public static boolean isSharingWiFi(final WifiManager manager)
{
try
{
final Method method = manager.getClass().getDeclaredMethod("isWifiApEnabled");
method.setAccessible(true); //in the case of visibility change in future APIs
return (Boolean) method.invoke(manager);
}
catch (final Throwable ignored)
{
}
return false;
}
Also you need to request a permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Here is the Xamarin C# version if anyone is looking:
static Method isWifiApEnabledMethod;
public static bool IsWifiApEnabled ()
{
var wifiManager = WifiManager.FromContext (Application.Context);
if (isWifiApEnabledMethod == null)
{
try
{
isWifiApEnabledMethod = wifiManager.Class.GetDeclaredMethod ("isWifiApEnabled");
isWifiApEnabledMethod.Accessible = true; //in the case of visibility change in future APIs
}
catch (NoSuchMethodException e)
{
Debug.WriteLine ("Can't get method by reflection" + e);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't get method by reflection" + ex);
}
}
if (isWifiApEnabledMethod != null)
{
try
{
return (bool)isWifiApEnabledMethod.Invoke (wifiManager);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't invoke by reflection" + ex);
}
}
return false;
}
(without using reflection since they say google is restricting it)
I'm writting this answer 10 years later. also I don't know if this can be considered a good aproach or not but I first get the Wlan network interface IPs
and if there is no address I assume that it tethering isn't enabled. if there is an address, I check using the connectivity manger whether WI-FI is connected to a network or not. if there is an IP for the Wlan network interface but it isn't connected to a network, I assume tethering is enabled.
you probably would need to add this line to your manifest file
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
code to get the ip of an inteface (this only gets the IPv4, you can modify it to get the IPv6 or both if you want)
// method used to retrieve Wlan ip addresses IPv4 of the device.
public static String IpAddresses() throws NoAddressFoundException, SocketException {
Enumeration<NetworkInterface> Nics = NetworkInterface.getNetworkInterfaces();
while (Nics.hasMoreElements()) {
NetworkInterface NIC = Nics.nextElement();
if (NIC.isUp() && !NIC.isLoopback() && NIC.getName().contains("wlan")) {
Enumeration<InetAddress> Addresses = NIC.getInetAddresses();
while (Addresses.hasMoreElements()) {
InetAddress WlanAddress = Addresses.nextElement();
if (WlanAddress instanceof Inet4Address)
return WlanAddress.getHostAddress();
}
}
}
throw new NoAddressFoundException("No suitable wifi address found");
}
then if there is an address i check if wifi is connected by this method:
//method to check if the device is connected to a Wi-Fi network; it doesn't matter if network has access to internet
public static boolean isWifiConnected(Context context) {
ConnectivityManager ConMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo WifiInfo = ConMan.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return WifiInfo.isConnected();
}
NOTE: the "NoAddressFoundException" is a custom exception in my app if anyone is wondering. it won't exist in your case.
Reflection is a poor way to achieve this.
We can inspect the DhcpInfo to determine if the device is allocating addresses (mobile hotspot) or is being allocated by another DHCP server.
Here is a kotlin function that will determine if a device is a mobile hotspot, it has not been widely tested so YMMV.
fun isMobileHotspot(manager: WifiManager): Boolean {
val info = manager.dhcpInfo
return (
info.ipAddress == 0
&& info.netmask == 0
&& info.gateway == 0
&& info.serverAddress == 16885952) // 192.168.1.1
}

Force Android to use 3G when on local area wifi without net access

I have a wifi LAN setup which does not have internet access. Just various other local wifi devices connected to it. The DHCP is configured to not return a gateway or dns server. Only an IP and netmask.
When I connect my android to this wifi AP it connects fine, but all internet connectivity on the phone stops working.
I would expect that since the wifi has no gateway setting that android should realize the internet can't go through that connection and should instead be routed through the 3G connection which is at 5 bars.
I've tried setting a static IP on the android phone as well, but this did not help.
The main reason for this setup is so that the android device can transfer data on this remote network to an internet based server since it can connect to the local devices without issue. However the 3G side is broken once the wifi is setup.
Any thoughts on how to work around this issue?
After a bit of coding and testing I have merged Squonk and this solution. This is the class I have created:
package it.helian.exampleprj.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;
public class NetworkUtils {
private static final String TAG_LOG = "ExamplePrj";
Context context;
WifiManager wifiMan = null;
WifiManager.WifiLock wifiLock = null;
public NetworkUtils(Context context) {
super();
this.context = context;
}
/**
* Enable mobile connection for a specific address
* #param context a Context (application or activity)
* #param address the address to enable
* #return true for success, else false
*/
public boolean forceMobileConnectionForAddress(Context context, String address) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null == connectivityManager) {
Log.d(TAG_LOG, "ConnectivityManager is null, cannot try to force a mobile connection");
return false;
}
//check if mobile connection is available and connected
State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.d(TAG_LOG, "TYPE_MOBILE_HIPRI network state: " + state);
if (0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING)) {
return true;
}
//activate mobile connection in addition to other connection already activated
int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
Log.d(TAG_LOG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt);
//-1 means errors
// 0 means already enabled
// 1 means enabled
// other values can be returned, because this method is vendor specific
if (-1 == resultInt) {
Log.e(TAG_LOG, "Wrong result of startUsingNetworkFeature, maybe problems");
return false;
}
if (0 == resultInt) {
Log.d(TAG_LOG, "No need to perform additional network settings");
return true;
}
//find the host name to route
String hostName = extractAddressFromUrl(address);
Log.d(TAG_LOG, "Source address: " + address);
Log.d(TAG_LOG, "Destination host address to route: " + hostName);
if (TextUtils.isEmpty(hostName)) hostName = address;
//create a route for the specified address
int hostAddress = lookupHost(hostName);
if (-1 == hostAddress) {
Log.e(TAG_LOG, "Wrong host address transformation, result was -1");
return false;
}
//wait some time needed to connection manager for waking up
try {
for (int counter=0; counter<30; counter++) {
State checkState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
if (0 == checkState.compareTo(State.CONNECTED))
break;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
//nothing to do
}
boolean resultBool = connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
Log.d(TAG_LOG, "requestRouteToHost result: " + resultBool);
if (!resultBool)
Log.e(TAG_LOG, "Wrong requestRouteToHost result: expected true, but was false");
state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.d(TAG_LOG, "TYPE_MOBILE_HIPRI network state after routing: " + state);
return resultBool;
}
/**
* This method extracts from address the hostname
* #param url eg. http://some.where.com:8080/sync
* #return some.where.com
*/
public String extractAddressFromUrl(String url) {
String urlToProcess = null;
//find protocol
int protocolEndIndex = url.indexOf("://");
if(protocolEndIndex>0) {
urlToProcess = url.substring(protocolEndIndex + 3);
} else {
urlToProcess = url;
}
// If we have port number in the address we strip everything
// after the port number
int pos = urlToProcess.indexOf(':');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have resource location in the address then we strip
// everything after the '/'
pos = urlToProcess.indexOf('/');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have ? in the address then we strip
// everything after the '?'
pos = urlToProcess.indexOf('?');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
return urlToProcess;
}
/**
* Transform host name in int value used by {#link ConnectivityManager.requestRouteToHost}
* method
*
* #param hostname
* #return -1 if the host doesn't exists, elsewhere its translation
* to an integer
*/
private int lookupHost(String hostname) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return -1;
}
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24)
| ((addrBytes[2] & 0xff) << 16)
| ((addrBytes[1] & 0xff) << 8 )
| (addrBytes[0] & 0xff);
return addr;
}
#SuppressWarnings("unused")
private int lookupHost2(String hostname) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return -1;
}
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24)
| ((addrBytes[2] & 0xff) << 16)
| ((addrBytes[1] & 0xff) << 8 )
| (addrBytes[0] & 0xff);
return addr;
}
public Boolean disableWifi() {
wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifiMan != null) {
wifiLock = wifiMan.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "HelianRCAWifiLock");
}
return wifiMan.setWifiEnabled(false);
}
public Boolean enableWifi() {
Boolean success = false;
if (wifiLock != null && wifiLock.isHeld())
wifiLock.release();
if (wifiMan != null)
success = wifiMan.setWifiEnabled(true);
return success;
}
}
This is the usage:
USAGE CODE
boolean mobileRoutingEnabled = checkMobileInternetRouting();
if(!mobileRoutingEnabled) {
networkUtils.disableWifi();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
networkUtils.forceMobileConnectionForAddress(context, RCA_URL);
if(!mobileRoutingEnabled) {
networkUtils.enableWifi();
}
// This second check is for testing purpose
checkMobileInternetRouting();
return callWebService(RCA_COMPLETE_URL, _plate);
where checkMobileInternetRouting is:
private boolean checkMobileInternetRouting() {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
State state = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
return 0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING);
}
USAGE PROCEDURE
Check if the routing to the host is enabled
If yes go with the communication regardless the wifi is connected or not and execute only points 6 (the point 4 will only check that routing is already enable without executing any rilevant action). Otherwise temporary disables the wifi.
Thread sleep of about 3 seconds for letting the 3g connection comes back
Set the 3g routing to the given url
Enable back the wifi
Now the given url can be called even with a wifi connection without net acces
CONCLUSIONS
This is a bit hacky but works properly. The only problem is that this routing has got a timeout of few seconds (like 20-30) that forces you to execute the entire above procedure once more. Setting this timeout to a higher value would be very good.
Google added some useful methods in Android SDK 21 for this purpose.
You can create NetworkRequest:
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
And then you can request such network using ConnectivityManager. For example, you want to be sure that all HTTP requests will be passed through the network with internet access. You can build your Retrofit API in this way:
ApiConfig apiConfig;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
apiConfig = new Retrofit.Builder()
.baseUrl("https://api.imatrix.io/")
.client(new OkHttpClient.Builder()
.socketFactory(network.getSocketFactory())
.build())
.build()
.create(ApiConfig.class);
}
#Override
public void onLost(Network network) {
apiConfig = null;
}
});
Please, mind the thread-safety when you're using such snippet of code.
In addition, I suggest check ConnectivityManager#bindProcessToNetwork and this blog.
ConnectivityManager.NetworkCallback is an empty class and it has several methods.
From code, when you detect there is no connectivity, you could switch off WiFi...
As for a setting, there is none (no good way to check if there really is connectivity universally and reliably). But some phones do just what you describe automatically, like for example my LG P-970.
(Note: Android disconnects from mobile networks when it connects to a WiFi, so there is no way to still be connected to a WiFi but route internet access through mobile, even though Linux can do it (with the ip route ... suite of tools))
I can't guarantee this will work as it's something I only experimented with some time ago. I had a similar need to use 3G (or other mobile network) when the wifi-connected network had no route to the outside world.
The following code should drop the wifi connection in order to allow the mobile network to come in to play. You'll need to do various tests along the way and re-establish the wifi connection again afterwards...
WifiManager wifiMan = null;
WifiManager.WifiLock wifiLock = null;
private Boolean disableWifi() {
wifiMan = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wifiMan != null) {
wifiLock = wifiMan.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "MyWifiLock");
}
return wifiMan.setWifiEnabled(false);
}
private Boolean enableWifi() {
Boolean success;
if (wifiLock != null)
wifiLock.release();
if (wifiMan != null)
success = wifiMan.setWifiEnabled(true);
return success;
}
you don't need to code anything. i found an app that do exactly this thing. you can configure to disconnect automatically from the wifi if there is no internet from this connection.
https://play.google.com/store/apps/details?id=com.nLabs.internetconnectivity&hl=en

Android socket programming without WIFi connection

I have written an app to start my server at home remotely. The app works without problems in the emulator and also on my smartphone (HTC desire, Android 2.2) when WiFi is enabled.
However it does not work when WiFi is disabled.
Before restarting I first check if it's already running. To do this I use sockets and I first connect to a dyndns address. After that I try to connect to my ip-box where I can switch on my computer by sending commands via a socket.
When the connection to that socket fails I know the server is not running.
The relevant code is:
socket = new Socket();
socket.connect(new InetSocketAddress(serverName, port), 10000);
status = socket.isConnected() == true;
socket.close();
If there's an exception (SocketException) I know that the server is not running.
This approach works perfectly when I have switched WiFi on. However if WiFi's not switched on then the connect always says it's ok, even if it could not establish a connection since the server is not available.
Is there a way to check if the the connection is really established, even if WiFi is disabled?
Any suggestions welcome!
Thanks,
Rudi
Try to open your socket like this :
public boolean connect(String ip, int port) {
try {
this.clientSocket = new Socket(ip, port);
clientSocket.setSoTimeout(timeout);
this.outToServer = new DataOutputStream(clientSocket
.getOutputStream());
this.inFromServer = clientSocket.getInputStream();
isconnected = true;
} catch (IOException e) {
Log.e("TCPclient", "connection failed on " + ip + ":" + port);
isconnected = false;
return isconnected;
}
Log.e("TCPclient", "connection to " + ip + " sucessfull");
return isconnected;
}
If connection is not successful , it will generate an IOException (work when wifi enabled and no server , and when wifi is not enabled(HTC desire 2.3)).
This code is not really correct ,it's just a short version
EDIT
Try to check wfi state like this (it is not practical but it should work)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (ni.isConnected()) {
Toast.makeText(this,"Wifi enabled", Toast.LENGTH_LONG).show();
Log.d("WiFiStateTestActivity", "WiFi!");
} else {
Toast.makeText(this,"Wifi not enabled", Toast.LENGTH_LONG).show();
Log.d("WiFiStateTestActivity", "not WiFi!");
}
}
Don't forget to set the permission in manifest.xml to allow you app to open a socket.

Categories

Resources