I have a prototype Android app that is listening for multicast packets to 'discover' clients to communicate with. The socket set up is similar to this:
InetAddress group = InetAddress.getByName("228.1.2.3");
MulticastSocket s = new MulticastSocket(4000);
s.joinGroup(group);
This works very well when all the devices are connected via WiFi. I would like to support this with the phone acting as a portable hotspot. However, while all my devices appear to connect to the hotspot correctly I no longer receive multicast data. I'm wondering if there are restrictions that disallow this type of communication in hotspot mode, or if there are is any additional network configuration required to enable this? I've tried this on a couple different devices running Gingerbread and Froyo with no luck.
As this article show:
https://plus.google.com/+Chainfire/posts/9NMemrKYnCd
MulticastSocket::setNetworkInterface()
would be the answer
you can find the wlan0 eth by :
public static NetworkInterface getWlanEth() {
Enumeration<NetworkInterface> enumeration = null;
try {
enumeration = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
e.printStackTrace();
}
NetworkInterface wlan0 = null;
StringBuilder sb = new StringBuilder();
while (enumeration.hasMoreElements()) {
wlan0 = enumeration.nextElement();
sb.append(wlan0.getName() + " ");
if (wlan0.getName().equals("wlan0")) {
//there is probably a better way to find ethernet interface
Log.i(TAG, "wlan0 found");
return wlan0;
}
}
return null;
}
Have a try and lemme know if it works or not in Hotspot mode...
Do you have the manifest permission and are you creating a lock?
For permission please see: 'CHANGE_WIFI_MULTICAST_STATE' in http://developer.android.com/reference/android/Manifest.permission.html
Also, to create a multicast lock... please see:
http://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock.html
I've had the same problem and came up with a solution by the combination of #braden, #user707606 and the mainly the post by Chainfire in this Link.
Post in the link is nice but doesn't really offer any code samples but here it's. First you need to Acquire Multicast Lock, this is needed for some Android devices, didn't try in most of them but it was mentioned in some other posts, so I've included it in my code.
Permission is required, so first, add the permissions into your Manifest file.
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Then the second step is to acquire multicast lock in your method.
/* Acquire MultiCast Lock */
WifiManager wifi = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
And then, find your Wifi Network Interface
/**
* Finds Network Interface of Wifi Ethernet.
*
* #return
*/
public static NetworkInterface findWifiNetworkInterface() {
Enumeration<NetworkInterface> enumeration = null;
try {
enumeration = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
e.printStackTrace();
}
NetworkInterface wlan0 = null;
while (enumeration.hasMoreElements()) {
wlan0 = enumeration.nextElement();
if (wlan0.getName().equals("wlan0")) {
return wlan0;
}
}
return null;
}
Later, create a Multicast socket with an available port and set your Wifi NetworkInterface.
MulticastSocket multicastSocket = new MulticastSocket();
/* Set NetworkInterface of MultiCast Socket */
NetworkInterface wifiNetworkInterface = findWifiNetworkInterface();
if (wifiNetworkInterface != null) multicastSocket.setNetworkInterface(wifiNetworkInterface);
Then the rest of your implementation remains the same. And once you are done with Multicast Lock, it's recommended to release it.
#Peter Jankuliak
This is a good idea. Here is a simpler way.
private fun findWifiNetworkInterface(): NetworkInterface? {
var enumeration: Enumeration<NetworkInterface?>? = null
try {
enumeration = NetworkInterface.getNetworkInterfaces()
} catch (e: SocketException) {
e.printStackTrace()
}
var wlan0: NetworkInterface? = null
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
wlan0 = enumeration.nextElement()
if (wlan0 != null) {
val list = wlan0.interfaceAddresses.requireNoNulls()
for (interfaceAddress in list) {
if(interfaceAddress.broadcast!=null){
return wlan0
}
}
}
}
}
return null
}
Related
everyone!
I'm developing an Android app that allows to chat with nearby devices that have installed this app. In order to accomplish this, I'm using the Wi-Fi P2P API and Network Service Discovery to search for such nearby devices.
I've written the code for searching the nearby devices in a thread started by a Service. When a device is detected, the Service sends it (through a broadcast intent) to an Activity which displays the devices detected so far.
The detected devices are added to a recyclerView and, when the user presses one of them, a connection must be established to such device.
The Wi-Fi Direct connection gets established successfully (that is, the WifiP2pManager.connect() method succeeds) and the WIFI_P2P_CONNECTION_CHANGED_ACTION is caught.
In the broadcast receiver, when such broadcast intent is caught, the following code is executed:
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
mManager.requestConnectionInfo(mChannel, connectionInfoListener); }
With the requestConnectionInfo() method I can obtain more information about the connection, such as the IP address of the device I'm trying to connect to.
To obtain such information, I provide an implementation of WifiP2pManager.ConnectionInfoListener to that method, which is denoted by the connectionInfoListener variable.
This is the code of my implementation of WifiP2pManager.ConnectionInfoListener:
private WifiP2pManager.ConnectionInfoListener connectionInfoListener = new WifiP2pManager.ConnectionInfoListener() {
#Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
InetAddress deviceIP = info.groupOwnerAddress;
int port = servicesConnectionInfo.get(device);
ConnectThread connectThread = new ConnectThread(deviceIP, port, device);
connectThread.start();
"device" is an instance variable of my implementation of BroadcastReceiver which is not important right now. What is important, instead, is the ConnectThread thread. That's the thread that handles the code necessary to connect the socket between the two devices. When I try to connect to a detected device, ConnectThread, in its run() method, creates a new instance of ChatConnection passing the IP address and the port number previously obtained to this constructor:
public ChatConnection(InetAddress srvAddress, int srvPort, String macAddress) throws IOException {
...
connSocket = new Socket(srvAddress, srvPort);
...
}
And here is where the problem occurs. When I test my app on my physical device, all I get is this exception:
W/System.err: java.net.ConnectException: failed to connect to /192.168.49.1 (port 6770): connect failed: ECONNREFUSED (Connection refused)
Of course, I installed my app on a second physical device too, which gets successfully detected and a Wi-Fi Direct connection gets successfully established. But, when comes to this line of code:
connSocket = new Socket(srvAddress, srvPort);
that exception is thrown...
I apologize for the length of this question, but I wanted to be the clearest possible.
I really thank you in advance for any help.
EDIT: I forgot to mention the code for initializing the ServerSocket.
The ServerSocket is initialized in a thread that is started as soon as the Wi-Fi is enabled.
That is, when the WifiP2pBroadcastReceiver (an inner class of the app's Service which extends BroadcastReceiver) catches a WIFI_P2P_STATE_CHANGED_ACTION intent, it checks if the Wi-Fi is enabled and, if enabled, it starts the the thread where the ServerSocket is located:
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
int statoWiFi = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (statoWiFi == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
mNsdService = new NsdProviderThread();
mNsdService.start();
}
The ServerSocket is initialized in the run() method of NsdProviderThread:
public void run() {
...
try {
server = new ServerSocket(0);
} catch (IOException ex) {
return;
}
...
while (!Thread.currentThread().isInterrupted()) {
Socket clientSocket = null;
try {
clientSocket = server.accept();
} catch (IOException ex) {
break;
}
try {
ChatConnection chatConn = new ChatConnection(clientSocket);
synchronized (connections) {
connections.add(chatConn);
}
} catch (IOException ex) {
continue;
}
}
"server" is an instance variable of NsdProviderThread declared as ServerSocket.
It looks like you just need to use the correct port number on both ends.
You're using zero, which from the documentation means:
A port number of 0 means that the port number is automatically
allocated, typically from an ephemeral port range.
So, when you create your ServerSocket, make sure it is listening on the same port that the other device uses to initiate the connection:
private static final int port = 6770;
//.....
try {
server = new ServerSocket(port);
} catch (IOException ex) {
ex.printStackTrace();
}
again! I've finally managed to get my app working. Here's what I've done:
Hard-code the port number;
When you get the group owner address in the ConnectionInfoListener implementation, make sure if it is the IP address of the device in use. If it is not, connect a client socket to the group owner address; otherwise, make your app wait for an incoming connection;
Initialize the ServerSocket as soon as possible (for example, when the app starts up).
In order to get the device actual IP address after a Wi-Fi Direct connection has been established, I've used this function which I've found in this project (which is derived by the original Android WiFiDirectdemo) in the "Utils" class:
public static String getLocalIPAddress() {
/*
* modified from:
*
* http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
*
* */
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
String iface = intf.getName();
if(iface.matches(".*" +p2pInt+ ".*")){
if (inetAddress instanceof Inet4Address) { // fix for Galaxy Nexus. IPv4 is easy to use :-)
return getDottedDecimalIP(inetAddress.getAddress());
}
}
}
}
} catch (SocketException ex) {
Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex);
} catch (NullPointerException ex) {
Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex);
}
return null;
}
"p2pInt" is a private static String costant declared in the Utils class as:
private final static String p2pInt = "p2p-p2p0"
However, in my app, I've changed the "p2p-p2p0" string in "p2p-wlan0" since it looks like the network interface of my device for Wi-Fi Direct has that (different) name.
I hope this can help any developer who's trying to create an app that uses Wi-Fi Direct connectivity.
Pre Marshmallow my app would obtain it's device MAC address via BluetoothAdapter.getDefaultAdapter().getAddress().
Now with Marshmallow Android is returning 02:00:00:00:00:00.
I saw some link(sorry not sure where now) that said you need to add the additional permission
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"/>
to be able to get it. However it isn't working for me.
Is there some additional permission needed to get the mac address?
I am not sure it is pertinent here but the manifest also includes
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
So is there a way to get the local bluetooth mac address?
zmarties is right but you can still get the mac address via reflection or Settings.Secure:
String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");
Access to the mac address has been deliberately removed:
To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs.
(from Android 6.0 Changes)
You can access Mac address from the file
"/sys/class/net/" + networkInterfaceName+ "/address" ,where networkInterfaceName can be wlan0 or eth1.But Its permission may be read-protected,so it may not work in some devices.
I am also attaching the code part which i got from SO.
public static String getWifiMacAddress() {
try {
String interfaceName = "wlan0";
List<NetworkInterface> interfaces = Collections
.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces) {
if (!intf.getName().equalsIgnoreCase(interfaceName)) {
continue;
}
byte[] mac = intf.getHardwareAddress();
if (mac == null) {
return "";
}
StringBuilder buf = new StringBuilder();
for (byte aMac : mac) {
buf.append(String.format("%02X:", aMac));
}
if (buf.length() > 0) {
buf.deleteCharAt(buf.length() - 1);
}
return buf.toString();
}
} catch (Exception exp) {
exp.printStackTrace();
}
return "";
}
First the following permissions have to be added to Manifest;
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
Then,
public static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
String macAddress = Settings.Secure.getString(getContentResolver(), SECURE_SETTINGS_BLUETOOTH_ADDRESS);
After that the application has to be signed with OEM / System key. Tested and verified on Android 8.1.0.
Please use the below code to get the bluetooth mac address. let me know if any issues.
private String getBluetoothMacAddress() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String bluetoothMacAddress = "";
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){
try {
Field mServiceField = bluetoothAdapter.getClass().getDeclaredField("mService");
mServiceField.setAccessible(true);
Object btManagerService = mServiceField.get(bluetoothAdapter);
if (btManagerService != null) {
bluetoothMacAddress = (String) btManagerService.getClass().getMethod("getAddress").invoke(btManagerService);
}
} catch (NoSuchFieldException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
} else {
bluetoothMacAddress = bluetoothAdapter.getAddress();
}
return bluetoothMacAddress;
}
Getting the MAC address via reflection can look like this:
private static String getBtAddressViaReflection() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Object bluetoothManagerService = new Mirror().on(bluetoothAdapter).get().field("mService");
if (bluetoothManagerService == null) {
Log.w(TAG, "couldn't find bluetoothManagerService");
return null;
}
Object address = new Mirror().on(bluetoothManagerService).invoke().method("getAddress").withoutArgs();
if (address != null && address instanceof String) {
Log.w(TAG, "using reflection to get the BT MAC address: " + address);
return (String) address;
} else {
return null;
}
}
using a reflection library (net.vidageek:mirror) but you'll get the idea.
Since below method return null for android O.
String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");
I found new way to get Bluetooth Mac address, you can try by using below command line.
su strings /data/misc/bluedroid/bt_config.conf | grep Address
NOTE: In my case, i was working with root device so my app has super user permission.
As it turns out, I ended up not getting the MAC address from Android. The bluetooth device ended up providing the Android device MAC address, which was stored and then used when needed. Yeah it seems a little funky but on the project I was on, the bluetooth device software was also being developed and this turned out to be the best way to deal with the situation.
Worked great
private String getBluetoothMacAddress() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String bluetoothMacAddress = "";
try {
Field mServiceField = bluetoothAdapter.getClass().getDeclaredField("mService");
mServiceField.setAccessible(true);
Object btManagerService = mServiceField.get(bluetoothAdapter);
if (btManagerService != null) {
bluetoothMacAddress = (String) btManagerService.getClass().getMethod("getAddress").invoke(btManagerService);
}
} catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignore) {
}
return bluetoothMacAddress;
}
I have update my mobile to Android Lollipop, before updating to Lollipop it works fine. Now I am facing problem with network interface.
if (isWifiConnected()) {
Log.d(TAG,"Wifi is connected");
mNetIf = Utils.getActiveNetworkInterface();
String name = mNetIf.getName();
Log.d(TAG, "network interface in constructor" + NetworkInterface.getByName(name));
//do some multicast Operations.
}
If the WiFi is connected I should do some multicast operation in WiFi.
iswifiConnected method
public boolean isWifiConnected(){
ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWifi.isConnected()) {
return true;
}
return false;
}
Utils.getActiveNetworkInterface
public static NetworkInterface getActiveNetworkInterface() {
Enumeration<NetworkInterface> interfaces = null;
try {
interfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
return null;
}
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
/* Check if we have a non-local address. If so, this is the active
* interface.
*
* This isn't a perfect heuristic: I have devices which this will
* still detect the wrong interface on, but it will handle the
* common cases of wifi-only and Ethernet-only.
*/
while (inetAddresses.hasMoreElements()) {
InetAddress addr = inetAddresses.nextElement();
if (!(addr.isLoopbackAddress() || addr.isLinkLocalAddress())) {
return iface;
}
}
}
return null;
}
Log
Wifi is connected
network interface in constructor**[rmnet0][3]t** [/fe80::32e3:daf0:ba51:f971%rmnet0%3][/27.57.104.11]//3g network interface
I am wondering how the app got 3g interface. It should get wlan interface, it work in all other mobile. Is it a bug?
Permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
You are using the ConnectivityManger but, to use the WiFi network in Android, the best choice is to use the WifiManager: it has many features dedicated to Wifi. In particular, if you want to get a NetworkInterface object referencing the WiFi Interface, you can use the following method:
public static NetworkInterface getActiveWifiInterface(Context context) throws SocketException, UnknownHostException {
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
//Return dynamic information about the current Wi-Fi connection, if any is active.
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if(wifiInfo == null) return null;
InetAddress address = intToInet(wifiInfo.getIpAddress());
return NetworkInterface.getByInetAddress(address);
}
public static byte byteOfInt(int value, int which) {
int shift = which * 8;
return (byte)(value >> shift);
}
public static InetAddress intToInet(int value) {
byte[] bytes = new byte[4];
for(int i = 0; i<4; i++) {
bytes[i] = byteOfInt(value, i);
}
try {
return InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
// This only happens if the byte array has a bad length
return null;
}
}
I think the problem is that getInetAddresses() returns a list of interfaces, and getActiveNetworkInterface is only returning the first one no matter what.
And so the interface you are getting depends on the order of the list which getInetAddresses() returns.
That being said, one of the solutions could be: look at the up interface, using isUp().
http://developer.android.com/reference/java/net/NetworkInterface.html#isUp()
Android would turn off the cellular connection to save power when connected to wifi networks, so by looking at only the UP interface, you should able to pin point the WiFi interface.
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
}
I am using the following function to get the local IP address of the Android device:
/**
* Loops through all network interfaces to find one with a connection
* #return the IP of the connected network device, on error returns null
*/
public String getIPAddress()
{
String strIPaddress = null;
try
{
Enumeration<NetworkInterface> enumNetIF = NetworkInterface.getNetworkInterfaces();
NetworkInterface netIF = null;
//loop whilst there are more interfaces
while(enumNetIF.hasMoreElements())
{
netIF = enumNetIF.nextElement();
for (Enumeration<InetAddress> enumIP = netIF.getInetAddresses(); enumIP.hasMoreElements();)
{
InetAddress inetAddress = enumIP.nextElement();
//check for valid IP, but exclude the loopback address
if(inetAddress.isLoopbackAddress() != true)
{
strIPaddress = inetAddress.getHostAddress();
break;
}
}
}
}
catch (SocketException e)
{
Log.e(TAG, e.getMessage());
}
return strIPaddress;
}
However, I also need to know for how long this IP address has been connected for.
I've searched through the InetAddress structure and couldn't find it:
http://developer.android.com/reference/java/net/InetAddress.html
is there another way to find out for how long the local IP address has existed / connected ?
AFAIK, you would have to watch for connectivity changes (via ConnectivityManager, CONNECTIVITY_ACTION, and your own BroadcastReceiver) and track it yourself.
You'll need to create a background service to handle the monitoring and record when changes are made to the ConnectivityManager.
Note that you'll want to make sure the service starts at boot (triggered by the intent android.intent.action.BOOT_COMPLETED), too; otherwise, it will only keep track of connection changes after the user launches the service.