blob: 056c788c690c6533c4b2ffe5f7c40684ee26b5bf [file] [log] [blame]
/*
* 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