Home | History | Annotate | Download | only in WebCoreSupport
      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 
     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 
     64 bool isPositionMoreAccurate(GeolocationPosition* position1, GeolocationPosition* position2)
     65 {
     66     return position2->accuracy() < position1->accuracy();
     67 }
     68 
     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 
     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 
     88 GeolocationClientImpl::~GeolocationClientImpl()
     89 {
     90 }
     91 
     92 void GeolocationClientImpl::geolocationDestroyed()
     93 {
     94     // Lifetime is managed by GeolocationManager.
     95 }
     96 
     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 
    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 
    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 
    143 GeolocationPosition* GeolocationClientImpl::lastPosition()
    144 {
    145     return m_lastPosition.get();
    146 }
    147 
    148 void GeolocationClientImpl::requestPermission(Geolocation* geolocation)
    149 {
    150     permissions()->queryPermissionState(geolocation->frame());
    151 }
    152 
    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.
    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 
    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 
    182 void GeolocationClientImpl::suspend()
    183 {
    184     m_isSuspended = true;
    185     if (m_javaBridge)
    186         m_javaBridge->stop();
    187 }
    188 
    189 void GeolocationClientImpl::resume()
    190 {
    191     m_isSuspended = false;
    192     if (m_javaBridge)
    193         m_javaBridge->start();
    194 }
    195 
    196 void GeolocationClientImpl::resetTemporaryPermissionStates()
    197 {
    198     permissions()->resetTemporaryPermissionStates();
    199 }
    200 
    201 void GeolocationClientImpl::providePermissionState(String origin, bool allow, bool remember)
    202 {
    203     permissions()->providePermissionState(origin, allow, remember);
    204 }
    205 
    206 GeolocationPermissions* GeolocationClientImpl::permissions() const
    207 {
    208     if (!m_permissions)
    209         m_permissions = new GeolocationPermissions(m_webViewCore);
    210     return m_permissions.get();
    211 }
    212 
    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