2

I created a Java plugin that utilizes the UsbManager devices to communicate with a specified serial device. I'm using Android Studio to run the plugin and can write to the proper device, but I don't understand how to integrate my code with Unity. I pass the Context in the constructor so I can create the UsbManager, but I don't know how to this in Unity or if there's another way to get the Context.

What's the proper way to pass the Context from Unity to my plugin? I'm also not sure if my function is working in Unity, because I don't know if permissions are needed for USB as well in the manifest file.

Unity Code:

void Start()
{
        ajc = new AndroidJavaObject("com.company.dg.USBController");
        int connected = ajc.Call<int>("startUSB");
}

Java Code:

public class USBController {

    private Context context;
    private static final String ACTION_USB_PERMISSION = "com.company.dg.USB_PERMISSION";
    private final int BAUD_RATE = 19200;

    private int bytesRead;
    private byte[] readBuffer;
    private UsbManager usbManager;
    private UsbDeviceConnection connection;
    private UsbSerialDevice serial;
    private UsbDevice dg = null;

    public USBController(Context context){
        this.context = context;
    }

    public int startUSB(){
        //usbManager = (UsbManager) context.getSystemService(context.USB_SERVICE);
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        UsbDevice dg = null;

        if(deviceList.size() == 0){
            return -2;
        }
        // 1st and only device
        dg = deviceList.values().iterator().next();

        if(dg != null){
            PendingIntent pi = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
            usbManager.requestPermission(dataglove, pi);
            UsbDeviceConnection connection = usbManager.openDevice(dataglove);

            UsbSerialDevice serial = UsbSerialDevice.createUsbSerialDevice(dg, connection);
            serial.open();
            serial.setBaudRate(BAUD_RATE);
            serial.setDataBits(UsbSerialInterface.DATA_BITS_8);
            serial.setStopBits(UsbSerialInterface.STOP_BITS_1);
            serial.setParity(UsbSerialInterface.PARITY_NONE);
            serial.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
            serial.read(callback);
        } else {
            return -1;
        }
        return 0;
    }

    private UsbSerialInterface.UsbReadCallback callback = new UsbSerialInterface.UsbReadCallback() {
        @Override
        public void onReceivedData(byte[] data) {
            bytesRead = data.length;
            readBuffer = data;
        }
    };
karamazovbros
  • 950
  • 1
  • 11
  • 40

1 Answers1

1

What's the proper way to pass the Context from Unity to my plugin?

C# side:

Your USBController class has a constructor that takes Context as an argument. Before calling the startUSB function, obtain the Unity Context then send it to the constructor when you're creating an instance of USBController.

Get Unity Context:

    AndroidJavaClass unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    AndroidJavaObject unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
    AndroidJavaObject unityContext = unityActivity.Call<AndroidJavaObject>("getApplicationContext");

Send the Context to your Java code when creating an instance of it:

ajc = new AndroidJavaObject("com.bebopsensors.dg.USBController", unityContext);

Now, you can call your startUSB function:

int connected = ajc.Call<int>("startUSB");

Java Side:

In your startUSB function, you can now use the Context with the getSystemService. I noticed you commented that out. Note that the context.USB_SERVICE should be Context.USB_SERVICE. The c in Context should be capitalized.

public int startUSB()
{
    usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
    ....
    ....
}

Don't know if permissions are needed for USB as well in the manifest file.

Not really sure about that but I believe that calling the requestPermission function which you did should be enough to handle that. If this is not working then I suggest you test your Java program in Android only and Without Unity to see if it's working. If it works there, the solution I suggested should also work.

Abra
  • 19,142
  • 7
  • 29
  • 41
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • thanks for the help, but it still doesn't work on the Unity side. It works when I make a build from Android Studio and use the app with a serial device plugged in, but in Unity it doesn't work. – karamazovbros Sep 25 '18 at 17:32
  • What do you consider as "working" and what's going on on the Unity side now? – Programmer Sep 25 '18 at 17:41
  • Within the startUSB function, I use serial to write a byte array message to signal the device to turn on. This will also turn on an LED, but in Unity it never gets to the write point, which makes me think my class wasn't loaded correctly or something is wrong before I call the function in Unity. In Unity, the app runs, but no read data is being received from the device and the device never gets the write message. – karamazovbros Sep 25 '18 at 17:45
  • First thing I suggest you do now is to check if there is a secret error being thrown by Android when your program is running. [This](https://stackoverflow.com/a/44690501/3785314) post shows how to obtain error log from Android. – Programmer Sep 25 '18 at 17:54
  • Hello @karamazovbros have you got this to work eventually? I am trying to do the same thing and found your post. Thank you! – HeyThere Aug 13 '19 at 18:19
  • @HeyThere I did get it working. As I recall I forgot to include the Android manifest file in the unity plugins folder. Unfortunately, I've switched from serial devices so I don't have current code to show, but this example looks correct. – karamazovbros Aug 13 '19 at 19:59