Compass java plugin for Unity Android

Hello,

I'm trying to create a java plugin to get compass info from Android. I started with this example:

http://docwiki.unity3d.com/uploads/Main/AndroidJavaPluginProject.zip

Then, I tried to include the necessary code from:

http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.html

The problem I found is that it is necessary to create a SensorListener and I'm not sure if this will work as a Unity plugin.

Anyone has tried to do this?

This is my piece of code:

private final SensorListener mSensorListener = new SensorListener()
{
    public void onSensorChanged(int sensor, float[] values)
    {
        if (sensor == SensorManager.SENSOR_MAGNETIC_FIELD)
        {
            float xmag = values[0];
            float ymag = values[1];
            float zmag = values[2];
        }
    }

    public void onAccuracyChanged(int sensor, int accuracy)
    {
        int i=0;
    }
};

The alternative is to code the plugin with native code (NDK), but sensor data is only available with Android SDK 2.3 (Almost every android phone runs 2.2 nowadays)

Thanks in advance,

Joel

I think you should be able to do it. However you will have to pull the data from the sensor each cycle, instead of having the data pushed to you from the java EventBus.

The following is just pseudo-code so don't hold me to it but it should be something like:

public class SensorClass {

private Activity mActivity;

float xmag;
float ymag;
float zmag;

private final SensorListener mSensorListener = new SensorListener() {

    public void onSensorChanged(int sensor, float[] values) {
        if (sensor == SensorManager.SENSOR_MAGNETIC_FIELD) {
            xmag = values[0];
            ymag = values[1];
            zmag = values[2];
        }
    }

    public void onAccuracyChanged(int sensor, int accuracy) {
        int i=0;
    }
};

public SensorClass(Activity currentActivity) {
    mActivity = currentActivity;

    mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
    mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

    mSensorManager.registerListener(mSensorListener, mSensor,
            SensorManager.SENSOR_DELAY_GAME);

}

public float getX() {
    return xmag;
}

public float getY() {
    return ymag;
}

public float getZ() {
    return zmag;
}

}

This way you have a standalone java class that is aggregating the sensor updates for you then you just need to instantiate and call the getters from your .cs code

public class CallJavaCode : MonoBehaviour {

private IntPtr  JavaClass;
private float   xValue;
private float   yValue;
private float   zValue;

void Start ()
{

    JavaVM.AttachCurrentThread();

    IntPtr cls_Activity = JNI.FindClass("com/unity3d/player/UnityPlayer");
    int fid_Activity    = JNI.GetStaticFieldID(cls_Activity, "currentActivity", "Landroid/app/Activity;");
    IntPtr obj_Activity = JNI.GetStaticObjectField(cls_Activity, fid_Activity);
    Debug.Log("obj_Activity = " + obj_Activity);

    IntPtr cls_JavaClass    = JNI.FindClass("org/example/SensorClass");
    int mid_JavaClass       = JNI.GetMethodID(cls_JavaClass, "<init>", "(Landroid/app/Activity;)V");
    IntPtr obj_JavaClass    = JNI.NewObject(cls_JavaClass, mid_JavaClass, obj_Activity);

    JavaClass   = JNI.NewGlobalRef(obj_JavaClass);

    // this is where the JNI magic happens
    xValue  = JNI.CallFloatMethod(JavaClass, JNI.GetMethodID(cls_JavaClass, "getX", "()F"))
    yValue  = JNI.CallFloatMethod(JavaClass, JNI.GetMethodID(cls_JavaClass, "getY", "()F"))
    zValue  = JNI.CallFloatMethod(JavaClass, JNI.GetMethodID(cls_JavaClass, "getZ", "()F"))

    }
    }

Then on each update cycle you can call the

xValue  = JNI.CallFloatMethod(JavaClass, JNI.GetMethodID(cls_JavaClass, "getX", "()F"))

methods to get the current X,Y,Z values respectively. Again this is just pseudocode so it probably won't compile :) But you get the idea.

There is a plugin by Prefrontal Cortex in the asset store, which provides access to each and every android sensor. If you don’t want to write your own, you could give it a try.

Demo scene (type into your mobiles’ browser to install): goo.gl/oLkOQ

Forum thread:
http://forum.unity3d.com/threads/101279-GyroDroid-2.0-Access-each-and-every-sensor-on-Android-devices-RELASED

I understand (in theory) how this code works, but i can't get the SensorManager to work.

I managed to build the JavaPluginSample project in Eclipse but the game crashes instantly when i include this part of the code:

mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);

Maybe you can push me in the right direction.

philo

philo, try this:

public SensorClass(Activity currentActivity)
{
    mActivity = currentActivity;
    mSensorManager = (SensorManager) mActivity.getSystemService(mActivity.SENSOR_SERVICE);
    mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
    mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_GAME);
}