Merge lp:~stolowski/unity-scopes-shell/location-changes into lp:unity-scopes-shell
- location-changes
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Marcus Tomlinson |
Approved revision: | 320 |
Merged at revision: | 328 |
Proposed branch: | lp:~stolowski/unity-scopes-shell/location-changes |
Merge into: | lp:unity-scopes-shell |
Diff against target: |
1800 lines (+461/-742) 23 files modified
CMakeLists.txt (+2/-2) debian/control (+3/-7) debian/control.in (+1/-5) po/POTFILES.in (+11/-4) src/CMakeLists.txt (+1/-7) src/Unity/CMakeLists.txt (+1/-1) src/Unity/locationaccesshelper.cpp (+105/-0) src/Unity/locationaccesshelper.h (+56/-0) src/Unity/locationservice.cpp (+0/-26) src/Unity/locationservice.h (+0/-72) src/Unity/overviewscope.cpp (+1/-1) src/Unity/overviewscope.h (+1/-1) src/Unity/scope.cpp (+46/-9) src/Unity/scope.h (+7/-5) src/Unity/scopes.cpp (+27/-5) src/Unity/scopes.h (+7/-3) src/Unity/settingsmodel.cpp (+8/-1) src/Unity/settingsmodel.h (+2/-1) src/Unity/ubuntulocationservice.cpp (+132/-269) src/Unity/ubuntulocationservice.h (+50/-20) tests/CMakeLists.txt (+0/-3) tests/geoip.ubuntu.com.py (+0/-66) tests/locationtest.cpp (+0/-234) |
To merge this branch: | bzr merge lp:~stolowski/unity-scopes-shell/location-changes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Marcus Tomlinson (community) | Approve | ||
PS Jenkins bot | continuous-integration | Pending | |
Review via email: mp+285332@code.launchpad.net |
Commit message
Use Qt Location API.
Description of the change
Use Qt Location API. It should be tested with corresponding unity8 branch that makes the Dash run confined with apparmor.
I've added a new section to the test plan https:/
Paweł Stołowski (stolowski) wrote : | # |
> Looks good, although one observation:
>
> I have Nearby favourited. Once I have enabled location access to scopes and I
> restart the phone, the scope says "Please enable location..." again. I also
> notice incorrect weather shown on the Today scope. There's obviously a race in
> scopes startup and the location becoming available/
> sure how easy this would be to fix, but it is a bit confusing.
Right. I've missed that during my refactoring. The implementation should handle this now, however for some reason I'm always getting error (access denied) from Qt location API on the initial request when Dash is starting. I asked Thomas to check the backend.
>
> + For some reason I can't edit the test plan page anymore, so I'll just add
> review comments for that here:
>
> 1) "for testing purposes, remove
> home/phablet/
>
> missing a / before "home"
>
> 2) Select 'Deny'.
>
> should say "Select 'Don't Allow'."
Ok, the test plan has been fixed.
Marcus Tomlinson (marcustomlinson) wrote : | # |
Something weird is happening now. When I select "Don't Allow" location access, scopes that use location appear completely blank (Nothing. Not even a title.).
Looks like we're stuck in a retry loop or something. unity8-dash.log: http://
When I enable location access, all scopes work fine again. After disabling location access and rebooting, I get the same blank scope behaviour again :(
Paweł Stołowski (stolowski) wrote : | # |
> Something weird is happening now. When I select "Don't Allow" location access,
> scopes that use location appear completely blank (Nothing. Not even a title.).
>
> Looks like we're stuck in a retry loop or something. unity8-dash.log:
> http://
>
> When I enable location access, all scopes work fine again. After disabling
> location access and rebooting, I get the same blank scope behaviour again :(
Okay, that should be fixed now.
Marcus Tomlinson (marcustomlinson) wrote : | # |
Awesome, so apart from the denied location access on startup, this looks good!
Marcus Tomlinson (marcustomlinson) wrote : | # |
:P Oops! As discussed on IRC: the location access request occurs on setActive(), which causes a weird situation where a user that lands on say: Today or Nearby won't ever get location-specific data if all he/she did was pull to refresh over and over.
Marcus Tomlinson (marcustomlinson) wrote : | # |
Yep, that does it :) Thanks for the perseverance!
Paweł Stołowski (stolowski) wrote : | # |
Simplified the logic to show location prompt immediately on first user-initiated search so long as affected scope needs location. This makes it less confusing. Setting to needing review again.
Marcus Tomlinson (marcustomlinson) wrote : | # |
> Simplified the logic to show location prompt immediately on first user-
> initiated search so long as affected scope needs location. This makes it less
> confusing. Setting to needing review again.
This is even better! Excellent job Pawel. Looks great.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-05-05 09:40:46 +0000 |
3 | +++ CMakeLists.txt 2016-06-10 15:06:19 +0000 |
4 | @@ -47,6 +47,7 @@ |
5 | find_package(Qt5Qml) |
6 | find_package(Qt5Quick) |
7 | find_package(Qt5Gui) |
8 | +find_package(Qt5Positioning) |
9 | find_package(Qt5Test) |
10 | find_package(Boost COMPONENTS regex REQUIRED) |
11 | |
12 | @@ -54,7 +55,6 @@ |
13 | pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=12) |
14 | |
15 | pkg_check_modules(GSETTINGSQT REQUIRED gsettings-qt) |
16 | -pkg_check_modules(UBUNTU_LOCATION_SERVICE REQUIRED ubuntu-location-service) |
17 | pkg_check_modules(ONLINE_ACCOUNTS_CLIENT REQUIRED OnlineAccountsClient) |
18 | |
19 | # Standard install paths |
20 | @@ -122,6 +122,6 @@ |
21 | add_subdirectory(src) |
22 | add_subdirectory(tests) |
23 | add_subdirectory(data) |
24 | -add_subdirectory(tools) |
25 | +#add_subdirectory(tools) |
26 | add_subdirectory(po) |
27 | add_subdirectory(docs) |
28 | |
29 | === modified file 'debian/control' |
30 | --- debian/control 2016-05-25 08:16:27 +0000 |
31 | +++ debian/control 2016-06-10 15:06:19 +0000 |
32 | @@ -13,17 +13,13 @@ |
33 | libgsettings-qt-dev (>= 0.1), |
34 | libqtdbustest1-dev (>= 0.2), |
35 | libqtdbusmock1-dev (>= 0.2), |
36 | - libubuntu-location-service-dev (>= 2.0.1), |
37 | pkg-config, |
38 | python3-dev, |
39 | -# the two python- lines should be removed once lp bug #1582280 is fixed |
40 | - python-singledispatch | python-tornado (<< 4.3.0), |
41 | - python-backports-abc | python-tornado (<< 4.3.0), |
42 | - python-tornado, |
43 | python3-sphinx, |
44 | qtdeclarative5-dev, |
45 | qtdeclarative5-dev-tools, |
46 | qtdeclarative5-qtquick2-plugin, |
47 | + qtpositioning5-dev, |
48 | unity-schemas (>= 7.3.1), |
49 | libonline-accounts-client-dev, |
50 | intltool, |
51 | @@ -61,7 +57,7 @@ |
52 | Description: QML plugin for Scopes |
53 | Plugin to integrate scopes with the Unity shell |
54 | |
55 | -Package: libscope-harness3 |
56 | +Package: libscope-harness2 |
57 | Section: libdevel |
58 | Architecture: any |
59 | Multi-Arch: same |
60 | @@ -77,7 +73,7 @@ |
61 | Multi-Arch: same |
62 | Depends: ${misc:Depends}, |
63 | ${shlibs:Depends}, |
64 | - libscope-harness3 (= ${binary:Version}) |
65 | + libscope-harness2 (= ${binary:Version}) |
66 | Description: Test harness for Unity scopes |
67 | Drive Unity scopes with a simple synchronous API. Make assertions |
68 | about results. Development files. |
69 | |
70 | === modified file 'debian/control.in' |
71 | --- debian/control.in 2016-05-25 08:16:18 +0000 |
72 | +++ debian/control.in 2016-06-10 15:06:19 +0000 |
73 | @@ -13,17 +13,13 @@ |
74 | libgsettings-qt-dev (>= 0.1), |
75 | libqtdbustest1-dev (>= 0.2), |
76 | libqtdbusmock1-dev (>= 0.2), |
77 | - libubuntu-location-service-dev (>= 2.0.1), |
78 | pkg-config, |
79 | python3-dev, |
80 | -# the two python- lines should be removed once lp bug #1582280 is fixed |
81 | - python-singledispatch | python-tornado (<< 4.3.0), |
82 | - python-backports-abc | python-tornado (<< 4.3.0), |
83 | - python-tornado, |
84 | python3-sphinx, |
85 | qtdeclarative5-dev, |
86 | qtdeclarative5-dev-tools, |
87 | qtdeclarative5-qtquick2-plugin, |
88 | + qtpositioning5-dev, |
89 | unity-schemas (>= 7.3.1), |
90 | libonline-accounts-client-dev, |
91 | intltool, |
92 | |
93 | === modified file 'po/POTFILES.in' |
94 | --- po/POTFILES.in 2016-03-30 09:43:27 +0000 |
95 | +++ po/POTFILES.in 2016-06-10 15:06:19 +0000 |
96 | @@ -6,11 +6,10 @@ |
97 | tests/previewtest.cpp |
98 | tests/overviewtest.cpp |
99 | tests/departmentstest.cpp |
100 | -tests/locationtest.cpp |
101 | tests/filtersendtoendtest.cpp |
102 | +tests/scopesinittest.cpp |
103 | tests/favoritestest.cpp |
104 | tests/optionselectorfiltertest.cpp |
105 | -tests/data/scopes/scopes.cpp |
106 | tests/data/mock-scope-departments/mock-scope-departments.cpp |
107 | tests/data/mock-scope-filters/mock-scope-filters.cpp |
108 | tests/data/mock-scope-ttl/mock-scope-ttl.cpp |
109 | @@ -64,6 +63,7 @@ |
110 | src/python/scope_harness/results-view-py.cpp |
111 | src/python/scope_harness/preview-widget-py.cpp |
112 | src/python/scope_harness/preview-widget-list-py.cpp |
113 | +src/Unity/rangeinputfilter.cpp |
114 | src/Unity/previewwidgetmodel.cpp |
115 | src/Unity/departmentnode.cpp |
116 | src/Unity/logintoaccount.cpp |
117 | @@ -75,16 +75,19 @@ |
118 | src/Unity/geoip.cpp |
119 | src/Unity/plugin.cpp |
120 | src/Unity/scopes.cpp |
121 | +src/Unity/filtergroupwidget.cpp |
122 | src/Unity/filters.cpp |
123 | src/Unity/optionselectoroptions.cpp |
124 | +src/Unity/locationaccesshelper.cpp |
125 | src/Unity/settingsmodel.cpp |
126 | src/Unity/utils.cpp |
127 | src/Unity/optionselectorfilter.cpp |
128 | src/Unity/resultsmap.cpp |
129 | -src/Unity/locationservice.cpp |
130 | src/Unity/ubuntulocationservice.cpp |
131 | +src/Unity/valueslidervalues.cpp |
132 | src/Unity/iconutils.cpp |
133 | src/Unity/department.cpp |
134 | +src/Unity/valuesliderfilter.cpp |
135 | src/Unity/categories.cpp |
136 | src/Unity/overviewresults.cpp |
137 | src/Unity/resultsmodel.cpp |
138 | @@ -134,16 +137,20 @@ |
139 | src/Unity/overviewresults.h |
140 | src/Unity/plugin.h |
141 | src/Unity/department.h |
142 | +src/Unity/valueslidervalues.h |
143 | +src/Unity/locationaccesshelper.h |
144 | src/Unity/scope.h |
145 | +src/Unity/rangeinputfilter.h |
146 | src/Unity/filters.h |
147 | src/Unity/logintoaccount.h |
148 | src/Unity/overviewcategories.h |
149 | src/Unity/modelupdate.h |
150 | -src/Unity/locationservice.h |
151 | src/Unity/overviewscope.h |
152 | src/Unity/settingsmodel.h |
153 | +src/Unity/valuesliderfilter.h |
154 | src/Unity/resultsmodel.h |
155 | src/Unity/geoip.h |
156 | +src/Unity/filtergroupwidget.h |
157 | src/Unity/resultsmap.h |
158 | src/Unity/collectors.h |
159 | src/Unity/previewwidgetmodel.h |
160 | |
161 | === modified file 'src/CMakeLists.txt' |
162 | --- src/CMakeLists.txt 2015-06-17 06:56:58 +0000 |
163 | +++ src/CMakeLists.txt 2016-06-10 15:06:19 +0000 |
164 | @@ -1,14 +1,8 @@ |
165 | - |
166 | -include_directories( |
167 | - ${UBUNTU_LOCATION_SERVICE_INCLUDE_DIRS} |
168 | -) |
169 | - |
170 | set( |
171 | SCOPES_SHELL_DEPENDENCIES |
172 | ${SCOPESLIB_LDFLAGS} |
173 | ${GSETTINGSQT_LDFLAGS} |
174 | ${U1DB_LDFLAGS} |
175 | - ${UBUNTU_LOCATION_SERVICE_LDFLAGS} |
176 | ${ONLINE_ACCOUNTS_CLIENT_LDFLAGS} |
177 | ) |
178 | |
179 | @@ -19,9 +13,9 @@ |
180 | Gui |
181 | Network |
182 | Qml |
183 | + Positioning |
184 | ) |
185 | |
186 | add_subdirectory(Unity) |
187 | add_subdirectory(scope-harness) |
188 | add_subdirectory(python) |
189 | - |
190 | |
191 | === modified file 'src/Unity/CMakeLists.txt' |
192 | --- src/Unity/CMakeLists.txt 2016-03-10 15:54:33 +0000 |
193 | +++ src/Unity/CMakeLists.txt 2016-06-10 15:06:19 +0000 |
194 | @@ -29,7 +29,7 @@ |
195 | valueslidervalues.cpp |
196 | geoip.cpp |
197 | localization.h |
198 | - locationservice.cpp |
199 | + locationaccesshelper.cpp |
200 | overviewcategories.cpp |
201 | overviewresults.cpp |
202 | overviewscope.cpp |
203 | |
204 | === added file 'src/Unity/locationaccesshelper.cpp' |
205 | --- src/Unity/locationaccesshelper.cpp 1970-01-01 00:00:00 +0000 |
206 | +++ src/Unity/locationaccesshelper.cpp 2016-06-10 15:06:19 +0000 |
207 | @@ -0,0 +1,105 @@ |
208 | +/* |
209 | + * Copyright (C) 2016 Canonical, Ltd. |
210 | + * |
211 | + * Authors: |
212 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
213 | + * |
214 | + * This program is free software; you can redistribute it and/or modify |
215 | + * it under the terms of the GNU General Public License as published by |
216 | + * the Free Software Foundation; version 3. |
217 | + * |
218 | + * This program is distributed in the hope that it will be useful, |
219 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
220 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
221 | + * GNU General Public License for more details. |
222 | + * |
223 | + * You should have received a copy of the GNU General Public License |
224 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
225 | + */ |
226 | + |
227 | +#include "locationaccesshelper.h" |
228 | +#include <QDir> |
229 | +#include <QFile> |
230 | +#include <QStandardPaths> |
231 | +#include <QDebug> |
232 | + |
233 | +namespace scopes_ng |
234 | +{ |
235 | + |
236 | +const QString LocationAccessHelper::scopesLocationDotFile = ".scopesLocationPrompt"; |
237 | + |
238 | +LocationAccessHelper::LocationAccessHelper(QObject *parent) : |
239 | + QObject(parent), |
240 | + m_dotFileExists(false), |
241 | + m_denied(true) |
242 | +{ |
243 | +} |
244 | + |
245 | +void LocationAccessHelper::init() |
246 | +{ |
247 | + auto const path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); |
248 | + QDir locationPromptFile(path); |
249 | + m_dotFileExists = locationPromptFile.exists(scopesLocationDotFile); |
250 | + |
251 | + if (m_dotFileExists) { |
252 | + // dot file exists, it means user was already prompted for location so we can |
253 | + // safely request location on startup without risking immediate trusted prompt. |
254 | + Q_EMIT requestInitialLocation(); |
255 | + } |
256 | +} |
257 | + |
258 | +bool LocationAccessHelper::trustedPromptWasShown() const |
259 | +{ |
260 | + return m_dotFileExists; |
261 | +} |
262 | + |
263 | +bool LocationAccessHelper::isLocationAccessDenied() const |
264 | +{ |
265 | + return m_denied; |
266 | +} |
267 | + |
268 | +void LocationAccessHelper::geoIpLookupFinished() |
269 | +{ |
270 | + qDebug() << "LocationAccessHelper::geoIpLookupFinished"; |
271 | + // This signal is not interesting at the moment. If, however we need to refresh scopes on location update, |
272 | + // then it should be re-emited (forwarded) here and in positonChanged() below. |
273 | +} |
274 | + |
275 | +void LocationAccessHelper::positionChanged() |
276 | +{ |
277 | + if (m_denied) { |
278 | + m_denied = false; |
279 | + Q_EMIT accessChanged(); |
280 | + } |
281 | + |
282 | + if (!m_dotFileExists) { |
283 | + createLocationPromptFile(); |
284 | + } |
285 | +} |
286 | + |
287 | +void LocationAccessHelper::accessDenied() |
288 | +{ |
289 | + qDebug() << "LocationAccessHelper::accessDenied"; |
290 | + if (!m_denied) { |
291 | + m_denied = true; |
292 | + Q_EMIT accessChanged(); |
293 | + } |
294 | + |
295 | + if (!m_dotFileExists) { |
296 | + createLocationPromptFile(); |
297 | + } |
298 | +} |
299 | + |
300 | +void LocationAccessHelper::createLocationPromptFile() |
301 | +{ |
302 | + auto const path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/" + scopesLocationDotFile; |
303 | + QFile locationPromptFile(path); |
304 | + if (locationPromptFile.open(QIODevice::WriteOnly)) { |
305 | + qDebug() << "Creating" << locationPromptFile.fileName(); |
306 | + m_dotFileExists = true; |
307 | + } else { |
308 | + qWarning() << "Failed to create" << locationPromptFile.fileName(); |
309 | + } |
310 | +} |
311 | + |
312 | +} |
313 | |
314 | === added file 'src/Unity/locationaccesshelper.h' |
315 | --- src/Unity/locationaccesshelper.h 1970-01-01 00:00:00 +0000 |
316 | +++ src/Unity/locationaccesshelper.h 2016-06-10 15:06:19 +0000 |
317 | @@ -0,0 +1,56 @@ |
318 | +/* |
319 | + * Copyright (C) 2016 Canonical, Ltd. |
320 | + * |
321 | + * Authors: |
322 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
323 | + * |
324 | + * This program is free software; you can redistribute it and/or modify |
325 | + * it under the terms of the GNU General Public License as published by |
326 | + * the Free Software Foundation; version 3. |
327 | + * |
328 | + * This program is distributed in the hope that it will be useful, |
329 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
330 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
331 | + * GNU General Public License for more details. |
332 | + * |
333 | + * You should have received a copy of the GNU General Public License |
334 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
335 | + */ |
336 | + |
337 | +#pragma once |
338 | + |
339 | +#include <QObject> |
340 | + |
341 | +namespace scopes_ng |
342 | +{ |
343 | + |
344 | +class Q_DECL_EXPORT LocationAccessHelper: public QObject |
345 | +{ |
346 | + Q_OBJECT |
347 | + |
348 | +public: |
349 | + LocationAccessHelper(QObject *parent = nullptr); |
350 | + void init(); |
351 | + |
352 | + bool trustedPromptWasShown() const; |
353 | + bool isLocationAccessDenied() const; |
354 | + |
355 | +public Q_SLOTS: |
356 | + void accessDenied(); |
357 | + void positionChanged(); |
358 | + void geoIpLookupFinished(); |
359 | + |
360 | +Q_SIGNALS: |
361 | + void accessChanged(); |
362 | + void requestInitialLocation(); |
363 | + |
364 | +private: |
365 | + void createLocationPromptFile(); |
366 | + |
367 | + bool m_dotFileExists; |
368 | + bool m_denied; |
369 | + |
370 | + static const QString scopesLocationDotFile; |
371 | +}; |
372 | + |
373 | +} |
374 | |
375 | === removed file 'src/Unity/locationservice.cpp' |
376 | --- src/Unity/locationservice.cpp 2014-07-15 08:37:40 +0000 |
377 | +++ src/Unity/locationservice.cpp 1970-01-01 00:00:00 +0000 |
378 | @@ -1,26 +0,0 @@ |
379 | -/* |
380 | - * Copyright (C) 2014 Canonical, Ltd. |
381 | - * |
382 | - * This program is free software; you can redistribute it and/or modify |
383 | - * it under the terms of the GNU General Public License as published by |
384 | - * the Free Software Foundation; version 3. |
385 | - * |
386 | - * This program is distributed in the hope that it will be useful, |
387 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
388 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
389 | - * GNU General Public License for more details. |
390 | - * |
391 | - * You should have received a copy of the GNU General Public License |
392 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
393 | - * |
394 | - * Authors: |
395 | - * Pete Woods <pete.woods@canonical.com> |
396 | - */ |
397 | - |
398 | -#include <locationservice.h> |
399 | - |
400 | -using namespace scopes_ng; |
401 | - |
402 | -LocationService::LocationService() { |
403 | - |
404 | -} |
405 | |
406 | === removed file 'src/Unity/locationservice.h' |
407 | --- src/Unity/locationservice.h 2015-02-26 18:02:32 +0000 |
408 | +++ src/Unity/locationservice.h 1970-01-01 00:00:00 +0000 |
409 | @@ -1,72 +0,0 @@ |
410 | -/* |
411 | - * Copyright (C) 2014 Canonical, Ltd. |
412 | - * |
413 | - * This program is free software; you can redistribute it and/or modify |
414 | - * it under the terms of the GNU General Public License as published by |
415 | - * the Free Software Foundation; version 3. |
416 | - * |
417 | - * This program is distributed in the hope that it will be useful, |
418 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
419 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
420 | - * GNU General Public License for more details. |
421 | - * |
422 | - * You should have received a copy of the GNU General Public License |
423 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
424 | - * |
425 | - * Authors: |
426 | - * Pete Woods <pete.woods@canonical.com> |
427 | - */ |
428 | - |
429 | -#ifndef LOCATIONSERVICE_H |
430 | -#define LOCATIONSERVICE_H |
431 | - |
432 | -#include <QObject> |
433 | - |
434 | -#include <com/ubuntu/location/heading.h> |
435 | -#include <com/ubuntu/location/position.h> |
436 | -#include <com/ubuntu/location/update.h> |
437 | -#include <com/ubuntu/location/velocity.h> |
438 | - |
439 | -#include <unity/scopes/Location.h> |
440 | - |
441 | -namespace scopes_ng |
442 | -{ |
443 | - |
444 | -class Q_DECL_EXPORT LocationService : public QObject |
445 | -{ |
446 | - Q_OBJECT |
447 | - |
448 | - Q_PROPERTY(unity::scopes::Location location READ location NOTIFY locationChanged) |
449 | - |
450 | - Q_PROPERTY(bool active READ isActive NOTIFY activeChanged) |
451 | - |
452 | -public: |
453 | - typedef QSharedPointer<LocationService> Ptr; |
454 | - |
455 | - class Token : public QObject |
456 | - { |
457 | - }; |
458 | - |
459 | - LocationService(); |
460 | - |
461 | - virtual ~LocationService() = default; |
462 | - |
463 | - virtual unity::scopes::Location location() const = 0; |
464 | - |
465 | - virtual bool hasLocation() const = 0; |
466 | - |
467 | - virtual bool isActive() const = 0; |
468 | - |
469 | -public Q_SLOTS: |
470 | - virtual QSharedPointer<Token> activate() = 0; |
471 | - |
472 | -Q_SIGNALS: |
473 | - void locationChanged(); |
474 | - |
475 | - void activeChanged(); |
476 | - |
477 | -}; |
478 | - |
479 | -} // namespace scopes_ng |
480 | - |
481 | -#endif /* LOCATIONSERVICE_H_ */ |
482 | |
483 | === modified file 'src/Unity/overviewscope.cpp' |
484 | --- src/Unity/overviewscope.cpp 2016-02-04 15:19:37 +0000 |
485 | +++ src/Unity/overviewscope.cpp 2016-06-10 15:06:19 +0000 |
486 | @@ -145,7 +145,7 @@ |
487 | categories->updateOtherScopes(otherScopes, scopeIdToName); |
488 | } |
489 | |
490 | -void OverviewScope::dispatchSearch() |
491 | +void OverviewScope::dispatchSearch(bool) |
492 | { |
493 | qWarning() << "Search is not implemented for Manage Dash"; |
494 | } |
495 | |
496 | === modified file 'src/Unity/overviewscope.h' |
497 | --- src/Unity/overviewscope.h 2016-02-04 15:19:37 +0000 |
498 | +++ src/Unity/overviewscope.h 2016-06-10 15:06:19 +0000 |
499 | @@ -37,7 +37,7 @@ |
500 | /* getters */ |
501 | QString id() const override; |
502 | |
503 | - void dispatchSearch() override; |
504 | + void dispatchSearch(bool) override; |
505 | void setActive(const bool) override; |
506 | |
507 | void updateFavorites(const QStringList& favorites); |
508 | |
509 | === modified file 'src/Unity/scope.cpp' |
510 | --- src/Unity/scope.cpp 2016-05-25 08:16:09 +0000 |
511 | +++ src/Unity/scope.cpp 2016-06-10 15:06:19 +0000 |
512 | @@ -24,8 +24,8 @@ |
513 | // local |
514 | #include "categories.h" |
515 | #include "collectors.h" |
516 | +#include "locationaccesshelper.h" |
517 | #include "previewmodel.h" |
518 | -#include "locationservice.h" |
519 | #include "utils.h" |
520 | #include "scopes.h" |
521 | #include "settingsmodel.h" |
522 | @@ -77,7 +77,8 @@ |
523 | |
524 | Scope::Ptr Scope::newInstance(scopes_ng::Scopes* parent) |
525 | { |
526 | - return Scope::Ptr(new Scope(parent), &QObject::deleteLater); |
527 | + auto scope = Scope::Ptr(new Scope(parent), &QObject::deleteLater); |
528 | + return scope; |
529 | } |
530 | |
531 | Scope::Scope(scopes_ng::Scopes* parent) : |
532 | @@ -696,7 +697,7 @@ |
533 | m_filterState = filterState; |
534 | } |
535 | |
536 | -void Scope::dispatchSearch() |
537 | +void Scope::dispatchSearch(bool programmaticSearch) |
538 | { |
539 | m_initialQueryDone = true; |
540 | |
541 | @@ -736,6 +737,20 @@ |
542 | // (i.e. while the loading bar is visible). |
543 | update_child_scopes(); |
544 | |
545 | + // handle the case where single scope is refreshed multiple times without switching |
546 | + // to another scope, which would never trigger location prompt. |
547 | + if (m_scopeMetadata && m_scopeMetadata->location_data_needed() && !m_locationToken) |
548 | + { |
549 | + if (m_isActive) |
550 | + { |
551 | + Q_ASSERT(m_scopesInstance); |
552 | + |
553 | + if ((!programmaticSearch) || m_scopesInstance->locationAccessHelper()->trustedPromptWasShown()) { |
554 | + m_locationToken = m_locationService->activate(); |
555 | + } |
556 | + } |
557 | + } |
558 | + |
559 | if (m_proxy) { |
560 | scopes::SearchMetadata meta(m_cardinality, QLocale::system().name().toStdString(), m_formFactor.toStdString()); |
561 | auto const userAgent = m_scopesInstance->userAgentString(); |
562 | @@ -764,6 +779,7 @@ |
563 | |
564 | scopes::SearchListenerBase::SPtr listener(new SearchResultReceiver(this)); |
565 | m_searchController->setListener(listener); |
566 | + |
567 | try { |
568 | qDebug() << "Dispatching search:" << id() << m_searchQuery << m_currentNavigationId; |
569 | scopes::QueryCtrlProxy controller = m_queryUserData ? |
570 | @@ -792,6 +808,11 @@ |
571 | m_customizations = converted.toMap(); |
572 | Q_EMIT customizationsChanged(); |
573 | |
574 | + createSettingsModel(); |
575 | +} |
576 | + |
577 | +void Scope::createSettingsModel() |
578 | +{ |
579 | try |
580 | { |
581 | scopes::Variant settings_definitions; |
582 | @@ -806,10 +827,20 @@ |
583 | shareDir = QDir::home().filePath(QStringLiteral(".config/unity-scopes")); |
584 | } |
585 | |
586 | + Q_ASSERT(m_scopesInstance); |
587 | + |
588 | m_settingsModel.reset( |
589 | new SettingsModel(shareDir, id(), |
590 | - scopeVariantToQVariant(settings_definitions), this)); |
591 | + scopeVariantToQVariant(settings_definitions), |
592 | + !m_scopesInstance->locationAccessHelper()->isLocationAccessDenied(), |
593 | + this)); |
594 | + |
595 | QObject::connect(m_settingsModel.data(), &SettingsModel::settingsChanged, this, &Scope::invalidateResults); |
596 | + |
597 | + // If the scope needs location, then changes to global location access need to be monitored. |
598 | + if (m_scopeMetadata->location_data_needed()) { |
599 | + QObject::connect(m_scopesInstance->locationAccessHelper().data(), &LocationAccessHelper::accessChanged, this, &Scope::locationAccessChanged); |
600 | + } |
601 | } |
602 | catch (unity::scopes::NotFoundException&) |
603 | { |
604 | @@ -906,6 +937,16 @@ |
605 | return m_settingsModel.data(); |
606 | } |
607 | |
608 | +void Scope::locationAccessChanged() |
609 | +{ |
610 | + qDebug() << "Location access changed, recreating settings model for scope" << id(); |
611 | + createSettingsModel(); |
612 | + |
613 | + // Force child scopes refresh |
614 | + m_childScopesDirty = true; |
615 | + update_child_scopes(); |
616 | +} |
617 | + |
618 | bool Scope::require_child_scopes_refresh() const |
619 | { |
620 | if (m_settingsModel && m_scopesInstance) |
621 | @@ -1116,11 +1157,7 @@ |
622 | |
623 | if (m_scopeMetadata && m_scopeMetadata->location_data_needed()) |
624 | { |
625 | - if (m_isActive) |
626 | - { |
627 | - m_locationToken = m_locationService->activate(); |
628 | - } |
629 | - else |
630 | + if (!m_isActive) |
631 | { |
632 | m_locationToken.reset(); |
633 | } |
634 | |
635 | === modified file 'src/Unity/scope.h' |
636 | --- src/Unity/scope.h 2016-05-06 07:32:13 +0000 |
637 | +++ src/Unity/scope.h 2016-06-10 15:06:19 +0000 |
638 | @@ -43,7 +43,8 @@ |
639 | #include "collectors.h" |
640 | #include "departmentnode.h" |
641 | #include "department.h" |
642 | -#include "locationservice.h" |
643 | +#include "ubuntulocationservice.h" |
644 | +#include "locationaccesshelper.h" |
645 | |
646 | namespace scopes_ng |
647 | { |
648 | @@ -51,7 +52,6 @@ |
649 | class Categories; |
650 | class PushEvent; |
651 | class PreviewModel; |
652 | -class LocationService; |
653 | class SettingsModel; |
654 | class Scopes; |
655 | |
656 | @@ -185,7 +185,7 @@ |
657 | public Q_SLOTS: |
658 | void invalidateChildScopes(); |
659 | void invalidateResults(); |
660 | - virtual void dispatchSearch(); |
661 | + virtual void dispatchSearch(bool programmaticSearch = false); |
662 | void setSearchInProgress(bool searchInProgress); |
663 | void setActivationInProgress(bool activationInProgress); |
664 | |
665 | @@ -200,6 +200,7 @@ |
666 | void flushUpdates(bool finalize = false); |
667 | void metadataRefreshed(); |
668 | void departmentModelDestroyed(QObject* obj); |
669 | + void locationAccessChanged(); |
670 | void filterStateChanged(); |
671 | void previewModelDestroyed(QObject *obj); |
672 | |
673 | @@ -208,6 +209,7 @@ |
674 | |
675 | void setStatus(unity::shell::scopes::ScopeInterface::Status status); |
676 | void invalidateLastSearch(); |
677 | + void createSettingsModel(); |
678 | |
679 | unity::scopes::ScopeProxy proxy() const; |
680 | |
681 | @@ -278,8 +280,8 @@ |
682 | QMultiMap<QString, Department*> m_departmentModels; |
683 | QMap<Department*, QString> m_inverseDepartments; |
684 | QMetaObject::Connection m_metadataConnection; |
685 | - QSharedPointer<LocationService> m_locationService; |
686 | - QSharedPointer<LocationService::Token> m_locationToken; |
687 | + QSharedPointer<UbuntuLocationService> m_locationService; |
688 | + QSharedPointer<UbuntuLocationService::Token> m_locationToken; |
689 | QNetworkConfigurationManager m_network_manager; |
690 | QList<PreviewModel*> m_previewModels; |
691 | }; |
692 | |
693 | === modified file 'src/Unity/scopes.cpp' |
694 | --- src/Unity/scopes.cpp 2016-05-05 09:41:13 +0000 |
695 | +++ src/Unity/scopes.cpp 2016-06-10 15:06:19 +0000 |
696 | @@ -107,6 +107,7 @@ |
697 | , m_listThread(nullptr) |
698 | , m_loaded(false) |
699 | , m_prepopulateFirstScope(true) |
700 | + , m_locationAccessHelper(new LocationAccessHelper(nullptr)) |
701 | , m_priv(new Priv()) |
702 | { |
703 | QByteArray noFav = qgetenv("UNITY_SCOPES_NO_FAVORITES"); |
704 | @@ -136,6 +137,11 @@ |
705 | connect(&m_registryRefreshTimer, SIGNAL(timeout()), this, SLOT(scopeRegistryChanged())); |
706 | |
707 | m_locationService.reset(new UbuntuLocationService()); |
708 | + QObject::connect(m_locationAccessHelper.data(), &LocationAccessHelper::requestInitialLocation, m_locationService.data(), &UbuntuLocationService::requestInitialLocation); |
709 | + QObject::connect(m_locationService.data(), &UbuntuLocationService::accessDenied, m_locationAccessHelper.data(), &LocationAccessHelper::accessDenied); |
710 | + QObject::connect(m_locationService.data(), &UbuntuLocationService::locationChanged, m_locationAccessHelper.data(), &LocationAccessHelper::positionChanged); |
711 | + QObject::connect(m_locationService.data(), &UbuntuLocationService::geoIpLookupFinished, m_locationAccessHelper.data(), &LocationAccessHelper::geoIpLookupFinished); |
712 | + m_locationAccessHelper->init(); |
713 | |
714 | createUserAgentString(); |
715 | |
716 | @@ -162,6 +168,11 @@ |
717 | m_scopesToDelete.clear(); |
718 | } |
719 | |
720 | +QSharedPointer<LocationAccessHelper> Scopes::locationAccessHelper() const |
721 | +{ |
722 | + return m_locationAccessHelper; |
723 | +} |
724 | + |
725 | int Scopes::rowCount(const QModelIndex& parent) const |
726 | { |
727 | Q_UNUSED(parent) |
728 | @@ -330,9 +341,15 @@ |
729 | } |
730 | else |
731 | { |
732 | + qDebug() << "Waiting for initial location update"; |
733 | + |
734 | // Otherwise we have to wait for location data |
735 | // Either the the location data needs to change, or the timeout happens |
736 | - connect(m_locationService.data(), &LocationService::locationChanged, |
737 | + connect(m_locationService.data(), &UbuntuLocationService::locationChanged, |
738 | + this, &Scopes::completeDiscoveryFinished); |
739 | + connect(m_locationService.data(), &UbuntuLocationService::accessDenied, |
740 | + this, &Scopes::completeDiscoveryFinished); |
741 | + connect(m_locationService.data(), &UbuntuLocationService::locationTimeout, |
742 | this, &Scopes::completeDiscoveryFinished); |
743 | connect(&m_startupQueryTimeout, &QTimer::timeout, this, |
744 | &Scopes::completeDiscoveryFinished); |
745 | @@ -344,11 +361,16 @@ |
746 | |
747 | void Scopes::completeDiscoveryFinished() |
748 | { |
749 | + qDebug() << "Scopes discovery completed"; |
750 | // Kill off everything that could potentially trigger the startup queries |
751 | m_startupQueryTimeout.stop(); |
752 | disconnect(&m_startupQueryTimeout, &QTimer::timeout, this, |
753 | &Scopes::completeDiscoveryFinished); |
754 | - disconnect(m_locationService.data(), &LocationService::locationChanged, |
755 | + disconnect(m_locationService.data(), &UbuntuLocationService::locationChanged, |
756 | + this, &Scopes::completeDiscoveryFinished); |
757 | + disconnect(m_locationService.data(), &UbuntuLocationService::accessDenied, |
758 | + this, &Scopes::completeDiscoveryFinished); |
759 | + disconnect(m_locationService.data(), &UbuntuLocationService::locationTimeout, |
760 | this, &Scopes::completeDiscoveryFinished); |
761 | |
762 | processFavoriteScopes(); |
763 | @@ -376,7 +398,7 @@ |
764 | qDebug() << "Pre-populating first scope"; |
765 | scope->setSearchQuery(QLatin1String("")); |
766 | // must dispatch search explicitly since setSearchQuery will not do that for inactive scope |
767 | - scope->dispatchSearch(); |
768 | + scope->dispatchSearch(true); |
769 | } |
770 | } |
771 | } |
772 | @@ -393,7 +415,7 @@ |
773 | qDebug() << "Pre-populating scope" << scope->id(); |
774 | scope->setSearchQuery(QLatin1String("")); |
775 | // must dispatch search explicitly since setSearchQuery will not do that for inactive scope |
776 | - scope->dispatchSearch(); |
777 | + scope->dispatchSearch(true); |
778 | } |
779 | } |
780 | break; |
781 | @@ -791,7 +813,7 @@ |
782 | return m_loaded; |
783 | } |
784 | |
785 | -LocationService::Ptr Scopes::locationService() const |
786 | +UbuntuLocationService::Ptr Scopes::locationService() const |
787 | { |
788 | return m_locationService; |
789 | } |
790 | |
791 | === modified file 'src/Unity/scopes.h' |
792 | --- src/Unity/scopes.h 2016-04-18 10:10:25 +0000 |
793 | +++ src/Unity/scopes.h 2016-06-10 15:06:19 +0000 |
794 | @@ -22,6 +22,7 @@ |
795 | |
796 | #include <unity/shell/scopes/ScopesInterface.h> |
797 | #include "scope.h" |
798 | +#include "locationaccesshelper.h" |
799 | |
800 | // Qt |
801 | #include <QList> |
802 | @@ -43,7 +44,8 @@ |
803 | namespace scopes_ng |
804 | { |
805 | |
806 | -class LocationService; |
807 | +class UbuntuLocationService; |
808 | +class LocationAccessHelper; |
809 | class Scope; |
810 | class OverviewScope; |
811 | |
812 | @@ -75,12 +77,13 @@ |
813 | unity::shell::scopes::ScopeInterface* overviewScope() const override; |
814 | Scope::Ptr overviewScopeSPtr() const; |
815 | |
816 | - QSharedPointer<LocationService> locationService() const; |
817 | + QSharedPointer<UbuntuLocationService> locationService() const; |
818 | QString userAgentString() const; |
819 | |
820 | Scope::Ptr findTempScope(QString const& id) const; |
821 | void addTempScope(Scope::Ptr const& scope); |
822 | Q_INVOKABLE void closeScope(unity::shell::scopes::ScopeInterface* scope) override; |
823 | + QSharedPointer<LocationAccessHelper> locationAccessHelper() const; |
824 | |
825 | Q_SIGNALS: |
826 | void metadataRefreshed(); |
827 | @@ -124,10 +127,11 @@ |
828 | bool m_loaded; |
829 | bool m_prepopulateFirstScope; |
830 | |
831 | - QSharedPointer<LocationService> m_locationService; |
832 | + QSharedPointer<UbuntuLocationService> m_locationService; |
833 | QTimer m_startupQueryTimeout; |
834 | QTimer m_scopesToDeleteTimer; |
835 | QTimer m_registryRefreshTimer; |
836 | + QSharedPointer<LocationAccessHelper> m_locationAccessHelper; |
837 | |
838 | unity::scopes::Runtime::SPtr m_scopesRuntime; |
839 | QMap<QString, Scope::Ptr> m_tempScopes; |
840 | |
841 | === modified file 'src/Unity/settingsmodel.cpp' |
842 | --- src/Unity/settingsmodel.cpp 2016-05-19 07:18:18 +0000 |
843 | +++ src/Unity/settingsmodel.cpp 2016-06-10 15:06:19 +0000 |
844 | @@ -74,7 +74,8 @@ |
845 | } // namespace |
846 | |
847 | SettingsModel::SettingsModel(const QDir& configDir, const QString& scopeId, |
848 | - const QVariant& settingsDefinitions, QObject* parent, |
849 | + const QVariant& settingsDefinitions, bool isLocationGloballyEnabled, |
850 | + QObject* parent, |
851 | int settingsTimeout) |
852 | : SettingsModelInterface(parent), m_scopeId(scopeId), m_settingsTimeout(settingsTimeout), |
853 | m_requireChildScopesRefresh(false) |
854 | @@ -98,6 +99,12 @@ |
855 | QVariantMap data = it.toMap(); |
856 | QString id = data[QStringLiteral("id")].toString(); |
857 | QString displayName = data[QStringLiteral("displayName")].toString(); |
858 | + |
859 | + if (id == "internal.location" && !isLocationGloballyEnabled) { |
860 | + qDebug() << "Location setting ignored, waiting for global location access to be enabled first"; |
861 | + continue; |
862 | + } |
863 | + |
864 | QVariantMap properties; |
865 | QVariant defaultValue; |
866 | if (data.contains(QStringLiteral("displayValues"))) |
867 | |
868 | === modified file 'src/Unity/settingsmodel.h' |
869 | --- src/Unity/settingsmodel.h 2016-05-19 07:06:55 +0000 |
870 | +++ src/Unity/settingsmodel.h 2016-06-10 15:06:19 +0000 |
871 | @@ -65,7 +65,8 @@ |
872 | |
873 | public: |
874 | explicit SettingsModel(const QDir& configDir, const QString& scopeId, |
875 | - const QVariant& settingsDefinitions, QObject* parent = 0, |
876 | + const QVariant& settingsDefinitions, bool isLocationGloballyEnabled = true, |
877 | + QObject* parent = 0, |
878 | int settingsTimeout = 300); |
879 | |
880 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const |
881 | |
882 | === modified file 'src/Unity/ubuntulocationservice.cpp' |
883 | --- src/Unity/ubuntulocationservice.cpp 2015-09-08 12:32:05 +0000 |
884 | +++ src/Unity/ubuntulocationservice.cpp 2016-06-10 15:06:19 +0000 |
885 | @@ -20,27 +20,10 @@ |
886 | #include "ubuntulocationservice.h" |
887 | |
888 | #include <QDebug> |
889 | -#include <QMutexLocker> |
890 | -#include <QRunnable> |
891 | -#include <QThreadPool> |
892 | -#include <QTimer> |
893 | - |
894 | -#include <com/ubuntu/location/service/stub.h> |
895 | - |
896 | -#include <core/dbus/resolver.h> |
897 | -#include <core/dbus/asio/executor.h> |
898 | - |
899 | -#include <memory> |
900 | |
901 | using namespace std; |
902 | -using namespace std::placeholders; |
903 | using namespace scopes_ng; |
904 | |
905 | -namespace cul = com::ubuntu::location; |
906 | -namespace culs = com::ubuntu::location::service; |
907 | -namespace culss = com::ubuntu::location::service::session; |
908 | -namespace culu = com::ubuntu::location::units; |
909 | -namespace dbus = core::dbus; |
910 | namespace scopes = unity::scopes; |
911 | |
912 | namespace |
913 | @@ -55,28 +38,9 @@ |
914 | * Re-do the GeoIP call every 60 seconds |
915 | */ |
916 | static const int GEOIP_INTERVAL = 60000; |
917 | - |
918 | - class DBusThread : public QThread |
919 | - { |
920 | - |
921 | - public: |
922 | - DBusThread(const dbus::Bus::Ptr& bus) : |
923 | - m_bus(bus) |
924 | - { |
925 | - } |
926 | - |
927 | - protected: |
928 | - void run() override |
929 | - { |
930 | - m_bus->run(); |
931 | - } |
932 | - |
933 | - dbus::Bus::Ptr m_bus; |
934 | - }; |
935 | - |
936 | } |
937 | |
938 | -class UbuntuLocationService::TokenImpl: public LocationService::Token |
939 | +class UbuntuLocationService::TokenImpl: public UbuntuLocationService::Token |
940 | { |
941 | Q_OBJECT |
942 | |
943 | @@ -96,220 +60,121 @@ |
944 | void destroyed(); |
945 | }; |
946 | |
947 | -class UbuntuLocationService::Priv : public QObject |
948 | -{ |
949 | -Q_OBJECT |
950 | - |
951 | -public: |
952 | - Priv() : |
953 | - m_lastLocationMutex(QMutex::Recursive), m_resultMutex( |
954 | - QMutex::Recursive) |
955 | - { |
956 | - } |
957 | - |
958 | - void init(const GeoIp::Ptr& geoIp) |
959 | - { |
960 | - m_geoIp = geoIp; |
961 | - m_geoIp->whollyMoveThread(thread()); |
962 | - |
963 | - m_deactivateTimer.moveToThread(thread()); |
964 | - m_deactivateTimer.setInterval(DEACTIVATE_INTERVAL); |
965 | - m_deactivateTimer.setSingleShot(true); |
966 | - m_deactivateTimer.setTimerType(Qt::VeryCoarseTimer); |
967 | - |
968 | - m_geoipTimer.moveToThread(thread()); |
969 | - m_geoipTimer.setInterval(GEOIP_INTERVAL); |
970 | - m_geoipTimer.setTimerType(Qt::CoarseTimer); |
971 | - |
972 | - QMetaObject::invokeMethod(m_geoIp.data(), "start", Qt::QueuedConnection); |
973 | - |
974 | - try |
975 | - { |
976 | - m_bus = make_shared<dbus::Bus>(dbus::WellKnownBus::system); |
977 | - m_bus->install_executor(dbus::asio::make_executor(m_bus)); |
978 | - |
979 | - m_dbusThread.reset(new DBusThread(m_bus)); |
980 | - m_dbusThread->start(); |
981 | - |
982 | - m_locationService = dbus::resolve_service_on_bus<culs::Interface, |
983 | - culs::Stub>(m_bus); |
984 | - } |
985 | - catch (exception& e) |
986 | - { |
987 | - qWarning() << e.what(); |
988 | - } |
989 | - |
990 | - // Wire up the deactivate timer |
991 | - connect(&m_deactivateTimer, &QTimer::timeout, this, &Priv::update, Qt::QueuedConnection); |
992 | - |
993 | - // Wire up the network request finished timer |
994 | - connect(m_geoIp.data(), &GeoIp::finished, this, &Priv::requestFinished, Qt::QueuedConnection); |
995 | - |
996 | - // Wire up the GeoIP repeat timer |
997 | - connect(&m_geoipTimer, &QTimer::timeout, m_geoIp.data(), &GeoIp::start, Qt::QueuedConnection); |
998 | - } |
999 | - |
1000 | - ~Priv() |
1001 | - { |
1002 | - if (m_bus) |
1003 | - { |
1004 | - m_bus->stop(); |
1005 | - } |
1006 | - |
1007 | - if (m_dbusThread && m_dbusThread->isRunning()) |
1008 | - { |
1009 | - m_dbusThread->wait(); |
1010 | - } |
1011 | - } |
1012 | - |
1013 | -Q_SIGNALS: |
1014 | - void locationChanged(); |
1015 | - |
1016 | -public Q_SLOTS: |
1017 | - void update() |
1018 | - { |
1019 | - if (!m_locationService) |
1020 | - { |
1021 | - qWarning() << "Location service not available"; |
1022 | - return; |
1023 | - } |
1024 | - |
1025 | - if (m_activationCount > 0) |
1026 | - { |
1027 | - // Update the GeoIp data again |
1028 | - m_geoIp->start(); |
1029 | - } |
1030 | - |
1031 | - try |
1032 | - { |
1033 | - if (!m_session) |
1034 | - { |
1035 | - m_session = m_locationService->create_session_for_criteria( |
1036 | - cul::Criteria()); |
1037 | - |
1038 | - m_session->updates().position.changed().connect( |
1039 | - bind(&UbuntuLocationService::Priv::positionChanged, |
1040 | - this, _1)); |
1041 | - } |
1042 | - |
1043 | - if (m_activationCount > 0 |
1044 | - && m_session->updates().position_status |
1045 | - == culss::Interface::Updates::Status::disabled) |
1046 | - { |
1047 | - qDebug() << "Enabling location updates"; |
1048 | - m_session->updates().position_status = |
1049 | - culss::Interface::Updates::Status::enabled; |
1050 | - m_geoipTimer.start(); |
1051 | - } |
1052 | - else if (m_activationCount == 0 |
1053 | - && m_session->updates().position_status |
1054 | - == culss::Interface::Updates::Status::enabled) |
1055 | - { |
1056 | - qDebug() << "Disabling location updates"; |
1057 | - m_session->updates().position_status = |
1058 | - culss::Interface::Updates::Status::disabled; |
1059 | - m_geoipTimer.stop(); |
1060 | - } |
1061 | - } |
1062 | - catch (exception& e) |
1063 | - { |
1064 | - qWarning() << e.what(); |
1065 | - } |
1066 | - } |
1067 | - |
1068 | - void positionChanged(const cul::Update<cul::Position>& newPosition) |
1069 | - { |
1070 | - QMutexLocker lock(&m_lastLocationMutex); |
1071 | - |
1072 | - m_locationUpdatedAtLeastOnce = true; |
1073 | - m_lastLocation = newPosition.value; |
1074 | - Q_EMIT locationChanged(); |
1075 | - } |
1076 | - |
1077 | - void requestFinished(const GeoIp::Result& result) |
1078 | - { |
1079 | - QMutexLocker lock(&m_resultMutex); |
1080 | - m_result = result; |
1081 | - Q_EMIT locationChanged(); |
1082 | - } |
1083 | - |
1084 | - void activate() |
1085 | - { |
1086 | - ++m_activationCount; |
1087 | - m_deactivateTimer.stop(); |
1088 | - update(); |
1089 | - } |
1090 | - |
1091 | - void deactivate() |
1092 | - { |
1093 | - --m_activationCount; |
1094 | - if (m_activationCount < 0) |
1095 | - { |
1096 | - m_activationCount = 0; |
1097 | - qWarning() << "Location service refcount error"; |
1098 | - } |
1099 | - m_deactivateTimer.start(); |
1100 | - } |
1101 | - |
1102 | -public: |
1103 | - dbus::Bus::Ptr m_bus; |
1104 | - |
1105 | - culs::Stub::Ptr m_locationService; |
1106 | - |
1107 | - culss::Interface::Ptr m_session; |
1108 | - |
1109 | - cul::Position m_lastLocation; |
1110 | - |
1111 | - QMutex m_lastLocationMutex; |
1112 | - |
1113 | - bool m_locationUpdatedAtLeastOnce = false; |
1114 | - |
1115 | - int m_activationCount = 0; |
1116 | - |
1117 | - QTimer m_geoipTimer; |
1118 | - |
1119 | - QTimer m_deactivateTimer; |
1120 | - |
1121 | - GeoIp::Ptr m_geoIp; |
1122 | - |
1123 | - QSharedPointer<QThread> m_dbusThread; |
1124 | - |
1125 | - QMutex m_resultMutex; |
1126 | - |
1127 | - GeoIp::Result m_result; |
1128 | -}; |
1129 | - |
1130 | -UbuntuLocationService::UbuntuLocationService(const GeoIp::Ptr& geoIp) : |
1131 | - p(new Priv()) |
1132 | -{ |
1133 | - p->moveToThread(&m_thread); |
1134 | - |
1135 | +UbuntuLocationService::UbuntuLocationService(const GeoIp::Ptr& geoIp) |
1136 | + : m_geoIp(geoIp) |
1137 | +{ |
1138 | // If the location service is disabled |
1139 | if (qEnvironmentVariableIsSet("UNITY_SCOPES_NO_LOCATION")) |
1140 | { |
1141 | return; |
1142 | } |
1143 | |
1144 | - p->init(geoIp); |
1145 | + m_deactivateTimer.setInterval(DEACTIVATE_INTERVAL); |
1146 | + m_deactivateTimer.setSingleShot(true); |
1147 | + m_deactivateTimer.setTimerType(Qt::VeryCoarseTimer); |
1148 | + |
1149 | + m_geoipTimer.setInterval(GEOIP_INTERVAL); |
1150 | + m_geoipTimer.setTimerType(Qt::CoarseTimer); |
1151 | + |
1152 | + m_locationSource = QGeoPositionInfoSource::createDefaultSource(this); |
1153 | + connect(m_locationSource, &QGeoPositionInfoSource::positionUpdated, this, &UbuntuLocationService::positionChanged); |
1154 | + connect(m_locationSource, &QGeoPositionInfoSource::updateTimeout, this, &UbuntuLocationService::onPositionUpdateTimeout); |
1155 | + connect(m_locationSource, SIGNAL(error(QGeoPositionInfoSource::Error)), this, SLOT(onError(QGeoPositionInfoSource::Error))); |
1156 | + |
1157 | + // Wire up the deactivate timer |
1158 | + connect(&m_deactivateTimer, &QTimer::timeout, this, &UbuntuLocationService::update); |
1159 | + |
1160 | + // Wire up the network request finished timer |
1161 | + connect(m_geoIp.data(), &GeoIp::finished, this, &UbuntuLocationService::requestFinished); |
1162 | + |
1163 | + // Wire up the GeoIP repeat timer |
1164 | + connect(&m_geoipTimer, &QTimer::timeout, m_geoIp.data(), &GeoIp::start); |
1165 | |
1166 | // Connect to signals (which will be queued) |
1167 | - connect(p.data(), &Priv::locationChanged, this, &LocationService::locationChanged, Qt::QueuedConnection); |
1168 | - connect(this, &UbuntuLocationService::enqueueActivate, p.data(), &Priv::activate, Qt::QueuedConnection); |
1169 | - connect(this, &UbuntuLocationService::enqueueDeactivate, p.data(), &Priv::deactivate, Qt::QueuedConnection); |
1170 | - |
1171 | - m_thread.start(); |
1172 | -} |
1173 | - |
1174 | -UbuntuLocationService::~UbuntuLocationService() |
1175 | -{ |
1176 | - p.reset(); |
1177 | - |
1178 | - m_thread.quit(); |
1179 | - |
1180 | - if (m_thread.isRunning()) |
1181 | - { |
1182 | - m_thread.wait(); |
1183 | - } |
1184 | + connect(this, &UbuntuLocationService::enqueueActivate, this, &UbuntuLocationService::doActivate, Qt::QueuedConnection); |
1185 | + connect(this, &UbuntuLocationService::enqueueDeactivate, this, &UbuntuLocationService::doDeactivate, Qt::QueuedConnection); |
1186 | + |
1187 | + m_geoIp->start(); |
1188 | +} |
1189 | + |
1190 | +void UbuntuLocationService::doActivate() |
1191 | +{ |
1192 | + m_active = true; |
1193 | + ++m_activationCount; |
1194 | + m_deactivateTimer.stop(); |
1195 | + update(); |
1196 | +} |
1197 | + |
1198 | +void UbuntuLocationService::doDeactivate() |
1199 | +{ |
1200 | + --m_activationCount; |
1201 | + if (m_activationCount < 0) |
1202 | + { |
1203 | + m_activationCount = 0; |
1204 | + qWarning() << "Location service refcount error"; |
1205 | + } |
1206 | + m_deactivateTimer.start(); |
1207 | +} |
1208 | + |
1209 | +void UbuntuLocationService::update() |
1210 | +{ |
1211 | + if (m_activationCount > 0) |
1212 | + { |
1213 | + // Update the GeoIp data again |
1214 | + m_geoIp->start(); |
1215 | + } |
1216 | + |
1217 | + try |
1218 | + { |
1219 | + if (m_activationCount > 0) |
1220 | + { |
1221 | + qDebug() << "Enabling location updates"; |
1222 | + m_locationSource->startUpdates(); |
1223 | + m_geoipTimer.start(); |
1224 | + } |
1225 | + else |
1226 | + { |
1227 | + qDebug() << "Disabling location updates"; |
1228 | + m_active = false; |
1229 | + m_locationSource->stopUpdates(); |
1230 | + m_geoipTimer.stop(); |
1231 | + } |
1232 | + } |
1233 | + catch (exception& e) |
1234 | + { |
1235 | + qWarning() << e.what(); |
1236 | + } |
1237 | +} |
1238 | + |
1239 | +void UbuntuLocationService::positionChanged(const QGeoPositionInfo& update) |
1240 | +{ |
1241 | + m_locationUpdatedAtLeastOnce = true; |
1242 | + m_lastLocation = update; |
1243 | + Q_EMIT locationChanged(); |
1244 | +} |
1245 | + |
1246 | +void UbuntuLocationService::onPositionUpdateTimeout() |
1247 | +{ |
1248 | + qWarning() << "Position update timeout"; |
1249 | + Q_EMIT locationTimeout(); |
1250 | +} |
1251 | + |
1252 | +void UbuntuLocationService::onError(QGeoPositionInfoSource::Error positioningError) |
1253 | +{ |
1254 | + qWarning() << "Position update error:" << positioningError; |
1255 | + if (positioningError == QGeoPositionInfoSource::AccessError) { |
1256 | + qDebug() << "Postion update denied"; |
1257 | + Q_EMIT accessDenied(); |
1258 | + } |
1259 | +} |
1260 | + |
1261 | +void UbuntuLocationService::requestFinished(const GeoIp::Result& result) |
1262 | +{ |
1263 | + qDebug() << "GeoIP request finished"; |
1264 | + { |
1265 | + m_result = result; |
1266 | + } |
1267 | + Q_EMIT geoIpLookupFinished(); |
1268 | } |
1269 | |
1270 | scopes::Location UbuntuLocationService::location() const |
1271 | @@ -318,8 +183,7 @@ |
1272 | |
1273 | GeoIp::Result result; |
1274 | { |
1275 | - QMutexLocker lock(&p->m_resultMutex); |
1276 | - result = p->m_result; |
1277 | + result = m_result; |
1278 | } |
1279 | |
1280 | if (result.valid) |
1281 | @@ -336,28 +200,21 @@ |
1282 | location.set_city(result.city.toStdString()); |
1283 | } |
1284 | |
1285 | - QMutexLocker lock(&p->m_lastLocationMutex); |
1286 | // We need to be active, and the location session must have updated at least once |
1287 | - if (isActive() && p->m_locationUpdatedAtLeastOnce) |
1288 | + if (isActive() && m_locationUpdatedAtLeastOnce) |
1289 | { |
1290 | - cul::Position pos = p->m_lastLocation; |
1291 | - |
1292 | - if (pos.accuracy.horizontal) |
1293 | - { |
1294 | - location.set_horizontal_accuracy(pos.accuracy.horizontal.get().value()); |
1295 | - } |
1296 | - if (pos.accuracy.vertical) |
1297 | - { |
1298 | - location.set_vertical_accuracy(pos.accuracy.vertical.get().value()); |
1299 | - } |
1300 | - |
1301 | - if (pos.altitude) |
1302 | - { |
1303 | - location.set_altitude(pos.altitude.get().value.value()); |
1304 | - } |
1305 | - |
1306 | - location.set_latitude(pos.latitude.value.value()); |
1307 | - location.set_longitude(pos.longitude.value.value()); |
1308 | + location.set_latitude(m_lastLocation.coordinate().latitude()); |
1309 | + location.set_longitude(m_lastLocation.coordinate().longitude()); |
1310 | + location.set_altitude(m_lastLocation.coordinate().altitude()); |
1311 | + |
1312 | + if (m_lastLocation.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) |
1313 | + { |
1314 | + location.set_horizontal_accuracy(m_lastLocation.attribute(QGeoPositionInfo::HorizontalAccuracy)); |
1315 | + } |
1316 | + if (m_lastLocation.hasAttribute(QGeoPositionInfo::VerticalAccuracy)) |
1317 | + { |
1318 | + location.set_vertical_accuracy(m_lastLocation.attribute(QGeoPositionInfo::VerticalAccuracy)); |
1319 | + } |
1320 | } |
1321 | else if (result.valid) |
1322 | { |
1323 | @@ -376,18 +233,24 @@ |
1324 | |
1325 | bool UbuntuLocationService::isActive() const |
1326 | { |
1327 | - return p->m_session ? (p->m_session->updates().position_status == |
1328 | - culss::Interface::Updates::Status::enabled) : false; |
1329 | + return m_active; |
1330 | } |
1331 | |
1332 | bool UbuntuLocationService::hasLocation() const |
1333 | { |
1334 | - return p->m_result.valid || p->m_locationUpdatedAtLeastOnce; |
1335 | + return m_lastLocation.isValid() || m_locationUpdatedAtLeastOnce; |
1336 | } |
1337 | |
1338 | -QSharedPointer<LocationService::Token> UbuntuLocationService::activate() |
1339 | +QSharedPointer<UbuntuLocationService::Token> UbuntuLocationService::activate() |
1340 | { |
1341 | return QSharedPointer<Token>(new TokenImpl(*this)); |
1342 | } |
1343 | |
1344 | +void UbuntuLocationService::requestInitialLocation() |
1345 | +{ |
1346 | + qDebug() << "Requesting initial location update"; |
1347 | + m_locationSource->requestUpdate(); |
1348 | + m_geoipTimer.start(); |
1349 | +} |
1350 | + |
1351 | #include "ubuntulocationservice.moc" |
1352 | |
1353 | === modified file 'src/Unity/ubuntulocationservice.h' |
1354 | --- src/Unity/ubuntulocationservice.h 2015-09-08 12:32:05 +0000 |
1355 | +++ src/Unity/ubuntulocationservice.h 2016-06-10 15:06:19 +0000 |
1356 | @@ -1,5 +1,5 @@ |
1357 | /* |
1358 | - * Copyright (C) 2014 Canonical, Ltd. |
1359 | + * Copyright (C) 2014-2016 Canonical, Ltd. |
1360 | * |
1361 | * This program is free software; you can redistribute it and/or modify |
1362 | * it under the terms of the GNU General Public License as published by |
1363 | @@ -15,50 +15,80 @@ |
1364 | * |
1365 | * Authors: |
1366 | * Pete Woods <pete.woods@canonical.com> |
1367 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
1368 | */ |
1369 | |
1370 | #ifndef UBUNTULOCATIONSERVICE_H |
1371 | #define UBUNTULOCATIONSERVICE_H |
1372 | |
1373 | #include "geoip.h" |
1374 | -#include "locationservice.h" |
1375 | |
1376 | +#include <QObject> |
1377 | #include <QSharedPointer> |
1378 | -#include <QThread> |
1379 | +#include <QTimer> |
1380 | +#include <QGeoPositionInfo> |
1381 | +#include <QGeoPositionInfoSource> |
1382 | +#include <unity/scopes/Location.h> |
1383 | |
1384 | namespace scopes_ng |
1385 | { |
1386 | |
1387 | -class Q_DECL_EXPORT UbuntuLocationService : public LocationService |
1388 | +class Q_DECL_EXPORT UbuntuLocationService: public QObject |
1389 | { |
1390 | Q_OBJECT |
1391 | + Q_PROPERTY(unity::scopes::Location location READ location NOTIFY locationChanged) |
1392 | + Q_PROPERTY(bool active READ isActive NOTIFY activeChanged) |
1393 | |
1394 | public: |
1395 | + typedef QSharedPointer<UbuntuLocationService> Ptr; |
1396 | + class Token : public QObject |
1397 | + { |
1398 | + }; |
1399 | + |
1400 | class TokenImpl; |
1401 | |
1402 | UbuntuLocationService(const GeoIp::Ptr& geoIp = GeoIp::Ptr(new GeoIp)); |
1403 | - |
1404 | - virtual ~UbuntuLocationService(); |
1405 | - |
1406 | - unity::scopes::Location location() const override; |
1407 | - |
1408 | - bool hasLocation() const override; |
1409 | - |
1410 | - bool isActive() const override; |
1411 | - |
1412 | - QSharedPointer<Token> activate() override; |
1413 | + unity::scopes::Location location() const; |
1414 | + bool hasLocation() const; |
1415 | + bool isActive() const; |
1416 | + QSharedPointer<Token> activate(); |
1417 | + |
1418 | +public Q_SLOTS: |
1419 | + void requestInitialLocation(); |
1420 | |
1421 | Q_SIGNALS: |
1422 | + // emited when location changes and only when access has been granted by apparmor |
1423 | + void locationChanged(); |
1424 | + |
1425 | + void locationTimeout(); |
1426 | + |
1427 | + // emited when geoip lookup finishes (including initial lookup on startup). regardless of apparmor permissions |
1428 | + // (receiving it doesn't mean position updates are allowed). |
1429 | + void geoIpLookupFinished(); |
1430 | + void activeChanged(); |
1431 | + void accessDenied(); |
1432 | void enqueueActivate(); |
1433 | - |
1434 | void enqueueDeactivate(); |
1435 | |
1436 | +protected Q_SLOTS: |
1437 | + void doActivate(); |
1438 | + void doDeactivate(); |
1439 | + void update(); |
1440 | + void positionChanged(const QGeoPositionInfo& update); |
1441 | + void onPositionUpdateTimeout(); |
1442 | + void onError(QGeoPositionInfoSource::Error positioningError); |
1443 | + void requestFinished(const GeoIp::Result& result); |
1444 | + |
1445 | protected: |
1446 | - class Priv; |
1447 | - |
1448 | - QThread m_thread; |
1449 | - |
1450 | - QSharedPointer<Priv> p; |
1451 | + bool m_active; |
1452 | + QGeoPositionInfoSource *m_locationSource; |
1453 | + QGeoPositionInfo m_lastLocation; |
1454 | + bool m_locationUpdatedAtLeastOnce = false; |
1455 | + int m_activationCount = 0; |
1456 | + QTimer m_geoipTimer; |
1457 | + QTimer m_deactivateTimer; |
1458 | + GeoIp::Ptr m_geoIp; |
1459 | + GeoIp::Result m_result; |
1460 | }; |
1461 | |
1462 | } // namespace scopes_ng |
1463 | |
1464 | === modified file 'tests/CMakeLists.txt' |
1465 | --- tests/CMakeLists.txt 2016-04-01 10:38:21 +0000 |
1466 | +++ tests/CMakeLists.txt 2016-06-10 15:06:19 +0000 |
1467 | @@ -7,7 +7,6 @@ |
1468 | add_subdirectory(data) |
1469 | |
1470 | add_definitions( |
1471 | - -DGEOIP_SERVER_BINARY="${CMAKE_CURRENT_SOURCE_DIR}/geoip.ubuntu.com.py" |
1472 | -DTEST_DATA_DIR="${TEST_DATA_DIR}" |
1473 | -DTEST_RUNTIME_CONFIG="${TEST_RUNTIME_CONFIG}" |
1474 | -DTEST_SETTINGS_UNICODE="${CMAKE_CURRENT_SOURCE_DIR}/data/settings-unicode.ini" |
1475 | @@ -18,7 +17,6 @@ |
1476 | ${CMAKE_SOURCE_DIR}/src |
1477 | ${CMAKE_CURRENT_BINARY_DIR} |
1478 | ${SCOPESLIB_INCLUDE_DIRS} |
1479 | - ${UBUNTU_LOCATION_SERVICE_INCLUDE_DIRS} |
1480 | ${QTDBUSTEST_INCLUDE_DIRS} |
1481 | ${QTDBUSMOCK_INCLUDE_DIRS} |
1482 | ${GSETTINGSQT_INCLUDE_DIRS} |
1483 | @@ -65,7 +63,6 @@ |
1484 | filtersendtoendtest |
1485 | optionselectorfiltertest |
1486 | favoritestest |
1487 | - locationtest |
1488 | overviewtest |
1489 | previewtest |
1490 | resultstest |
1491 | |
1492 | === removed file 'tests/geoip.ubuntu.com.py' |
1493 | --- tests/geoip.ubuntu.com.py 2014-07-23 11:10:53 +0000 |
1494 | +++ tests/geoip.ubuntu.com.py 1970-01-01 00:00:00 +0000 |
1495 | @@ -1,66 +0,0 @@ |
1496 | -#!/usr/bin/env python |
1497 | -# -*- coding: utf-8 -*- |
1498 | -# |
1499 | -# Copyright (C) 2014 Canonical Ltd |
1500 | -# |
1501 | -# This program is free software: you can redistribute it and/or modify |
1502 | -# it under the terms of the GNU Lesser General Public License version 3 as |
1503 | -# published by the Free Software Foundation. |
1504 | -# |
1505 | -# This program is distributed in the hope that it will be useful, |
1506 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1507 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1508 | -# GNU Lesser General Public License for more details. |
1509 | -# |
1510 | -# You should have received a copy of the GNU Lesser General Public License |
1511 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1512 | -# |
1513 | -# Authored by: Pete Woods <pete.woods@canonical.com> |
1514 | - |
1515 | -import tornado.httpserver |
1516 | -import tornado.ioloop |
1517 | -import tornado.netutil |
1518 | -import tornado.web |
1519 | -import sys |
1520 | - |
1521 | -RESPONSE = '''<Response> |
1522 | -<Ip>1.2.3.4</Ip> |
1523 | -<Status>OK</Status> |
1524 | -<CountryCode>GB</CountryCode> |
1525 | -<CountryCode3>GBR</CountryCode3> |
1526 | -<CountryName>United Kingdom</CountryName> |
1527 | -<RegionCode>H2</RegionCode> |
1528 | -<RegionName>Lancashire</RegionName> |
1529 | -<City>Accrington</City> |
1530 | -<ZipPostalCode>BB5</ZipPostalCode> |
1531 | -<Latitude>55.7654</Latitude> |
1532 | -<Longitude>-2.7467</Longitude> |
1533 | -<AreaCode>0</AreaCode> |
1534 | -<TimeZone>Europe/London</TimeZone> |
1535 | -</Response> |
1536 | -''' |
1537 | - |
1538 | -class Lookup(tornado.web.RequestHandler): |
1539 | - def get(self): |
1540 | - sys.stderr.write('GeoIP location requested\n') |
1541 | - sys.stderr.flush() |
1542 | - |
1543 | - self.write(RESPONSE) |
1544 | - self.finish() |
1545 | - |
1546 | -def new_app(): |
1547 | - application = tornado.web.Application([ |
1548 | - (r"/lookup", Lookup), |
1549 | - ], gzip=True) |
1550 | - sockets = tornado.netutil.bind_sockets(0, '127.0.0.1') |
1551 | - server = tornado.httpserver.HTTPServer(application) |
1552 | - server.add_sockets(sockets) |
1553 | - |
1554 | - sys.stdout.write('%d\n' % sockets[0].getsockname()[1]) |
1555 | - sys.stdout.flush() |
1556 | - |
1557 | - return application |
1558 | - |
1559 | -if __name__ == "__main__": |
1560 | - application = new_app() |
1561 | - tornado.ioloop.IOLoop.instance().start() |
1562 | |
1563 | === removed file 'tests/locationtest.cpp' |
1564 | --- tests/locationtest.cpp 2015-02-26 18:02:32 +0000 |
1565 | +++ tests/locationtest.cpp 1970-01-01 00:00:00 +0000 |
1566 | @@ -1,234 +0,0 @@ |
1567 | -/* |
1568 | - * Copyright (C) 2013-2014 Canonical, Ltd. |
1569 | - * |
1570 | - * This program is free software; you can redistribute it and/or modify |
1571 | - * it under the terms of the GNU General Public License as published by |
1572 | - * the Free Software Foundation; version 3. |
1573 | - * |
1574 | - * This program is distributed in the hope that it will be useful, |
1575 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1576 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1577 | - * GNU General Public License for more details. |
1578 | - * |
1579 | - * You should have received a copy of the GNU General Public License |
1580 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1581 | - * |
1582 | - * Authors: |
1583 | - * Pete Woods <pete.woods@canonical.com> |
1584 | - */ |
1585 | - |
1586 | -#include "ubuntulocationservice.h" |
1587 | - |
1588 | -#include <QProcess> |
1589 | -#include <QSignalSpy> |
1590 | -#include <QTest> |
1591 | -#include <string> |
1592 | - |
1593 | -#include <libqtdbusmock/DBusMock.h> |
1594 | -#include <libqtdbustest/DBusTestRunner.h> |
1595 | - |
1596 | -using namespace std; |
1597 | -using namespace scopes_ng; |
1598 | -using namespace unity::scopes; |
1599 | -using namespace QtDBusTest; |
1600 | -using namespace QtDBusMock; |
1601 | - |
1602 | -namespace |
1603 | -{ |
1604 | - |
1605 | -static const char* LOCATION_SERVICE_NAME = "com.ubuntu.location.Service"; |
1606 | -static const char* LOCATION_SERVICE_PATH = "/com/ubuntu/location/Service"; |
1607 | -static const char* LOCATION_SERVICE_INTERFACE = "com.ubuntu.location.Service"; |
1608 | - |
1609 | -static const char* SESSION_NAME = "com.ubuntu.location.Service.Session"; |
1610 | -static const QString SESSION_PATH = "/com/ubuntu/location/session/%1"; |
1611 | -static const QString SESSION_INTERFACE = "com.ubuntu.location.Service.Session"; |
1612 | - |
1613 | -static Variant geoip() |
1614 | -{ |
1615 | - VariantMap result; |
1616 | - result["area_code"] = "0"; |
1617 | - result["city"] = "Accrington"; |
1618 | - result["country_code"] = "GB"; |
1619 | - result["country_name"] = "United Kingdom"; |
1620 | - result["horizontal_accuracy"] = 100000.0; |
1621 | - result["latitude"] = 55.76540; |
1622 | - result["longitude"] = -2.74670; |
1623 | - result["region_code"] = "H2"; |
1624 | - result["region_name"] = "Lancashire"; |
1625 | - result["zip_postal_code"] = "BB5"; |
1626 | - return Variant(result); |
1627 | -} |
1628 | - |
1629 | -static Variant gps() |
1630 | -{ |
1631 | - VariantMap result; |
1632 | - result["altitude"] = 3.0; |
1633 | - result["area_code"] = "0"; |
1634 | - result["city"] = "Accrington"; |
1635 | - result["country_code"] = "GB"; |
1636 | - result["country_name"] = "United Kingdom"; |
1637 | - result["horizontal_accuracy"] = 4.0; |
1638 | - result["latitude"] = 1.0; |
1639 | - result["longitude"] = 2.0; |
1640 | - result["region_code"] = "H2"; |
1641 | - result["region_name"] = "Lancashire"; |
1642 | - result["vertical_accuracy"] = 5.0; |
1643 | - result["zip_postal_code"] = "BB5"; |
1644 | - return Variant(result); |
1645 | -} |
1646 | - |
1647 | -class LocationTest: public QObject |
1648 | -{ |
1649 | -Q_OBJECT |
1650 | - |
1651 | -public: |
1652 | - LocationTest() : |
1653 | - mock(dbus) |
1654 | - { |
1655 | - } |
1656 | - |
1657 | -private: |
1658 | - OrgFreedesktopDBusMockInterface& interface() |
1659 | - { |
1660 | - return mock.mockInterface(LOCATION_SERVICE_NAME, LOCATION_SERVICE_PATH, |
1661 | - LOCATION_SERVICE_INTERFACE, |
1662 | - QDBusConnection::SystemBus); |
1663 | - } |
1664 | - |
1665 | - OrgFreedesktopDBusMockInterface& session(int id) |
1666 | - { |
1667 | - return mock.mockInterface(SESSION_NAME, SESSION_PATH.arg(id), |
1668 | - SESSION_INTERFACE, QDBusConnection::SystemBus); |
1669 | - } |
1670 | - |
1671 | - DBusTestRunner dbus; |
1672 | - |
1673 | - DBusMock mock; |
1674 | - |
1675 | - QScopedPointer<LocationService> locationService; |
1676 | - |
1677 | - QProcess geoIpServer; |
1678 | - |
1679 | - QUrl url; |
1680 | - |
1681 | -private Q_SLOTS: |
1682 | - void initTestCase() |
1683 | - { |
1684 | - DBusMock::registerMetaTypes(); |
1685 | - |
1686 | - // Register the main interface object |
1687 | - mock.registerCustomMock(LOCATION_SERVICE_NAME, LOCATION_SERVICE_PATH, |
1688 | - LOCATION_SERVICE_INTERFACE, |
1689 | - QDBusConnection::SystemBus); |
1690 | - |
1691 | - // Register the first session object |
1692 | - mock.registerCustomMock(SESSION_NAME, SESSION_PATH.arg(0), |
1693 | - SESSION_INTERFACE, |
1694 | - QDBusConnection::SystemBus); |
1695 | - |
1696 | - dbus.startServices(); |
1697 | - |
1698 | - // Set up the main interface |
1699 | - { |
1700 | - interface().AddMethod(LOCATION_SERVICE_INTERFACE, |
1701 | - "CreateSessionForCriteria", "bbbbdbbb", "o", |
1702 | - "ret='/com/ubuntu/location/session/0'"); |
1703 | - } |
1704 | - |
1705 | - // Set up the first session |
1706 | - { |
1707 | - session(0).AddMethod(SESSION_INTERFACE, "StartPositionUpdates", "", "", ""); |
1708 | - session(0).AddMethod(SESSION_INTERFACE, "StopPositionUpdates", "", "", ""); |
1709 | - } |
1710 | - |
1711 | - geoIpServer.setProcessChannelMode(QProcess::ForwardedErrorChannel); |
1712 | - geoIpServer.start(GEOIP_SERVER_BINARY); |
1713 | - QVERIFY(geoIpServer.waitForStarted()); |
1714 | - QVERIFY(geoIpServer.waitForReadyRead()); |
1715 | - |
1716 | - url = "http://127.0.0.1:" + geoIpServer.readAllStandardOutput().trimmed() + "/lookup"; |
1717 | - } |
1718 | - |
1719 | - void cleanupTestCase() { |
1720 | - geoIpServer.terminate(); |
1721 | - QVERIFY(geoIpServer.waitForFinished()); |
1722 | - } |
1723 | - |
1724 | - void init() |
1725 | - { |
1726 | - locationService.reset(new UbuntuLocationService(GeoIp::Ptr(new GeoIp(url)))); |
1727 | - } |
1728 | - |
1729 | - void cleanup() |
1730 | - { |
1731 | - locationService.reset(); |
1732 | - } |
1733 | - |
1734 | - void compareVariant(const Variant& expected_in, const Variant& actual_in) |
1735 | - { |
1736 | - VariantMap expected(expected_in.get_dict()); |
1737 | - VariantMap actual(actual_in.get_dict()); |
1738 | - |
1739 | - QVERIFY2( |
1740 | - expected.size() <= actual.size(), |
1741 | - qPrintable(QString("We need at least %1 entries, had %2").arg( |
1742 | - expected.size()).arg(actual.size()))); |
1743 | - for(const auto entry: expected) |
1744 | - { |
1745 | - QVERIFY(actual.find(entry.first) != actual.end()); |
1746 | - |
1747 | - Variant expectedVariant = entry.second; |
1748 | - Variant actualVariant = actual[entry.first]; |
1749 | - |
1750 | - if (expectedVariant.which() == Variant::Double) |
1751 | - { |
1752 | - bool comparison = qFuzzyCompare(expectedVariant.get_double(), actualVariant.get_double()); |
1753 | - if (!comparison) |
1754 | - { |
1755 | - qWarning() << "Comparison:" << expectedVariant.get_double() << "!=" << actualVariant.get_double(); |
1756 | - } |
1757 | - QVERIFY(comparison); |
1758 | - } |
1759 | - else |
1760 | - { |
1761 | - QCOMPARE(expectedVariant, actualVariant); |
1762 | - } |
1763 | - } |
1764 | - } |
1765 | - |
1766 | - void testLocation() |
1767 | - { |
1768 | - QSignalSpy spy(locationService.data(), SIGNAL(locationChanged())); |
1769 | - auto token = locationService->activate(); |
1770 | - |
1771 | - // The GeoIP HTTP call should return now |
1772 | - QVERIFY(spy.wait()); |
1773 | - compareVariant(geoip(), Variant(locationService->location().serialize())); |
1774 | - |
1775 | - // Call the object that the location service client creates |
1776 | - QDBusInterface remoteObject(":1.4", SESSION_PATH.arg(0), SESSION_INTERFACE, |
1777 | - QDBusConnection::systemBus()); |
1778 | - |
1779 | - QString errorMessage("never called"); |
1780 | - for (int i = 0; i < 10 && !errorMessage.isEmpty(); ++i) |
1781 | - { |
1782 | - QDBusMessage reply = remoteObject.callWithArgumentList( |
1783 | - QDBus::Block, |
1784 | - "UpdatePosition", |
1785 | - QVariantList() << 1.0 << 2.0 << true << 3.0 << true << 4.0 |
1786 | - << true << 5.0 << qint64(1234)); |
1787 | - errorMessage = reply.errorMessage(); |
1788 | - } |
1789 | - QCOMPARE(QString(), errorMessage); |
1790 | - |
1791 | - // The GPS update should return now |
1792 | - QVERIFY(spy.wait()); |
1793 | - QTRY_COMPARE((unsigned int) locationService->location().serialize().size(), 12u); |
1794 | - compareVariant(gps(), Variant(locationService->location().serialize())); |
1795 | - } |
1796 | -}; |
1797 | - |
1798 | -} |
1799 | -QTEST_GUILESS_MAIN(LocationTest) |
1800 | -#include <locationtest.moc> |
Looks good, although one observation:
I have Nearby favourited. Once I have enabled location access to scopes and I restart the phone, the scope says "Please enable location..." again. I also notice incorrect weather shown on the Today scope. There's obviously a race in scopes startup and the location becoming available/ accessible/ enabled. Not sure how easy this would be to fix, but it is a bit confusing.
+ For some reason I can't edit the test plan page anymore, so I'll just add review comments for that here:
1) "for testing purposes, remove home/phablet/ .local/ share/UbuntuLoc ationService/ trust.db"
missing a / before "home"
2) Select 'Deny'.
should say "Select 'Don't Allow'."