Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
acc9864283
commit
96a281873c
|
@ -0,0 +1,292 @@
|
|||
package fr.quentinroy.plugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
|
||||
import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.PluginResult;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Sensors extends CordovaPlugin {
|
||||
|
||||
// Receives sensor updates.
|
||||
private CallbackContext eventCallback;
|
||||
// Register the listeners with a hash created with getHash.
|
||||
private Map<String, SensorEventListener> listeners = new HashMap<String, SensorEventListener>();
|
||||
// The activity's sensor manager.
|
||||
private SensorManager sensorManager;
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param cordova The context of the main Activity.
|
||||
* @param webView The CordovaWebView Cordova is running in.
|
||||
*/
|
||||
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
||||
super.initialize(cordova, webView);
|
||||
this.sensorManager = (SensorManager) cordova
|
||||
.getActivity()
|
||||
.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackContext The callback id used when calling back into JavaScript.
|
||||
* @return True if the action was valid.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
if (action.equals("registerCallback")) {
|
||||
registerCallback(args, callbackContext);
|
||||
} else if (action.equals("subscribe")) {
|
||||
subscribe(args, callbackContext);
|
||||
} else if (action.equals("unsubscribe")) {
|
||||
unsubscribe(args, callbackContext);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This register the callback that should be called when a sensor event is received (any sensor
|
||||
* event).
|
||||
*
|
||||
* @param args The arguments of the registration call. Currently ignored.
|
||||
* @param callbackContext The callback context to register as callback for every events.
|
||||
*/
|
||||
private void registerCallback(JSONArray args, CallbackContext callbackContext)
|
||||
throws JSONException {
|
||||
if (this.eventCallback != null) {
|
||||
callbackContext.error("Callback already exist");
|
||||
}
|
||||
this.eventCallback = callbackContext;
|
||||
// Send the expected confirmation (JS is expecting for this).
|
||||
PluginResult result = new PluginResult(
|
||||
PluginResult.Status.OK,
|
||||
"registered"
|
||||
);
|
||||
result.setKeepCallback(true);
|
||||
callbackContext.sendPluginResult(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribed to a sensor event. Following this call, the registered callback will be called
|
||||
* each time a new value is received from the corresponding sensor.
|
||||
*
|
||||
* @param args The subscription arguments. Must contains two strings:
|
||||
* - the sensor type's constant name (as defined by
|
||||
* https://developer.android.com/guide/topics/sensors/sensors_overview.html
|
||||
* but without the "TYPE_" prefix)
|
||||
* - the sampling period's constant name (as accepted by registerLister
|
||||
* https://developer.android.com/reference/android/hardware/SensorManager.html#registerListener(android.hardware.SensorEventListener,%20android.hardware.Sensor,%20int)
|
||||
* without the "SENSOR_DELAY_" prefix.
|
||||
* @param callbackContext The callback context to receive confirmation of the subscription.
|
||||
* @throws JSONException Thrown when the arguments cannot be properly parsed.
|
||||
*/
|
||||
private void subscribe(JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
if (this.eventCallback == null) {
|
||||
callbackContext.error("Cannot subscribe to anything before registering a callback");
|
||||
}
|
||||
|
||||
// Fetch and check the target sensor.
|
||||
final String sensorTypeName = args.getString(0);
|
||||
int sensorType;
|
||||
try {
|
||||
sensorType = Sensor.class
|
||||
.getDeclaredField("TYPE_" + sensorTypeName)
|
||||
.getInt(Sensor.class);
|
||||
} catch (NoSuchFieldException e) {
|
||||
callbackContext.error("Unavailable sensor type: " + sensorTypeName);
|
||||
return;
|
||||
} catch (IllegalAccessException e) {
|
||||
callbackContext.error("Unavailable sensor type: " + sensorTypeName);
|
||||
return;
|
||||
}
|
||||
List<Sensor> sensorList = this.sensorManager.getSensorList(sensorType);
|
||||
if (sensorList == null || sensorList.size() == 0) {
|
||||
callbackContext.error("Sensor " + sensorTypeName + " could not be retrieved");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch and check the target sampling rate.
|
||||
final String samplingPeriodName = args.getString(1);
|
||||
int samplingPeriodUs;
|
||||
try {
|
||||
samplingPeriodUs = SensorManager.class
|
||||
.getDeclaredField("SENSOR_DELAY_" + samplingPeriodName)
|
||||
.getInt(SensorManager.class);
|
||||
} catch (NoSuchFieldException e) {
|
||||
callbackContext.error("Unavailable sampling period: " + samplingPeriodName);
|
||||
return;
|
||||
} catch (IllegalAccessException e) {
|
||||
callbackContext.error("Unavailable sampling period: " + samplingPeriodName);
|
||||
return;
|
||||
}
|
||||
|
||||
String hash = getListenerHash(sensorTypeName, samplingPeriodName);
|
||||
|
||||
if (listeners.containsKey(hash)) {
|
||||
// If that sensor is already subscribed to, there is nothing to do here.
|
||||
callbackContext.error(
|
||||
"Listener already registered for sensor " +
|
||||
sensorTypeName +
|
||||
" at sampling period " +
|
||||
samplingPeriodName
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the event listener.
|
||||
SensorEventListener listener = new SensorEventListener() {
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
Sensors.this.onSensorChanged(
|
||||
sensorTypeName,
|
||||
samplingPeriodName,
|
||||
event
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// Just in case we might want to do something with this one day.
|
||||
Sensors.this.onAccuracyChanged(
|
||||
sensorTypeName,
|
||||
samplingPeriodName,
|
||||
sensor,
|
||||
accuracy
|
||||
);
|
||||
}
|
||||
};
|
||||
listeners.put(hash, listener);
|
||||
sensorManager.registerListener(listener, sensorList.get(0), samplingPeriodUs);
|
||||
callbackContext.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from a sensor.
|
||||
*
|
||||
* @param args The arguments. Must contains one string: the type of the sensor
|
||||
* and the listener sampling period as specified when calling
|
||||
* {@link Sensors#subscribe}.
|
||||
* @param callbackContext The callback context to receive confirmation of the un-subscription.
|
||||
* @throws JSONException Thrown when the arguments cannot be properly parsed.
|
||||
*/
|
||||
private void unsubscribe(JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
String hash = getListenerHash(args.getString(0), args.getString(1));
|
||||
SensorEventListener listener = listeners.remove(hash);
|
||||
sensorManager.unregisterListener(listener);
|
||||
if (listener != null) {
|
||||
callbackContext.success();
|
||||
} else {
|
||||
callbackContext.error(
|
||||
"No listener found for sensor " +
|
||||
args.getString(0) +
|
||||
" at sampling period " +
|
||||
args.getString(1)
|
||||
);
|
||||
}
|
||||
callbackContext.success(listener == null ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param sensor The type of the sensor.
|
||||
* @param sampling The name of the sampling period.
|
||||
* @return a hash to store the corresponding listener in listeners.
|
||||
*/
|
||||
private static String getListenerHash(String sensor, String sampling) {
|
||||
// This is safe, neither sensor nor sampling can contain ':'
|
||||
return sensor + ':' + sampling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive sensor events.
|
||||
*
|
||||
* @param sensorTypeName The type of the sensor.
|
||||
* @param samplingPeriodName The name of the sampling period.
|
||||
* @param event The event.
|
||||
*/
|
||||
private void onSensorChanged(
|
||||
String sensorTypeName,
|
||||
String samplingPeriodName,
|
||||
SensorEvent event
|
||||
) {
|
||||
try {
|
||||
// Convert the sensor event into JSON.
|
||||
JSONObject eventArg = new JSONObject();
|
||||
JSONArray values = new JSONArray();
|
||||
for (int i = 0; i < event.values.length; i++) {
|
||||
values.put(event.values[i]);
|
||||
}
|
||||
eventArg.put("values", values);
|
||||
eventArg.put("timeStamp", event.timestamp);
|
||||
eventArg.put("sensor", sensorTypeName);
|
||||
eventArg.put("sampling", samplingPeriodName);
|
||||
|
||||
// Send the result.
|
||||
PluginResult result = new PluginResult(
|
||||
PluginResult.Status.OK,
|
||||
eventArg
|
||||
);
|
||||
result.setKeepCallback(true);
|
||||
eventCallback.sendPluginResult(result);
|
||||
} catch (Exception e) {
|
||||
// If anything bad happens we notify JS and print the stack.
|
||||
PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
|
||||
result.setKeepCallback(true);
|
||||
eventCallback.sendPluginResult(result);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Currently ignored.
|
||||
private void onAccuracyChanged(
|
||||
String sensorTypeName,
|
||||
String samplingPeriodName,
|
||||
Sensor sensor,
|
||||
int accuracy) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when listener is to be shut down and object is being destroyed.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
// Clear the listeners and the eventCallback.
|
||||
for (SensorEventListener listener : listeners.values()) {
|
||||
this.sensorManager.unregisterListener(listener);
|
||||
}
|
||||
listeners.clear();
|
||||
eventCallback = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when app has navigated and JS listeners have been destroyed.
|
||||
*/
|
||||
public void onReset() {
|
||||
this.stop();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user