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