Android: Check network and real internet connectivity - android

Below is the piece of Android code which works fine to check if network is connected or not.
public static boolean isNetworkAvailable(Context context)
{
ConnectivityManager mConnectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
return (mConnectivityManager != null && mConnectivityManager.getActiveNetworkInfo().isConnectedOrConnecting()) ? true : false;
}
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
But having an active network interface doesn't guarantee that a particular networked service is available.
A lot of time happens that we are connected to network but still not reachable to common internet network services, e.g. Google
Common scenario:
Android device connected to a Wi-Fi, which turns out to be a private
network. So isNetworkAvailable will return that network is connected, but could
not be connected to any other service
Some times the phone signal shows it is connected to service provider data plan. so network connectivity is true , but still cannot access Google/Yahoo.
One way is to check if "isNetworkAvailable" function returns TRUE, then run following code
HttpGet request = new HttpGet(url));
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 60000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
int timeoutSocket = 60000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
request.addHeader("Content-Type", "application/json");
HttpResponse response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null)
{
result = EntityUtils.toString(entity);
}
}
catch (SocketException e)
{
return "Socket Exceptiopn:" + e.toString();
}
catch (Exception e)
{
return "General Execption:" + e.toString();
}
But I think this is not an good way because it may consume lot of time
So is there any alternative efficient (in terms of time taken,speed) way ensure that we are connected to network as well as reachable to most common internet services ?

check this code... it worked for me :)
public static void isNetworkAvailable(final Handler handler, final int timeout) {
// ask fo message '0' (not connected) or '1' (connected) on 'handler'
// the answer must be send before before within the 'timeout' (in milliseconds)
new Thread() {
private boolean responded = false;
#Override
public void run() {
// set 'responded' to TRUE if is able to connect with google mobile (responds fast)
new Thread() {
#Override
public void run() {
HttpGet requestForTest = new HttpGet("http://m.google.com");
try {
new DefaultHttpClient().execute(requestForTest); // can last...
responded = true;
} catch (Exception e) {}
}
}.start();
try {
int waited = 0;
while(!responded && (waited < timeout)) {
sleep(100);
if(!responded ) {
waited += 100;
}
}
}
catch(InterruptedException e) {} // do nothing
finally {
if (!responded) { handler.sendEmptyMessage(0); }
else { handler.sendEmptyMessage(1); }
}
}
}.start();
}
Then, I define the handler:
Handler h = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what != 1) { // code if not connected
} else { // code if connected
}
}
};
and launch the test:
isNetworkAvailable(h,2000); // get the answser within 2000 ms
Code from Gilbou https://stackoverflow.com/a/5803489/2603719
I hope i can Help you

Issue #1:
Android device connected to a Wi-Fi, which turns out to be a private network.
So isNetworkAvailable will return that network is connected, but could not be connected to any other service.
Issue #2:
Sometimes the phone signal shows it is connected to service provider data plan. so network connectivity is true , but still cannot access google/yahoo.
I'm not sure about Issue #1 but I'm sure that following approach will solve Issue #2.
Ultimately, you will need to Monitor the change in Network connection,
Step 1:
Just register a BroadcastReceiver for following action
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
Step 2:
when you get callback on onReceive(Context context,Intent intent) method ,check for connectivity status.
i.e:
boolean isConnected = getIntent().getExtras().getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY);
//apart from EXTRA_NO_CONNECTIVITY, there are other parameters also which will be useful to monitor
Reference:
Examples:
Working Example of Step1,Step2: how-to-monitor-network-connectivity-in-android
Android-getting-notified-of-connectivity-changes
Github: Example for network-detect-notify
Android Docs:
Connectivity Monitoring
Connectivity Manager
I hope it will be helpful !!

Use This code to check internet connection, it check all the internet connection over device. And Make Sure you have added Internet Permission in menifest.
boolean flag=false;
ConnectivityManager connectivity = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null)
{
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null)
for (int i = 0; i < info.length; i++)
if (info[i].getState() == NetworkInfo.State.CONNECTED)
{
flag=true;
}
}
if(flag==true)
{
Log.e("TAG","Internet Is Connected");
}
else
{
Log.e("TAG","Internet Is Not Connected");
}

Related

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

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 :)

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()

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

Best Practice maintaining SocketConnection while network (Mobile -> Wifi) changes

I have an android app which connects to a server using a socket connection which is kept open while the app is active. If the phone gets inactive (lock screen) or the user presses the home button, the application closes the socket connection and reopens it if the app becomes visible again.
This Pattern works fine on most of the android phones we have (about 15 devices), but the Motorola Milestone, Defy, SE Xperia Arc and the LG Optimus One need very long (>10 secs) to detect if a Wifi is available after and connect to it. So to wait for the best network connection I use the following code (before opening the socket to the server):
public static boolean waitNetworkConnection(Context context, int retries) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = getNetworkToTest(cm);
if (ni == null || !ni.isConnected()) {
// sleep a short while to allow system to switch connecting networks.
Tools.sleep(1000);
int counter = 0;
while (counter < retries && (ni == null || (ni.isAvailable() &&
!ni.isConnected()))) {
Tools.sleep(500);
ni = getNetworkToTest(cm);
counter++;
}
}
return (cm.getActiveNetworkInfo() != null &&
cm.getActiveNetworkInfo().isConnected());
}
and this method (use by the one above) to get the connection to test, which prefers a Wifi-Connection if one (not necessary connected) is available:
private static NetworkInfo getNetworkToTest(ConnectivityManager cm) {
NetworkInfo[] nis = cm.getAllNetworkInfo();
NetworkInfo ni = cm.getActiveNetworkInfo();
for (int i = 0; i < nis.length; i++) {
if (nis[i].getType() == 1 /* Wifi */ && nis[i].isAvailable()) {
ni = nis[i];
return(ni);
}
}
return(ni);
}
This works fine for most of the devices, but for the mentioned ones this very often fails and this method tells me to use a mobile network connection and the device switches the connection type while I open a socket connection which leads to a SocketException with a very generic error message so I'm unable to determine if the socket connection is caused by this issue or because of some other network error.
Simply doing a retry doesn't fix this either, as this breaks the handling for the other network errors because it then takes very long to detect a socket timeout (because it is checked twice).
Has anyone else ran into this problem (very slowing connect to Wifi) and has a solution for this?
Yes, this is a tricky problem. One option would be to wait for the right network state broadcast using a BroadcastReceiver.
As described here: How to detect when WIFI Connection has been established in Android?
And here: How can I monitor the network connection status in Android?
There is a project called droidfu that has a HTTP wrapper, that gets round the wi-fi / 3g issue.
Here is a snippet from the code for the BetterHttpRequestBase class:
public BetterHttpResponse send() throws ConnectException {
BetterHttpRequestRetryHandler retryHandler = new BetterHttpRequestRetryHandler(maxRetries);
// tell HttpClient to user our own retry handler
httpClient.setHttpRequestRetryHandler(retryHandler);
HttpContext context = new BasicHttpContext();
// Grab a coffee now and lean back, I'm not good at explaining stuff. This code realizes
// a second retry layer on top of HttpClient. Rationale: HttpClient.execute sometimes craps
// out even *before* the HttpRequestRetryHandler set above is called, e.g. on a
// "Network unreachable" SocketException, which can happen when failing over from Wi-Fi to
// 3G or vice versa. Hence, we catch these exceptions, feed it through the same retry
// decision method *again*, and align the execution count along the way.
boolean retry = true;
IOException cause = null;
while (retry) {
try {
return httpClient.execute(request, this, context);
} catch (IOException e) {
cause = e;
retry = retryRequest(retryHandler, cause, context);
} catch (NullPointerException e) {
// there's a bug in HttpClient 4.0.x that on some occasions causes
// DefaultRequestExecutor to throw an NPE, see
// http://code.google.com/p/android/issues/detail?id=5255
cause = new IOException("NPE in HttpClient" + e.getMessage());
retry = retryRequest(retryHandler, cause, context);
} finally {
// if timeout was changed with this request using withTimeout(), reset it
if (oldTimeout != BetterHttp.getSocketTimeout()) {
BetterHttp.setSocketTimeout(oldTimeout);
}
}
}
// no retries left, crap out with exception
ConnectException ex = new ConnectException();
ex.initCause(cause);
throw ex;
}

Categories

Resources