Android Question Use foreign Java code

Blueforcer

Well-Known Member
Licensed User
Longtime User
Were working with industrial Android HMI Panels.
In our application we need to set the ethernet settings.
I got a Android studio project from the manufacturer.
But i dont know how to use it in B4A. I tried inline java but getting lots of error due my missing java knowledge.
Can someone help me to convert this?

Java:
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.EthernetManager;
import android.net.IpConfiguration;
import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.net.StaticIpConfiguration;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.a).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                insetNet(MainActivity.this,"192.168.1.111","255.255.255.0","192.168.1.0","192.168.1.0","144.144.144.144");
            }
        });
        findViewById(R.id.b).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                insetNet(MainActivity.this,"192.168.1.122","255.255.255.0","192.168.1.0","192.168.1.0","144.144.144.144");
            }
        });

    }


    @SuppressLint("WrongConstant")
    public void insetNet(Context context, String address, String netmask, String gateway, String dns1, String dns2){
        Log.e("insetNet","address="+address+"   netmask="+netmask+"   gateway="+gateway+"  dns1="+dns1+"  dns2="+dns2);
        mEthManager = (EthernetManager)context.getSystemService("ethernet");
        Inet4Address inetAddr = getIPv4Address(address);
        int prefixLength = maskStr2InetMask(netmask);
        InetAddress gatewayAddr = getIPv4Address(gateway);
        InetAddress dnsAddr = getIPv4Address(dns1);
        mStaticIpConfiguration = new StaticIpConfiguration();
        //mStaticIpConfiguration.ipAddress = new LinkAddress(inetAddr, prefixLength);
        updateLinkAddress(inetAddr, prefixLength);
        mStaticIpConfiguration.gateway = gatewayAddr;
        mStaticIpConfiguration.dnsServers.add(dnsAddr);
        mStaticIpConfiguration.dnsServers.add(getIPv4Address(dns2));
        mIpConfiguration = new IpConfiguration(IpConfiguration.IpAssignment.STATIC, IpConfiguration.ProxySettings.NONE, mStaticIpConfiguration, null);
        mEthManager.setConfiguration(mIpConfiguration);
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void updateLinkAddress(Inet4Address inetAddr, int prefixLength){
        Class<?> clazz = null;
        try {
            clazz = Class.forName("android.net.LinkAddress");
        } catch (Exception e) {
            // TODO: handle exception
        }

        Class[] cl = new Class[]{InetAddress.class, int.class};
        Constructor cons = null;

        //取得所有构造函数
        try {
            cons = clazz.getConstructor(cl);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        //给传入参数赋初值
        Object[] x = {inetAddr, prefixLength};
        try {
            mStaticIpConfiguration.ipAddress = (LinkAddress) cons.newInstance(x);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    EthernetManager mEthManager;
    IpConfiguration mIpConfiguration;
    StaticIpConfiguration mStaticIpConfiguration;
    private Inet4Address getIPv4Address(String text) {
        try {
            return (Inet4Address) NetworkUtils.numericToInetAddress(text);
        } catch (IllegalArgumentException | ClassCastException e) {
            return null;
        }
    }
    private int maskStr2InetMask(String maskStr) {
        StringBuffer sb;
        String str;
        int inetmask = 0;
        int count = 0;
        /*
         * check the subMask format
         */
        Pattern pattern = Pattern.compile("(^((\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])$)|^(\\d|[1-2]\\d|3[0-2])$");
        if (pattern.matcher(maskStr).matches() == false) {
            Log.e("ethernet", "subMask is error");
            return 0;
        }

        String[] ipSegment = maskStr.split("\\.");
        for (int n = 0; n < ipSegment.length; n++) {
            sb = new StringBuffer(Integer.toBinaryString(Integer.parseInt(ipSegment[n])));
            str = sb.reverse().toString();
            count = 0;
            for (int i = 0; i < str.length(); i++) {
                i = str.indexOf("1", i);
                if (i == -1)
                    break;
                count++;
            }
            inetmask += count;
        }
        return inetmask;
    }
}
 

OliverA

Expert
Licensed User
Longtime User
See code below.

The issues I ran into are:
(A) this seems to require a special android.jar file that exposes the hidden classes within android.jar (such as android.net.EthernetManager)
(B) it seems to require some java compiler flags (--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED) that would be simple in B4J but I can't seem to figure out how to do in B4A.

(A) I solved via https://github.com/anggrayudi/android-hidden-api (I happened to have SDK 28 installed, so I downloaded the appropriate android.jar for SDK 28)
(B) is the showstopper (without being able to set this and maybe more flags, the project won't compile). If (B) can be resolved (which may not be an issue, just me not knowing how to do it), then it should be as simple as:

B4X:
    Dim jo As JavaObject = Me
    Dim ctx As JavaObject
    ctx.InitializeContext
    jo.RunMethod("insetNet", Array (ctx, "192.168.1.122","255.255.255.0","192.168.1.0","192.168.1.0","144.144.144.144"))

Here's the #if java/#end if block for the code in post #1:
B4X:
#if java

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.EthernetManager;
import android.net.IpConfiguration;
import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.net.StaticIpConfiguration;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.regex.Pattern;

    @SuppressLint("WrongConstant")
    public void insetNet(Context context, String address, String netmask, String gateway, String dns1, String dns2){
        Log.e("insetNet","address="+address+"   netmask="+netmask+"   gateway="+gateway+"  dns1="+dns1+"  dns2="+dns2);
        mEthManager = (EthernetManager)context.getSystemService("ethernet");
        Inet4Address inetAddr = getIPv4Address(address);
        int prefixLength = maskStr2InetMask(netmask);
        InetAddress gatewayAddr = getIPv4Address(gateway);
        InetAddress dnsAddr = getIPv4Address(dns1);
        mStaticIpConfiguration = new StaticIpConfiguration();
        //mStaticIpConfiguration.ipAddress = new LinkAddress(inetAddr, prefixLength);
        updateLinkAddress(inetAddr, prefixLength);
        mStaticIpConfiguration.gateway = gatewayAddr;
        mStaticIpConfiguration.dnsServers.add(dnsAddr);
        mStaticIpConfiguration.dnsServers.add(getIPv4Address(dns2));
        mIpConfiguration = new IpConfiguration(IpConfiguration.IpAssignment.STATIC, IpConfiguration.ProxySettings.NONE, mStaticIpConfiguration, null);
        mEthManager.setConfiguration("hello",mIpConfiguration);
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void updateLinkAddress(Inet4Address inetAddr, int prefixLength){
        Class<?> clazz = null;
        try {
            clazz = Class.forName("android.net.LinkAddress");
        } catch (Exception e) {
            // TODO: handle exception
        }

        Class[] cl = new Class[]{InetAddress.class, int.class};
        Constructor cons = null;

        try {
            cons = clazz.getConstructor(cl);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        Object[] x = {inetAddr, prefixLength};
        try {
            mStaticIpConfiguration.ipAddress = (LinkAddress) cons.newInstance(x);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    EthernetManager mEthManager;
    IpConfiguration mIpConfiguration;
    StaticIpConfiguration mStaticIpConfiguration;
    private Inet4Address getIPv4Address(String text) {
        try {
            return (Inet4Address) NetworkUtils.numericToInetAddress(text);
        } catch (IllegalArgumentException | ClassCastException e) {
            return null;
        }
    }
    private int maskStr2InetMask(String maskStr) {
        StringBuffer sb;
        String str;
        int inetmask = 0;
        int count = 0;
        /*
         * check the subMask format
         */
        Pattern pattern = Pattern.compile("(^((\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])$)|^(\\d|[1-2]\\d|3[0-2])$");
        if (pattern.matcher(maskStr).matches() == false) {
            Log.e("ethernet", "subMask is error");
            return 0;
        }

        String[] ipSegment = maskStr.split("\\.");
        for (int n = 0; n < ipSegment.length; n++) {
            sb = new StringBuffer(Integer.toBinaryString(Integer.parseInt(ipSegment[n])));
            str = sb.reverse().toString();
            count = 0;
            for (int i = 0; i < str.length(); i++) {
                i = str.indexOf("1", i);
                if (i == -1)
                    break;
                count++;
            }
            inetmask += count;
        }
        return inetmask;
    }

#End If
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
What happens with Java 8?
javac 1.8.0_402-402
An exception has occurred in the compiler (1.8.0_402-402). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.NullPointerException
at com.sun.tools.javac.code.Symbol$ClassSymbol.isSubClass(Symbol.java:1020)
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
You should start with the Android Studio project and see how it compiles. Maybe the manufacturer already included a modified framework that will work.
But if one looks up the error message, it looks like the --add-exports would do the trick.

Link:
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Looks like this may be one of the edge cases that can only be solved by keeping the project in Android Studio. :-(
 
Upvote 0
Top