I have a small issue regarding Ethernet.
My three questions are:
Can we programmatically Turn-On/Off Ethernet?
Can we programmatically Enable/Disable Ethernet?
Can we programmatically Connect Ethernet?
The above Questions are done with the Wifi. Like
We can programmatically Turn-On/Off Wifi.
We can programmatically Enable/Disable Wifi.
We can programmatically Connect Wifi using WifiManager.
Does android provides any EthernetManager like as WifiManager to handle Ethernet?
Or, if this doesn't seem feasible, then my original requirement is:
The first thing I am going to clear is "DEVICE IS ROOTED" .
Can I manipulate the Settings (Default)? Like I don't want any other option in the Settings.apk other than WIFI and Ethernet. It should show only Wifi and Ethernet. That's it. Can I disable all the options from the Settings or Can I remove all the other options from the Settings?
The solution I will present here is a hack using reflection and does only work on a rooted android system.
Your device might have the popular android.net.ethernet package. In an Activity, try
Object emInstance = getSystemService("ethernet");
It returns an valid instance of the EthernetManager or null. Null means you are out of luck.
An additional requirement might be depending on your device: Ethernet and Wifi might only work exclusively. You might need to disable Wifi to enable Ethernet and vice versa.
To enable Ethernet by reflection use your instance of the EthernetManager.
The method you want to invoke is setEthEnabled(boolean enabled)
Class<?> emClass = null;
try {
emClass = Class.forName("android.net.ethernet.EthernetManager");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object emInstance = getSystemService("ethernet");
Method methodSetEthEnabled = null;
try {
methodSetEthEnabled = emClass.getMethod("setEthEnabled", Boolean.TYPE);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
methodSetEthEnabled.setAccessible(true);
try {
// new Boolean(true) to enable, new Boolean(false) to disable
methodSetEthEnabled.invoke(emInstance, new Boolean(false));
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Your application manifest needs these permissions
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
The permission WRITE_SECURE_SETTINGS can only be acquired by system apps. The app does not need to be signed by a system key. It can be any valid sign (like the regular Android App Export function). Use busybox to remount the system partition for write access and move your apk into the /system/app folder. Reboot the device and it should work.
Can we programmatically Connect Ethernet ?
There is no Access Point to connect you like with Wifi. You either configure it for DHCP or provide static values. This can of course also be done via reflection.
You will need the class EthernetDevInfo for that.
The actual implementation of the EthernetManager and EthernetDevInfo might slightly differ between Android versions and devices as it doesn't have to conform to a public api (yet) and might even be a custom version.
To get a list of getters and setters you can use a Introspector or reflection in general.
Ok here are some methods i made for manipulating with the ETHERNET INTERFACE (eth0).
1) A method for checking if an ethernet interface exists
public static boolean doesEthExist() {
List<String> list = getListOfNetworkInterfaces();
return list.contains("eth0");
}
public static List<String> getListOfNetworkInterfaces() {
List<String> list = new ArrayList<String>();
Enumeration<NetworkInterface> nets;
try {
nets = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
e.printStackTrace();
return null;
}
for (NetworkInterface netint : Collections.list(nets)) {
list.add(netint.getName());
}
return list;
}
2) A method for checking if the ETHERNET is enabled or ON
public static boolean isEthOn() {
try {
String line;
boolean r = false;
Process p = Runtime.getRuntime().exec("netcfg");
BufferedReader input = new BufferedReader (new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
if(line.contains("eth0")){
if(line.contains("UP")){
r=true;
}
else{
r=false;
}
}
}
input.close();
Log.e("OLE","isEthOn: "+r);
return r;
} catch (IOException e) {
Log.e("OLE","Runtime Error: "+e.getMessage());
e.printStackTrace();
return false;
}
}
3) A method for enabling or disabling the Ethernet depending on the state in which it is
public static void turnEthOnOrOff() {
try {
if(isEthOn()){
Runtime.getRuntime().exec("ifconfig eth0 down");
}
else{
Runtime.getRuntime().exec("ifconfig eth0 up");
}
} catch (IOException e) {
Log.e("OLE","Runtime Error: "+e.getMessage());
e.printStackTrace();
}
}
4) A method for connecting via ethernet depending on the chosen type (dhcp/static)
private boolean connectToStaticSettingsViaIfconfig(StaticConnectionSettings scs) {
try {
if(typeChosen.equalsIgnoreCase("dhcp")){
Runtime.getRuntime().exec("ifconfig eth0 dhcp start");
}
else{
Runtime.getRuntime().exec("ifconfig eth0 "+scs.getIp()+" netmask "+scs.getNetmask()+" gw "+scs.getGateway());
}
} catch (IOException e) {
Log.e("OLE","Runtime Error: "+e.getMessage());
e.printStackTrace();
return false;
}
return true;
}
There is one more class which i created for storing all the eth values needed. This class is than initialized with the values the user inserts.
public class StaticConnectionSettings {
private String ip, netmask, dns, mac, gateway, type;
//Getters and Setters
}
This is it ... I will test it shortly... This code lacks a test phase (ping). And maybe it needs setting of DNS. But this can be done easily. I have not included it because i think on our device it will work also without the DNS setting.
It works for Android 6.0.1
Class<?> ethernetManagerClass = Class.forName("android.net.ethernet.EthernetManager");
Method methodGetInstance = ethernetManagerClass.getMethod("getInstance");
Object ethernetManagerObject = methodGetInstance.invoke(ethernetManagerClass);
Method methodSetEthEnabled = ethernetManagerClass.getMethod("setEthernetEnabled", Boolean.TYPE);
methodSetEthEnabled.invoke(ethernetManagerObject, isEnabled);
Three Answeres to your above questions:
Yes. You could try using ifconfig eth0 down ; ifconfig eth0 up. But i have not tested it by myself yet.
Yes, but you do not have to. Android does the switching for you. If you connect to WiFi, Ethernet disables. If you are already connected to WiFi and you plug your ethernet cable into the device; you need only to disable WiFi (which you know how to) and android switches automatically to ethernet.
Not so easy as you may think. I have the same problem and until now i have found only one solution which i have not yet tested. Since android runs on the linux kernel, we can use ifconfig in order to manipulate the ethernet connection.
An explanation is hidden here:
http://elinux.org/images/9/98/Dive_Into_Android_Networking-_Adding_Ethernet_Connectivity.pdf
And the youtube video of this lecture
http://www.youtube.com/watch?v=LwI2NBq7BWM
And a reference on how to use ifconfig for android
Android ethernet configure IP using dhcp
So if you come to a possible solution, please share it!! If i will do it before you i will certenly.
Related
I would like to manually connect a bluetooth device with its MAC address because it is faster and I know exactly which MAC to connect.
I use this method to get the BluetoothDevice : http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getRemoteDevice%28byte[]%29
But the Android doc does not say if Android ensure that the device is in range before creating the BluetoothDevice object.
Do you have this information ?
My code can automatically connect the device, and I would like to check if the target is in range before trying to connect, but without perform a large scan (which can be long...)
When local device connects to remote device using BluetoothSocket, an exception is required.
If remote device isn't in range, It's not found
private class ConnectThread extends Thread {
public ConnectThread(BluetoothDevice device, boolean isSecure, UUID sharedUUID) throws IncorrectSetupException {
try {
//Secure connections requires to get paired before connect
//Insecure connections allows to connect without pairing
if (isSecure) {
mSocket = device.createRfcommSocketToServiceRecord(sharedUUID);
} else {
mSocket = device.createInsecureRfcommSocketToServiceRecord(sharedUUID);
}
} catch (IOException e) {
//Is there some problem with the setup?
}
}
public void run() {
try {
mSocket.connect();
} catch (IOException e) {
//If device is not found, this exception is throwed
}
}
}
I am trying to build an app in Android that would need the IP addresses of all devices (PCs and other mobile devices) connected to a wifi router (my local router). The IP addresses are the ones assigned to the devices by the router using DHCP. Moreover, the app that I am trying to build would be local to a device connected to the same router. I have looked all over the web for Android code that could accomplish this, but all I found was how to scan for wifi access-points. Is what I am trying to do possible using Android programming?
There's no direct API for this. Its not like the wifi router gives everyone a list of all IPs it assigns. You could try pinging every IP on your wifi network (you can tell what IPs those are by netmask), but that will only work if the device is configured to return ICMP packets and your router doesn't block them.
What might work for your app is Wi-fi direct (http://developer.android.com/guide/topics/connectivity/wifip2p.html).
It totally depends on your router: if it has this sort of functionality exposed via API or other. Most routers don't permit this sort of deep-querying. You might look at tomato or dd-wrt if you want to have more control over it.
You can do this by using the arp cache table by:
BufferedReader br = null;
ArrayList<String[]> ipCache = new ArrayList<>(3);
try {
br = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = br.readLine()) != null) {
String[] split = line.split(" +");
if (split.length >= 4 ) {
if(!split[0].equals("IP") &&!split[0].equals(ROUTER_IP) ){
ipCache.add(split);
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
int ipsPonged = ipCache.size();
if(ipsPonged>0){
for (String[] client :
ipCache) {
// if one ping test succeeds we are fine
if(!ping(client[0])){
ipsPonged--;
}
}
if(ipsPonged == 0){
return true;
}
}else{
return false;
}
I'm developing an app that needs that the device creates an access point. I'm testing the code on a Nexus 7 (Android 4.2.1) and a Nexus 10 (4.2.2) and I get the same problem in both. I manage to enable the access point but every device that tries to connect stays "Obtaining ip address". Any idea why? I tested the same code in a galaxy tab 10" (Android 4.0.3) and it works perfect.
private void createWifiAccessPoint(String pSSID)
{
if(mWifiManager.isWifiEnabled())
{
mWifiManager.setWifiEnabled(false);
}
Method[] wmMethods = mWifiManager.getClass().getDeclaredMethods();
boolean methodFound=false;
for(Method method: wmMethods){
if(method.getName().equals("setWifiApEnabled"))
{
methodFound=true;
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = pSSID;
try {
boolean apstatus = (Boolean) method.invoke(mWifiManager, netConfig,true);
for (Method isWifiApEnabledmethod: wmMethods)
{
if(isWifiApEnabledmethod.getName().equals("isWifiApEnabled"))
{
while(!(Boolean)isWifiApEnabledmethod.invoke(mWifiManager)){
};
for(Method method1: wmMethods){
if(method1.getName().equals("getWifiApState")){
int apstate;
apstate=(Integer)method1.invoke(mWifiManager);
Toast.makeText(this, netConfig.SSID + String.valueOf(apstate), Toast.LENGTH_LONG).show();
}
}
}
}
if(apstatus)
{
System.out.println("success");
}else
{
System.out.println("failed");
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
if(!methodFound){
}
}
I suspect your problem is that the device you are trying to connect with is expected to be supplied with an IP address etc, from the DHCP server in the Nexus device. Your code is just creating an access point. You probably need a static IP address on both ends of the link. That said, I'm not sure how that should be done, as I have more or less exactly the same problem myself.
See Unable to programatically create working Wi-Fi access point on Jellybean tablet
I have attempted to associate an IP address with the access point, and although I appear to have done that, I have still been unable to establish a connection so I only have a partial answer to your question I'm afraid.
I've read many questions here on SO that ask how to enable USB tethering programmatically.
The answer is always the same, ordinary applications can't do it, only system apps.
Yet for 2.3 you could download an app in the market that would do it for you.
https://play.google.com/store/apps/details?id=org.tdtran.autousbtethering
On ICS (Android 4.0.3) it no longer works.
How did they do it for 2.3? Is it possible also for 4.0?
using the following code you can enable USB tethering. i didt test in 4.0.
public void switchOnTethering() {
Object obj = getSystemService(Context.CONNECTIVITY_SERVICE);
for (Method m : obj.getClass().getDeclaredMethods()) {
if (m.getName().equals("tether")) {
try {
m.invoke(obj, "usb0");
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
ICS and above: To execute the reflection method, the application would require the WRITE_SECURE_SETTINGS permission.
This is not available unless the phone is rooted.
since this is one of the most popular pages in the Google results for this topic I'd like to contribute my code which is checking the available interfaces. It does work on a Gingerbread phone I have, but not my Galaxy S3.
// DETECT INTERFACE NAME
Log.i("UsbTethering","Detecting tetherable usb interface.");
String[] available = null;
ConnectivityManager connMgr = (ConnectivityManager)connectivityServiceObject;
Method[] wmMethods = connMgr.getClass().getDeclaredMethods();
for(Method getMethod: wmMethods)
{
if(getMethod.getName().equals("getTetherableUsbRegexs"))
{
try
{
available = (String[]) getMethod.invoke(connMgr);
break;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
// DETECT INTERFACE NAME
if(available.length > 0)
{
for(String interfaceName : available)
{
Log.i("UsbTethering", "Detected " + String.valueOf(available.length) + " tetherable usb interfaces.");
Log.i("UsbTethering", "Trying to " + desiredString + " UsbTethering on interface " + interfaceName + "...");
Integer returnCode = (Integer)method.invoke(connectivityServiceObject, interfaceName);
if(returnCode == 0)
{
Log.i("UsbTethering", "UsbTethering " + desiredString + "d.");
return true;
}
else
{
Log.w("UsbTethering", "Failed to " + desiredString + "Usb Tethering. ReturnCode of method " + method.getName() + ": " + String.valueOf(returnCode));
}
}
}
On Samsumg Galaxy Tab 2 10.1 the interface isn't called "usb0" but "rndis0". Maybe that's the same for Galaxy SII
The port "rndis0" is enabled dynamically not availble in the the Tetherable interfaces list.
It gets added when the user selects the USB Tethering option in the menu.
The function ConnectivityManager::setUsbTethering(bool) is called when the option is selected. And this function call is allowed only for System applications.
I know its an old thread but i hope this could help some other people in the future ,
That code worked for me in Android 4.4(with root privilege)
code:
the trick is to use reflection , the method which changes the usb tethring is called "setUsbTethering"
I wont write the entire class but here is what you need:
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Method usbTethering = connectivityManager.getClass().getMethod('setUsbTethering')
int returnCode = (Integer)usbTethering.invoke(connectivityManager, true);
0 = success
you can print the entire class methods using the following code
private static void printClassMethod(#NonNull Class aClazz) {
Method[] wmMethods = aClazz.getDeclaredMethods();
for (Method method : wmMethods) {
Log.i('anytag', method.getName());
}
}
then call printClassMethod(ConnectivityManager.class)
More Over, you can go onto the class itself and check the methods and arguments needed.
to get things work:
you must set your app as System app,
Declare in manifest : android:sharedUserId="android.uid.system"
add writing secure permission<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"
Sign the apk using google certificate key(apk-with-system-privileges) and push it to /system/app
Mind, that usbTethering is turned on while USB is attached, so a nicer solution will be to register to both USB_STATE and USB_ATTACH and enable/disable it correspondingly in onReceive Method. (USB tethering is turned off automatically when USB is de-attached)
I want to know how to detect state of WiFi tethering. I've seen an article: Android 2.3 wifi hotspot API But it doesn't work! It returns always WIFI_AP_STATE_DISABLED = 1. It doesn't depend on real state of WiFi tethering.
Using reflection:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Method[] wmMethods = wifi.getClass().getDeclaredMethods();
for (Method method: wmMethods) {
if (method.getName().equals("isWifiApEnabled")) {
try {
boolean isWifiAPenabled = method.invoke(wifi);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
As you can see here
In addition to the reflexion, to get the Wifi tethering status update, you can listen to this broadcast Action :
IntentFilter filter = new IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED");
To get all tethering option update :
IntentFilter filter = new IntentFilter("android.net.conn.TETHER_STATE_CHANGED");
Those actions are hidden inside the Android source code
First, you need to get WifiManager:
Context context = ...
final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Then:
public static boolean isSharingWiFi(final WifiManager manager)
{
try
{
final Method method = manager.getClass().getDeclaredMethod("isWifiApEnabled");
method.setAccessible(true); //in the case of visibility change in future APIs
return (Boolean) method.invoke(manager);
}
catch (final Throwable ignored)
{
}
return false;
}
Also you need to request a permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Here is the Xamarin C# version if anyone is looking:
static Method isWifiApEnabledMethod;
public static bool IsWifiApEnabled ()
{
var wifiManager = WifiManager.FromContext (Application.Context);
if (isWifiApEnabledMethod == null)
{
try
{
isWifiApEnabledMethod = wifiManager.Class.GetDeclaredMethod ("isWifiApEnabled");
isWifiApEnabledMethod.Accessible = true; //in the case of visibility change in future APIs
}
catch (NoSuchMethodException e)
{
Debug.WriteLine ("Can't get method by reflection" + e);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't get method by reflection" + ex);
}
}
if (isWifiApEnabledMethod != null)
{
try
{
return (bool)isWifiApEnabledMethod.Invoke (wifiManager);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't invoke by reflection" + ex);
}
}
return false;
}
(without using reflection since they say google is restricting it)
I'm writting this answer 10 years later. also I don't know if this can be considered a good aproach or not but I first get the Wlan network interface IPs
and if there is no address I assume that it tethering isn't enabled. if there is an address, I check using the connectivity manger whether WI-FI is connected to a network or not. if there is an IP for the Wlan network interface but it isn't connected to a network, I assume tethering is enabled.
you probably would need to add this line to your manifest file
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
code to get the ip of an inteface (this only gets the IPv4, you can modify it to get the IPv6 or both if you want)
// method used to retrieve Wlan ip addresses IPv4 of the device.
public static String IpAddresses() throws NoAddressFoundException, SocketException {
Enumeration<NetworkInterface> Nics = NetworkInterface.getNetworkInterfaces();
while (Nics.hasMoreElements()) {
NetworkInterface NIC = Nics.nextElement();
if (NIC.isUp() && !NIC.isLoopback() && NIC.getName().contains("wlan")) {
Enumeration<InetAddress> Addresses = NIC.getInetAddresses();
while (Addresses.hasMoreElements()) {
InetAddress WlanAddress = Addresses.nextElement();
if (WlanAddress instanceof Inet4Address)
return WlanAddress.getHostAddress();
}
}
}
throw new NoAddressFoundException("No suitable wifi address found");
}
then if there is an address i check if wifi is connected by this method:
//method to check if the device is connected to a Wi-Fi network; it doesn't matter if network has access to internet
public static boolean isWifiConnected(Context context) {
ConnectivityManager ConMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo WifiInfo = ConMan.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return WifiInfo.isConnected();
}
NOTE: the "NoAddressFoundException" is a custom exception in my app if anyone is wondering. it won't exist in your case.
Reflection is a poor way to achieve this.
We can inspect the DhcpInfo to determine if the device is allocating addresses (mobile hotspot) or is being allocated by another DHCP server.
Here is a kotlin function that will determine if a device is a mobile hotspot, it has not been widely tested so YMMV.
fun isMobileHotspot(manager: WifiManager): Boolean {
val info = manager.dhcpInfo
return (
info.ipAddress == 0
&& info.netmask == 0
&& info.gateway == 0
&& info.serverAddress == 16885952) // 192.168.1.1
}