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 "GeolocationClientImpl.h"
28
29 #include <Frame.h>
30 #include <Page.h>
31 #include <GeolocationController.h>
32 #include <GeolocationError.h>
33 #include <GeolocationPosition.h>
34 #include <WebViewCore.h>
35 #if PLATFORM(ANDROID)
36 // Required for sim-eng build
37 #include <math.h>
38 #endif
39 #include <wtf/CurrentTime.h>
40
41 using WebCore::Geolocation;
42 using WebCore::GeolocationError;
43 using WebCore::GeolocationPosition;
44 using WebCore::Timer;
45
46 using namespace std;
47
48 namespace {
49
isPositionMovement(GeolocationPosition * position1,GeolocationPosition * position2)50 bool isPositionMovement(GeolocationPosition* position1, GeolocationPosition* position2)
51 {
52 // For the small distances in which we are likely concerned, it's reasonable
53 // to approximate the distance between the two positions as the sum of the
54 // differences in latitude and longitude.
55 double delta = fabs(position1->latitude() - position2->latitude()) + fabs(position1->longitude() - position2->longitude());
56 // Approximate conversion from degrees of arc to metres.
57 delta *= 60 * 1852;
58 // The threshold is when the distance between the two positions exceeds the
59 // worse (larger) of the two accuracies.
60 int maxAccuracy = max(position1->accuracy(), position2->accuracy());
61 return delta > maxAccuracy;
62 }
63
isPositionMoreAccurate(GeolocationPosition * position1,GeolocationPosition * position2)64 bool isPositionMoreAccurate(GeolocationPosition* position1, GeolocationPosition* position2)
65 {
66 return position2->accuracy() < position1->accuracy();
67 }
68
isPositionMoreTimely(GeolocationPosition * position1)69 bool isPositionMoreTimely(GeolocationPosition* position1)
70 {
71 double currentTime = WTF::currentTime();
72 double maximumAge = 10 * 60; // 10 minutes
73 return currentTime - position1->timestamp() > maximumAge;
74 }
75
76 } // anonymous namespace
77
78 namespace android {
79
GeolocationClientImpl(WebViewCore * webViewCore)80 GeolocationClientImpl::GeolocationClientImpl(WebViewCore* webViewCore)
81 : m_webViewCore(webViewCore)
82 , m_timer(this, &GeolocationClientImpl::timerFired)
83 , m_isSuspended(false)
84 , m_useGps(false)
85 {
86 }
87
~GeolocationClientImpl()88 GeolocationClientImpl::~GeolocationClientImpl()
89 {
90 }
91
geolocationDestroyed()92 void GeolocationClientImpl::geolocationDestroyed()
93 {
94 // Lifetime is managed by GeolocationManager.
95 }
96
startUpdating()97 void GeolocationClientImpl::startUpdating()
98 {
99 // This method is called every time a new watch or one-shot position request
100 // is started. If we already have a position or an error, call back
101 // immediately.
102 if (m_lastPosition || m_lastError) {
103 m_timer.startOneShot(0);
104 }
105
106 // Lazilly create the Java object.
107 bool haveJavaBridge = m_javaBridge;
108 if (!haveJavaBridge)
109 m_javaBridge.set(new GeolocationServiceBridge(this, m_webViewCore));
110 ASSERT(m_javaBridge);
111
112 // Set whether to use GPS before we start the implementation.
113 m_javaBridge->setEnableGps(m_useGps);
114
115 // If we're suspended, don't start the service. It will be started when we
116 // get the call to resume().
117 if (!haveJavaBridge && !m_isSuspended)
118 m_javaBridge->start();
119 }
120
stopUpdating()121 void GeolocationClientImpl::stopUpdating()
122 {
123 // TODO: It would be good to re-use the Java bridge object.
124 m_javaBridge.clear();
125 m_useGps = false;
126 // Reset last position and error to make sure that we always try to get a
127 // new position from the client when a request is first made.
128 m_lastPosition = 0;
129 m_lastError = 0;
130
131 if (m_timer.isActive())
132 m_timer.stop();
133 }
134
setEnableHighAccuracy(bool enableHighAccuracy)135 void GeolocationClientImpl::setEnableHighAccuracy(bool enableHighAccuracy)
136 {
137 // On Android, high power == GPS.
138 m_useGps = enableHighAccuracy;
139 if (m_javaBridge)
140 m_javaBridge->setEnableGps(m_useGps);
141 }
142
lastPosition()143 GeolocationPosition* GeolocationClientImpl::lastPosition()
144 {
145 return m_lastPosition.get();
146 }
147
requestPermission(Geolocation * geolocation)148 void GeolocationClientImpl::requestPermission(Geolocation* geolocation)
149 {
150 permissions()->queryPermissionState(geolocation->frame());
151 }
152
cancelPermissionRequest(Geolocation * geolocation)153 void GeolocationClientImpl::cancelPermissionRequest(Geolocation* geolocation)
154 {
155 permissions()->cancelPermissionStateQuery(geolocation->frame());
156 }
157
158 // Note that there is no guarantee that subsequent calls to this method offer a
159 // more accurate or updated position.
newPositionAvailable(PassRefPtr<GeolocationPosition> position)160 void GeolocationClientImpl::newPositionAvailable(PassRefPtr<GeolocationPosition> position)
161 {
162 ASSERT(position);
163 if (!m_lastPosition
164 || isPositionMovement(m_lastPosition.get(), position.get())
165 || isPositionMoreAccurate(m_lastPosition.get(), position.get())
166 || isPositionMoreTimely(m_lastPosition.get())) {
167 m_lastPosition = position;
168 // Remove the last error.
169 m_lastError = 0;
170 m_webViewCore->mainFrame()->page()->geolocationController()->positionChanged(m_lastPosition.get());
171 }
172 }
173
newErrorAvailable(PassRefPtr<WebCore::GeolocationError> error)174 void GeolocationClientImpl::newErrorAvailable(PassRefPtr<WebCore::GeolocationError> error)
175 {
176 ASSERT(error);
177 // We leave the last position
178 m_lastError = error;
179 m_webViewCore->mainFrame()->page()->geolocationController()->errorOccurred(m_lastError.get());
180 }
181
suspend()182 void GeolocationClientImpl::suspend()
183 {
184 m_isSuspended = true;
185 if (m_javaBridge)
186 m_javaBridge->stop();
187 }
188
resume()189 void GeolocationClientImpl::resume()
190 {
191 m_isSuspended = false;
192 if (m_javaBridge)
193 m_javaBridge->start();
194 }
195
resetTemporaryPermissionStates()196 void GeolocationClientImpl::resetTemporaryPermissionStates()
197 {
198 permissions()->resetTemporaryPermissionStates();
199 }
200
providePermissionState(String origin,bool allow,bool remember)201 void GeolocationClientImpl::providePermissionState(String origin, bool allow, bool remember)
202 {
203 permissions()->providePermissionState(origin, allow, remember);
204 }
205
permissions() const206 GeolocationPermissions* GeolocationClientImpl::permissions() const
207 {
208 if (!m_permissions)
209 m_permissions = new GeolocationPermissions(m_webViewCore);
210 return m_permissions.get();
211 }
212
timerFired(Timer<GeolocationClientImpl> * timer)213 void GeolocationClientImpl::timerFired(Timer<GeolocationClientImpl>* timer)
214 {
215 ASSERT(&m_timer == timer);
216 ASSERT(m_lastPosition || m_lastError);
217 if (m_lastPosition)
218 m_webViewCore->mainFrame()->page()->geolocationController()->positionChanged(m_lastPosition.get());
219 else
220 m_webViewCore->mainFrame()->page()->geolocationController()->errorOccurred(m_lastError.get());
221 }
222
223 } // namespace android
224