1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 #import <jni.h>
  26 #import <CoreMotion/CoreMotion.h>
  27 #import <CoreLocation/CoreLocation.h>
  28 #import <UIKit/UIKit.h>
  29 
  30 extern JNIEnv *jEnv;
  31 #define GET_MAIN_JENV \
  32 if (jEnv == NULL) NSLog(@"ERROR: Java has been detached already, but someone is still trying to use it at %s:%s:%d\n", __FUNCTION__, __FILE__, __LINE__);\
  33 JNIEnv *env = jEnv;
  34 
  35 
  36 jclass jIOSMotionManagerClass = NULL;
  37 jmethodID jIOSMotionManagerDidAccelerate = NULL;
  38 jmethodID jIOSMotionManagerDidRotate = NULL;
  39 
  40 jclass jIOSLocationManagerClass = NULL;
  41 jmethodID jIOSLocationManagerDidUpdateHeading = NULL;
  42 jmethodID jIOSLocationManagerDidUpdateLocation = NULL;
  43 
  44 CMMotionManager * motionManager = NULL;
  45 
  46 
  47 @interface MyCLLocationManagerDelegate : NSObject<CLLocationManagerDelegate>
  48 @end
  49 
  50 
  51 @implementation MyCLLocationManagerDelegate
  52 
  53 - (void)locationManager:(CLLocationManager *)manager
  54        didUpdateHeading:(CLHeading *)newHeading
  55 {
  56     GET_MAIN_JENV;
  57         (*env)->CallStaticVoidMethod(
  58         env,
  59         jIOSLocationManagerClass,
  60         jIOSLocationManagerDidUpdateHeading,
  61 
  62         (jdouble)newHeading.magneticHeading ,
  63         (jdouble)newHeading.trueHeading,
  64         (jdouble)newHeading.x,
  65         (jdouble)newHeading.y,
  66         (jdouble)newHeading.z
  67     );
  68 }
  69 
  70 
  71 - (void)locationManager:(CLLocationManager *)manager
  72     didUpdateToLocation:(CLLocation *)newLocation
  73     fromLocation:(CLLocation *)oldLocation
  74 {
  75     GET_MAIN_JENV;
  76         (*env)->CallStaticVoidMethod(
  77         env,
  78         jIOSLocationManagerClass,
  79         jIOSLocationManagerDidUpdateLocation,
  80 
  81         (jdouble)newLocation.coordinate.latitude,
  82         (jdouble)newLocation.coordinate.longitude,
  83         (jdouble)newLocation.altitude,
  84         (jdouble)newLocation.course,
  85         (jdouble)newLocation.speed
  86     );
  87 }
  88 
  89 @end
  90 
  91 
  92 
  93 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSMotionManager_isAccelerometerAvailable
  94 (JNIEnv *env, jclass jClass)
  95 {
  96     return motionManager.accelerometerAvailable == YES ? JNI_TRUE : JNI_FALSE;
  97 }
  98 
  99 
 100 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSMotionManager_isGyroAvailable
 101 (JNIEnv *env, jclass jClass)
 102 {
 103     return motionManager.gyroAvailable == YES ? JNI_TRUE : JNI_FALSE;
 104 }
 105 
 106 /*
 107  * Class:     com_sun_javafx_ext_device_ios_sensors_IOSMotionManager
 108  * Method:    _initIDs
 109  * Signature: ()V
 110  */
 111 JNIEXPORT void JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSMotionManager__1init
 112 (JNIEnv *env, jclass jClass)
 113 {
 114     if (jIOSMotionManagerClass == NULL)
 115     {
 116         jIOSMotionManagerClass = (*env)->NewGlobalRef(env, jClass);
 117     }
 118 
 119     if (jIOSMotionManagerDidAccelerate == NULL)
 120     {
 121         jIOSMotionManagerDidAccelerate =
 122             (*env)->GetStaticMethodID(
 123                 env, jIOSMotionManagerClass,
 124                 "didAccelerate", "(FFF)V");
 125     }
 126 
 127 
 128     if (jIOSMotionManagerDidRotate == NULL)
 129     {
 130         jIOSMotionManagerDidRotate =
 131             (*env)->GetStaticMethodID(
 132                 env, jIOSMotionManagerClass,
 133                 "didRotate", "(FFF)V");
 134     }
 135 
 136 
 137     motionManager = [[CMMotionManager alloc] init];
 138     if (motionManager.accelerometerAvailable)
 139     {
 140         if (motionManager.isAccelerometerActive == NO)
 141         {
 142             motionManager.accelerometerUpdateInterval = 0.05; // 20Hz
 143             [motionManager startAccelerometerUpdates];
 144             [motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
 145                                                 withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
 146 
 147                 const CMAcceleration acceleration = accelerometerData.acceleration;
 148                 GET_MAIN_JENV;
 149                 (*env)->CallStaticVoidMethod(
 150                     env,
 151                     jIOSMotionManagerClass,
 152                     jIOSMotionManagerDidAccelerate,
 153 
 154                     (jfloat)acceleration.x,
 155                     (jfloat)acceleration.y,
 156                     (jfloat)acceleration.z
 157                 );
 158             }];
 159         }
 160     }
 161 
 162 
 163     if (motionManager.isGyroAvailable)
 164     {
 165         /* Start the gyroscope if it is not active already */
 166         if (motionManager.isGyroActive == NO)
 167         {
 168             motionManager.gyroUpdateInterval = 0.1f;
 169 
 170             [motionManager startGyroUpdatesToQueue:[NSOperationQueue mainQueue]
 171                                        withHandler:^(CMGyroData *gyroData, NSError *error)
 172             {
 173                 GET_MAIN_JENV;
 174                 const CMRotationRate rotationRate = gyroData.rotationRate;
 175                 (*env)->CallStaticVoidMethod(
 176                     env,
 177                     jIOSMotionManagerClass,
 178                     jIOSMotionManagerDidRotate,
 179 
 180                     (jfloat)rotationRate.x ,
 181                     (jfloat)rotationRate.y,
 182                     (jfloat)rotationRate.z
 183                 );
 184             }];
 185         }
 186         else NSLog(@"Gyro is already active");
 187     }
 188     else NSLog(@"Gyro not available!");
 189 }
 190 
 191 
 192 
 193 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSLocationManager_isHeadingAvailable
 194 (JNIEnv *env, jclass jClass)
 195 {
 196     return [CLLocationManager headingAvailable] == YES ? JNI_TRUE : JNI_FALSE;
 197 }
 198 
 199 
 200 /*
 201  * Class:     com_sun_javafx_ext_device_ios_sensors_IOSLocationManager
 202  * Method:    _init
 203  * Signature: ()V
 204  */
 205 JNIEXPORT void JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSLocationManager__1init
 206 (JNIEnv *env, jclass jClass)
 207 {
 208     if (jIOSLocationManagerClass == NULL)
 209     {
 210         jIOSLocationManagerClass = (*env)->NewGlobalRef(env, jClass);
 211     }
 212 
 213     if (jIOSLocationManagerDidUpdateHeading == NULL)
 214     {
 215         jIOSLocationManagerDidUpdateHeading =
 216             (*env)->GetStaticMethodID(
 217                 env, jIOSLocationManagerClass,
 218                 "didUpdateHeading", "(DDDDD)V");
 219     }
 220 
 221     if (jIOSLocationManagerDidUpdateLocation == NULL)
 222     {
 223         jIOSLocationManagerDidUpdateLocation =
 224             (*env)->GetStaticMethodID(
 225                 env, jIOSLocationManagerClass,
 226                 "didUpdateLocation", "(DDDDD)V");
 227     }
 228 
 229     CLLocationManager *const locationManager = [[CLLocationManager alloc] init];
 230     locationManager.delegate = [[MyCLLocationManagerDelegate alloc] init];
 231 
 232     if ([CLLocationManager headingAvailable]) {
 233         locationManager.headingFilter = 5; //degrees
 234         [locationManager startUpdatingHeading];
 235     }
 236     if ([CLLocationManager locationServicesEnabled]) {
 237         locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
 238         locationManager.distanceFilter = 10;
 239         [locationManager startUpdatingLocation];
 240     }
 241 }
 242 
 243 
 244 
 245 /*
 246  * Class:     com_sun_javafx_ext_device_ios_sensors_IOSDevice
 247  * Method:    setProximityMonitoringEnabled
 248  * Signature: (Z)V
 249  */
 250 JNIEXPORT void JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSDevice_setProximityMonitoringEnabled
 251 (JNIEnv *env, jobject jObject, jboolean value)
 252 {
 253     [UIDevice currentDevice].proximityMonitoringEnabled = value == JNI_TRUE ? YES : NO;
 254 }
 255 
 256 
 257 /*
 258  * Class:     com_sun_javafx_ext_device_ios_sensors_IOSDevice
 259  * Method:    isProximityMonitoringEnabled
 260  * Signature: (V)Z
 261  */
 262 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSDevice_isProximityMonitoringEnabled
 263 (JNIEnv *env, jobject jObject)
 264 {
 265     return [UIDevice currentDevice].proximityMonitoringEnabled == YES ? JNI_TRUE : JNI_FALSE;
 266 }
 267 
 268 
 269 /*
 270  * Class:     com_sun_javafx_ext_device_ios_sensors_IOSDevice
 271  * Method:    getProximityState
 272  * Signature: (V)Z
 273  */
 274 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSDevice_getProximityState
 275 (JNIEnv *env, jobject jObject)
 276 {
 277     return [UIDevice currentDevice].proximityState == YES ? JNI_TRUE : JNI_FALSE;
 278 }
 279 
 280 
 281 
 282 /*
 283  * Class:     com_sun_javafx_ext_device_ios_sensors_IOSDevice
 284  * Method:    setBatteryMonitoringEnabled
 285  * Signature: (Z)V
 286  */
 287 JNIEXPORT void JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSDevice_setBatteryMonitoringEnabled
 288 (JNIEnv *env, jobject jObject, jboolean value)
 289 {
 290     [UIDevice currentDevice].batteryMonitoringEnabled = value == JNI_TRUE ? YES : NO;
 291 }
 292 
 293 
 294 JNIEXPORT jfloat JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSDevice_getBatteryLevel
 295 (JNIEnv *env, jobject jObject)
 296 {
 297     return [UIDevice currentDevice].batteryLevel;
 298 }
 299 
 300 JNIEXPORT jint JNICALL Java_com_sun_javafx_ext_device_ios_sensors_IOSDevice__1getBatteryState
 301 (JNIEnv *env, jobject jObject)
 302 {
 303     return [UIDevice currentDevice].batteryState;
 304 }