Search Unity

AndroidJavaObject / JNI with float arrays

Discussion in 'Scripting' started by fherbst, Jul 8, 2019.

  1. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    I have a particular piece of Android JNI code that I just can't get to work.

    Code (CSharp):
    1.     public float[] getOrientation()
    2.     {
    3.         const int matrix_size = 16;
    4.         float[] R = new float[matrix_size];
    5.         float[] I = new float[matrix_size];
    6.         float[] values = new float[3];
    7.  
    8.         if (map[Sensor.Type.Accelerometer].sensor != null && map[Sensor.Type.MagneticField].sensor != null)
    9.         {
    10.             SensorManager.getRotationMatrix(R, I, map.get(Sensor.TYPE_ACCELEROMETER).values, map.get(Sensor.TYPE_MAGNETIC_FIELD).values);
    11.             SensorManager.getOrientation(R, values);
    12.         }
    13.  
    14.         return values;
    15.     }
    The part about the map / sensor stuff is easy and works, but I can't get the in/out array creation to work. The main issue is that I don't seem to be able to construct AndroidJavaObjects that hold R, I and "values". There's a constructor for AndroidJavaObject that sounded promising
    Code (CSharp):
    1. _R = new AndroidJavaObject(new object[] { R });
    , but only exists in the Editor (??) and throws a compiler error saying the signature should be (string, params object[]).

    What's the right way to create those arrays and pass them into the function? Do I have to resort to raw JNI methods for calling it with IntPtr arguments?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    I have done this to pass Color32[] blobs over to a native plugin, basically pinning the object and passing it over. This approach works well with iOS, Android (the C code was JNI-compiled into an AAR), MacOSX and Win32, all same-same on the C# side (except for subtle naming differences in the DLLImport decorator of the extern declarations).

    Here is the codelets I used, first the calling site:

    Code (csharp):
    1.     public static void PinTextureAndCallNativeRenderColor( Texture2D t2d, int span, bool clean = false)
    2.     {
    3.         if (clean || (pixels == null) || (span != pixelSpan))
    4.         {
    5.             pixelSpan = span;
    6.             pixels = new Color32[ pixelSpan * pixelSpan];
    7.         }
    8.  
    9.         GCHandle handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
    10.         try
    11.         {
    12.             dispatcher1_rendercolor( handle.AddrOfPinnedObject(), span, 0);
    13.         }
    14.         finally
    15.         {
    16.             if (handle.IsAllocated)
    17.             {
    18.                 handle.Free ();
    19.             }
    20.         }
    21.      
    22.         t2d.SetPixels32( pixels);
    23.         t2d.Apply();
    24.     }
    And then the C# interop declaration was:

    Code (csharp):
    1.     [DllImport ("vanilib")]
    2.     private static extern void dispatcher1_rendercolor ( System.IntPtr pixels, int span, int flags);