11

I am connecting different devices with wifi hotspot AP programatically in my android app, How can i detect the clients being connected and disconnected and to the wifi hotspot AP Programmatically ? Is there any callback event in Android API to give information regarding the connection or disconnection events of individual devices ? Thanks in advance.

Prabhu
  • 590
  • 2
  • 9
  • 22
  • You are only able to control the device which is running your application using `BroadcastReceiver` targeting to `Connectivity`. – Stan Feb 03 '14 at 09:47
  • Duplicate of http://stackoverflow.com/questions/19879708/android-wifi-hotspot-client-connection-events. But that question don't have an answer. – leesei Feb 04 '14 at 08:01

5 Answers5

13

Unfortunately there is no public API to give information about this... But you can read /proc/net/arp file and see the clients connected to your Access Point.

/proc/net/arp file have 6 fields: IP address, HW type, Flags, HW address, Mask and Device

The problem is when a client get disconnected, because it doesn't disappear from the file. A solution may be to do ping to every client and wait for response, but for me this isn't a good solution because some clients don't respond to ping. If you like this solution check this project on GitHub --> https://github.com/nickrussler/Android-Wifi-Hotspot-Manager-Class/tree/master/src/com/whitebyte

What i have did is: read /proc/net/arp and check the FLAGS field, when the value is 0x2 the station is connected and 0x0 is disconnected, but to refresh this field I need to clear ARP cache from time to time, and i did it with this command: ip neigh flush all

I hope i helped you

Amap
  • 151
  • 1
  • 3
  • Have you implemented code to clear ARP and did you able to get updated status of each clients connected? If YES, please share me the code... Thanks in advance. – SomeswarReddy Jun 03 '15 at 12:54
  • 1
    As of now (on API 23, 24 and 26) the flag for each listed device is `0x2` even if the device is disconnected – Cliff Burton Jan 06 '18 at 19:49
  • Hey As mentioned about even after I disconnect on reading /proc/net/arp it shows disconnected device so as it is mentioned in answer that we have to pass command ip neigh flush all.How can I do this?And is rooting necessary to issue this command then? – Nimish Bansal Mar 10 '18 at 19:46
  • Anyone got the answer for getting only the connected clients? – Nimish Bansal Mar 20 '18 at 14:38
  • is it possible to write this arp file? (Like disconnect the devices that are connect in to hotspot) – Dinith Feb 12 '20 at 04:28
12

This method works for me but this is detecting only version 4.0 and above; it is not able to find the devices with version 2.2 or 2.3 which is connected with hotspot.

public void getClientList() {
    int macCount = 0;
    BufferedReader br = null;
    try {
        br = new BufferedReader(new FileReader("/proc/net/arp"));
        String line;
        while ((line = br.readLine()) != null) {
            String[] splitted = line.split(" +");
            if (splitted != null ) {
                // Basic sanity check
                String mac = splitted[3];
                System.out.println("Mac : Outside If "+ mac );
                if (mac.matches("..:..:..:..:..:..")) {
                    macCount++;
                   /* ClientList.add("Client(" + macCount + ")");
                    IpAddr.add(splitted[0]);
                    HWAddr.add(splitted[3]);
                    Device.add(splitted[5]);*/
                    System.out.println("Mac : "+ mac + " IP Address : "+splitted[0] );
                    System.out.println("Mac_Count  " + macCount + " MAC_ADDRESS  "+ mac);
                Toast.makeText(
                        getApplicationContext(),
                        "Mac_Count  " + macCount + "   MAC_ADDRESS  "
                                + mac, Toast.LENGTH_SHORT).show();

                }
               /* for (int i = 0; i < splitted.length; i++)
                    System.out.println("Addressssssss     "+ splitted[i]);*/

            }
        }
    } catch(Exception e) {

    }               
}
Matt
  • 74,352
  • 26
  • 153
  • 180
Prabhu
  • 590
  • 2
  • 9
  • 22
4

Android 10 restricts the permission for access to the /proc/net directory, so some of the solutions above are no longer feasible, but the 'ip' command is still available

private fun getARPIps(): List<Pair<String, String>> {
    val result = mutableListOf<Pair<String, String>>()
    try {
//        val args = listOf("ip", "neigh")
//        val cmd = ProcessBuilder(args)
//        val process: Process = cmd.start()
      val process = Runtime.getRuntime().exec("ip neigh")
        val reader = BufferedReader(InputStreamReader(process.inputStream))
        reader.forEachLine {
            if (!it.contains("FAILED")) {
                val split = it.split("\\s+".toRegex())
                if (split.size > 4 && split[0].matches(Regex("([0-9]{1,3}\\.){3}[0-9]{1,3}"))) {
                    result.add(Pair(split[0], split[4]))
                }
            }
        }
        val errReader = BufferedReader(InputStreamReader(process.errorStream))
        errReader.forEachLine {
            Log.e(TAG, it)
            // post the error message to server
        }
        reader.close()
        errReader.close()
        process.destroy()
    } catch (e: Exception){
        e.printStackTrace()
        // post the error message to server
    }
    return result
}
tigerZ
  • 169
  • 1
  • 7
1
@SuppressWarnings("ConstantConditions")
public static String getClientMacByIP(String ip)
{
    String res = "";
    if (ip == null)
        return res;

    String flushCmd = "sh ip -s -s neigh flush all";
    Runtime runtime = Runtime.getRuntime();
    try
    {
        runtime.exec(flushCmd,null,new File("/proc/net"));
    }

    BufferedReader br;
    try
    {
        br = new BufferedReader(new FileReader("/proc/net/arp"));
        String line;
        while ((line = br.readLine()) != null)
        {
            String[] sp = line.split(" +");
            if (sp.length >= 4 && ip.equals(sp[0]))
            {Assistance.Log(sp[0]+sp[2]+sp[3],ALERT_STATES.ALERT_STATE_LOG);
                String mac = sp[3];
                if (mac.matches("..:..:..:..:..:..") && sp[2].equals("0x2"))
                {
                    res = mac;
                    break;
                }
            }
        }

        br.close();
    }
    catch (Exception e)
    {}

    return res;
}

//--------------------------------------------------------

@SuppressWarnings("ConstantConditions")
public static String getClientIPByMac(String mac)
{
    String res = "";
    if (mac == null)
        return res;

    String flushCmd = "sh ip -s -s neigh flush all";
    Runtime runtime = Runtime.getRuntime();
    try
    {
        runtime.exec(flushCmd,null,new File("/proc/net"));
    }

    BufferedReader br;
    try
    {
        br = new BufferedReader(new FileReader("/proc/net/arp"));
        String line;
        while ((line = br.readLine()) != null)
        {
            String[] sp = line.split(" +");
            if (sp.length >= 4 && mac.equals(sp[3]))
            {
                String ip = sp[0];
                if (ip.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}") && sp[2].equals("0x2"))
                {
                    res = ip;
                    break;
                }
            }
        }

        br.close();
    }
    catch (Exception e)
    {}

    return res;
}
Ali Bagheri
  • 3,068
  • 27
  • 28
-1

you can use BroadcastReciever "android.net.wifi.WIFI_HOTSPOT_CLIENTS_CHANGED" to detect client connection. In your AndroidManifest:

<receiver
            android:name=".WiFiConnectionReciever"
            android:enabled="true"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.net.wifi.WIFI_HOTSPOT_CLIENTS_CHANGED" />
            </intent-filter>
        </receiver>

and in your activity

IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction("android.net.wifi.WIFI_HOTSPOT_CLIENTS_CHANGED");
                        rcv = new WiFiConnectionReciever();
                        registerReceiver(rcv,
                                mIntentFilter);
HraD
  • 1