How to check the connection status in Android avoiding StrictMode - android

I created a function that returns a boolean based on the presence of an internet connection, this function it is called different times from different java classes.
The only way that I find to use it is to use the StrictMode.setThreadPolicy (i know that it's not a good practice).
How I can solve my problem ?
public boolean checkConnection() {
boolean response = false;
try {
//StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
URL url = new URL(databaseManagement.getSettingValue("urlCheckConnection", context));
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(3000);
httpURLConnection.setReadTimeout(3000);
httpURLConnection.connect();
response = httpURLConnection.getResponseCode() == 200;
httpURLConnection.disconnect();
httpURLConnection.getInputStream().close();
}
}
} catch (Exception e) {
response = false;
wil.WriteFile("checkConnection - Exception: " + e.getMessage(), context);
}
return response;
}

It is possible that this method will block the calling thread for up to 3 seconds. Generally speaking you should not do network or file I/O on the main (UI) thread because that can cause the app to appear non-responsive (and Android will generate an ANR exception in that case). There are various alternatives you could use, depending on your situation. Here are two:
Don't ever call this method on the main (UI) thread. Always perform your Internet connectivity checks on background threads
Make the method asynchronous and provide a callback interface. The caller would then call the method (which will return immediately after launching the connectivity check on a background thread) and then the callback would be triggered when the connectivity check is completed. If this must be done on the main (UI) thread, you should show a progress dialog or similar while you are executing the connectivity check so that the user doesn't think the app is stuck.

Your question is a bit unclear.
Here is how internet connection is checked in my app:
private fun isConnected(): Boolean {
val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo: NetworkInfo? = connMgr.activeNetworkInfo
return networkInfo?.isConnected == true
}
It still should be tested on the latest Android APIs as there are known changes, e.g. lack of options to emulate network on\off programmatically from tests since some specific version of Android API.
On another hand StrictMode is used to force you and all the rest software developers to write correct programs. Your code which operates with network and data storages should not be executed in the main thread (which is done by default), it should be run in the separate thread. StrictMode tracks this and notify you about violation of this practice either by warning message in logs or by crashing your app (I prefer second one as it is more obvious).
However sometimes you depend on 3rd party library which violates this good practices and keeping yourStrictMode enabled prevents you from using this library.
In any cases StrictMode is usually enabled only for development stage like this:
if (BuildConfig.DEBUG) {
// TODO enable StrictMode policies
}

Related

How know when a device is connecting to WiFi/Mobile/Internet?

I have button that needs to get some data from a back-end server. The button is disabled while the device is not connected to WiFi/Mobile/Internet. The problem is that when pressing the WiFi button it takes some time till it actually connects (2-3 seconds). How to know when the devices is connecting so I can display a ProgressBar in that periode of time? Thanks
plenty of methods in THIS SO question. In short you should use BroadcastReceiver with IntentFilter with ConnectivityManager.CONNECTIVITY_ACTION action. Check out NetworkInfo.State DOC and pick appriopiate for reporting (create own listener with needed callbacks)
if you can afford only newer APIs then you can use NetworkCallback, in DOC you can see all methods, use appriopiate. But I doubt sadly due to Android fragmentation, still better way is mentioned first one.
Also remember that since Android N this broadcast won't fire when was declared in manifest, use Java examples and (un)register with Activity lifecycle
fun isInternetOncheck(context: Context): Boolean {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = cm.activeNetworkInfo
return networkInfo != null && networkInfo.isConnectedOrConnecting
}
if (!NetworkCaller.isInternetOncheck(context!!)) {
println("no internet connection")
} else {
fetchDataFromServer()
}
fetchDataFromServer(){
showProgressbar()
......
......
//code for fetching data
......
......
hideProgressbar()
}

How to access Muliple network interface in android (WiFi and mobile data)

Ok, so my question is may be off topic but i really did not found any useful content to use both network interface simulnasily in my application is simple image uplaod to server using both open network for better speed.here can we use both network by programing in java?
i found this code snippet but its return only connection status.
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
Network etherNetwork = null;
for (Network network : connectivityManager.getAllNetworks()) {
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
if (networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
etherNetwork = network;
}
}
Network boundNetwork = connectivityManager.getBoundNetworkForProcess();
if (boundNetwork != null) {
NetworkInfo boundNetworkInfo = connectivityManager.getNetworkInfo(boundNetwork);
if (boundNetworkInfo.getType() != ConnectivityManager.TYPE_ETHERNET) {
if (etherNetwork != null) {
connectivityManager.bindProcessToNetwork(etherNetwork);
}
}
}
As far as I know it is not possible.
Nevertheless:
MPTCP exists, and you may find roms that support it, but it is not out of the box.
Speedify claims to be able to do it, but since it doesn't require root, I assume it's just a clever use of a VPN connection and a sort of load balancing trick between connection types.
Basically, in order to really have the 2 connection types active, you would need to modify the kernel so that both network interfaces can be used at the same time.
You can follow the approach I'm using in this app if it helps
https://github.com/yschimke/OkHttpAndroidApp/
You can bind each socket yourself to a specific network interface before you connect. Each individual socket needs to be on a single network, but you can use both.
https://github.com/yschimke/OkHttpAndroidApp/blob/master/android/app/src/main/java/com/okhttpandroidapp/factory/AndroidNetworkManager.kt#L123

Background IntentService Force Closes because device is connected to WiFi but is not authenticated

I am currently using a background IntentService in my Android App to connect to my server to fetch some data and update the App only if connection is available. If the device is connected to mobile network data or a authenticated wifi connection or open wifi connection it works perfectly.
The problem occurs when the device does not have access to Mobile Data Network and is connected to a Wifi source that requires authentication and the connection is not authenticated yet, the service force closes since it is unable to transfer any data through the unauthenticated connection.
My check to the entry point to connect to the server and do the background task is the check below.
ConnectivityManager conMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if((conMgr.getActiveNetworkInfo() != null &&
conMgr.getActiveNetworkInfo().isAvailable() &&
conMgr.getActiveNetworkInfo().isConnected()) || WifiConnected() == true){
//do background processing
}
The WifiConnected() method looks like this below.
private boolean WifiConnected() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
SupplicantState supState;
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
supState = wifiInfo.getSupplicantState();
return (networkInfo != null && networkInfo.isConnected() && supState.toString().contentEquals("COMPLETED"));
}
So basically what I am checking before doing the background task is whether the device has active network connectivity and is connected or if the connection is wifi, if that connection is authentication complete so that data transfer is possible.
This doesn't seem to work and fails too making the service still force close.
What is the right way to do this check for network connectivity when wifi authentication is involved and then do the background processing?
Thanks.
A good example of this problem is when you are in any starbucks nationwide your android device will automatically connect to attwifi and the wifi status changes to connected because i check isConnected returns true but you will notice that the attwifi at starbucks will not let you transfer any data until you pseudo sign in by navigating to a browser page and accepting their terms of usage and agreement
Method conMgr.getActiveNetworkInfo() calls into ConnectivityService and the result of this call can be null. In the statement (conMgr.getActiveNetworkInfo() != null && conMgr.getActiveNetworkInfo().isAvailable() && conMgr.getActiveNetworkInfo().isConnected()) you call three times. I suspect there can be NPE here, as one of these calls can return null if network changes from 3g to WiFi at that time. What if you get NetworkInfo instance first, and them call isAvailable() and isConnected() on it (similar to how you did it in WifiConnected())?
You could move the connectivity check in your activity (or wherever else you have the context) and start the service from there.
Thus you won't have the force close constraint of the intentService and it should work fine.
Edit:
Ok got it! Here's what you can do to be sure that the user has access to Internet:
private boolean hasInternetAccess() {
boolean hasInternetAccess = false;
try {
//I set google but you can try anything "reliable"...
//isReachable(1) the timeout in seconds
hasInternetAccess = InetAddress.getByName("www.google.com").isReachable(1);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return hasInternetAccess;
}
So your check becomes:
If(WifiConnected() && hasInternetAccess()){
//Do background Work...
}
This is does some sort of ping to ensure the user has internet.
Don't forget that this method needs to be executed in a separate thread or it'll throw a NetworkOnMainthreadException. Here you're safe since you are in an IntentService that has its own thread. But I precise for the ones that might see this thread. By the way I suggest you to change the title of the this thread since the actual problem is not really related to the service but the access to internet.
Here's the reference: Test Internet Connection Android
I hope this helps.
or you can write a receiver for Connectivity change. It would be the best in your case.
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />

check internet activity

I done an app that uses a webview to listen audio from internet. Now, I add a method (isOnline) to check if there's (or not) an internet activity. I've a doubt: I can use this method running always in OnCreate?
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
If you block the execution of the onCreate() aka the UI thread will be blocked and your app will throw ANR (Application Not Responding) exception.
However your method doesn't tell you that you are connected to the interned, it just tell you that your device isConnectedOrConnecting to nearest router. What is after that you don't know.
For check real internet connection you need to make a request to a server, such as www.google.com and if you get the answer then you have the connection live.
And another thing, you don't need to monitor your connection continuously. In the most simple manner you can do this in a background thread from time to time, but only if you cannot get events from your radio player.

Android - Detect if Wifi Requires Browser Login

My university has an open wifi access point, however it requires you to enter your e-mail before it allows you to use the web. My problem is that the Wifi is stupid in that it seems to drop my connection and force me to enter my e-mail again every 10 minutes.
I wanted to create my own app that I can use to automatically do this step for me, but I cannot seem to find any documentation for a nice and easy way to detect if a Wifi access point has a browser login page. Is there a way in Android to get this information, or is it just to see if my connection to something is always redirected to 1.1.1.1?
See the "Handling Network Sign-On" section of the HttpUrlConnection documentation:
Some Wi-Fi networks block Internet access until the user clicks through a sign-on page. Such sign-on pages are typically presented by using HTTP redirects. You can use getURL() to test if your connection has been unexpectedly redirected. This check is not valid until after the response headers have been received, which you can trigger by calling getHeaderFields() or getInputStream().
They have a snippet of sample code there. Whether this will cover your particular WiFi AP, I can't say, but it is worth a shot.
Ping an external IP address (like google.com) to see if it responds.
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("ping -c 1 " + "google.com");
proc.waitFor();
int exitCode = proc.exitValue();
if(exitCode == 0) {
Log.d("Ping", "Ping successful!";
} else {
Log.d("Ping", "Ping unsuccessful.");
}
}
catch (IOException e) {}
catch (InterruptedException e) {}
The only downside is this would also indicate that a web login is required when there is simply no internet connectivity on the WiFi access point.
#CommonsWare I believe this is a better answer than opening a UrlConnection and checking the host, since the host doesn't always change even when displaying the redirect page. For example, I tested on a Belkin router and it leaves whatever you typed in the browser as is, but still displays its own page. urlConnection.getUrl().getHost() returns what it should because of this.
I think #FlyWheel is on the right path, but I would use http://clients1.google.com/generate_204 and if you don't get a 204, you know you are behind a captive portal. You can run this in a loop until you do get a 204 in which case you know you are not behind a captive portal anymore.
#FlyWheel wrote: The only downside is this would also indicate that a web login is required when there is simply no internet connectivity on the WiFi access point.
You can solve this by registering a receiver to android.net.conn.CONNECTIVITY_CHANGE. You can check if Wifi is ON and is connected by looking at the Supplicant State of the connection.
Here is a snippet, but I didn't run it:
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wm.getConnectionInfo();
SupplicantState suppState = wifiInfo.getSupplicantState();
if (wm.isWifiEnabled()) {
if (suppState == SupplicantState.COMPLETED){
// TODO - while loop checking generate_204 (FlyWheels code)Using intent service.
}
}
I can't remember if the SupplicantState is COMPLETED or ASSOCIATED, you will have to check that. You should use an IntentService for checking the generate_204 since broadcast receivers have a short lifetime.
I used the following code using google's 204 endpoint.
private boolean networkAvailable() {
ConnectivityManager mManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if(mManager != null) {
NetworkInfo activeNetwork = mManager.getActiveNetworkInfo();
if(activeNetwork== null || !activeNetwork.isConnectedOrConnecting()){
return false;
}
}
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://clients1.google.com/generate_204")
.build();
try {
Response response = client.newCall(request).execute();
if(response.code() != 204)
return false; // meaning it either responded with a captive html page or did a redirection to captive portal.
return true;
} catch (IOException e) {
return true;
}
}
Many applications including Google Chrome use http://clients1.google.com/generate_204 to verify that the the connection is not locked under captive portal.
The issue might rather be - today at least - that newer Android versions (5.1+?) keep the 3G/4G connection up and running until the wifi login actually leads to a fully functional wifi connection.
I haven't tried it, but maybe with the enum value CAPTIVE_PORTAL_CHECK of NetworkInfos DetailedState one can try to detect such a mode properly?

Categories

Resources