Callback via AndroidJavaProxy
Overview
In this guide, we will outline how to utilize Unity's AndroidJavaProxy object for the ability to receive callbacks from our Android Plug-in. This class can be used to implement any java interface. Any java vm method invocation matching the interface on the proxy object will automatically be passed to the C# implementation.
Create a callback in Android Studio
The first thing we need to do is create a callback that we can use.
- Right click the folder that contains
AccelerometerListener.java
, select New->Java Class. Select Interface and call itSensorDataCallback
- Inside this file, define a function called
onSensorData
with 2 parameters,String sensorData, long timestamp
package com.magicleap.accelerometerlibrary;
public interface SensorDataCallback {
void onSensorData(String sensorData, long timestamp);
}
Using the callback in our Android Plug-in
Now that we have a callback, we need to use it inside of our plug-in. We will do this by calling callback.onSensorData
when a callback has been assigned inside of the onSensorChanged
function.
- First, let's modify the
startSensorListening
function to take a new parameter,SensorDataCallback sensorDataCallback
and assign it to a variable for later use,SensorDataCallback callback
private SensorDataCallback callback = null;
public void startSensorListening(SensorDataCallback sensorDataCallback)
{
//initialize sensorManager
sensorManager = (SensorManager) unityActivity.getSystemService(Context.SENSOR_SERVICE);
//use sensorManager to obtain the devices default accelerometer
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//register this sensor to begin listening and receiving SensorEventListener callbacks
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
//assign callback
callback = sensorDataCallback;
}
- Now, let's modify the
onSensorChanged
function to callcallback.onSensorData
and pass the data and timestamp with it.
@Override
public void onSensorChanged(SensorEvent event)
{
if(callback != null)
{
long timestamp = event.timestamp;
String sensorData = Arrays.toString(event.values);
callback.onSensorData(sensorData, timestamp);
}
}
Your plug-in class should now look like this:
package com.magicleap.accelerometerlibrary;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import java.util.Arrays;
public class AccelerometerListener implements SensorEventListener
{
private static Activity unityActivity;
private SensorManager sensorManager;
private Sensor accelerometer;
private SensorDataCallback callback = null;
public static void setUnityActivity(Activity _activity)
{
unityActivity = _activity;
}
@Override
public void onSensorChanged(SensorEvent event)
{
if(callback != null)
{
long timestamp = event.timestamp;
String sensorData = Arrays.toString(event.values);
callback.onSensorData(sensorData, timestamp);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
public void startSensorListening(SensorDataCallback sensorDataCallback)
{
//initialize sensorManager
sensorManager = (SensorManager) unityActivity.getSystemService(Context.SENSOR_SERVICE);
//use sensorManager to obtain the devices default accelerometer
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//register this sensor to begin listening and receiving SensorEventListener callbacks
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
callback = sensorDataCallback;
}
}
Build a new Android Archive file
Now that the plug-in updates are finished, go ahead and build a new .aar file. We will need to paste this into our Unity project.
- In the Android Studio toolbar, navigate to Build->Make Module 'ExampleSensorPlugin.AccelerometerLibrary'.
- In a file explorer, navigate to
ExampleSensorPlugin\AccelerometerLibrary\build\outputs\aar\AccelerometerLibrary-debug.aar
Copy this file! - Paste this file inside your Unity project at
Assets\Plugins\Android
. If you already have anAccelerometerLibrary-debug
file at this location, delete it before you paste the new version.
Create AndroidJavaProxy
object in Unity
Now that we have our callback setup in the Android plug-in, it's time to move over to the Unity side to begin using it!
- Create a new C# script called
SensorDataCallbackProxy
. This script will Inherit fromAndroidJavaProxy
.
public class SensorDataCallbackProxy : AndroidJavaProxy
{
}
- Add a constructor that calls the base constructor from
AndroidJavaProxy
. As a parameter, we will need to pass our plugin-in packagename along with the name of the callback script we made in our plug-in. For this example, the full string iscom.magicleap.accelerometerlibrary.SensorDataCallback
public class SensorDataCallbackProxy : AndroidJavaProxy
{
public SensorDataCallbackProxy() : base("com.magicleap.accelerometerlibrary.SensorDataCallback")
{
}
}
- Finally, we need to add a function with the same signature as the one from our Android plug-in
SensorDataCallback
script. You can just copy the function signature from that file if you like. Inside this function, we will just log the sensorData and timestamp to the console.
public void onSensorData(string sensorDataString, long timestamp)
{
Debug.Log($"Sensor Data: {sensorDataString} at time: {timestamp}");
}
The full SensorDataCallbackProxy
script should look like this:
using UnityEngine;
public class SensorDataCallbackProxy : AndroidJavaProxy
{
public SensorDataCallbackProxy() : base("com.magicleap.accelerometerlibrary.SensorDataCallback") { }
public void onSensorData(string sensorDataString, long timestamp)
{
Debug.Log($"Sensor Data: {sensorDataString} at time: {timestamp}");
}
}
Using AndroidJavaProxy object as a callback
The last step here will be modifying our AccelerometerPluginManager
script to accomodate for the new parameter we added to startSensorListening
.
- Inside of the
AccelerometerPluginManager
script, let's add a new variable to store our callbackSensorDataCallbackProxy callbackProxy
. - Now, in the start function, locate the section where we call
startSensorListening
. Inside this function, let's create a newcallbackProxy
object like this:callbackProxy = new SensorDataCallbackProxy();
- Next, we will need to pass the
callbackProxy
variable we just created above tostartSensorListening
. The final script should look like this:
using UnityEngine;
public class AccelerometerPluginManager : MonoBehaviour
{
private AndroidJavaClass unityClass;
private AndroidJavaObject unityActivity;
private AndroidJavaObject pluginInstance;
private SensorDataCallbackProxy callbackProxy;
// Start is called before the first frame update
void Start()
{
unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
pluginInstance = new AndroidJavaObject("com.magicleap.accelerometerlibrary.AccelerometerListener");
if (pluginInstance != null)
{
Debug.Log("Plugin Instance Loaded!");
pluginInstance.CallStatic("setUnityActivity", unityActivity);
// Create the callback proxy
callbackProxy = new SensorDataCallbackProxy();
pluginInstance.Call("startSensorListening", callbackProxy);
}
}
}
Build and Run the project
That's it! Now you can build and run this Unity project on your ML2 device!
You will see the sensor values being logged to the console when the app is running.