In my code I am using requestRouteToHost() method:
Does this routing means changing the WIFI to 3G or vice versa??
My code is not working...
public static boolean isHostAvailable(Context context, String urlString) throws UnknownHostException, MalformedURLException {
boolean ret = false;
int networkType = ConnectivityManager.TYPE_WIFI;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm != null){
NetworkInfo nf = cm.getActiveNetworkInfo();
if(nf != null){
networkType = nf.getType();
}
URL url = new URL(urlString);
InetAddress iAddress = InetAddress.getByName(url.getHost());
ret = cm.requestRouteToHost(networkType, ipToInt(iAddress.getHostAddress()));
}
return ret;
}
public static int ipToInt(String addr) {
String[] addrArray = addr.split("\\.");
int num = 0;
for (int i=0;i<addrArray.length;i++) {
int power = 3-i;
num += ((Integer.parseInt(addrArray[i])%256 * Math.pow(256,power)));
}
return num;
}
Thanks
I think this is an extremely poorly documented method, and while an above comment saying "consider it a ping" might be a reasonable interpretation, I don't think it's correct. The fact that it takes an int as a host address suggests it is a much lower-level method than that, and the comment in the JavaDoc This method requires the caller to hold the permission CHANGE_NETWORK_STATE is another clue, suggesting that this makes a change in the internal routing table of the device. This link provides a better explanation:
requestRouteToHost() doesn't establish connectivity on any network, it
only ensures that any traffic for the specified host will be routed
via the specified network type (wifi or mobile). Connectivity must
already exist on the specified network.
This explanation makes MUCH more sense, considering the permission required. It also appears that it will not work with WiFi. So, it appears what this method is useful for is the following: You wish to ensure that the connection made to a particular host will be made via a SPECIFIC interface and that interface is not WiFi. This might make sense for a long-term, low traffic, battery efficient connection, such as when you wish to keep a socket open to a server and wait for the server to send the occasional message. The mobile data interface would make more sense than WiFi, since you wouldn't need to keep the WiFi radio active the whole time, and the mobile network radio is always on anyway. Incidentally, this is EXACTLY how an iPhone's server "push" mechanism works: It keeps a socket to an Apple server constantly connected over the mobile data interface, waiting for the server to say something.
So, in opposition to the (currently chosen) correct answer, I suggest that the answer to the asker's question: Does this routing means changing the WIFI to 3G or vice versa?? is actually, "Yes, sort of!" If the method returns true, the caller is assured that connections to that IP address will happen over the indicated interface.
And to Google: Boo on you for not documenting some of your APIs better!
Method requestRouteToHost() does not change wifi to 3G or vice versa!
Official Documentation :
public boolean requestRouteToHost (int networkType, int hostAddress)
Ensure that a network route exists to deliver traffic to the specified host via the specified network interface. An attempt to add a route that already exists is ignored, but treated as successful.
Parameters
networkType the type of the network over which traffic to the specified host is to be routed
hostAddress the IP address of the host to which the route is desired
Returns
true on success, false on failure
Related
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
I am trying to detect the IP of a device (ESP8266), which is acting as a server and is connected to the same network. So that I can send some GET requests to it, but every time my router restarts the device get assigned a different address, so every time I have to lookup its IP from the router and put it in the app to let it start to work again.
I have found something that does my job rorist/android-network-discovery but it will be hard for me to implement it in my app (lack of documentation), secondly my antivirus detects it as a virus.
I am trying to do something like the Belking WeMo app.
What are my options now?
there is no straight way in android where you could do this unless if you have root access, however you could do it the classic way, for example we are sure that the range of the second part range will be always between 0-255 so first thing we need to do is, getting our IP by using this method:
public static String getMyIPAddress() {//P.S there might be better way to get your IP address (NetworkInfo) could do it.
String myIP = null;
try {
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces) {
List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
for (InetAddress addr : addrs) {
if (!addr.isLoopbackAddress()) {
String sAddr = addr.getHostAddress().toUpperCase();
boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
if (isIPv4)
myIP = sAddr;
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
return myIP;
}
method above will return the current IPthat assigned to our phone, from this we could start doing PING to indicates others who are connected to the same network, if the PING ever returned response then definitely the IP exists in the same network follow code below in a background thread:
String ipAddress = getMyIPAddress();
String subnet = ipAddress.substring(0, ipAddress.lastIndexOf("."));
String currentHost;
for (int i = 0; i < 255; i++) {
currentHost = subnet + "." + i;
Process p1 = Runtime.getRuntime().exec("ping -c 1 " + currentHost);
int returnVal = p1.waitFor();
boolean reachable = (returnVal == 0);
if (reachable) {
//currentHost (the IP Address) actually exists in the network
}
}
as you can see in above code, we are looping through between 0-255 and Pining each IP Address whoever falls into reachable is actually within the network.
Both IP Tools and Fing can do network discovery. They are free apps.
I believe they just ping every IP address in the device's subnet and wait for a response. You could make code to do this yourself.
You might want to check out this article for more info on it:
java code to ping an IP address
Tip: Use a ThreadPoolExecutor for good parallelization while waiting for the timeouts.
Why wouldn't you use static IP address assignment? If you have some access restrictions to your router configuration, then you may try some other options:
Remember a MAC-address of your device. Make your application on ESP8266 to request something from server and use arp -a command to find IP - MAC mapping.
Write a service, that answers broadcast/multicast queries and refresh your IP-address information periodically.
Develop an application that gets data from router about IP-address scope and look for you MAC there.
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?
I have 2 Android devices using WiFi Direct. On one device I can get information about the other device using the WifiP2pManager class, and request a connection to the other device. However when I request a connection, the other device pops up a little window and asks the user if they want to accept the connection request.
Is it possible to auto-accept these connection requests? I.E to be able to connect to the other device without user confirmation?
It can be easily done with the help of Xposed framework. You just need to replace the single method inside one of android java classes (see the link from snihalani's answer). But of course to use Xposed your device must be rooted. The main idea can be expressed in the following code (using Xposed)
#Override
public void handleLoadPackage(LoadPackageParam lpparam) {
try {
Class<?> wifiP2pService = Class.forName("android.net.wifi.p2p.WifiP2pService", false, lpparam.classLoader);
for (Class<?> c : wifiP2pService.getDeclaredClasses()) {
//XposedBridge.log("inner class " + c.getSimpleName());
if ("P2pStateMachine".equals(c.getSimpleName())) {
XposedBridge.log("Class " + c.getName() + " found");
Method notifyInvitationReceived = c.getDeclaredMethod("notifyInvitationReceived");
final Method sendMessage = c.getMethod("sendMessage", int.class);
XposedBridge.hookMethod(notifyInvitationReceived, new XC_MethodReplacement() {
#Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
final int PEER_CONNECTION_USER_ACCEPT = 0x00023000 + 2;
sendMessage.invoke(param.thisObject, PEER_CONNECTION_USER_ACCEPT);
return null;
}
});
break;
}
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
I tested it on SGS4 stock 4.2.2 ROM and it worked.
I guess the same could be done with the help of Substrate for android.
From my current understanding of the API, You cannot really accept connections automatically without user's intervention. You can initiate a connection, that doesn't require user intervention. If both of your devices are mobile devices, you will have to accept connection request on one end.
I have put this as a feature request in android project hosting.
You can monitor their response here: https://code.google.com/p/android/issues/detail?id=30880
Based on the comments, do you really need to connect to the devices if you just want to track and log the vehicles around you ?
I don't know the scope of the project, but you could simply use the WifiP2pDeviceList that you get when you request the peers in the WifiP2pManager. You could get the list of the devices (~= vehicles) around you and could log this.
Connection is useful if you want to send more detailed information I guess.
If you can modify the framework, you can ignore the accept window and direct send the "PEER_CONNECTION_USER_ACCEPT".
Base on Android 5.0, "frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java".
You must find the "notifyInvitationReceived", and modify to ...
private void notifyInvitationReceived() {
/*Direct sends the accept message.*/
sendMessage(PEER_CONNECTION_USER_ACCEPT);
/*
... old code
*/
}
I have am having some issues with getting consistent results when checking if the network is available or not.
I use this code snippet inside a class AppPreferences to check the availability of a network.
/**
* #return the networkAvailable
*/
public boolean isNetworkAvailable() {
connectionManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
networkAvailable = connectionManager.getActiveNetworkInfo() != null && connectionManager.getActiveNetworkInfo().isConnected();
return networkAvailable;
}
Before each run I set the context as below:
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
appPreferences.setContext(getBaseContext());
if (appPreferences.isNetworkAvailable()){
// perform task
}
}
},
0,
UPDATE_INTERVAL);
I do know it is not tied to the background thread as I have a onReceive call doing the same logic and still this check fails.
It seems to predominantly happen when it moves between a cellular data connection and to wifi, or vice versa. The Context in which it was started seems to stay even though I update it.
Does anyone have any idea what could be the issue here?
It seems as if the active network info will stay on the state of when the Context of the Service/Activity/Receiver is started. Hence if you start it on a network, and then later disconnect from that (i.e. moves from 3G to Wifi and disconnect the 3G connection) it will stay on the first active connection making the app believe the phone is offline even though it is not.
It seems to me that the best solution is to user getApplicationContext instead as that will not be tied to when you started the particular "task".
Update: Related is that if you run applications on Androids (in particular Nexus One) for a long period of time when connected to Wifi do check that you make sure you do not let the Wifi sleep when the screen sleeps. You will be able to set that at the Advanced option under Wireless Networks.