1/* 2 * Copyright (C) 2012 Igalia S.L. 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. 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 APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "GeolocationProviderGeoclue.h" 28 29#if ENABLE(GEOLOCATION) 30 31#include <wtf/gobject/GOwnPtr.h> 32 33using namespace WebCore; 34 35static void getPositionCallback(GeocluePosition* position, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy, GError* error, GeolocationProviderGeoclue* provider) 36{ 37 if (error) { 38 provider->errorOccurred(error->message); 39 g_error_free(error); 40 return; 41 } 42 provider->positionChanged(position, fields, timestamp, latitude, longitude, altitude, accuracy); 43} 44 45static void positionChangedCallback(GeocluePosition* position, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy, GeolocationProviderGeoclue* provider) 46{ 47 provider->positionChanged(position, fields, timestamp, latitude, longitude, altitude, accuracy); 48} 49 50static void createGeocluePositionCallback(GeoclueMasterClient*, GeocluePosition* position, GError *error, GeolocationProviderGeoclue* provider) 51{ 52 if (error) { 53 provider->errorOccurred(error->message); 54 g_error_free(error); 55 return; 56 } 57 provider->initializeGeocluePosition(position); 58} 59 60static void geoclueClientSetRequirementsCallback(GeoclueMasterClient* client, GError* error, GeolocationProviderGeoclue* provider) 61{ 62 if (error) { 63 provider->errorOccurred(error->message); 64 g_error_free(error); 65 } 66} 67 68static void createGeoclueClientCallback(GeoclueMaster*, GeoclueMasterClient* client, char*, GError* error, GeolocationProviderGeoclue* provider) 69{ 70 if (error) { 71 provider->errorOccurred(error->message); 72 g_error_free(error); 73 return; 74 } 75 provider->initializeGeoclueClient(client); 76} 77 78GeolocationProviderGeoclue::GeolocationProviderGeoclue(GeolocationProviderGeoclueClient* client) 79 : m_client(client) 80 , m_geoclueClient(0) 81 , m_geocluePosition(0) 82 , m_latitude(0) 83 , m_longitude(0) 84 , m_altitude(0) 85 , m_accuracy(0) 86 , m_altitudeAccuracy(0) 87 , m_timestamp(0) 88 , m_enableHighAccuracy(false) 89 , m_isUpdating(false) 90{ 91 ASSERT(m_client); 92} 93 94GeolocationProviderGeoclue::~GeolocationProviderGeoclue() 95{ 96} 97 98void GeolocationProviderGeoclue::startUpdating() 99{ 100 ASSERT(!m_geoclueClient); 101 102 GRefPtr<GeoclueMaster> master = adoptGRef(geoclue_master_get_default()); 103 geoclue_master_create_client_async(master.get(), reinterpret_cast<GeoclueCreateClientCallback>(createGeoclueClientCallback), this); 104 m_isUpdating = true; 105} 106 107void GeolocationProviderGeoclue::stopUpdating() 108{ 109 m_geocluePosition.clear(); 110 m_geoclueClient.clear(); 111 m_isUpdating = false; 112} 113 114void GeolocationProviderGeoclue::setEnableHighAccuracy(bool enable) 115{ 116 m_enableHighAccuracy = enable; 117 118 // If we're already updating we should report the new requirements in order 119 // to change to a more suitable provider if needed. If not, return. 120 if (!m_isUpdating) 121 return; 122 123 updateClientRequirements(); 124} 125 126void GeolocationProviderGeoclue::initializeGeoclueClient(GeoclueMasterClient* geoclueClient) 127{ 128 ASSERT(GEOCLUE_IS_MASTER_CLIENT(geoclueClient)); 129 130 // Store the GeoclueMasterClient object as created by GeoClue. 131 m_geoclueClient = adoptGRef(geoclueClient); 132 133 // Set the requirement for the client and ask it to create a position associated to it. 134 updateClientRequirements(); 135 geoclue_master_client_create_position_async(m_geoclueClient.get(), reinterpret_cast<CreatePositionCallback>(createGeocluePositionCallback), this); 136} 137 138void GeolocationProviderGeoclue::initializeGeocluePosition(GeocluePosition* geocluePosition) 139{ 140 ASSERT(GEOCLUE_IS_POSITION(geocluePosition)); 141 142 // Stores the GeocluePosition object associated with the GeoclueMasterClient. 143 m_geocluePosition = adoptGRef(geocluePosition); 144 145 // Get the initial position and keep updated of further changes. 146 geoclue_position_get_position_async(m_geocluePosition.get(), reinterpret_cast<GeocluePositionCallback>(getPositionCallback), this); 147 g_signal_connect(m_geocluePosition.get(), "position-changed", G_CALLBACK(positionChangedCallback), this); 148} 149 150void GeolocationProviderGeoclue::updateClientRequirements() 151{ 152 if (!m_geoclueClient) 153 return; 154 155 GeoclueAccuracyLevel accuracyLevel = m_enableHighAccuracy ? GEOCLUE_ACCURACY_LEVEL_DETAILED : GEOCLUE_ACCURACY_LEVEL_LOCALITY; 156 geoclue_master_client_set_requirements_async(m_geoclueClient.get(), accuracyLevel, 0, false, GEOCLUE_RESOURCE_ALL, reinterpret_cast<GeoclueSetRequirementsCallback>(geoclueClientSetRequirementsCallback), this); 157} 158 159void GeolocationProviderGeoclue::positionChanged(GeocluePosition* position, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy) 160{ 161 if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) { 162 errorOccurred("Position could not be determined."); 163 return; 164 } 165 166 m_timestamp = timestamp; 167 m_latitude = latitude; 168 m_longitude = longitude; 169 m_altitude = altitude; 170 171 geoclue_accuracy_get_details(accuracy, 0, &m_accuracy, &m_altitudeAccuracy); 172 173 m_client->notifyPositionChanged(m_timestamp, m_latitude, m_longitude, m_altitude, m_accuracy, m_altitudeAccuracy); 174} 175 176void GeolocationProviderGeoclue::errorOccurred(const char* message) 177{ 178 m_client->notifyErrorOccurred(message); 179} 180 181#endif // ENABLE(GEOLOCATION) 182