Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2009, 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 "GeolocationServiceAndroid.h"
     30 #include "Geoposition.h"
     31 #include "PositionError.h"
     32 #include "WebViewCore.h"
     33 #include <JNIHelp.h>
     34 
     35 namespace WebCore {
     36 
     37 using JSC::Bindings::getJNIEnv;
     38 
     39 static const char* javaGeolocationServiceClassName = "android/webkit/GeolocationService";
     40 enum javaGeolocationServiceClassMethods {
     41     GeolocationServiceMethodInit = 0,
     42     GeolocationServiceMethodStart,
     43     GeolocationServiceMethodStop,
     44     GeolocationServiceMethodSetEnableGps,
     45     GeolocationServiceMethodCount,
     46 };
     47 static jmethodID javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodCount];
     48 
     49 static const JNINativeMethod javaGeolocationServiceClassNativeMethods[] = {
     50     { "nativeNewLocationAvailable", "(JLandroid/location/Location;)V",
     51         (void*) GeolocationServiceBridge::newLocationAvailable },
     52     { "nativeNewErrorAvailable", "(JLjava/lang/String;)V",
     53         (void*) GeolocationServiceBridge::newErrorAvailable }
     54 };
     55 
     56 static const char *javaLocationClassName = "android/location/Location";
     57 enum javaLocationClassMethods {
     58     LocationMethodGetLatitude = 0,
     59     LocationMethodGetLongitude,
     60     LocationMethodHasAltitude,
     61     LocationMethodGetAltitude,
     62     LocationMethodHasAccuracy,
     63     LocationMethodGetAccuracy,
     64     LocationMethodHasBearing,
     65     LocationMethodGetBearing,
     66     LocationMethodHasSpeed,
     67     LocationMethodGetSpeed,
     68     LocationMethodGetTime,
     69     LocationMethodCount,
     70 };
     71 static jmethodID javaLocationClassMethodIDs[LocationMethodCount];
     72 
     73 GeolocationServiceBridge::GeolocationServiceBridge(ListenerInterface* listener)
     74     : m_listener(listener)
     75     , m_javaGeolocationServiceObject(0)
     76 {
     77     ASSERT(m_listener);
     78     startJavaImplementation();
     79 }
     80 
     81 GeolocationServiceBridge::~GeolocationServiceBridge()
     82 {
     83     stop();
     84     stopJavaImplementation();
     85 }
     86 
     87 void GeolocationServiceBridge::start()
     88 {
     89     ASSERT(m_javaGeolocationServiceObject);
     90     getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
     91                                 javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart]);
     92 }
     93 
     94 void GeolocationServiceBridge::stop()
     95 {
     96     ASSERT(m_javaGeolocationServiceObject);
     97     getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
     98                                 javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop]);
     99 }
    100 
    101 void GeolocationServiceBridge::setEnableGps(bool enable)
    102 {
    103     ASSERT(m_javaGeolocationServiceObject);
    104     getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
    105                                 javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps],
    106                                 enable);
    107 }
    108 
    109 void GeolocationServiceBridge::newLocationAvailable(JNIEnv* env, jclass, jlong nativeObject, jobject location)
    110 {
    111     ASSERT(nativeObject);
    112     ASSERT(location);
    113     GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject);
    114     object->m_listener->newPositionAvailable(toGeoposition(env, location));
    115 }
    116 
    117 void GeolocationServiceBridge::newErrorAvailable(JNIEnv* env, jclass, jlong nativeObject, jstring message)
    118 {
    119     GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject);
    120     RefPtr<PositionError> error =
    121         PositionError::create(PositionError::POSITION_UNAVAILABLE, android::to_string(env, message));
    122     object->m_listener->newErrorAvailable(error.release());
    123 }
    124 
    125 PassRefPtr<Geoposition> GeolocationServiceBridge::toGeoposition(JNIEnv *env, const jobject &location)
    126 {
    127     // Altitude is optional and may not be supplied.
    128     bool hasAltitude =
    129         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAltitude]);
    130     double Altitude =
    131         hasAltitude ?
    132         env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetAltitude]) :
    133         0.0;
    134     // Accuracy is required, but is not supplied by the emulator.
    135     double Accuracy =
    136         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAccuracy]) ?
    137         env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetAccuracy]) :
    138         0.0;
    139     // heading is optional and may not be supplied.
    140     bool hasHeading =
    141         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasBearing]);
    142     double heading =
    143         hasHeading ?
    144         env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetBearing]) :
    145         0.0;
    146     // speed is optional and may not be supplied.
    147     bool hasSpeed =
    148         env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasSpeed]);
    149     double speed =
    150         hasSpeed ?
    151         env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetSpeed]) :
    152         0.0;
    153 
    154     RefPtr<Coordinates> newCoordinates = WebCore::Coordinates::create(
    155         env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLatitude]),
    156         env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLongitude]),
    157         hasAltitude, Altitude,
    158         Accuracy,
    159         false, 0.0,  // AltitudeAccuracy not provided.
    160         hasHeading, heading,
    161         hasSpeed, speed);
    162 
    163     return WebCore::Geoposition::create(
    164          newCoordinates.release(),
    165          env->CallLongMethod(location, javaLocationClassMethodIDs[LocationMethodGetTime]));
    166 }
    167 
    168 void GeolocationServiceBridge::startJavaImplementation()
    169 {
    170     JNIEnv* env = getJNIEnv();
    171 
    172     // Get the Java GeolocationService class.
    173     jclass javaGeolocationServiceClass = env->FindClass(javaGeolocationServiceClassName);
    174     ASSERT(javaGeolocationServiceClass);
    175 
    176     // Set up the methods we wish to call on the Java GeolocationService class.
    177     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit] =
    178             env->GetMethodID(javaGeolocationServiceClass, "<init>", "(J)V");
    179     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart] =
    180             env->GetMethodID(javaGeolocationServiceClass, "start", "()V");
    181     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop] =
    182             env->GetMethodID(javaGeolocationServiceClass, "stop", "()V");
    183     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps] =
    184             env->GetMethodID(javaGeolocationServiceClass, "setEnableGps", "(Z)V");
    185 
    186     // Create the Java GeolocationService object.
    187     jlong nativeObject = reinterpret_cast<jlong>(this);
    188     jobject object = env->NewObject(javaGeolocationServiceClass,
    189                                     javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit],
    190                                     nativeObject);
    191 
    192     m_javaGeolocationServiceObject = getJNIEnv()->NewGlobalRef(object);
    193     ASSERT(m_javaGeolocationServiceObject);
    194 
    195     // Register to handle calls to native methods of the Java GeolocationService
    196     // object. We register once only.
    197     static int registered = jniRegisterNativeMethods(env,
    198                                                      javaGeolocationServiceClassName,
    199                                                      javaGeolocationServiceClassNativeMethods,
    200                                                      NELEM(javaGeolocationServiceClassNativeMethods));
    201     ASSERT(registered == JNI_OK);
    202 
    203     // Set up the methods we wish to call on the Java Location class.
    204     jclass javaLocationClass = env->FindClass(javaLocationClassName);
    205     ASSERT(javaLocationClass);
    206     javaLocationClassMethodIDs[LocationMethodGetLatitude] =
    207         env->GetMethodID(javaLocationClass, "getLatitude", "()D");
    208     javaLocationClassMethodIDs[LocationMethodGetLongitude] =
    209         env->GetMethodID(javaLocationClass, "getLongitude", "()D");
    210     javaLocationClassMethodIDs[LocationMethodHasAltitude] =
    211         env->GetMethodID(javaLocationClass, "hasAltitude", "()Z");
    212     javaLocationClassMethodIDs[LocationMethodGetAltitude] =
    213         env->GetMethodID(javaLocationClass, "getAltitude", "()D");
    214     javaLocationClassMethodIDs[LocationMethodHasAccuracy] =
    215         env->GetMethodID(javaLocationClass, "hasAccuracy", "()Z");
    216     javaLocationClassMethodIDs[LocationMethodGetAccuracy] =
    217         env->GetMethodID(javaLocationClass, "getAccuracy", "()F");
    218     javaLocationClassMethodIDs[LocationMethodHasBearing] =
    219         env->GetMethodID(javaLocationClass, "hasBearing", "()Z");
    220     javaLocationClassMethodIDs[LocationMethodGetBearing] =
    221         env->GetMethodID(javaLocationClass, "getBearing", "()F");
    222     javaLocationClassMethodIDs[LocationMethodHasSpeed] =
    223         env->GetMethodID(javaLocationClass, "hasSpeed", "()Z");
    224     javaLocationClassMethodIDs[LocationMethodGetSpeed] =
    225         env->GetMethodID(javaLocationClass, "getSpeed", "()F");
    226     javaLocationClassMethodIDs[LocationMethodGetTime] =
    227         env->GetMethodID(javaLocationClass, "getTime", "()J");
    228 }
    229 
    230 void GeolocationServiceBridge::stopJavaImplementation()
    231 {
    232     // Called by GeolocationServiceAndroid on WebKit thread.
    233     ASSERT(m_javaGeolocationServiceObject);
    234     getJNIEnv()->DeleteGlobalRef(m_javaGeolocationServiceObject);
    235 }
    236 
    237 } // namespace WebCore
    238