amc: actually use the provided application class loader
[platform/upstream/gst-plugins-bad.git] / sys / androidmedia / gst-android-hardware-sensor.c
1 /*
2  * Copyright (C) 2016 SurroundIO
3  *   Author: Martin Kelly <martin@surround.io>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * The UNION_CAST macro is copyright:
21  * Copyright (C) 2008-2016 Matt Gallagher ( http://cocoawithlove.com ).
22  * All rights reserved.
23  * Permission to use, copy, modify, and/or distribute this software for any purpose
24  * with or without fee is hereby granted, provided that the above copyright notice
25  * and this permission notice appear in all copies.
26
27  * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
28  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
29  * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
30  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
31  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
32  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
33  * THIS SOFTWARE.
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <glib.h>
41 #include <gmodule.h>
42
43 #include "gstjniutils.h"
44 #include "gst-android-hardware-sensor.h"
45
46 static jobject (*gst_android_get_application_context) (void) = NULL;
47
48 GST_DEBUG_CATEGORY_STATIC (ahs_debug);
49 #define GST_CAT_DEFAULT ahs_debug
50
51 /*
52  * See:
53  * http://www.cocoawithlove.com/2008/04/using-pointers-to-recast-in-c-is-bad.html
54  * for details.
55  */
56 #define UNION_CAST(x, destType) \
57         (((union {__typeof__(x) a; destType b;})x).b)
58
59 static struct
60 {
61   jclass klass;
62   jstring SENSOR_SERVICE;
63   jmethodID getSystemService;
64 } android_content_context = {
65 0};
66
67 static struct
68 {
69   jclass klass;
70   jfieldID accuracy;
71   jfieldID values;
72 } android_hardware_sensor_event = {
73 0};
74
75 static struct
76 {
77   jclass klass;
78   jmethodID getDefaultSensor;;
79   jmethodID registerListener;
80   jmethodID unregisterListener;
81 } android_hardware_sensor_manager = {
82 0};
83
84 static struct
85 {
86   jclass klass;
87   jmethodID constructor;
88 } org_freedesktop_gstreamer_androidmedia_gstahscallback = {
89 0};
90
91 GHashTable *sensor_sizes = NULL;
92 static void
93 gst_ah_sensor_sensor_sizes_init (void)
94 {
95   gint i;
96   static struct
97   {
98     gint type;
99     gsize size;
100   } types[] = {
101     {
102     AHS_SENSOR_TYPE_ACCELEROMETER, sizeof (GstAHSAccelerometerValues)}
103     , {
104     AHS_SENSOR_TYPE_AMBIENT_TEMPERATURE,
105           sizeof (GstAHSAmbientTemperatureValues)}
106     , {
107     AHS_SENSOR_TYPE_GAME_ROTATION_VECTOR,
108           sizeof (GstAHSGameRotationVectorValues)}
109     , {
110     AHS_SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR,
111           sizeof (GstAHSGeomagneticRotationVectorValues)}
112     , {
113     AHS_SENSOR_TYPE_GRAVITY, sizeof (GstAHSGravityValues)}
114     , {
115     AHS_SENSOR_TYPE_GYROSCOPE, sizeof (GstAHSGyroscopeValues)}
116     , {
117     AHS_SENSOR_TYPE_GYROSCOPE_UNCALIBRATED,
118           sizeof (GstAHSGyroscopeUncalibratedValues)}
119     , {
120     AHS_SENSOR_TYPE_HEART_RATE, sizeof (GstAHSHeartRateValues)}
121     , {
122     AHS_SENSOR_TYPE_LIGHT, sizeof (GstAHSLightValues)}
123     , {
124     AHS_SENSOR_TYPE_LINEAR_ACCELERATION,
125           sizeof (GstAHSLinearAccelerationValues)}
126     , {
127     AHS_SENSOR_TYPE_MAGNETIC_FIELD, sizeof (GstAHSMagneticFieldValues)}
128     , {
129     AHS_SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
130           sizeof (GstAHSMagneticFieldUncalibratedValues)}
131     , {
132     AHS_SENSOR_TYPE_ORIENTATION, sizeof (GstAHSOrientationValues)}
133     , {
134     AHS_SENSOR_TYPE_PRESSURE, sizeof (GstAHSPressureValues)}
135     , {
136     AHS_SENSOR_TYPE_PROXIMITY, sizeof (GstAHSProximityValues)}
137     , {
138     AHS_SENSOR_TYPE_RELATIVE_HUMIDITY, sizeof (GstAHSRelativeHumidityValues)}
139     , {
140     AHS_SENSOR_TYPE_ROTATION_VECTOR, sizeof (GstAHSRotationVectorValues)}
141     , {
142     AHS_SENSOR_TYPE_STEP_COUNTER, sizeof (GstAHSStepCounterValues)}
143     , {
144     AHS_SENSOR_TYPE_STEP_DETECTOR, sizeof (GstAHSStepDetectorValues)}
145   ,};
146
147   g_assert_null (sensor_sizes);
148
149   sensor_sizes = g_hash_table_new (g_int_hash, g_int_equal);
150   for (i = 0; i < G_N_ELEMENTS (types); i++)
151     g_hash_table_insert (sensor_sizes, &types[i].type, &types[i].size);
152 }
153
154 static void
155 gst_ah_sensor_sensor_sizes_deinit (void)
156 {
157   g_hash_table_unref (sensor_sizes);
158   sensor_sizes = NULL;
159 }
160
161 gsize
162 gst_ah_sensor_get_sensor_data_size (gint sensor_type)
163 {
164   return *((gsize *) g_hash_table_lookup (sensor_sizes, &sensor_type));
165 }
166
167 static void
168 gst_ah_sensor_on_sensor_changed (JNIEnv * env, jclass klass,
169     jobject sensor_event, jlong callback, jlong user_data)
170 {
171   GstAHSensorCallback cb = (GstAHSensorCallback) (gsize) callback;
172
173   if (cb)
174     cb (sensor_event, (gpointer) (gsize) user_data);
175 }
176
177 static void
178 gst_ah_sensor_on_accuracy_changed (JNIEnv * env, jclass klass,
179     jobject sensor, jint accuracy, jlong callback, jlong user_data)
180 {
181   GstAHSAccuracyCallback cb = (GstAHSAccuracyCallback) (gsize) callback;
182
183   if (cb)
184     cb (sensor, accuracy, (gpointer) (gsize) user_data);
185 }
186
187 static gboolean natives_registered = FALSE;
188
189 static JNINativeMethod native_methods[] = {
190   {(gchar *) "gst_ah_sensor_on_sensor_changed",
191         (gchar *) "(Landroid/hardware/SensorEvent;JJ)V",
192       (void *) gst_ah_sensor_on_sensor_changed},
193   {(gchar *) "gst_ah_sensor_on_accuracy_changed",
194         (gchar *) "(Landroid/hardware/Sensor;IJJ)V",
195       (void *) gst_ah_sensor_on_accuracy_changed}
196 };
197
198 static gboolean
199 _init_classes (void)
200 {
201   gint32 delay;
202   JNIEnv *env = gst_amc_jni_get_env ();
203   GError *err = NULL;
204   jclass klass;
205   jfieldID fieldID;
206   GModule *module;
207   gboolean success;
208   gint32 type;
209
210   /*
211    * Lookup the Android function to get an Android context. This function will
212    * be provided when the plugin is built via ndk-build.
213    */
214   module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
215   if (!module)
216     goto failed;
217   success = g_module_symbol (module, "gst_android_get_application_context",
218       (gpointer *) & gst_android_get_application_context);
219   if (!success || !gst_android_get_application_context)
220     goto failed;
221   g_module_close (module);
222
223   /* android.content.Context */
224   klass = android_content_context.klass = gst_amc_jni_get_class (env, &err,
225       "android/content/Context");
226   if (!klass)
227     goto failed;
228   android_content_context.getSystemService =
229       gst_amc_jni_get_method_id (env, &err, klass, "getSystemService",
230       "(Ljava/lang/String;)Ljava/lang/Object;");
231   if (!android_content_context.getSystemService)
232     goto failed;
233
234   fieldID =
235       gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_SERVICE",
236       "Ljava/lang/String;");
237   if (!fieldID)
238     goto failed;
239   if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
240           &android_content_context.SENSOR_SERVICE))
241     goto failed;
242   android_content_context.SENSOR_SERVICE =
243       gst_amc_jni_object_make_global (env,
244       android_content_context.SENSOR_SERVICE);
245   if (!android_content_context.SENSOR_SERVICE)
246     goto failed;
247
248   /* android.hardware.SensorEvent */
249   klass = android_hardware_sensor_event.klass =
250       gst_amc_jni_get_class (env, &err, "android/hardware/SensorEvent");
251   if (!klass)
252     goto failed;
253   android_hardware_sensor_event.accuracy =
254       gst_amc_jni_get_field_id (env, &err, klass, "accuracy", "I");
255   if (!android_hardware_sensor_event.accuracy)
256     goto failed;
257   android_hardware_sensor_event.values =
258       gst_amc_jni_get_field_id (env, &err, klass, "values", "[F");
259   if (!android_hardware_sensor_event.values)
260     goto failed;
261
262   /* android.hardware.SensorManager */
263   klass = android_hardware_sensor_manager.klass =
264       gst_amc_jni_get_class (env, &err, "android/hardware/SensorManager");
265   if (!klass)
266     goto failed;
267   android_hardware_sensor_manager.getDefaultSensor =
268       gst_amc_jni_get_method_id (env, &err, klass,
269       "getDefaultSensor", "(I)Landroid/hardware/Sensor;");
270   if (!android_hardware_sensor_manager.getDefaultSensor)
271     goto failed;
272   android_hardware_sensor_manager.registerListener =
273       gst_amc_jni_get_method_id (env, &err, klass,
274       "registerListener",
275       "(Landroid/hardware/SensorEventListener;Landroid/hardware/Sensor;I)Z");
276   if (!android_hardware_sensor_manager.registerListener)
277     goto failed;
278   android_hardware_sensor_manager.unregisterListener =
279       gst_amc_jni_get_method_id (env, &err, klass,
280       "unregisterListener", "(Landroid/hardware/SensorEventListener;)V");
281   if (!android_hardware_sensor_manager.unregisterListener)
282     goto failed;
283
284   fieldID =
285       gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_FASTEST",
286       "I");
287   if (!fieldID)
288     goto failed;
289   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay))
290     goto failed;
291   if (delay != AHS_SENSOR_DELAY_FASTEST) {
292     GST_ERROR ("SENSOR_DELAY_FASTEST has changed value");
293     goto failed;
294   }
295
296   fieldID =
297       gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_GAME",
298       "I");
299   if (!fieldID)
300     goto failed;
301   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay))
302     goto failed;
303   if (delay != AHS_SENSOR_DELAY_GAME) {
304     GST_ERROR ("SENSOR_DELAY_GAME has changed value");
305     goto failed;
306   }
307
308   fieldID =
309       gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_NORMAL",
310       "I");
311   if (!fieldID)
312     goto failed;
313   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay))
314     goto failed;
315   if (delay != AHS_SENSOR_DELAY_NORMAL) {
316     GST_ERROR ("SENSOR_DELAY_NORMAL has changed value");
317     goto failed;
318   }
319
320   fieldID =
321       gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_UI",
322       "I");
323   if (!fieldID)
324     goto failed;
325   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay))
326     goto failed;
327   if (delay != AHS_SENSOR_DELAY_UI) {
328     GST_ERROR ("SENSOR_DELAY_UI has changed value");
329     goto failed;
330   }
331
332   /* android.hardware.Sensor */
333   klass = gst_amc_jni_get_class (env, &err, "android/hardware/Sensor");
334   if (!klass)
335     goto failed;
336
337   fieldID =
338       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_ACCELEROMETER",
339       "I");
340   if (!fieldID)
341     goto failed;
342   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
343     goto failed;
344   if (type != AHS_SENSOR_TYPE_ACCELEROMETER) {
345     GST_ERROR ("TYPE_ACCELEROMETER has changed value");
346     goto failed;
347   }
348
349   fieldID = gst_amc_jni_get_static_field_id (env, &err, klass,
350       "TYPE_AMBIENT_TEMPERATURE", "I");
351   if (!fieldID)
352     goto failed;
353   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
354     goto failed;
355   if (type != AHS_SENSOR_TYPE_AMBIENT_TEMPERATURE) {
356     GST_ERROR ("TYPE_AMBIENT_TEMPERATURE has changed value");
357     goto failed;
358   }
359
360   fieldID = gst_amc_jni_get_static_field_id (env, &err, klass,
361       "TYPE_GAME_ROTATION_VECTOR", "I");
362   if (!fieldID)
363     goto failed;
364   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
365     goto failed;
366   if (type != AHS_SENSOR_TYPE_GAME_ROTATION_VECTOR) {
367     GST_ERROR ("TYPE_GAME_ROTATION_VECTOR has changed value");
368     goto failed;
369   }
370
371   fieldID = gst_amc_jni_get_static_field_id (env, &err, klass,
372       "TYPE_GEOMAGNETIC_ROTATION_VECTOR", "I");
373   if (!fieldID)
374     goto failed;
375   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
376     goto failed;
377   if (type != AHS_SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR) {
378     GST_ERROR ("TYPE_GEOMAGNETIC_ROTATION_VECTOR has changed value");
379     goto failed;
380   }
381
382   fieldID =
383       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_GRAVITY", "I");
384   if (!fieldID)
385     goto failed;
386   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
387     goto failed;
388   if (type != AHS_SENSOR_TYPE_GRAVITY) {
389     GST_ERROR ("TYPE_GRAVITY has changed value");
390     goto failed;
391   }
392
393   fieldID =
394       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_GYROSCOPE", "I");
395   if (!fieldID)
396     goto failed;
397   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
398     goto failed;
399   if (type != AHS_SENSOR_TYPE_GYROSCOPE) {
400     GST_ERROR ("TYPE_GYROSCOPE has changed value");
401     goto failed;
402   }
403
404   fieldID =
405       gst_amc_jni_get_static_field_id (env, &err, klass,
406       "TYPE_GYROSCOPE_UNCALIBRATED", "I");
407   if (!fieldID)
408     goto failed;
409   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
410     goto failed;
411   if (type != AHS_SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
412     GST_ERROR ("TYPE_GYROSCOPE_UNCALIBRATED has changed value");
413     goto failed;
414   }
415
416   fieldID =
417       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_HEART_RATE",
418       "I");
419   if (!fieldID)
420     goto failed;
421   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
422     goto failed;
423   if (type != AHS_SENSOR_TYPE_HEART_RATE) {
424     GST_ERROR ("TYPE_HEART_RATE has changed value");
425     goto failed;
426   }
427
428   fieldID =
429       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_LIGHT", "I");
430   if (!fieldID)
431     goto failed;
432   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
433     goto failed;
434   if (type != AHS_SENSOR_TYPE_LIGHT) {
435     GST_ERROR ("TYPE_LIGHT has changed value");
436     goto failed;
437   }
438
439   fieldID =
440       gst_amc_jni_get_static_field_id (env, &err, klass,
441       "TYPE_LINEAR_ACCELERATION", "I");
442   if (!fieldID)
443     goto failed;
444   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
445     goto failed;
446   if (type != AHS_SENSOR_TYPE_LINEAR_ACCELERATION) {
447     GST_ERROR ("TYPE_LINEAR_ACCELERATION has changed value");
448     goto failed;
449   }
450
451   fieldID =
452       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_MAGNETIC_FIELD",
453       "I");
454   if (!fieldID)
455     goto failed;
456   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
457     goto failed;
458   if (type != AHS_SENSOR_TYPE_MAGNETIC_FIELD) {
459     GST_ERROR ("TYPE_MAGNETIC_FIELD has changed value");
460     goto failed;
461   }
462
463   fieldID =
464       gst_amc_jni_get_static_field_id (env, &err, klass,
465       "TYPE_MAGNETIC_FIELD_UNCALIBRATED", "I");
466   if (!fieldID)
467     goto failed;
468   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
469     goto failed;
470   if (type != AHS_SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED) {
471     GST_ERROR ("TYPE_MAGNETIC_FIELD_UNCALIBRATED has changed value");
472     goto failed;
473   }
474
475   fieldID =
476       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_ORIENTATION",
477       "I");
478   if (!fieldID)
479     goto failed;
480   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
481     goto failed;
482   if (type != AHS_SENSOR_TYPE_ORIENTATION) {
483     GST_ERROR ("TYPE_ORIENTATION has changed value");
484     goto failed;
485   }
486
487   fieldID =
488       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_PRESSURE", "I");
489   if (!fieldID)
490     goto failed;
491   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
492     goto failed;
493   if (type != AHS_SENSOR_TYPE_PRESSURE) {
494     GST_ERROR ("TYPE_PRESSURE has changed value");
495     goto failed;
496   }
497
498   fieldID =
499       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_PROXIMITY", "I");
500   if (!fieldID)
501     goto failed;
502   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
503     goto failed;
504   if (type != AHS_SENSOR_TYPE_PROXIMITY) {
505     GST_ERROR ("TYPE_PROXIMITY has changed value");
506     goto failed;
507   }
508
509   fieldID =
510       gst_amc_jni_get_static_field_id (env, &err, klass,
511       "TYPE_RELATIVE_HUMIDITY", "I");
512   if (!fieldID)
513     goto failed;
514   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
515     goto failed;
516   if (type != AHS_SENSOR_TYPE_RELATIVE_HUMIDITY) {
517     GST_ERROR ("TYPE_RELATIVE_HUMIDITY has changed value");
518     goto failed;
519   }
520
521   fieldID =
522       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_ROTATION_VECTOR",
523       "I");
524   if (!fieldID)
525     goto failed;
526   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
527     goto failed;
528   if (type != AHS_SENSOR_TYPE_ROTATION_VECTOR) {
529     GST_ERROR ("TYPE_ROTATION_VECTOR has changed value");
530     goto failed;
531   }
532
533   fieldID =
534       gst_amc_jni_get_static_field_id (env, &err, klass,
535       "TYPE_SIGNIFICANT_MOTION", "I");
536   if (!fieldID)
537     goto failed;
538   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
539     goto failed;
540   if (type != AHS_SENSOR_TYPE_SIGNIFICANT_MOTION) {
541     GST_ERROR ("TYPE_SIGNIFICANT_MOTION has changed value");
542     goto failed;
543   }
544
545   fieldID =
546       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_STEP_COUNTER",
547       "I");
548   if (!fieldID)
549     goto failed;
550   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
551     goto failed;
552   if (type != AHS_SENSOR_TYPE_STEP_COUNTER) {
553     GST_ERROR ("TYPE_STEP_COUNTER has changed value");
554     goto failed;
555   }
556
557   fieldID =
558       gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_STEP_DETECTOR",
559       "I");
560   if (!fieldID)
561     goto failed;
562   if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type))
563     goto failed;
564   if (type != AHS_SENSOR_TYPE_STEP_DETECTOR) {
565     GST_ERROR ("TYPE_STEP_DETECTOR has changed value");
566     goto failed;
567   }
568
569   /* org.freedesktop.gstreamer.androidmedia.GstAhsCallback */
570   if (!org_freedesktop_gstreamer_androidmedia_gstahscallback.klass) {
571     org_freedesktop_gstreamer_androidmedia_gstahscallback.klass =
572         gst_amc_jni_get_application_class (env,
573         "org/freedesktop/gstreamer/androidmedia/GstAhsCallback", &err);
574   }
575   if (!org_freedesktop_gstreamer_androidmedia_gstahscallback.klass)
576     goto failed;
577   org_freedesktop_gstreamer_androidmedia_gstahscallback.constructor =
578       gst_amc_jni_get_method_id (env, &err,
579       org_freedesktop_gstreamer_androidmedia_gstahscallback.klass, "<init>",
580       "(JJJ)V");
581   if (!org_freedesktop_gstreamer_androidmedia_gstahscallback.constructor)
582     goto failed;
583
584   if ((*env)->RegisterNatives (env,
585           org_freedesktop_gstreamer_androidmedia_gstahscallback.klass,
586           native_methods, G_N_ELEMENTS (native_methods))) {
587     GST_ERROR ("Failed to register native methods for GstAhsCallback");
588     goto failed;
589   }
590   natives_registered = TRUE;
591
592   return TRUE;
593
594 failed:
595   if (err) {
596     GST_ERROR ("Failed to initialize Android classes: %s", err->message);
597     g_clear_error (&err);
598   }
599
600   return FALSE;
601 }
602
603 gboolean
604 gst_android_hardware_sensor_init (void)
605 {
606   GST_DEBUG_CATEGORY_INIT (ahs_debug, "ahs", 0,
607       "Android Gstreamer Hardware Sensor");
608   if (!_init_classes ()) {
609     gst_android_hardware_sensor_deinit ();
610     return FALSE;
611   }
612
613   gst_ah_sensor_sensor_sizes_init ();
614
615   return TRUE;
616 }
617
618 void
619 gst_android_hardware_sensor_deinit (void)
620 {
621   JNIEnv *env = gst_amc_jni_get_env ();
622
623   if (android_content_context.SENSOR_SERVICE) {
624     gst_amc_jni_object_unref (env, android_content_context.SENSOR_SERVICE);
625     android_content_context.SENSOR_SERVICE = NULL;
626   }
627
628   if (android_content_context.klass) {
629     gst_amc_jni_object_unref (env, android_content_context.klass);
630     android_content_context.klass = NULL;
631   }
632
633   if (android_hardware_sensor_event.klass) {
634     gst_amc_jni_object_unref (env, android_hardware_sensor_event.klass);
635     android_hardware_sensor_event.klass = NULL;
636   }
637
638   if (android_hardware_sensor_manager.klass) {
639     gst_amc_jni_object_unref (env, android_hardware_sensor_manager.klass);
640     android_hardware_sensor_manager.klass = NULL;
641   }
642
643   if (org_freedesktop_gstreamer_androidmedia_gstahscallback.klass) {
644     if (natives_registered) {
645       (*env)->UnregisterNatives (env,
646           org_freedesktop_gstreamer_androidmedia_gstahscallback.klass);
647       natives_registered = FALSE;
648     }
649     gst_amc_jni_object_unref (env,
650         org_freedesktop_gstreamer_androidmedia_gstahscallback.klass);
651     org_freedesktop_gstreamer_androidmedia_gstahscallback.klass = NULL;
652   }
653
654   if (sensor_sizes)
655     gst_ah_sensor_sensor_sizes_deinit ();
656 }
657
658 GstAHSensorManager *
659 gst_ah_sensor_get_manager (void)
660 {
661   jobject context;
662   GError *err = NULL;
663   JNIEnv *env = gst_amc_jni_get_env ();
664   GstAHSensorManager *manager;
665   jobject object;
666   gboolean success;
667
668   context = gst_android_get_application_context ();
669   success = gst_amc_jni_call_object_method (env, &err, context,
670       android_content_context.getSystemService,
671       &object, android_content_context.SENSOR_SERVICE);
672   if (!success)
673     return NULL;
674
675   object = gst_amc_jni_object_make_global (env, object);
676   if (!object)
677     return NULL;
678
679   manager = g_slice_new (GstAHSensorManager);
680   manager->object = object;
681
682   return manager;
683 }
684
685 GstAHSensor *
686 gst_ah_sensor_get_default_sensor (GstAHSensorManager * self, gint32 sensor_type)
687 {
688   JNIEnv *env = gst_amc_jni_get_env ();
689   GError *err = NULL;
690   jobject object;
691   GstAHSensor *sensor;
692
693   if (!gst_amc_jni_call_object_method (env, &err, self->object,
694           android_hardware_sensor_manager.getDefaultSensor,
695           &object, sensor_type))
696     return NULL;
697
698   object = gst_amc_jni_object_make_global (env, object);
699   if (!object)
700     return NULL;
701
702   sensor = g_slice_new (GstAHSensor);
703   sensor->object = object;
704
705   return sensor;
706 }
707
708 GstAHSensorEventListener *
709 gst_ah_sensor_create_listener (GstAHSensorCallback sensor_cb,
710     GstAHSAccuracyCallback accuracy_cb, gpointer user_data)
711 {
712   JNIEnv *env = gst_amc_jni_get_env ();
713   GError *err = NULL;
714   GstAHSensorEventListener *listener;
715   jobject object;
716
717   object = gst_amc_jni_new_object (env,
718       &err,
719       TRUE,
720       org_freedesktop_gstreamer_androidmedia_gstahscallback.klass,
721       org_freedesktop_gstreamer_androidmedia_gstahscallback.constructor,
722       UNION_CAST (sensor_cb, jlong),
723       UNION_CAST (accuracy_cb, jlong), UNION_CAST (user_data, jlong));
724   if (err) {
725     GST_ERROR ("Failed to create listener callback class");
726     g_clear_error (&err);
727     return NULL;
728   }
729
730   listener = g_slice_new (GstAHSensorEventListener);
731   listener->object = object;
732
733   return listener;
734 }
735
736 gboolean
737 gst_ah_sensor_register_listener (GstAHSensorManager * self,
738     GstAHSensorEventListener * listener, GstAHSensor * sensor, gint32 delay)
739 {
740   JNIEnv *env = gst_amc_jni_get_env ();
741   GError *err = NULL;
742   gboolean success;
743
744   gst_amc_jni_call_boolean_method (env, &err, self->object,
745       android_hardware_sensor_manager.registerListener, &success,
746       listener->object, sensor->object, (jint) delay);
747   if (err) {
748     GST_ERROR
749         ("Failed to call android.hardware.SensorManager.registerListener: %s",
750         err->message);
751     g_clear_error (&err);
752     return FALSE;
753   }
754   listener->registered = TRUE;
755
756   return TRUE;
757 }
758
759 void
760 gst_ah_sensor_unregister_listener (GstAHSensorManager * self,
761     GstAHSensorEventListener * listener)
762 {
763   JNIEnv *env = gst_amc_jni_get_env ();
764   GError *err = NULL;
765
766   gst_amc_jni_call_void_method (env, &err, self->object,
767       android_hardware_sensor_manager.unregisterListener, listener->object);
768   if (err) {
769     GST_ERROR
770         ("Failed to call android.hardware.SensorManager.unregisterListener: %s",
771         err->message);
772     g_clear_error (&err);
773   }
774   listener->registered = FALSE;
775 }
776
777 gboolean
778 gst_ah_sensor_populate_event (GstAHSensorEvent * event, jobject event_object,
779     gint size)
780 {
781   JNIEnv *env = gst_amc_jni_get_env ();
782   GError *err = NULL;
783   jfloatArray object_array;
784   jfloat *values;
785
786   gst_amc_jni_get_int_field (env, &err,
787       event_object, android_hardware_sensor_event.accuracy, &event->accuracy);
788   if (err) {
789     GST_ERROR ("Failed to get sensor accuracy field: %s", err->message);
790     goto error;
791   }
792
793   gst_amc_jni_get_object_field (env, &err, event_object,
794       android_hardware_sensor_event.values, &object_array);
795   if (err) {
796     GST_ERROR ("Failed to get sensor values field: %s", err->message);
797     goto error;
798   }
799
800   values = (*env)->GetFloatArrayElements (env, object_array, NULL);
801   if (!values) {
802     GST_ERROR ("Failed to get float array elements from object array");
803     gst_amc_jni_object_local_unref (env, object_array);
804     return FALSE;
805   }
806   /* We can't use gst_amc_jni_object_make_global here because we need to call
807    * ReleaseFloatArrayElements before doing a local unref in the failure case,
808    * but gst_amc_jni_object_make_global would unref before we could Release.
809    */
810   event->data.array = gst_amc_jni_object_ref (env, object_array);
811   if (!event->data.array) {
812     (*env)->ReleaseFloatArrayElements (env, object_array, values, JNI_ABORT);
813     gst_amc_jni_object_local_unref (env, object_array);
814     return FALSE;
815   }
816   event->data.values = values;
817   gst_amc_jni_object_local_unref (env, object_array);
818
819   return TRUE;
820
821 error:
822   g_clear_error (&err);
823   return FALSE;
824 }
825
826 void
827 gst_ah_sensor_free_sensor_data (GstAHSensorData * data)
828 {
829   JNIEnv *env = gst_amc_jni_get_env ();
830
831   (*env)->ReleaseFloatArrayElements (env, data->array, data->values, JNI_ABORT);
832   gst_amc_jni_object_unref (env, data->array);
833 }