| /* |
| * Copyright 2012, The Android Open Source Project |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "GeolocationServiceBridge.h" |
| |
| #include "WebViewCore.h" |
| |
| #include <GeolocationError.h> |
| #include <GeolocationPosition.h> |
| #include <JNIHelp.h> |
| |
| using JSC::Bindings::getJNIEnv; |
| using WebCore::GeolocationError; |
| using WebCore::GeolocationPosition; |
| |
| namespace android { |
| |
| static const char* javaGeolocationServiceClassName = "android/webkit/GeolocationService"; |
| enum javaGeolocationServiceClassMethods { |
| GeolocationServiceMethodInit = 0, |
| GeolocationServiceMethodStart, |
| GeolocationServiceMethodStop, |
| GeolocationServiceMethodSetEnableGps, |
| GeolocationServiceMethodCount, |
| }; |
| static jmethodID javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodCount]; |
| |
| static const JNINativeMethod javaGeolocationServiceClassNativeMethods[] = { |
| { "nativeNewLocationAvailable", "(JLandroid/location/Location;)V", |
| (void*) GeolocationServiceBridge::newLocationAvailable }, |
| { "nativeNewErrorAvailable", "(JLjava/lang/String;)V", |
| (void*) GeolocationServiceBridge::newErrorAvailable } |
| }; |
| |
| static const char *javaLocationClassName = "android/location/Location"; |
| enum javaLocationClassMethods { |
| LocationMethodGetLatitude = 0, |
| LocationMethodGetLongitude, |
| LocationMethodHasAltitude, |
| LocationMethodGetAltitude, |
| LocationMethodHasAccuracy, |
| LocationMethodGetAccuracy, |
| LocationMethodHasBearing, |
| LocationMethodGetBearing, |
| LocationMethodHasSpeed, |
| LocationMethodGetSpeed, |
| LocationMethodGetTime, |
| LocationMethodCount, |
| }; |
| static jmethodID javaLocationClassMethodIDs[LocationMethodCount]; |
| |
| GeolocationServiceBridge::GeolocationServiceBridge(Listener* listener, WebViewCore* webViewCore) |
| : m_listener(listener) |
| , m_javaGeolocationServiceObject(0) |
| { |
| ASSERT(m_listener); |
| startJavaImplementation(webViewCore); |
| } |
| |
| GeolocationServiceBridge::~GeolocationServiceBridge() |
| { |
| stop(); |
| stopJavaImplementation(); |
| } |
| |
| bool GeolocationServiceBridge::start() |
| { |
| if (!m_javaGeolocationServiceObject) |
| return false; |
| return getJNIEnv()->CallBooleanMethod(m_javaGeolocationServiceObject, |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart]); |
| } |
| |
| void GeolocationServiceBridge::stop() |
| { |
| if (!m_javaGeolocationServiceObject) |
| return; |
| getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject, |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop]); |
| } |
| |
| void GeolocationServiceBridge::setEnableGps(bool enable) |
| { |
| if (!m_javaGeolocationServiceObject) |
| return; |
| getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject, |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps], |
| enable); |
| } |
| |
| void GeolocationServiceBridge::newLocationAvailable(JNIEnv* env, jclass, jlong nativeObject, jobject location) |
| { |
| ASSERT(nativeObject); |
| ASSERT(location); |
| GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject); |
| object->m_listener->newPositionAvailable(toGeolocationPosition(env, location)); |
| } |
| |
| void GeolocationServiceBridge::newErrorAvailable(JNIEnv* env, jclass, jlong nativeObject, jstring message) |
| { |
| GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject); |
| RefPtr<GeolocationError> error = GeolocationError::create(GeolocationError::PositionUnavailable, jstringToWtfString(env, message)); |
| object->m_listener->newErrorAvailable(error.release()); |
| } |
| |
| PassRefPtr<GeolocationPosition> GeolocationServiceBridge::toGeolocationPosition(JNIEnv *env, const jobject &location) |
| { |
| // Altitude is optional and may not be supplied. |
| bool hasAltitude = |
| env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAltitude]); |
| double Altitude = |
| hasAltitude ? |
| env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetAltitude]) : |
| 0.0; |
| // Accuracy is required, but is not supplied by the emulator. |
| double Accuracy = |
| env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAccuracy]) ? |
| env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetAccuracy]) : |
| 0.0; |
| // heading is optional and may not be supplied. |
| bool hasHeading = |
| env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasBearing]); |
| double heading = |
| hasHeading ? |
| env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetBearing]) : |
| 0.0; |
| // speed is optional and may not be supplied. |
| bool hasSpeed = |
| env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasSpeed]); |
| double speed = |
| hasSpeed ? |
| env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetSpeed]) : |
| 0.0; |
| |
| return GeolocationPosition::create( |
| env->CallLongMethod(location, javaLocationClassMethodIDs[LocationMethodGetTime]) / 1000.0, |
| env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLatitude]), |
| env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLongitude]), |
| Accuracy, |
| hasAltitude, Altitude, |
| false, 0.0, // AltitudeAccuracy not provided. |
| hasHeading, heading, |
| hasSpeed, speed); |
| } |
| |
| void GeolocationServiceBridge::startJavaImplementation(WebViewCore* webViewCore) |
| { |
| JNIEnv* env = getJNIEnv(); |
| |
| // Get the Java GeolocationService class. |
| jclass javaGeolocationServiceClass = env->FindClass(javaGeolocationServiceClassName); |
| ASSERT(javaGeolocationServiceClass); |
| |
| // Set up the methods we wish to call on the Java GeolocationService class. |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit] = |
| env->GetMethodID(javaGeolocationServiceClass, "<init>", "(Landroid/content/Context;J)V"); |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart] = |
| env->GetMethodID(javaGeolocationServiceClass, "start", "()Z"); |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop] = |
| env->GetMethodID(javaGeolocationServiceClass, "stop", "()V"); |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps] = |
| env->GetMethodID(javaGeolocationServiceClass, "setEnableGps", "(Z)V"); |
| |
| // Create the Java GeolocationService object. |
| jobject context = webViewCore->getContext(); |
| if (!context) |
| return; |
| jlong nativeObject = reinterpret_cast<jlong>(this); |
| jobject object = env->NewObject(javaGeolocationServiceClass, |
| javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit], |
| context, |
| nativeObject); |
| |
| m_javaGeolocationServiceObject = getJNIEnv()->NewGlobalRef(object); |
| ASSERT(m_javaGeolocationServiceObject); |
| |
| // Register to handle calls to native methods of the Java GeolocationService |
| // object. We register once only. |
| static int registered = jniRegisterNativeMethods(env, |
| javaGeolocationServiceClassName, |
| javaGeolocationServiceClassNativeMethods, |
| NELEM(javaGeolocationServiceClassNativeMethods)); |
| ASSERT(registered == JNI_OK); |
| |
| // Set up the methods we wish to call on the Java Location class. |
| jclass javaLocationClass = env->FindClass(javaLocationClassName); |
| ASSERT(javaLocationClass); |
| javaLocationClassMethodIDs[LocationMethodGetLatitude] = |
| env->GetMethodID(javaLocationClass, "getLatitude", "()D"); |
| javaLocationClassMethodIDs[LocationMethodGetLongitude] = |
| env->GetMethodID(javaLocationClass, "getLongitude", "()D"); |
| javaLocationClassMethodIDs[LocationMethodHasAltitude] = |
| env->GetMethodID(javaLocationClass, "hasAltitude", "()Z"); |
| javaLocationClassMethodIDs[LocationMethodGetAltitude] = |
| env->GetMethodID(javaLocationClass, "getAltitude", "()D"); |
| javaLocationClassMethodIDs[LocationMethodHasAccuracy] = |
| env->GetMethodID(javaLocationClass, "hasAccuracy", "()Z"); |
| javaLocationClassMethodIDs[LocationMethodGetAccuracy] = |
| env->GetMethodID(javaLocationClass, "getAccuracy", "()F"); |
| javaLocationClassMethodIDs[LocationMethodHasBearing] = |
| env->GetMethodID(javaLocationClass, "hasBearing", "()Z"); |
| javaLocationClassMethodIDs[LocationMethodGetBearing] = |
| env->GetMethodID(javaLocationClass, "getBearing", "()F"); |
| javaLocationClassMethodIDs[LocationMethodHasSpeed] = |
| env->GetMethodID(javaLocationClass, "hasSpeed", "()Z"); |
| javaLocationClassMethodIDs[LocationMethodGetSpeed] = |
| env->GetMethodID(javaLocationClass, "getSpeed", "()F"); |
| javaLocationClassMethodIDs[LocationMethodGetTime] = |
| env->GetMethodID(javaLocationClass, "getTime", "()J"); |
| } |
| |
| void GeolocationServiceBridge::stopJavaImplementation() |
| { |
| if (!m_javaGeolocationServiceObject) |
| return; |
| getJNIEnv()->DeleteGlobalRef(m_javaGeolocationServiceObject); |
| } |
| |
| } // namespace android |