• 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 "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