Using Java ConnectivityManager to allow Android to use both Wifi and (local) Ethernet at the same time

Viewed 44

I have an Android app that runs a motor controller via ethernet and connects to some servers for API operations over wifi. Using Android Studio's simulator I can use both wifi and ethernet at the same time and everything works fine. However, when I use my actual android tablet it only allows me to use ethernet OR wifi.

The android tablet is running android 7.1.2. I have the setting "Wifi Ethernet Share" toggled ON in network settings on the tablet which appears to allow wifi to be connected to the internet when the device is also connected to ethernet. With this setting OFF, the app prioritizes ethernet and I cannot use Wifi for API operations.

Here is my class which handles Modbus operations (reading from the motor controller over ethernet):

public class ModbusRead {

    private static final String TAG = "MODBUS READ";

    ModbusClient mClientReadAll;

    public ModbusRead()
    {
//        IP = "192.168.124.2";
//        port = 502;
        mClientReadAll = new ModbusClient(Modbus.IP, Integer.valueOf(Modbus.port));
        mClientReadAll.setUnitIdentifier((byte)255);
    }

    public Runnable readAll()
    {
        return () -> {

                ReadAllFromModbus mReadAll = new ReadAllFromModbus();
                mReadAll.execute();
        };
    }

    public class ReadAllFromModbus extends AsyncTask<String, Void, String> {

        private final String TAG = "READ ALL FROM MODBUS";

        @Override
        protected String doInBackground(String... params) {

            try
            {
                mClientReadAll.Connect();

                // get all registers
                int[] registerBlock = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_MODE.getRegister()- 1, 16);
                int[] wideRegisters = new int[] {
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_POSITION.getRegister() - 1, 2)),
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_TARGET_POSITION.getRegister() - 1, 2)),
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ROM_DELTA.getRegister() - 1, 2)),
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_REWIND_ZERO.getRegister() - 1, 2))
                };
                int[] tensionRegister = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_TENSION.getRegister() - 1, 1);

                Modbus.updateAllRegisters(registerBlock, wideRegisters, tensionRegister);

            }
            catch (Exception e)
            {
                Log.i(TAG, "ERROR IN GETTING ALL REGISTERS LOOP: " + e.getMessage());
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            Log.i(TAG, "CURRENT MODE: " + State.OP_MODE);
            try
            {
                mClientReadAll.Disconnect();
            }
            catch(Exception e)
            {
                Log.i(TAG, "ERROR IN DISCONNECTING");
            }
        }
    }
}

Here is the relevant code from my MainActivity.java class that is the launch activity of my app:

final ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);

        final NetworkRequest requestEthernet = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
                .build();

        final ConnectivityManager.NetworkCallback cbEthernet = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {

                // connectivityManager.bindProcessToNetwork(network);

                try
                {
                    // Modbus.IP = "192.168.124.2"
                    // Modbus.port = 502
                    Log.i(TAG, "TRYING TO BIND SOCKET...");

                    Socket socket = new Socket(Modbus.IP, Modbus.port);

                    Log.i(TAG, "SOCKET CREATED..." + socket.getInetAddress());

                    network.bindSocket(socket);

                    Log.i(TAG, "BOUND ETHERNET");

                    ModbusRead modbusRead = new ModbusRead();

                    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
                    executorService.scheduleAtFixedRate(modbusRead.readAll(), 2000, 250, TimeUnit.MILLISECONDS);

                }
                catch (Exception e)
                {
                    e.printStackTrace();
                    Log.i(TAG, "EXCEPTION: " + e.getMessage());
                }
            }
        };


        connectivityManager.requestNetwork(requestEthernet, cbEthernet);

I was pointed to this type of solution by user @AlwaysLearning who helped me get this far in a different post. My problem now is that when I try and create the socket, it hangs until eventually throwing a "Connection Timed Out" exception. If I use the commented-out command of connectivityManager.bindProcessToNetwork(network); instead of the socket-creation code block it does connect to the motor controller no problem, but then I cannot use wifi for API operations as the whole system is directing network traffic through ethernet.

Does anyone know how to proceed from here? I only have some experience in Java, none in networking, and am brand new to Android itself so any help at all is appreciated!

0 Answers
Related