Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2012, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "GeolocationServiceBridge.h"
     28 
     29 #include "WebViewCore.h"
     30 
     31 #include <GeolocationError.h>
     32 #include <GeolocationPosition.h>
     33 #include <JNIHelp.h>
     34 
     35 using JSC::Bindings::getJNIEnv;
     36 using WebCore::GeolocationError;
     37 using WebCore::GeolocationPosition;
     38 
     39 namespace android {
     40 
     41 static const char* javaGeolocationServiceClassName = "android/webkit/GeolocationService";
     42 enum javaGeolocationServiceClassMethods {
     43     GeolocationServiceMethodInit = 0,
     44     GeolocationServiceMethodStart,
     45     GeolocationServiceMethodStop,
     46     GeolocationServiceMethodSetEnableGps,
     47     GeolocationServiceMethodCount,
     48 };
     49 static jmethodID javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodCount];
     50 
     51 static const JNINativeMethod javaGeolocationServiceClassNativeMethods[] = {
     52     { "nativeNewLocationAvailable", "(JLandroid/location/Location;)V",
     53         (void*) GeolocationServiceBridge::newLocationAvailable },
     54     { "nativeNewErrorAvailable", "(JLjava/lang/String;)V",
     55         (void*) GeolocationServiceBridge::newErrorAvailable }
     56 };
     57 
     58 static const char *javaLocationClassName = "android/location/Location";
     59 enum javaLocationClassMethods {
     60     LocationMethodGetLatitude = 0,
     61     LocationMethodGetLongitude,
     62     LocationMethodHasAltitude,
     63     LocationMethodGetAltitude,
     64     LocationMethodHasAccuracy,
     65     LocationMethodGetAccuracy,
     66     LocationMethodHasBearing,
     67     LocationMethodGetBearing,
     68     LocationMethodHasSpeed,
     69     LocationMethodGetSpeed,
     70     LocationMethodGetTime,
     71     LocationMethodCount,
     72 };
     73 static jmethodID javaLocationClassMethodIDs[LocationMethodCount];
     74 
     75 GeolocationServiceBridge::GeolocationServiceBridge(Listener* listener, WebViewCore* webViewCore)
     76     : m_listener(listener)
     77     , m_javaGeolocationServiceObject(0)
     78 {
     79     ASSERT(m_listener);
     80     startJavaImplementation(webViewCore);
     81 }
     82 
     83 GeolocationServiceBridge::~GeolocationServiceBridge()
     84 {
     85     stop();
     86     stopJavaImplementation();
     87 }
     88 
     89 bool GeolocationServiceBridge::start()
     90 {
     91     if (!m_javaGeolocationServiceObject)
     92         return false;
     93     return getJNIEnv()->CallBooleanMethod(m_javaGeolocationServiceObject,
     94                                           javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart]);
     95 }
     96 
     97 void GeolocationServiceBridge::stop()
     98 {
     99     if (!m_javaGeolocationServiceObject)
    100         return;
    101     getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
    102                                 javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop]);
    103 }
    104 
    105 void GeolocationServiceBridge::setEnableGps(bool enable)
    106 {
    107     if (!m_javaGeolocationServiceObject)
    108         return;
    109     getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
    110                                 javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps],
    111                                 enable);
    112 }
    113 
    114 void GeolocationServiceBridge::newLocationAvailable(JNIEnv* env, jclass, jlong nativeObject, jobject location)
    115 {
    116     ASSERT(nativeObject);
    117     ASSERT(location);
    118     GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject);
    119     object->m_listener->newPositionAvailable(toGeolocationPosition(env, location));
    120 }
    121 
    122 void GeolocationServiceBridge::newErrorAvailable(JNIEnv* env, jclass, jlong nativeObject, jstring message)
    123 {
    124     GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject);
    125     RefPtr<GeolocationError> error = GeolocationError::create(GeolocationError::PositionUnavailable, jstringToWtfString(env, message));
    126     object->m_listener->newErrorAvailable(error.release());
    127 }
    128 
    129 PassRefPtr<GeolocationPosition> GeolocationServiceBridge::toGeolocationPosition(JNIEnv *env, const jobject &location)
    130 {
    131     // Altitude is optional and may not be supplied.
    132     bool hasAltitude =
    133         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAltitude]);
    134     double Altitude =
    135         hasAltitude ?
    136         env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetAltitude]) :
    137         0.0;
    138     // Accuracy is required, but is not supplied by the emulator.
    139     double Accuracy =
    140         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAccuracy]) ?
    141         env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetAccuracy]) :
    142         0.0;
    143     // heading is optional and may not be supplied.
    144     bool hasHeading =
    145         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasBearing]);
    146     double heading =
    147         hasHeading ?
    148         env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetBearing]) :
    149         0.0;
    150     // speed is optional and may not be supplied.
    151     bool hasSpeed =
    152         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasSpeed]);
    153     double speed =
    154         hasSpeed ?
    155         env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetSpeed]) :
    156         0.0;
    157 
    158     return GeolocationPosition::create(
    159         env->CallLongMethod(location, javaLocationClassMethodIDs[LocationMethodGetTime]) / 1000.0,
    160         env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLatitude]),
    161         env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLongitude]),
    162         Accuracy,
    163         hasAltitude, Altitude,
    164         false, 0.0,  // AltitudeAccuracy not provided.
    165         hasHeading, heading,
    166         hasSpeed, speed);
    167 }
    168 
    169 void GeolocationServiceBridge::startJavaImplementation(WebViewCore* webViewCore)
    170 {
    171     JNIEnv* env = getJNIEnv();
    172 
    173     // Get the Java GeolocationService class.
    174     jclass javaGeolocationServiceClass = env->FindClass(javaGeolocationServiceClassName);
    175     ASSERT(javaGeolocationServiceClass);
    176 
    177     // Set up the methods we wish to call on the Java GeolocationService class.
    178     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit] =
    179             env->GetMethodID(javaGeolocationServiceClass, "<init>", "(Landroid/content/Context;J)V");
    180     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart] =
    181             env->GetMethodID(javaGeolocationServiceClass, "start", "()Z");
    182     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop] =
    183             env->GetMethodID(javaGeolocationServiceClass, "stop", "()V");
    184     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps] =
    185             env->GetMethodID(javaGeolocationServiceClass, "setEnableGps", "(Z)V");
    186 
    187     // Create the Java GeolocationService object.
    188     jobject context = webViewCore->getContext();
    189     if (!context)
    190         return;
    191     jlong nativeObject = reinterpret_cast<jlong>(this);
    192     jobject object = env->NewObject(javaGeolocationServiceClass,
    193                                     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit],
    194                                     context,
    195                                     nativeObject);
    196 
    197     m_javaGeolocationServiceObject = getJNIEnv()->NewGlobalRef(object);
    198     ASSERT(m_javaGeolocationServiceObject);
    199 
    200     // Register to handle calls to native methods of the Java GeolocationService
    201     // object. We register once only.
    202     static int registered = jniRegisterNativeMethods(env,
    203                                                      javaGeolocationServiceClassName,
    204                                                      javaGeolocationServiceClassNativeMethods,
    205                                                      NELEM(javaGeolocationServiceClassNativeMethods));
    206     ASSERT(registered == JNI_OK);
    207 
    208     // Set up the methods we wish to call on the Java Location class.
    209     jclass javaLocationClass = env->FindClass(javaLocationClassName);
    210     ASSERT(javaLocationClass);
    211     javaLocationClassMethodIDs[LocationMethodGetLatitude] =
    212         env->GetMethodID(javaLocationClass, "getLatitude", "()D");
    213     javaLocationClassMethodIDs[LocationMethodGetLongitude] =
    214         env->GetMethodID(javaLocationClass, "getLongitude", "()D");
    215     javaLocationClassMethodIDs[LocationMethodHasAltitude] =
    216         env->GetMethodID(javaLocationClass, "hasAltitude", "()Z");
    217     javaLocationClassMethodIDs[LocationMethodGetAltitude] =
    218         env->GetMethodID(javaLocationClass, "getAltitude", "()D");
    219     javaLocationClassMethodIDs[LocationMethodHasAccuracy] =
    220         env->GetMethodID(javaLocationClass, "hasAccuracy", "()Z");
    221     javaLocationClassMethodIDs[LocationMethodGetAccuracy] =
    222         env->GetMethodID(javaLocationClass, "getAccuracy", "()F");
    223     javaLocationClassMethodIDs[LocationMethodHasBearing] =
    224         env->GetMethodID(javaLocationClass, "hasBearing", "()Z");
    225     javaLocationClassMethodIDs[LocationMethodGetBearing] =
    226         env->GetMethodID(javaLocationClass, "getBearing", "()F");
    227     javaLocationClassMethodIDs[LocationMethodHasSpeed] =
    228         env->GetMethodID(javaLocationClass, "hasSpeed", "()Z");
    229     javaLocationClassMethodIDs[LocationMethodGetSpeed] =
    230         env->GetMethodID(javaLocationClass, "getSpeed", "()F");
    231     javaLocationClassMethodIDs[LocationMethodGetTime] =
    232         env->GetMethodID(javaLocationClass, "getTime", "()J");
    233 }
    234 
    235 void GeolocationServiceBridge::stopJavaImplementation()
    236 {
    237     if (!m_javaGeolocationServiceObject)
    238         return;
    239     getJNIEnv()->DeleteGlobalRef(m_javaGeolocationServiceObject);
    240 }
    241 
    242 } // namespace android
    243