How to check programmatically whether the Wifi network the phone is connected to has internet access ?
I cannot use "ping google.com" type solutions because it does not work on some devices such as Honor 10
Well, in order to decide whether a device is connected to the internet we have to define what "connected to the internet" actually means. As far as I know, the Android SDK doesn't offer any way to check that and I think that is because you have to ping a specific address after all, in order to see if it is reachable.
On my Android device, the WiFi indicator in the status bar shows an exclamation point whenever I am connected to the WiFi network but my internet connection is down. I am not sure, but I think it pings a google server (like 8.8.8.8) behind the scenes in order to find out.
I think the best approach is not to ping Google, rather ping the specific address that you use in your app, for example if you use Last.fm API, ping that instead, because you could get in a situation where the Google server is reachable but the Last.fm API is down. This is just a general example, but the solution depends on your goal.
Just try connecting to whatever it is that you need to talk to, and handle failures in a graceful way.
Pinging something (even the server you want to talk to) isn't reliable, as the server, or some part of the network may block PING.
Pinging something "well known" (like Google's name-server on 8.8.8.8) isn't reliable because it only tells you that it is up, not necessarily that you can reach the server you want to talk to. (Or, it might even be that the "well known" entity is down or unreachable, but your server is working OK).
Doing something other than just trying to connect to what you want risks introducing TOCTOU (Time-of-check to time-of-use) errors.
I've found a solution that is quick and does not require using ping command or having to load a page.
The solution uses Volley, Android's HTTP library:
public static void isInternetAccessWorking(Context context, final InternetAccessListener listener) {
StringRequest stringRequest = new StringRequest(Request.Method.GET, "https://www.google.com",
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
listener.hasInternet(true);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
listener.hasInternet(false);
}
});
Volley.newRequestQueue(context).add(stringRequest);
}
This method is not blocking: the activity or fragment calling isInternetAccessWorking() has to provide a parameter implementing InternetAccessListener that will receive the response
public interface InternetAccessListener {
void hasInternet(Boolean result);
}
Related
I am working with WebRTC to make a basic video call application that works between two Android phones, I have been searching for about more than 10 days, I have understood everything regarding the Android side, but I really can't get it in the web side, signalling, TURN and STUN. Unfortunately I am not a web guy (at least not now) and I am very very confused about what to do about the servers setup. I don't even understand exactly when to use what and why. to make the story shorter what I need is:
I need a roadmap to continue in the servers setup.
thank you in advance.
UPDATE:
The backend has been implemented and it seems to be working cuz I receive voice without any problem, I also receive the MediaStream which contains both the video and the audio, but no video is being displayed.
private void gotRemoteStream(MediaStream stream) {
//we have remote video stream. add to the renderer.
Log.d("KingArmstring", "gotRemoteStream: 1 stream == null" + String.valueOf(stream == null));
Log.d("KingArmstring", "the value of the received stream: " + String.valueOf(stream));
final VideoTrack videoTrack = stream.videoTracks.get(0);
Log.d("TAG", "gotRemoteStream: we get here");
runOnUiThread(() -> {
try {
Log.d("TAG", "we get here");
remoteRenderer = new VideoRenderer(new VideoRenderer.Callbacks() {
#Override
public void renderFrame(VideoRenderer.I420Frame i420Frame) {
Log.d("TAG", "renderFrame: we get here");
}
});
remoteVideoView.setVisibility(View.VISIBLE);
videoTrack.addRenderer(remoteRenderer);
} catch (Exception e) {
e.printStackTrace();
}
});
}
I played around with webRTC on Android and web. I was able to make my own project with the help of these projects:
https://github.com/pchab/ProjectRTC
https://github.com/pchab/AndroidRTC
What I suggest is to run these projects. After you success doing it, you can try to change the code to meet with your needs. Now I will explain some details about TURN and STUN.
STUN - this is a way to know what is you real ip. If you use your phone with wifi, what will happen is that you will have ip like: 192.168.1.14. This is internal ip. Your real ip is something else. You need some server like google to tell you what is your real ip. Try typing on google search what is my ip and you will see it is different than what you see in the ifconfig.
TURN - This is a relay of the stream of voice/video data. What happen is some cellular carrier cut of the voice/video data for some reason, what you can do to overcome this is use TURN, you send the data to the TURN and it transfer this to the other side.
Signaling - this is a way 1 side calls the other side. lets say you have 2 guys that want to communicate, they need a way to send the communication data before the call starts. webRTC doesn't give you a mechanism. It gives you a json that you need 1 guy to send it to the second guy. The links I provided uses socket.io but there are other implementation like FCM. The data that travels is the first guy ip, the codacs that he wants to use, and things like that. The second guy needs to send the accept response and the voice call begins.
I have figured finally the problem, thanks to Uriel cuz his answer helped me a lot my answer can't stand alone, it can only be added to his answer. You can see that the remoteRenderer has been initialized this way:
remoteRenderer = new VideoRenderer(new VideoRenderer.Callbacks() {
#Override
public void renderFrame(VideoRenderer.I420Frame i420Frame) {
Log.d("TAG", "renderFrame: we get here");
}
});
(I have add that in the UPDATE in my qustion)
instead of that we should initialize it this way:
remoteRenderer = new VideoRenderer(remoteVideoView);
when I finish this part of the app, I will try to add a git repo for this webRTC part so that anyone can take advantage of using any part of it.
I am connecting two devices using wifi p2p from Android. I would like to know if there is any way for both devices to know the name of each other when the connection is established. When the device is starting the connection request, it is easy because you choose the peer from the list so you see the name. The question is focus to the device that receives the connection request!!!
I guess it has to be possible since the first time you try to connect you see a pop up with the name of the peer to accept the connection. But I don't know where this information can be found when programming an app.
I guess it has to be stored either in NetworkInfo (when you received a change of state) or in WifiP2pInfo (when the connection info is available).
When you receive the WIFI_P2P_CONNECTION_CHANGED_ACTION broadcast, if you are on API level 18 or higher, there is an extra in the intent, called EXTRA_WIFI_P2P_GROUP.
EXTRA_WIFI_P2P_GROUP
This returns a WifiP2pGroup on which you can call getClientList(). This gives you a collection of WifiP2pDevices. Once you have a WifiP2pDevice you can just get the field "deviceName".
Getting peer name is straight forward. Once you get the device list
public String getName(WifiP2pDevice device){
return device.deviceName;
}
Not sure if this is what you are asking for, pardon me if this is not the answer.
There is requestConnectionInfo method by this you can get all information about connected deivce simply implement this after connection is made like below
wifiManager.requestConnectionInfo(wifichannel, new WifiP2pManager.ConnectionInfoListener() {
#Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
//by info you can get host address and isGroupowner or else information you to
implement your code after this
}
I running into an issue routing network calls using OkHttp. I'm trying to send HTTP requests to a local device (via the device's ip) using an Access Point that has no internet access. Due to some changes in Android 5.0, OkHttp will try to route the request over data instead, which then fails.
In Android 5.0's Network API, I could use the NetworkCapabilities class along with the NetworkRequest.Builder in order to tell the request to only go over Wi-Fi, However, I'm already using OkHttp and I don't want to overhaul my code. Is there anyway to do a similar thing with OkHttp?
I came up with a workaround:
final Network currentNetwork = (Network) network;
newClientBuilder.socketFactory(((Network)network).getSocketFactory())
.dns(new Dns() {
#Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
return Arrays.asList(currentNetwork.getAllByName(hostname));
}
});
We’d like to eventually include such functionality directly in OkHttp, and you might be the first volunteer/victim to test things out. What you probably want to do is use OkHttp 2.6’s new Dns interface to call through to the network of your choice. If that works, either the IP address will cause OkHttp to do the right thing anyway, or you’ll also need to replace the SocketFactory.
Im trying to let my Google Glass and my android phone connect to a NodeJs server that Im running on my computer, so that I can send messages from my android phone to my Google Glass.
For this Im using koush's AndroidAsync library, which works great on my android phone and I have absolutely no trouble connecting my phone to the NodeJS server with this library.
However, the same code doesnt seem to work on my Google Glass. My Google Glass DOES connect, because the on connection eventhandler of my NodeJS server IS triggered, it just doesnt seem to trigger any of the ConnectCallback functions on my Google Glass.
Here is the code Im using in my Google Glass app:
SocketIOClient.connect(AsyncHttpClient.getDefaultInstance(), "http://192.168.1.229:5000", new ConnectCallback() {
#Override
public void onConnectCompleted(Exception ex, SocketIOClient client) {
Log.i("SOCKET", "CONNECTION COMPLETED");
if (ex != null) {
ex.printStackTrace();
return;
}
client.setStringCallback(new StringCallback() {
#Override
public void onString(String string, Acknowledge acknowledge) {
Log.d("SOCKET", string);
}
});
client.setJSONCallback(new JSONCallback() {
#Override
public void onJSON(JSONObject jsonObject, Acknowledge acknowledge) {
Log.d("SOCKET", jsonObject.toString());
}
});
client.on("event", new EventCallback() {
#Override
public void onEvent(JSONArray jsonArray, Acknowledge acknowledge) {
Log.i("DATA: ", jsonArray.toString());
Gson gson = new Gson();
}
});
mClient = client;
}
});
}
As you can see, Im trying to log "CONNECTION COMPLETED" in the "onConnectCompleted" function, but it never fires and nothing is ever logged.
I find this rather strange, as the same code DOES work on my android phone and "CONNECTION COMPLETED" IS logged when I run this bit of code on my android phone. The strangest thing is that my node server actually picks up the Google Glass as the on connection event is triggered on the server when my Glass connects.
So, can anybody help me find out why my Google Glass IS apparently connecting to my NodeJS server, but is NOT triggering any events when it connects. (Not triggering the ConnectCallback functions, "CONNECTION COMPLETED" is never logged)?
Thanks in advance,
Bram
I was facing the same issue here and noticed although my Glass showed it was connected to my Wifi network, it actually wasn't. I tried adb shell netcfg on it and to my surprise the wlan0 interface had no IP assigned. I reconnected it to the wifi network again and it all started to work just fine.
The weird thing though is that I was expecting some sort of error to be logged (even though I was using a different Socket.IO client). I believe the case to be a timeout that didn't expire (connection/socket timeout) so it was still attempting to connect and didn't fail in time for us to see the log entry. I guess these libraries have a relatively high connection timeout set by default, so you wouldn't see an error before many seconds would go by.
I am trying to create a WI-FI Direct network with say 3 tablet PCs. I want to run WiFi-Direct as background service, with one device set as autonomous GO. Could someone please tell me how can this be done in Android? Also someone please tell me how we can set dedicated SSID and passphrase so that any time new devices are added to this network, they can search for a specific ssid and passphrase for connection establishment during the application initiation ?
I am using Android API Level 18 for my development ...
Thanks in advance ...
This is how an autonomous Group Owner is created i.e. using the following code you can deliberately set a device in Wifi direct Network as a Group Owner
manager.createGroup(channel,new WifiP2pManager.ActionListener()
{
#Override
public void onSuccess()
{
Toast.makeText(WiFiDirectActivity.this, "Group Created",Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(int reason)
{}
});
You can use this code on any event like Button click etc.
Bluemoon10 was almost right. I can't comment yet because I need 50 reputation :/. The config.groupOwnerIntent ranges from 1-15 with 15 being the highest intent to be group owner.
If 2 devices try to connect with both GO intents == 15, the connect call will fail. If there is a GO intent tie lower than 15, the devices agree on a tie breaker bit and will succeed. So if you want one device to be group owner, you have to make sure that it is the only one trying to be. You can do this with Service Discovery, i.e. if there is a service running set your GO intent to 15 on the device with the service and 1 on the connecting device. Only one device needs to call connect to initiate connection.
Link to Service Discovery tutorial: http://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct.html
To create autonomous group you can just invoke createGroup() method from your manager. In order to set ssid and passPhrase you must invoke the hidden methods of WifiP2pGroup class setPassphrase and setNetworkName.
To achieve that, you use java reflection. Try the following example.
Let us assume WifiP2pGroup group your current object.
Method
setPassPhraseMethod=group.getClass().getMethod("setPassphrase", new Class[ {String.class});
and now you invoke the method:
setPassPhraseMethod.invoke(group, "yourNewPassPrhase");
hope it is helpful.
Normally the Group Owner is decided by the WiFi Direct protocol.
However you can force it's hand by, using the config class.
final WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress=myDeviceAddr;
config.wps.setup = WpsInfo.PBC;
config.groupOwnerIntent =15;
In this case I think I'm correct in saying that 15 mean least likely to become GO, you set this to zero, if you want that device to be the GO.
Also this might be where you can set pin etc take a look at WpsInfo.
this config info in then passed into your connect call.
mManager.connect(mChannel, config, new WifiP2pManager.ActionListener().
Hope this helps.