checking for Internet access? - android

I have a Service which downloads a list of files one by one. However, when the internet connection goes down or it is disconnected the downloading gets stuck. I did some research on internet connection checking and found some examples utilizing the ConnectivityManager class.
However, the ConnectivityManager class seems to be checking only if the phone is connected to a network using WIFI or MOBILE. It doesn't check whether there actually is internet access. So you could be connected to a network and still be unable to browse using HTTP.
Is there any way other than ConnectivityManager?
I'm using the following alternative:
public boolean isOnline(){
try{
URL url = new URL("http://www.google.com");
HttpURLConnection urlc = (HttpURLConnection)url.openConnection();
urlc.connect();
urlc.setConnectTimeout(1000 * 2);
if(urlc.getResponseCode() == 200){
return true;
}else{
}
}catch(Exception e){
return false;
}
return true;
}
The problem with this approach is that it's too slow. Since I'm checking inside a while loop (where the downloading of the file is taking place) the download speed is decreased due to the calls to isOnline():
while(..something){
if(!isOnline())
killService();
return;
}
Any other way of doing this or improving on that one
EDIT:
I was thinking of running a thread that checks if the download is stuck within a specified amount of time such as 20 secs or 30secs and if it is stop the service (meaning that the internet is down).
int downloadProgress;
Runnable checkNet = new Runnable(){
public void run(){
// code to check download using Timer - need help implementing this
}
};

Related

How to raise an Exception while inserting to firebase if the data is not synced to server immediately? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am inserting some values to Firebase. I want to mark the insert operation as failed if the data is not synced to server after a few second delay.
I tried onCompleteListener and onFailureListeneron Task, but onFailureListener doesn't fire if the device is offline then,onCompleteListener immediately fires after successful sync with firebase server (the device comes online).
I want to fire the onFailureListener immediately if the device is offline. How can I achieve that?
You can check availability of network before inserting values by using the following function
public static boolean isNetworkAvailable(Context context){
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
return info != null;
}
UPDATE
You can check if internet is working or not even if it's connected.
public static boolean hasActiveInternetConnection(Context context){
if(isNetworkAvailable(context)) {
try {
HttpURLConnection connection = (HttpURLConnection) (new URL("http://clients3.google.com/generate_204")).openConnection();
connection.setRequestProperty("User-Agent", "Test");
connection.setRequestProperty("Connection", "close");
connection.setReadTimeout(1500);
connection.connect();
return (connection.getResponseCode() == 204 && connection.getContentLength() == 0);
} catch (IOException e){
Log.e("ERROR", "Error checking internet connection");
}
} else Log.e("ERROR", "No network available");
return false;
}
you can create your own exception or you can create your own listenerwith interface according to your requirement. if there will be no connectivity with the internet then it will help you to call your desired code.

Connect to LAN and internet at same time?

Simply put, I want to use my Android device to connect to a LAN but not lose my internet capabilities.
I have dug through Google's guides on network connections, but the only possible solution I have found is Wi-Fi Direct. Unfortunately, I don't think this is possible because the LAN does not support the Wi-Fi Direct protocol.
Is there a way to a connect to a Wi-Fi access point with no internet and remain connected to either cellular or a previous Wi-Fi access point which has internet?
Re-configuring the LAN is something I can do, if that helps
Edit: I have seen this question, but it does not look like there is an answer and it was asked over 3 years ago
You need to build a HttpClient that knows to only use the WiFi.
Android will check internet connections to see if it can get onto the internet with them and ignore them if it can't. Even for local IP addresses, which can be a pain.
This is part of a Dagger module I wrote to create a correctly configured OkHttp client.
/**
* Find the WiFi Network object. If the WiFi is off this will return null. You might want to listen to the broadcasts from the WiFi system to retry when the WiFi is turned on.
*/
#Provides
public Network provideNetwork(ConnectivityManager connectivityManager) {
for (final Network network : connectivityManager.getAllNetworks()) {
final NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
final int networkType = networkInfo.getType();
if (networkType == ConnectivityManager.TYPE_WIFI) {
return network;
}
}
return null;
}
/**
* Create a HttpClient that will only use the network supplied. Changing this for the built in Apache HttpClient should be easy enough.
*/
#Provides
public OkHttpClient provideOkHttpClient(final Network network) {
if (network != null) {
final OkHttpClient httpClient = new OkHttpClient();
httpClient.setSocketFactory(network.getSocketFactory());
Internal.instance.setNetwork(httpClient, new com.squareup.okhttp.internal.Network() {
#Override
public InetAddress[] resolveInetAddresses(String host) throws UnknownHostException {
return network.getAllByName(host);
}
});
return httpClient;
}
return null;
}

Make Android simultaneously use WiFi to talk to a device and mobile data to talk to a server?

I'm developing an Android application which connects to an OBD2 device by Wifi and app can read Speed, RPM, Engine coolant temperature details etc. So wifi is used only for connecting with the OBD2 device(it doesn't have facility to connect with internet, only for communication with local clients). I also need an internet connection for web services. But after connecting my wifi I am not able to connect internet via my mobile data network in android.
The similar application is also developed for iOS. In iOS, I can use device over Wifi (Static Wifi setting) and Internet connection from my cellular network. It means configure my wifi with some static ip I am able to use mobile data network for Internet connection in iOS.
But in Android, If I use static wifi and check for Internet connection, it is not available.
How can I use Wifi and Internet connection both run parallel or any other way by configuring wifi settings in android ?
Firstly, the problem we may face here is that because there is no internet connection on WiFi network, HTTP data will not go through that connection. See Send request over WiFi (without connection) even if Mobile data is ON (with connection) on Android M for solution
However, I have faced issue where sometimes no HTTP request is successful. To solve this problem, we can use ConnectivityManager.requestNetwork() and Network.openConnection() to achieve this.
Make sure that Mobile data and WiFi network is enabled and Android Manifest has proper connections:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
Variables:
private ConnectivityManager.NetworkCallback mWifiNetworkCallback, mMobileNetworkCallback;
private Network mWifiNetwork, mMobileNetwork;
Get the connectivity manager:
final ConnectivityManager manager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Build network callbacks:
if(mWifiNetworkCallback == null){
//Init only once
mWifiNetworkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(final Network network) {
try {
//Save this network for later use
mWifiNetwork = network;
} catch (NullPointerException npe) {
npe.printStackTrace();
}
}
};
}
if(mMobileNetworkCallback == null){
//Init only once
mMobileNetworkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(final Network network) {
try {
//Save this network for later use
mMobileNetwork = network;
} catch (NullPointerException npe) {
npe.printStackTrace();
}
}
};
}
Request networks:
NetworkRequest.Builder wifiBuilder;
wifiBuilder = new NetworkRequest.Builder();
//set the transport type do WIFI
wifiBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
manager.requestNetwork(wifiBuilder.build(), mWifiNetworkCallback);
NetworkRequest.Builder mobileNwBuilder;
mobileNwBuilder = new NetworkRequest.Builder();
//set the transport type do Cellular
mobileNwBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
manager.requestNetwork(mobileNwBuilder.build(), mMobileNetworkCallback);
Make the appropriate request like this:
public void makeHTTPRequest(final String httpUrl, final String payloadJson, final int timeout,
final boolean hasHeaders, final String header1, final String header2) {
try {
URL url = new URL(httpUrl);
HttpURLConnection conn = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
conn = (HttpURLConnection) mWifiNetwork.openConnection(url);
//Or use mMobileNetwork, if and when required
//conn = (HttpURLConnection) mMobileNetwork.openConnection(url);
} else {
conn = (HttpURLConnection) url.openConnection();
}
conn.setRequestProperty("Content-Type", "application/json");
conn.setReadTimeout(timeout * 1000);
conn.setConnectTimeout(timeout * 1000);
conn.setDoInput(true);
conn.setDoOutput(true);
if(hasHeaders){
conn.setRequestProperty("header1", header1);
conn.setRequestProperty("header2", header2);
}
conn.setRequestMethod("PUT");
OutputStream os = conn.getOutputStream();
os.write(payloadJson.getBytes());
os.close();
final int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
final String statusMessage = conn.getResponseMessage();
//Log this
}
} catch (SocketException se){
se.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
}
Note:
These functions are avaialble from Android Lollipop and above. So, it is necessary to use Build.Version.SDK_INT at appropriate place, like this:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
You can request for a certain hostAddress that it must use that type of connectivity.
IF you use Hipri then it will take the mobile network.
But this can fail ! If it works, then ALL connections to that address will go over that type of connectivity.
You might have to activate it first.
int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
This can take a couple of seconds, since the hardware modules has to start up.
I've use this on several projects and works great.
On old device such as 2.2 it will react really unstable !
But I haven't found any problems on 4.0+

How to check internet access?

So, my question is how to check if I am receiving any data or not. The scenario is that I am connected to a wifi network such as Starbucks wifi (which user should first connect to the network and then accept the agreement before receiving any data.)
This code is not serving my purpose.
ConnectivityManager cm =
(ConnectivityManager) _mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
return true;
}
return false;
It returns true when I am connected to the network but I have not accepted the agreement yet. Thanks,
There's no way to know that, because that isn't something handled at an OS level- its handled at the router. THe OS only knows whether it has completed the handshake with the router and received an IP. Whether the router is going to throw him to a login screen is beyond the scope of the OS.
My app connects to a bunch of web services running on a web server on the cloud. So I need to make sure this connection is established before my app tries to do stuff. Instead of trying to check if internet is available, all I do is call one of my services. I have a simple one called TestService that just returns the word "success". So my app calls the service, receives the string "success" and knows that it is connected to the internet and successfully reaching my services. I don't have to worry about ConnectivityManager and NetworkInfo because this solution works well.
Of course, if my services themselves were to go down, then I would not know for sure if the device is connecting to the internet, I would only know for sure it is not reaching my service. However a) I make sure my services are redundant and have 99.9% uptime, and b) my app wouldn't be much use if not connecting to my services anyway. An alternative to just check for internet might be to try to connect to a public service from a reputable company that you know will alyways be online.
YOu can check this by trying to ping a website. For example
try {
Socket s = new Socket("www.google.com", 80);
return s.getLocalAddress().getHostAddress();
// network connection available
} catch (Exception e) {
// no network connection
}
I haven't tried it thogh.. But I think it should work.
If it doesn't work then you can try another thing. Send a httprequest to google and wait for response.
Heres what I have run in an asynctask:
public Boolean testServer(){
//stackoverflow.com/questions/9552743/proper-way-to-test-if-server-is-up-in-java
//stackoverflow.com/questions/9180072/android-check-connection-to-server
Boolean boolconnect = false;
try {
myUrl = new URL(UPLOAD_URL);
connection = myUrl.openConnection();
connection.setConnectTimeout(30*1000);
connection.connect();
Log.i(TAG, "FROM SERVER Connection made to: " + UPLOAD_URL);
boolconnect = true;
} catch (SocketException e) {
// TODO Auto-generated catch block
Log.i(TAG, "FROM SERVER socket exception:" + e);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
Log.i(TAG, "FROM SERVER Unknown host:" + e);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.i(TAG, "FROM SERVER IOexception:" + e);
}
return boolconnect;
}

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