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