• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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