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