/* * 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 #include #include 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(nativeObject); object->m_listener->newPositionAvailable(toGeolocationPosition(env, location)); } void GeolocationServiceBridge::newErrorAvailable(JNIEnv* env, jclass, jlong nativeObject, jstring message) { GeolocationServiceBridge* object = reinterpret_cast(nativeObject); RefPtr error = GeolocationError::create(GeolocationError::PositionUnavailable, jstringToWtfString(env, message)); object->m_listener->newErrorAvailable(error.release()); } PassRefPtr 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, "", "(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(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