• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Holger Hans Peter Freyther
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 #include "GeolocationServiceGtk.h"
22 
23 #include "CString.h"
24 #include "GOwnPtr.h"
25 #include "NotImplemented.h"
26 #include "PositionOptions.h"
27 
28 namespace WTF {
freeOwnedGPtr(GeoclueAccuracy * accuracy)29     template<> void freeOwnedGPtr<GeoclueAccuracy>(GeoclueAccuracy* accuracy)
30     {
31         if (!accuracy)
32             return;
33 
34         geoclue_accuracy_free(accuracy);
35     }
36 }
37 
38 namespace WebCore {
39 
create(GeolocationServiceClient * client)40 GeolocationService* GeolocationServiceGtk::create(GeolocationServiceClient* client)
41 {
42     return new GeolocationServiceGtk(client);
43 }
44 
45 GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceGtk::create;
46 
GeolocationServiceGtk(GeolocationServiceClient * client)47 GeolocationServiceGtk::GeolocationServiceGtk(GeolocationServiceClient* client)
48     : GeolocationService(client)
49     , m_geoclueClient(0)
50     , m_geocluePosition(0)
51     , m_latitude(0.0)
52     , m_longitude(0.0)
53     , m_altitude(0.0)
54     , m_altitudeAccuracy(0.0)
55     , m_timestamp(0)
56 {
57 }
58 
~GeolocationServiceGtk()59 GeolocationServiceGtk::~GeolocationServiceGtk()
60 {
61     if (m_geoclueClient)
62         g_object_unref(m_geoclueClient);
63 
64     if (m_geocluePosition)
65         g_object_unref(m_geocluePosition);
66 }
67 
68 //
69 // 1.) Initialize Geoclue with our requirements
70 // 2.) Try to get a GeocluePosition
71 // 3.) Update the Information and get the current position
72 //
73 // TODO: Also get GeoclueVelocity but there is no master client
74 //       API for that.
75 //
startUpdating(PositionOptions * options)76 bool GeolocationServiceGtk::startUpdating(PositionOptions* options)
77 {
78     ASSERT(!m_geoclueClient);
79 
80     m_lastPosition = 0;
81     m_lastError = 0;
82 
83     GOwnPtr<GError> error;
84     GeoclueMaster* master = geoclue_master_get_default();
85     GeoclueMasterClient* client = geoclue_master_create_client(master, 0, 0);
86     g_object_unref(master);
87 
88     if (!client) {
89         setError(PositionError::POSITION_UNAVAILABLE, "Could not connect to location provider.");
90         return false;
91     }
92 
93     GeoclueAccuracyLevel accuracyLevel = GEOCLUE_ACCURACY_LEVEL_LOCALITY;
94     int timeout = 0;
95     if (options) {
96         accuracyLevel = options->enableHighAccuracy() ? GEOCLUE_ACCURACY_LEVEL_DETAILED : GEOCLUE_ACCURACY_LEVEL_LOCALITY;
97         timeout = options->timeout();
98     }
99 
100     gboolean result = geoclue_master_client_set_requirements(client, accuracyLevel, timeout,
101                                                              true, GEOCLUE_RESOURCE_ALL, &error.outPtr());
102 
103     if (!result) {
104         setError(PositionError::POSITION_UNAVAILABLE, error->message);
105         g_object_unref(client);
106         return false;
107     }
108 
109     m_geocluePosition = geoclue_master_client_create_position(client, &error.outPtr());
110     if (!m_geocluePosition) {
111         setError(PositionError::POSITION_UNAVAILABLE, error->message);
112         g_object_unref(client);
113         return false;
114     }
115 
116     g_signal_connect(G_OBJECT(m_geocluePosition), "position-changed",
117                      G_CALLBACK(position_changed), this);
118 
119     m_geoclueClient = client;
120     updateLocationInformation();
121 
122     return true;
123 }
124 
stopUpdating()125 void GeolocationServiceGtk::stopUpdating()
126 {
127     if (!m_geoclueClient)
128         return;
129 
130     g_object_unref(m_geocluePosition);
131     g_object_unref(m_geoclueClient);
132 
133     m_geocluePosition = 0;
134     m_geoclueClient = 0;
135 }
136 
suspend()137 void GeolocationServiceGtk::suspend()
138 {
139     // not available with geoclue
140     notImplemented();
141 }
142 
resume()143 void GeolocationServiceGtk::resume()
144 {
145     // not available with geoclue
146     notImplemented();
147 }
148 
lastPosition() const149 Geoposition* GeolocationServiceGtk::lastPosition() const
150 {
151     return m_lastPosition.get();
152 }
153 
lastError() const154 PositionError* GeolocationServiceGtk::lastError() const
155 {
156     return m_lastError.get();
157 }
158 
updateLocationInformation()159 void GeolocationServiceGtk::updateLocationInformation()
160 {
161     ASSERT(m_geocluePosition);
162 
163     GOwnPtr<GError> error;
164     GOwnPtr<GeoclueAccuracy> accuracy;
165 
166     GeocluePositionFields fields = geoclue_position_get_position(m_geocluePosition, &m_timestamp,
167                                                                  &m_latitude, &m_longitude,
168                                                                  &m_altitude, &accuracy.outPtr(),
169                                                                  &error.outPtr());
170     if (error) {
171         setError(PositionError::POSITION_UNAVAILABLE, error->message);
172         return;
173     } else if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
174         setError(PositionError::POSITION_UNAVAILABLE, "Position could not be determined.");
175         return;
176     }
177 
178 
179 }
180 
updatePosition()181 void GeolocationServiceGtk::updatePosition()
182 {
183     m_lastError = 0;
184 
185     RefPtr<Coordinates> coordinates = Coordinates::create(m_latitude, m_longitude,
186                                                           true, m_altitude, m_accuracy,
187                                                           true, m_altitudeAccuracy, false, 0.0, false, 0.0);
188     m_lastPosition = Geoposition::create(coordinates.release(), m_timestamp * 1000.0);
189     positionChanged();
190 }
191 
position_changed(GeocluePosition *,GeocluePositionFields fields,int timestamp,double latitude,double longitude,double altitude,GeoclueAccuracy * accuracy,GeolocationServiceGtk * that)192 void GeolocationServiceGtk::position_changed(GeocluePosition*, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy, GeolocationServiceGtk* that)
193 {
194     if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
195         that->setError(PositionError::POSITION_UNAVAILABLE, "Position could not be determined.");
196         return;
197     }
198 
199     that->m_timestamp = timestamp;
200     that->m_latitude = latitude;
201     that->m_longitude = longitude;
202     that->m_altitude = altitude;
203 
204     GeoclueAccuracyLevel level;
205     geoclue_accuracy_get_details(accuracy, &level, &that->m_accuracy, &that->m_altitudeAccuracy);
206     that->updatePosition();
207 }
208 
setError(PositionError::ErrorCode errorCode,const char * message)209 void GeolocationServiceGtk::setError(PositionError::ErrorCode errorCode, const char* message)
210 {
211     m_lastPosition = 0;
212     m_lastError = PositionError::create(errorCode, String::fromUTF8(message));
213 }
214 
215 }
216