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