Search code examples
androidshelladbcommand-line-arguments

Toggle android device data connection


I need to toggle data connection on my android device connected via usb to my system using C# code. Searching the web, I found madb and madbee libraries to manipulate devices from pc, but seems there is no such functionality in these libraries(I couldn't find straight-forward documentations).

Most examples are all about file operations and package management.

My questions:

1) Is it possible to toggle android data connection using my C# program??

2) Is there any shell-command to do this??

3) Are there any other libraries( in other languages) that are capable of this operation??

Any useful links can also be helpful.

Thanks in advance.


Solution

  • Special thanks to @Nick Cardoso for his detailed and useful answer(awarded below).

    I found the solution which is working on both ROOTED and UNROOTED devices(without requiring to install any app on device).

    Since MabBee library has some problems with x86 and x64 architectures (problem with MoreLinq library), I decided not to use MabBee and execute ShellCommands directly from adb.exe file using C# Process class(probably possible in other languages). The only three necessary files are adb.exe, AdbWinApi.dll and AdbWinUsbApi.dll(all exist in android sdk platform-tools folder)

    I created two classes MyAdbManager.cs and MyDevice.cs as below:

    MyAdbManager.cs

    public class MyAdbManager
        {
            private string _adbFileName;
    
            public MyAdbManager(string adbFileName)
            {
                _adbFileName = adbFileName;
            }
    
            public string ExecuteShellCommand(string command)
            {
                Process proc = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = _adbFileName,
                        Arguments = command,
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        CreateNoWindow = true
                    }
                };
    
                proc.Start();
                return proc.StandardOutput.ReadToEnd().Trim();
            }
    
            //this method skips unauthorized devices, becuase commands do not execute
            //on unauthorized devices and we need to run adb kill-server, which
            //doesnt solve the problem all the time.
            public List<MyDevice> GetDevices()
            {
                string output = ExecuteShellCommand("devices");
                List<string> serials = output.Split('\n').ToList();
                serials = serials.GetRange(1, serials.Count - 1); //skip the first line of output
                List<MyDevice> myDevices = new List<MyDevice>();
                foreach (var item in serials)
                {
                    if (item.Contains("device"))
                    {
                        myDevices.Add(new MyDevice(item.Split('\t')[0], _adbFileName));
                    }
                }
    
                return myDevices;
            }
        }
    

    MyDevice.cs

    public class MyDevice
        {
            private string _adbFileNme;
            public string Serial { get; }
            public string Model { get; }
            public string Product { get; }
    
            public MyDevice(string serial, string adbFileName)
            {
                _adbFileNme = adbFileName;
                Serial = serial;
                Model = GetSpecificProperty("ro.product.model");
                Product = GetSpecificProperty("ro.build.product");
            }
    
            public override string ToString()
            {
                return $"Model: {Model}, Serial: {Serial}, Product: {Product}";
            }
            public string ExecuteShellCommand(string command)
            {
                Process proc = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = _adbFileNme,
                        Arguments = command,
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        CreateNoWindow = true
                    }
                };
    
                proc.Start();
                return proc.StandardOutput.ReadToEnd().Trim();
            }
    
            public string GetAllPropertirs()
            {
                return ExecuteShellCommand($"-s {Serial} shell getprop");
            }
    
            public string GetSpecificProperty(string propertyName)
            {
                return ExecuteShellCommand($"-s {Serial} shell getprop {propertyName}");
            }
    
            public void EnableData()
            {
                ExecuteShellCommand($"-s {Serial} shell svc data enable");
            }
    
            public void DisableData()
            {
                ExecuteShellCommand($"-s {Serial} shell svc data disable");
            }
    
            public void RestartData()
            {
                DisableData();
                EnableData();
            }
        }
    

    Having these classes, we can use simple code as below to toggle data connection on/off:

    Usage:

    MyAdbManager manager = new MyAdbManager("/path/to/adb.exe"); // with AdbWinApi.dll and AdbWinUsbApi.dll files in directory
    myDevices = manager.GetDevices();
    myDevices[0].EnableData(); 
    myDevices[1].DisableData();
    myDevices[2].RestartData();
    

    We can execute raw shell commands on each device or with MyAdbManager. We can also extend this class to suite our needs like what I did for geting properties of device:

    Other usages:

    Console.WriteLine(myDevices[0].GetAllPropertirs());
    Console.WriteLine(myDevices[0].GetSpecificProperty("ro.build.version.release"));
    Console.WriteLine(myDevices[0].GetSpecificProperty("ro.build.version.incremental"));
    Console.WriteLine(myDevices[0].GetSpecificProperty("vzw.os.rooted"));
    Console.WriteLine(myDevices[0].GetSpecificProperty("wifi.interface"));
    

    NOTE: Just enable usb debugging on your device and check "Always Allow usb debugging from this computer". Make sure that you get "device" state after the serial number. By running "adb devices" command from adb shell, you will get sth like this:

    List of devices attached
    48a4ce9f        device      //This device will work
    de16d6b2        offline     //This device will not work
    g5e23f2a        unauthorize //This device will not work
    

    If you don't get "device" state(like second and third devices above), disconnect cable from device side and reconnect again.

    That's all.

    My special thanks to @Nick Cardoso again because this answer is based on his answer.