Internet Connection Check behaving weirdly - java

I've been needing a way to check if the user has Internet. I used this approach:
public class InternetCheck extends AsyncTask<Void, Void, Boolean> {
private Consumer mConsumer;
public interface Consumer {
void accept(Boolean internet);
}
public InternetCheck(Consumer consumer) {
mConsumer = consumer;
execute();
}
#Override
protected Boolean doInBackground(Void... voids) {
try {
Socket sock = new Socket();
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
Log.w("INTERNET CHECK", "has Internet");
return true;
} catch (IOException e) {
Log.w("INTERNET CHECK", "NO Internet");
return false;
}
}
#Override
protected void onPostExecute(Boolean internet) {
mConsumer.accept(internet);
}
}
... the following way:
new InternetCheck(hasInternet -> { /* do something with boolean response */ });
However, it seems like it isn't as robust as one would think: sometimes (not so often) my phone is connected to WiFi and yet this method returns false.
What are the possible scenarios/diagnostics as of why this behaviour might happen?
My personal experience is that it seems to happen when my phone has my application open and is connected to a WiFi. Then, the phone goes to sleep and I move places and open it back up to the application on a new WiFi connection. The check returns false despite my phone displaying that it clearly has established the new WiFi connection (since it was a saved network).
However, this is not the only way this method seems to have failed. Another developer had it happen while he didn't change his WiFi connection.

Wifi connections are disconnected when the phone goes to sleep. It takes time for the connection to be re-established when the phone wakes up again.
Your 1.5 second connection timeout is too short to accommodate that extra delay.
Also, the DNS server, or the intermediate network, may simply be busy. Again, the connection timeout is too short.
Before inventing your own way to check internet connectivity, you should read these:
Android Developer Guide: Determine and monitor the connectivity status
StackOverflow: Android check internet connection

Related

Socket.io connection doesn't work for multiple fragments

I am creating a project with socket.io. It works really fine as long as there is just one fragment. However as I add more fragments in main activity, it starts creating multiple connections, which i think is not a good idea.
At first I connected to socket.io directly from fragments but that was creating one connection for each fragment. So I created a connection in Application class and used that in fragments which instantly solved multiple connection problem. But now a new problem has occurred.
In case of internet disconnection and reconnection, fragment doesn't get reestablished connection from Application class. I have been trying for over a week but no solution. strange thing is, i searched on internet and stackoverflow but not a single such question is ever asked.
here is connection code in Application class
synchronized public Socket getSocket() {
if (mSocket == null) {
try {
IO.Options opts = new IO.Options();
opts.reconnection = true;
opts.reconnectionDelay = 1000;
mSocket = IO.socket("http://ddbharti.in", opts);
mSocket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d(TAG, "EVENT_CONNECT");
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d(TAG, "EVENT_DISCONNECT");
}
}).on(Socket.EVENT_ERROR, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d(TAG, "error");
}
});
mSocket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return mSocket;
}
and this is how each fragment is connecting
socket = application.getSocket();
socket.emit("tag", tag);
If internet is working fine, this setup works flawlessly, loads in 300 milliseconds. However as i disconnect/reconnect internet or I keep internet disconnected and start the app and then connect to internet. Connection in Application class connects quickly, but due to some reason connection in current fragment just doesn't get it.
If i switch fragments then it starts listening to connection from Application class again.
So am i missing something here? How can i force fragment to get connection from application class again in case of reconnection without reloading whole fragment?
Any help is greatly appreciated.
So i created an event listner to listen to socket connection status and show ui accordingly. Just one connect with event listner was all that was needed.

Android application is hanged and showing black screen for 5-6 seconds when checking if a server port is open or not using ThreadPoolExecutor

I need to run a service if a server port is open. I am doing this by using below method.
public Future<Boolean> ifPortIsOpenThenStartIridiumService(final Context context, final String device_mac, final String device_imei, final String input_mobile) {
return Executors.newFixedThreadPool(20).submit(new Callable<Boolean>() {
#Override
public Boolean call() {
try {
String SERVER_IP = "IP Address";
int SERVER_PORT = Server_port;
int DURATION = 1000;
Socket socket = new Socket();
socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), DURATION);
socket.close();
Log.d(TAG, "Port is Open");
runIridiumService(context, device_mac, device_imei, input_mobile);
return true;
} catch (Exception ex) {
Log.d(TAG, "Port is not Open");
CustomToast.showToast(context, "No Internet Access.", "If in flight, please switch to \"Aeroplane Mode\" and connect to the airline's Wi-Fi network.", 1);
return false;
}
}
});
}
Above code is working but when I run this method the application is getting hanged and black screen is shown for 5-6 seconds.
I found below message on Logcat.
W/ActivityManager: Launch timeout has expired, giving up wake lock!
After that service is started and application is working well. How can I get rid of this problem?
Thanks in advance.
After some study, as far as I understood,
Android application is hanged and showing black screen for 5-6 seconds Because,
Future -
A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation.
So, it waits until operation is finished. You can get more info from here.
newFixedThreadPool -
At any point, at most nThreads threads will be active processing tasks. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available.
Get more info from here.
The possible solution of your problem is to use ScheduledExecutorService.
Before that you can check Future is completed or not using
if (YOUR_FUTURE.isDone()){
result = (String) YOUR_FUTURE.get();
}
to avoid unwanted or extra loop.

BLE Android - onConnectionStateChange not being called

I have a problem trying to connect to a peripheral. Sometimes the callback onConnectionStateChange(...) is not called after BluetoothDevice#connectGatt(...). What I'm trying to achieve is fast and short connections triggered by user action.
This situation occurs about 1 every 10 times without specific prior action. It lasts about 20 to 30 seconds or until the application is killed and reopened. The normal sequence of steps I follow is:
Scan devices to find the peripheral.
Call BluetoothDevice#connectGatt(...). If it takes longer than 1 second to connect, it means that the connection is "stuck" and therefore it won't connect, so BluetoothDevice#connectGatt(...) is called again. This is done with a limit of 5 attempts.
onConnectionStateChange(...) is called with newState CONNECTED and begins the services discovery.
The rest of the operations are performed without problems.
After disconnection BluetoothGatt#close() is called.
The problem occurs at point 3. Sometimes onConnectionStateChange(...)is not called. I have noticed that most of the times the problem starts with a specific behavior. After calling BluetoothDevice#connectGatt(...), onConnectionStateChange(...) is called with newState CONNECTED, but almost immediately afterwards (~40 milliseconds) is called again with newStatus DISCONNECTED. Due to the short time of the status change, I can deduce that the device does not even tried to make the connection and changed the state to DISCONNECTED.
The problem ends when:
20-30 seconds have passed. During this time onConnectionStateChange(...) is never called. When the problem ends, onConnectionStateChange(...) is called the number of times that the app tried to connect. For example, if BluetoothDevice#connectGatt(...) is called 15 times, onConnectionStateChange(...) is called 15 times with newState equal to DISCONNECTED. This is curious because never in any of those connection attempts the status changed to CONNECTED.
The app is killed and started again.
This error occurs in SDK18 and SDK 21.
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
String deviceName = device.getName();
if (deviceName == null) return;
Log.d("BLUETOOTH CONNECTION", "Device found: " + device.getName());
if (mMode == SCAN_MODE) {
mListener.deviceFound(device, rssi, scanRecord);
}
else {
mDevices.put(device.hashCode(), device);
stopScan();
// Samsung devices with SDK 18 or 19 requires that connectGatt is called in main thread.
mHandler.post(new Runnable() {
#Override
public void run() {
Log.d("BLUETOOTH CONNECTION", "Executing first device.connectGatt()");
BluetoothGatt gatt = device.connectGatt(mContext, false, mGattCallback);
retryIfNecessary(device, gatt);
mTryingToConnect = true;
}
});
}
}
private void retryIfNecessary(final BluetoothDevice device, final BluetoothGatt gatt) {
if (isRetryLimitReached()) {
Log.d("BLUETOOTH CONNECTION", "Try count limit reached");
finishConnection(gatt);
mRetryCount = 0;
mListener.error(TIMEOUT);
return;
}
mRetryCount++;
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("BLUETOOTH CONNECTION", "Check if it is frozen.");
if (isWorking()) {
Log.d("BLUETOOTH CONNECTION", "Frozen, create new connection.");
BluetoothGatt gatt = device.connectGatt(mContext, false, mGattCallback);
retryIfNecessary(device, gatt);
}
}
}, RETRY_INTERVAL_MS);
}
#Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
Log.d("BLUETOOTH CONNECTION", "On connection state changed. Device: "+ gatt.getDevice().getAddress());
if (!mConnected && BluetoothGatt.STATE_CONNECTED == newState) {
Log.d("BLUETOOTH CONNECTION", "Connected");
mTryingToConnect = false;
mTryingToDiscoverServices = true;
mConnected = true;
gatt.discoverServices();
}
else if(BluetoothGatt.STATE_DISCONNECTED == newState) {
Log.d("BLUETOOTH CONNECTION", "Disconnected and closing gatt.");
mConnected = false;
gatt.close();
if (!mConnectionFinished && mRetryCount == 0) {
finishConnection(gatt);
}
}
}
I think that the peripheral is not relevant, because the iOS app can always connect without this problem.
Any ideas? Thanks in advance.
Edit!
This answer say that:
Direct connection has interval of 60ms and window of 30ms so
connections complete much faster. Additionally there can only be one
direct connection request pending at a time and it times out after 30
seconds. onConnectionStateChange() gets called with state=2,
status=133 to indicate this timeout.
So in this 30 seconds interval there is a pending connection request and times out at the second 30. It's unlikely but, is there anything I can do to make this time shorter? Or maybe there is an explanation for the connection failure that I am not seeing. Thanks.
EDIT 02/03/2016
A new information that may help. When the problem starts (when onConnectionStateChange(...) is called with newState=DISCONNECTED after ~40ms of being called with newState=CONNECTED), the status is 62 = 0x03E. Looking here that status code means GATT_CONN_FAIL_ESTABLISH. When I detect this status I'm closing the gatt connection, but the problem persists. I also tried disconnecting and closing. Ideas? Thanks.
If someone is having a similar issue, the problem was finally solved by changing the BLE chip used by the peripheral (arduino). Before that change, a workaround I found was turning off and on the BLE after each connection. The solution was not perfect, but improved the connection rate a lot.
Android Bluetooth needs to be recycled occasionally, have you tried restarting the BLE on the device when you encounter this timeount?
Here's a snippet I've used to restart the BLE when strange things start happening.
static Handler mHandler = new Handler();
public static void restartBle() {
final BluetoothManager mgr = (BluetoothManager) ApplicationBase.getAppContext().getSystemService(Context.BLUETOOTH_SERVICE);
final BluetoothAdapter adp = mgr.getAdapter();
if (null != adp) {
if (adp.isEnabled()) {
adp.disable();
// TODO: display some kind of UI about restarting BLE
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (!adp.isEnabled()) {
adp.enable();
} else {
mHandler.postDelayed(this, 2500);
}
}
}, 2500);
}
}
}
I am not sure if you're still looking for an answer for this question. Personally, I would not advise making "fast and short connections triggered by user action" for low energy devices. Instead you could set the autoConnect option to "true" in your connectGatt method.
device.connectGatt(mContext, true, mGattCallback); [instead of false]
Hope it helps!

BluetoothServerSocket doesn't return from accept()

I'm trying to build a little Bluetooth-Android-App for a project in school.
I'm quite new to Android (got my phone since 2 days). I'm experimenting since 2 weeks with android programming on my laptop. Installed a VirtualBox with Android x86 (eeepc) so I can use the BluetoothAdapter of the laptop. Emulator doesn't support Bluetooth and is quite slow. That's about the project...
The problem/question:
A Bluetoothconnection has 2 devices - a connecting and a listening one. The listening device has a BluetoothServerSocket, that loops accept() method until accept() returns a BluetoothSocket.
In my case the accept() method doesn't return so I get stuck and the app freezes with blackscreen asking mit to stop the app or just to wait. When I pass a timeout to accept() --> accept(10000) I get an IOException after the timeout.
listening device:
private class AcceptThread extends Thread {
private BluetoothSocket tSocket;
private BluetoothServerSocket bss = null;
public void run() {
try {
Log.d(TAG, "erzeuge ServerSocket");
bss = BluetoothAdapter.getDefaultAdapter().listenUsingInsecureRfcommWithServiceRecord("BluetoothChatInsecure", MainActivity.BT_UUID);
Log.d(TAG, "ServerSocket OK");
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Fehler Serversocket");
}
while (true) {
Log.d(TAG, "Versuche zu akzeptieren");
try {
Log.d(TAG, "Akzeptieren Anfang");
tSocket = bss.accept(10000);
//this line is never reached
Log.d(TAG, "Akzeptieren Ende");
if (tSocket != null){
//Hier wollen wir hin!
Log.d(TAG, "Verbindung akzeptiert");
ConnectedThread conThread = new ConnectedThread(tSocket);
conThread.run();
bss.close();
break;
} else {
Log.e(TAG, "Fehler, keine Verbindung");
}
} catch (IOException e) {
Log.e(TAG, "IOException währent accept-loop");
//this exception is triggered every 10 sec, when the accept(10000) times out
e.printStackTrace();
}
}
Log.i(TAG, "Acceptthread hat fertig");
}
}
connecting device:
try {
socket = device.createInsecureRfcommSocketToServiceRecord(MainActivity.BT_UUID);
outstr = socket.getOutputStream();
instr = socket.getInputStream();
ois = new ObjectInputStream(instr);
oos = new ObjectOutputStream(outstr);
} catch (IOException e) {
e.printStackTrace();
}
I've read a lot of threads on stackoverflow and some other forums about this topic, but I didn't got a solution for the problem.
Sorry about my English, but I am not a native speaker.
Thanks for any help!
EDIT:
I forgot to write, that I test the app with 2 devices. My laptop does accept-loop, while I use my phone and try to connect.
This is just the normal behavior: accept() will "wait" (block) until a connection has been made from another device. Then it returns the socket representing that connection for further data transfer.
As you have seen, the timeout is signalled via an IOException. The contract of accept() is that it never returns null but always a valid socket, or fails with an exception thrown.
Therefore, thejh is right in saying that you should have a dedicated thread which waits for connections in accept().
When accept() returns a new socket, you may want to spawn another thread to handle further communication over that socket, while the accept() thread loops to wait for the next connection.
N.b.: You cannot shut down a thread blocked in IO (as in accept()) via Thread.interrupt(), but you have to close the ServerSocket from another thread to cause an IOException to 'wake up' the blocked thread.
I've been facing this problem for a couple of days. Finally, I realized why:
I was creating the Thread that accepts incoming connections in the server twice. Thus, the ServerSocket was being created to times, although only the second time the accept() method was called.
This leads to server not accepting any connection!!
It seems that you didn't call socket.connect() from client side in the shown codes.
Today I continued work on project. I got IOException after failing connect() from connecting device.
Now I managed the devices to have a socket, after pairing them before running the app.
EDIT: accept() returns a socket now, but it isn't connected when asking with isConnected().
Socket of the connecting device is connected.

How to check if internet connection is present in Java?

How do you check if you can connect to the internet via java? One way would be:
final URL url = new URL("http://www.google.com");
final URLConnection conn = url.openConnection();
... if we got here, we should have net ...
But is there something more appropriate to perform that task, especially if you need to do consecutive checks very often and a loss of internet connection is highly probable?
You should connect to the place that your actual application needs. Otherwise you're testing whether you have a connection to somewhere irrelevant (Google in this case).
In particular, if you're trying to talk to a web service, and if you're in control of the web service, it would be a good idea to have some sort of cheap "get the status" web method. That way you have a much better idea of whether your "real" call is likely to work.
In other cases, just opening a connection to a port that should be open may be enough - or sending a ping. InetAddress.isReachable may well be an appropriate API for your needs here.
The code you basically provided, plus a call to connect should be sufficient. So yeah, it could be that just Google's not available but some other site you need to contact is on but how likely is that? Also, this code should only execute when you actually fail to access your external resource (in a catch block to try and figure out what the cause of the failure was) so I'd say that if both your external resource of interest and Google are not available chances are you have a net connectivity problem.
private static boolean netIsAvailable() {
try {
final URL url = new URL("http://www.google.com");
final URLConnection conn = url.openConnection();
conn.connect();
conn.getInputStream().close();
return true;
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
return false;
}
}
People have suggested using INetAddress.isReachable. The problem is that some sites configure their firewalls to block ICMP Ping messages. So a "ping" might fail even though the web service is accessible.
And of course, the reverse is true as well. A host may respond to a ping even though the webserver is down.
And of course, a machine may be unable to connect directly to certain (or all) web servers due to local firewall restrictions.
The fundamental problem is that "can connect to the internet" is an ill-defined question, and this kind of thing is difficult to test without:
information on the user's machine and "local" networking environment, and
information on what the app needs to access.
So generally, the simplest solution is for an app to just try to access whatever it needs to access, and fall back on human intelligence to do the diagnosis.
If you're on java 6 can use NetworkInterface to check for available network interfaces.
I.e. something like this:
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface interf = interfaces.nextElement();
if (interf.isUp() && !interf.isLoopback())
return true;
}
Haven't tried it myself, yet.
This code should do the job reliably.
Note that when using the try-with-resources statement we don't need to close the resources.
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class InternetAvailabilityChecker
{
public static boolean isInternetAvailable() throws IOException
{
return isHostAvailable("google.com") || isHostAvailable("amazon.com")
|| isHostAvailable("facebook.com")|| isHostAvailable("apple.com");
}
private static boolean isHostAvailable(String hostName) throws IOException
{
try(Socket socket = new Socket())
{
int port = 80;
InetSocketAddress socketAddress = new InetSocketAddress(hostName, port);
socket.connect(socketAddress, 3000);
return true;
}
catch(UnknownHostException unknownHost)
{
return false;
}
}
}
This code:
"127.0.0.1".equals(InetAddress.getLocalHost().getHostAddress().toString());
Returns - to me - true if offline, and false, otherwise. (well, I don't know if this true to all computers).
This works much faster than the other approaches, up here.
EDIT: I found this only working, if the "flip switch" (on a laptop), or some other system-defined option, for the internet connection, is off. That's, the system itself knows not to look for any IP addresses.
InetAddress.isReachable sometime return false if internet connection exist.
An alternative method to check internet availability in java is : This function make a real ICMP ECHO ping.
public static boolean isReachableByPing(String host) {
try{
String cmd = "";
if(System.getProperty("os.name").startsWith("Windows")) {
// For Windows
cmd = "ping -n 1 " + host;
} else {
// For Linux and OSX
cmd = "ping -c 1 " + host;
}
Process myProcess = Runtime.getRuntime().exec(cmd);
myProcess.waitFor();
if(myProcess.exitValue() == 0) {
return true;
} else {
return false;
}
} catch( Exception e ) {
e.printStackTrace();
return false;
}
}
I usually break it down into three steps.
I first see if I can resolve the domain name to an IP address.
I then try to connect via TCP (port 80 and/or 443) and close gracefully.
Finally, I'll issue an HTTP request and check for a 200 response back.
If it fails at any point, I provide the appropriate error message to the user.
URL url=new URL("http://[any domain]");
URLConnection con=url.openConnection();
/*now errors WILL arise here, i hav tried myself and it always shows "connected" so we'll open an InputStream on the connection, this way we know for sure that we're connected to d internet */
/* Get input stream */
con.getInputStream();
Put the above statements in try catch blocks and if an exception in caught means that there's no internet connection established. :-)
The code using NetworkInterface to wait for the network worked for me until I switched from fixed network address to DHCP. A slight enhancement makes it work also with DHCP:
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface interf = interfaces.nextElement();
if (interf.isUp() && !interf.isLoopback()) {
List<InterfaceAddress> adrs = interf.getInterfaceAddresses();
for (Iterator<InterfaceAddress> iter = adrs.iterator(); iter.hasNext();) {
InterfaceAddress adr = iter.next();
InetAddress inadr = adr.getAddress();
if (inadr instanceof Inet4Address) return true;
}
}
}
This works for Java 7 in openSuse 13.1 for IPv4 network. The problem with the original code is that although the interface was up after resuming from suspend, an IPv4 network address was not yet assigned. After waiting for this assignment, the program can connect to servers. But I have no idea what to do in case of IPv6.
1) Figure out where your application needs to be connecting to.
2) Set up a worker process to check InetAddress.isReachable to monitor the connection to that address.
This code is contained within a jUnit test class I use to test if a connection is available. I always receive a connection, but if you check the content length it should be -1 if not known :
try {
URL url = new URL("http://www.google.com");
URLConnection connection = url.openConnection();
if(connection.getContentLength() == -1){
fail("Failed to verify connection");
}
}
catch (IOException e) {
fail("Failed to open a connection");
e.printStackTrace();
}
public boolean checkInternetConnection()
{
boolean status = false;
Socket sock = new Socket();
InetSocketAddress address = new InetSocketAddress("www.google.com", 80);
try
{
sock.connect(address, 3000);
if(sock.isConnected()) status = true;
}
catch(Exception e)
{
status = false;
}
finally
{
try
{
sock.close();
}
catch(Exception e){}
}
return status;
}
You can simply write like this
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Main {
private static final String HOST = "localhost";
public static void main(String[] args) throws UnknownHostException {
boolean isConnected = !HOST.equals(InetAddress.getLocalHost().getHostAddress().toString());
if (isConnected) System.out.println("Connected");
else System.out.println("Not connected");
}
}
There are (nowadays) APIs for this, but they are platform specific:
On Android ConnectivityManager (https://developer.android.com/training/basics/network-ops/reading-network-state) does everything you need.
On Windows INetworkListManager::GetConnectivity (for which you'll need a JNI)
On generic Linux, you are probably stuck with testing if you have access to a DNS server and Google, as above.
there is probably an Apple way to do this as well
(I'd use the specific tools where available)
This have worked well for me.
try{
InetAddress addr = InetAddress.getByName("google.com" );
}catch(IOException e){
JOptionPane.showMessageDialog(new JFrame(),"No Internet connection.\nTry again later", "Network Error", JOptionPane.ERROR_MESSAGE);
}
There is also a gradle option --offline which maybe results in the behavior you want.
The following piece of code allows us to get the status of the network on our Android device
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView mtv=findViewById(R.id.textv);
ConnectivityManager connectivityManager=
(ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(((Network)connectivityManager.getActiveNetwork())!=null)
mtv.setText("true");
else
mtv.setText("fasle");
}
}
}

Categories