Merge lp:~jonas-drange/ubuntu-system-settings/wifi-connect-is-not-dialog-fix-1366006 into lp:ubuntu-system-settings
- wifi-connect-is-not-dialog-fix-1366006
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Ken VanDine | ||||||||
Approved revision: | 1054 | ||||||||
Merged at revision: | 1083 | ||||||||
Proposed branch: | lp:~jonas-drange/ubuntu-system-settings/wifi-connect-is-not-dialog-fix-1366006 | ||||||||
Merge into: | lp:ubuntu-system-settings | ||||||||
Diff against target: |
1278 lines (+857/-174) 11 files modified
plugins/wifi/CMakeLists.txt (+1/-0) plugins/wifi/Common.qml (+99/-0) plugins/wifi/NetworkDetailsBrief.qml (+1/-1) plugins/wifi/OtherNetwork.qml (+349/-125) plugins/wifi/PageComponent.qml (+15/-4) plugins/wifi/nm_manager_proxy.h (+1/-1) plugins/wifi/wifidbushelper.cpp (+46/-36) plugins/wifi/wifidbushelper.h (+5/-1) tests/autopilot/ubuntu_system_settings/__init__.py (+163/-1) tests/autopilot/ubuntu_system_settings/tests/__init__.py (+42/-5) tests/autopilot/ubuntu_system_settings/tests/test_wifi.py (+135/-0) |
||||||||
To merge this branch: | bzr merge lp:~jonas-drange/ubuntu-system-settings/wifi-connect-is-not-dialog-fix-1366006 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ken VanDine | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Sebastien Bacher (community) | Needs Fixing | ||
Review via email: mp+234842@code.launchpad.net |
Commit message
[wifi] connect to hidden network is now a dialog
Description of the change
Changes the "Connect to hidden network" item to act as a Dialog instead of a page.
It also adds behaviour on failure, which the old page did not have.
QA/translators: POT file will be updated in separate branch.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1038. By Jonas G. Drange
-
fix code fails
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1038
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 1039. By Jonas G. Drange
-
refactoring, cleaning up
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1039
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 1040. By Jonas G. Drange
-
proper tests
- 1041. By Jonas G. Drange
-
some tweaks and workarounds
- 1042. By Jonas G. Drange
-
update pot file
- 1043. By Jonas G. Drange
-
readme entry note to self
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1040
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1043
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 1044. By Jonas G. Drange
-
merge trunk
- 1045. By Jonas G. Drange
-
waiting longer may let tests pass?
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1045
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 1046. By Jonas G. Drange
-
make testing more robust
Ken VanDine (ken-vandine) wrote : | # |
Please add a comment to Common.qml including information on where the reason codes come from. The mapping to strings is probably the best we can do, but that mapping will need to be maintained as reason codes get added or changed.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1046
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1047. By Jonas G. Drange
-
fixing pep errors and docs in Common.qml
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1048
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Ken VanDine (ken-vandine) wrote : | # |
The item for connecting to the hidden network now opens a dialog, so shouldn't show progression and the title should include the "..."
I'm still find the interaction with the OSK annoying, but I don't know what we can do about it.
- 1048. By Jonas G. Drange
-
bar
- 1049. By Jonas G. Drange
-
merge trunk
- 1050. By Jonas G. Drange
-
update pot
- 1051. By Jonas G. Drange
-
adding ellipsis
- 1052. By Jonas G. Drange
-
resolve divergence
Jonas G. Drange (jonas-drange) wrote : | # |
> The item for connecting to the hidden network now opens a dialog, so shouldn't
> show progression and the title should include the "..."
Right, fixed.
> I'm still find the interaction with the OSK annoying, but I don't know what we
> can do about it.
What are you referring to? If these[1][2] bugs were fixed, that would make the dialog pretty small, i.e. letting anchorToKeyboard property do its thing and keep the OSK from hiding essential things.
[1] https:/
[2] https:/
Sebastien Bacher (seb128) wrote : | # |
Thanks, it looks fine for an easy read but somebody should do a real review. One comment, can you take the README update to another merge request? It has nothing to do with the changeset/commit message there. The pot update could also be done in a different commit to avoid conflicts with other changes in the same landing
- 1053. By Jonas G. Drange
-
reverting readme, and pot change
Jonas G. Drange (jonas-drange) wrote : | # |
> Thanks, it looks fine for an easy read but somebody should do a real review.
> One comment, can you take the README update to another merge request? It has
> nothing to do with the changeset/commit message there. The pot update could
> also be done in a different commit to avoid conflicts with other changes in
> the same landing
Thanks Seb. I've reverted changes to both failes.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1052
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1053
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 1054. By Jonas G. Drange
-
skip flaky tests
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1054
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'plugins/wifi/CMakeLists.txt' |
2 | --- plugins/wifi/CMakeLists.txt 2014-08-28 15:08:55 +0000 |
3 | +++ plugins/wifi/CMakeLists.txt 2014-09-25 13:39:43 +0000 |
4 | @@ -1,6 +1,7 @@ |
5 | set(QML_SOURCES |
6 | AccessPoint.qml |
7 | BaseMenuItem.qml |
8 | +Common.qml |
9 | DivMenuItem.qml |
10 | FramedMenuItem.qml |
11 | HLine.qml |
12 | |
13 | === added file 'plugins/wifi/Common.qml' |
14 | --- plugins/wifi/Common.qml 1970-01-01 00:00:00 +0000 |
15 | +++ plugins/wifi/Common.qml 2014-09-25 13:39:43 +0000 |
16 | @@ -0,0 +1,99 @@ |
17 | +/* |
18 | + * Copyright (C) 2014 Canonical Ltd |
19 | + * |
20 | + * This program is free software: you can redistribute it and/or modify |
21 | + * it under the terms of the GNU General Public License version 3 as |
22 | + * published by the Free Software Foundation. |
23 | + * |
24 | + * This program is distributed in the hope that it will be useful, |
25 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
27 | + * GNU General Public License for more details. |
28 | + * |
29 | + * You should have received a copy of the GNU General Public License |
30 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
31 | + * |
32 | + * Authors: |
33 | + * Jonas G. Drange <jonas.drange@canonical.com> |
34 | + * |
35 | +*/ |
36 | +import QtQuick 2.0 |
37 | + |
38 | +Item { |
39 | + |
40 | + |
41 | + /* |
42 | + The mapping of code to string is taken from |
43 | + http://bazaar.launchpad.net/~vcs-imports/ |
44 | + network-manager/trunk/view/head:/cli/src/common.c |
45 | + |
46 | + NetworkManager documentation: https://developer.gnome.org/ |
47 | + NetworkManager/0.9/spec.html#type-NM_DEVICE_STATE_REASON |
48 | + */ |
49 | + function reasonToString (reason) { |
50 | + switch (reason) { |
51 | + case 0: |
52 | + return i18n.tr("Unknown error"); |
53 | + case 1: |
54 | + return i18n.tr("No reason given"); |
55 | + case 2: |
56 | + return i18n.tr("Device is now managed"); |
57 | + case 3: |
58 | + return i18n.tr("Device is now unmanaged"); |
59 | + case 4: |
60 | + return i18n.tr("The device could not be readied for configuration"); |
61 | + case 5: |
62 | + return i18n.tr("IP configuration could not be reserved (no available address, timeout, etc.)"); |
63 | + case 6: |
64 | + return i18n.tr("The IP configuration is no longer valid"); |
65 | + case 7: |
66 | + return i18n.tr("Your authentication details were incorrect"); |
67 | + case 8: |
68 | + return i18n.tr("802.1X supplicant disconnected"); |
69 | + case 9: |
70 | + return i18n.tr("802.1X supplicant configuration failed"); |
71 | + case 10: |
72 | + return i18n.tr("802.1X supplicant failed"); |
73 | + case 11: |
74 | + return i18n.tr("802.1X supplicant took too long to authenticate"); |
75 | + case 15: |
76 | + return i18n.tr("DHCP client failed to start"); |
77 | + case 16: |
78 | + return i18n.tr("DHCP client error"); |
79 | + case 17: |
80 | + return i18n.tr("DHCP client failed"); |
81 | + case 18: |
82 | + return i18n.tr("Shared connection service failed to start"); |
83 | + case 19: |
84 | + return i18n.tr("Shared connection service failed"); |
85 | + case 35: |
86 | + return i18n.tr("Necessary firmware for the device may be missing"); |
87 | + case 36: |
88 | + return i18n.tr("The device was removed"); |
89 | + case 37: |
90 | + return i18n.tr("NetworkManager went to sleep"); |
91 | + case 38: |
92 | + return i18n.tr("The device's active connection disappeared"); |
93 | + case 39: |
94 | + return i18n.tr("Device disconnected by user or client"); |
95 | + case 41: |
96 | + return i18n.tr("The device's existing connection was assumed"); |
97 | + case 42: |
98 | + return i18n.tr("The supplicant is now available"); |
99 | + case 43: |
100 | + return i18n.tr("The modem could not be found"); |
101 | + case 44: |
102 | + return i18n.tr("The Bluetooth connection failed or timed out"); |
103 | + case 50: |
104 | + return i18n.tr("A dependency of the connection failed"); |
105 | + case 52: |
106 | + return i18n.tr("ModemManager is unavailable"); |
107 | + case 53: |
108 | + return i18n.tr("The Wi-Fi network could not be found"); |
109 | + case 54: |
110 | + return i18n.tr("A secondary connection of the base connection failed"); |
111 | + default: |
112 | + return i18n.tr("Unknown"); |
113 | + } |
114 | + } |
115 | +} |
116 | |
117 | === modified file 'plugins/wifi/NetworkDetailsBrief.qml' |
118 | --- plugins/wifi/NetworkDetailsBrief.qml 2014-08-29 18:12:33 +0000 |
119 | +++ plugins/wifi/NetworkDetailsBrief.qml 2014-09-25 13:39:43 +0000 |
120 | @@ -46,7 +46,7 @@ |
121 | margins: units.gu(2) |
122 | } |
123 | onClicked: { |
124 | - if (DbusHelper.deactivateConnection()) { |
125 | + if (DbusHelper.disconnectDevice()) { |
126 | accessPoint.checked = false; |
127 | accessPoint.checkedChanged(false) |
128 | } |
129 | |
130 | === modified file 'plugins/wifi/OtherNetwork.qml' |
131 | --- plugins/wifi/OtherNetwork.qml 2014-09-13 02:44:36 +0000 |
132 | +++ plugins/wifi/OtherNetwork.qml 2014-09-25 13:39:43 +0000 |
133 | @@ -19,141 +19,365 @@ |
134 | import SystemSettings 1.0 |
135 | import Ubuntu.Components 0.1 |
136 | import Ubuntu.Components.ListItems 0.1 as ListItem |
137 | +import Ubuntu.Components.Popups 0.1 |
138 | import Ubuntu.SystemSettings.Wifi 1.0 |
139 | import QMenuModel 0.1 |
140 | |
141 | -ItemPage { |
142 | - id: othernetwork |
143 | - title: i18n.tr("Connect to hidden network") |
144 | - |
145 | - function settingsValid() { |
146 | - if(networkname.length == 0) { |
147 | - return false; |
148 | - } |
149 | - if(securityList.selectedIndex == 0) { |
150 | - return true |
151 | - } |
152 | - if(securityList.selectedIndex == 1) { |
153 | - return password.length >= 8 |
154 | - } |
155 | - // WEP |
156 | - return password.length === 5 || |
157 | - password.length === 10 || |
158 | - password.length === 13 || |
159 | - password.length === 26; |
160 | - } |
161 | - |
162 | - Component.onCompleted: { |
163 | - flickable: otherNetworkFlickable |
164 | - } |
165 | - |
166 | - Flickable { |
167 | - id: otherNetworkFlickable |
168 | - contentWidth: parent.width |
169 | - contentHeight: otherview.height + units.gu(8) |
170 | - anchors.fill: parent |
171 | - |
172 | - Column { |
173 | - id : otherview |
174 | +Component { |
175 | + |
176 | + Dialog { |
177 | + |
178 | + id: otherNetworkDialog |
179 | + objectName: "otherNetworkDialog" |
180 | + anchorToKeyboard: true |
181 | + |
182 | + /* The following is a (bad) workaround for bugs |
183 | + #1337556 |
184 | + #1337555 |
185 | + |
186 | + If the Dialog does not shrink after a user chooses e.g. WPA, |
187 | + the anchorToKeyboard setting of OrientationHelper have no effect, |
188 | + since the dialog never shrinks in size. |
189 | + |
190 | + This workaround resizes the Dialog. |
191 | + */ |
192 | + |
193 | + property int dialogVisualsHeight |
194 | + function getVisibleChildren () { |
195 | + var children = [feedback, networknameLabel, networkname, |
196 | + securityListLabel, securityList, passwordListLabel, |
197 | + password, passwordVisiblityRow, buttonRow]; |
198 | + var ret = []; |
199 | + children.forEach(function (child) { |
200 | + if (child.visible) { |
201 | + ret.push(child); |
202 | + } |
203 | + }); |
204 | + return ret; |
205 | + } |
206 | + |
207 | + function getVisibleChildrenHeight () { |
208 | + var h = 0; |
209 | + getVisibleChildren().forEach(function (child) { |
210 | + h = h + child.height; |
211 | + }); |
212 | + return h; |
213 | + } |
214 | + |
215 | + Component.onCompleted: { |
216 | + dialogVisualsHeight = |
217 | + __foreground.height - getVisibleChildrenHeight(); |
218 | + } |
219 | + |
220 | + Binding { |
221 | + target: __foreground |
222 | + property: "height" |
223 | + value: dialogVisualsHeight + getVisibleChildrenHeight() |
224 | + when: dialogVisualsHeight |
225 | + } |
226 | + |
227 | + function settingsValid() { |
228 | + if(networkname.length == 0) { |
229 | + return false; |
230 | + } |
231 | + if(securityList.selectedIndex == 0) { |
232 | + return true |
233 | + } |
234 | + if(securityList.selectedIndex == 1) { |
235 | + return password.length >= 8 |
236 | + } |
237 | + // WEP |
238 | + return password.length === 5 || |
239 | + password.length === 10 || |
240 | + password.length === 13 || |
241 | + password.length === 26; |
242 | + } |
243 | + |
244 | + title: i18n.tr("Connect to Hidden Network") |
245 | + text: feedback.enabled ? feedback.text : ""; |
246 | + |
247 | + Common { |
248 | + id: common |
249 | + } |
250 | + |
251 | + states: [ |
252 | + State { |
253 | + name: "CONNECTING" |
254 | + PropertyChanges { |
255 | + target: connectAction |
256 | + enabled: false |
257 | + } |
258 | + PropertyChanges { |
259 | + target: connectButtonIndicator |
260 | + running: true |
261 | + } |
262 | + PropertyChanges { |
263 | + target: passwordVisibleSwitch |
264 | + enabled: false |
265 | + } |
266 | + PropertyChanges { |
267 | + target: passwordVisibleLabel |
268 | + opacity: 0.5 |
269 | + } |
270 | + PropertyChanges { |
271 | + target: password |
272 | + enabled: false |
273 | + } |
274 | + PropertyChanges { |
275 | + target: passwordListLabel |
276 | + opacity: 0.5 |
277 | + } |
278 | + PropertyChanges { |
279 | + target: securityList |
280 | + enabled: false |
281 | + opacity: 0.5 |
282 | + } |
283 | + PropertyChanges { |
284 | + target: securityListLabel |
285 | + opacity: 0.5 |
286 | + } |
287 | + PropertyChanges { |
288 | + target: networkname |
289 | + enabled: false |
290 | + } |
291 | + PropertyChanges { |
292 | + target: networknameLabel |
293 | + opacity: 0.5 |
294 | + } |
295 | + PropertyChanges { |
296 | + target: feedback |
297 | + enabled: true |
298 | + } |
299 | + }, |
300 | + State { |
301 | + name: "FAILED" |
302 | + PropertyChanges { |
303 | + target: feedback |
304 | + enabled: true |
305 | + } |
306 | + }, |
307 | + State { |
308 | + name: "SUCCEEDED" |
309 | + PropertyChanges { |
310 | + target: successIndicator |
311 | + running: true |
312 | + } |
313 | + PropertyChanges { |
314 | + target: cancelButton |
315 | + enabled: false |
316 | + } |
317 | + PropertyChanges { |
318 | + target: connectAction |
319 | + enabled: false |
320 | + } |
321 | + } |
322 | + ] |
323 | + |
324 | + Label { |
325 | + property bool enabled: false |
326 | + id: feedback |
327 | + horizontalAlignment: Text.AlignHCenter |
328 | + height: contentHeight |
329 | + wrapMode: Text.Wrap |
330 | + visible: false |
331 | + } |
332 | + |
333 | + Label { |
334 | + id: networknameLabel |
335 | + text : i18n.tr("Network name") |
336 | + objectName: "networknameLabel" |
337 | + fontSize: "medium" |
338 | + font.bold: true |
339 | + color: Theme.palette.selected.backgroundText |
340 | + elide: Text.ElideRight |
341 | + } |
342 | + |
343 | + TextField { |
344 | + id : networkname |
345 | + objectName: "networkname" |
346 | + inputMethodHints: Qt.ImhNoPredictiveText |
347 | + } |
348 | + |
349 | + Label { |
350 | + id: securityListLabel |
351 | + text : i18n.tr("Security") |
352 | + objectName: "securityListLabel" |
353 | + fontSize: "medium" |
354 | + font.bold: true |
355 | + color: Theme.palette.selected.backgroundText |
356 | + elide: Text.ElideRight |
357 | + } |
358 | + |
359 | + ListItem.ItemSelector { |
360 | + id: securityList |
361 | + objectName: "securityList" |
362 | + model: [i18n.tr("None"), // index: 0 |
363 | + i18n.tr("WPA & WPA2 Personal"), // index: 1 |
364 | + i18n.tr("WEP"), // index: 2 |
365 | + ] |
366 | + } |
367 | + |
368 | + Label { |
369 | + id: passwordListLabel |
370 | + text : i18n.tr("Password") |
371 | + objectName: "passwordListLabel" |
372 | + fontSize: "medium" |
373 | + font.bold: true |
374 | + color: Theme.palette.selected.backgroundText |
375 | + elide: Text.ElideRight |
376 | + visible: securityList.selectedIndex !== 0 |
377 | + } |
378 | + |
379 | + TextField { |
380 | + id : password |
381 | + objectName: "password" |
382 | + visible: securityList.selectedIndex !== 0 |
383 | + echoMode: passwordVisibleSwitch.checked ? |
384 | + TextInput.Normal : TextInput.Password |
385 | + inputMethodHints: passwordVisibleSwitch.checked ? |
386 | + Qt.ImhHiddenText : Qt.ImhNoPredictiveText; |
387 | + onAccepted: { |
388 | + connectAction.trigger(); |
389 | + } |
390 | + } |
391 | + |
392 | + Row { |
393 | + id: passwordVisiblityRow |
394 | + layoutDirection: Qt.LeftToRight |
395 | + spacing: units.gu(2) |
396 | + visible: securityList.selectedIndex !== 0 |
397 | + |
398 | + CheckBox { |
399 | + id: passwordVisibleSwitch |
400 | + } |
401 | + |
402 | + Label { |
403 | + id: passwordVisibleLabel |
404 | + text : i18n.tr("Show password") |
405 | + objectName: "passwordVisibleLabel" |
406 | + fontSize: "medium" |
407 | + color: Theme.palette.selected.backgroundText |
408 | + elide: Text.ElideRight |
409 | + height: passwordVisibleSwitch.height |
410 | + verticalAlignment: Text.AlignVCenter |
411 | + MouseArea { |
412 | + anchors { |
413 | + fill: parent |
414 | + } |
415 | + onClicked: { |
416 | + passwordVisibleSwitch.checked = |
417 | + !passwordVisibleSwitch.checked |
418 | + } |
419 | + } |
420 | + } |
421 | + } |
422 | + |
423 | + RowLayout { |
424 | + id: buttonRow |
425 | anchors { |
426 | - top: parent.top |
427 | left: parent.left |
428 | right: parent.right |
429 | } |
430 | - |
431 | - ListItem.Standard { |
432 | - text : i18n.tr("Network name") |
433 | - showDivider: false |
434 | - } |
435 | - |
436 | - TextField { |
437 | - id : networkname |
438 | - width: parent.width - units.gu(4) |
439 | - anchors.horizontalCenter: parent.horizontalCenter |
440 | - inputMethodHints: Qt.ImhNoPredictiveText |
441 | - } |
442 | - |
443 | - ListItem.ItemSelector { |
444 | - id: securityList |
445 | - text: i18n.tr("Security") |
446 | - model: [i18n.tr("None"), // index: 0 |
447 | - i18n.tr("WPA & WPA2 Personal"), // index: 1 |
448 | - i18n.tr("WEP"), // index: 2 |
449 | - ] |
450 | - } |
451 | - |
452 | - ListItem.Standard { |
453 | - id: passwordList |
454 | - visible: securityList.selectedIndex !== 0 |
455 | - text: i18n.tr("Password") |
456 | - control : TextInput { |
457 | - } |
458 | - showDivider: false |
459 | - } |
460 | - |
461 | - TextField { |
462 | - id : password |
463 | - visible: securityList.selectedIndex !== 0 |
464 | - width: parent.width - units.gu(4) |
465 | - anchors.horizontalCenter: parent.horizontalCenter |
466 | - echoMode: passwordVisibleSwitch.checked ? TextInput.Normal : TextInput.Password |
467 | - onActiveFocusChanged: { |
468 | - parent.parent.contentY = 1000 |
469 | - } |
470 | - } |
471 | - |
472 | - ListItem.Standard { |
473 | - text: i18n.tr("Password visible") |
474 | - visible: securityList.selectedIndex !== 0 |
475 | - id: passwordVisible |
476 | - control: Switch { |
477 | - id: passwordVisibleSwitch |
478 | - } |
479 | - } |
480 | - |
481 | - Rectangle { |
482 | - id: buttons |
483 | - color: Theme.palette.normal.background |
484 | - anchors { |
485 | - left: parent.left |
486 | - right: parent.right |
487 | - } |
488 | - height: buttonRow.height + units.gu(4) |
489 | - |
490 | - RowLayout { |
491 | - id: buttonRow |
492 | - anchors { |
493 | - margins: units.gu(2) |
494 | - verticalCenter: parent.verticalCenter |
495 | - left: parent.left |
496 | - right: parent.right |
497 | - } |
498 | - spacing: units.gu(2) |
499 | - height: cancelButton.height |
500 | - |
501 | - Button { |
502 | - id: cancelButton |
503 | - Layout.fillWidth: true |
504 | - text: i18n.tr("Cancel") |
505 | - onClicked: { |
506 | - pageStack.pop() |
507 | - } |
508 | - } |
509 | - |
510 | - Button { |
511 | - id: connectButton |
512 | - Layout.fillWidth: true |
513 | - text: i18n.tr("Connect") |
514 | - enabled: settingsValid() |
515 | - onClicked: { |
516 | - DbusHelper.connect(networkname.text, |
517 | - securityList.selectedIndex, |
518 | - password.text) |
519 | - pageStack.pop() |
520 | - } |
521 | + spacing: units.gu(2) |
522 | + height: cancelButton.height |
523 | + |
524 | + Button { |
525 | + id: cancelButton |
526 | + objectName: "cancel" |
527 | + Layout.fillWidth: true |
528 | + text: i18n.tr("Cancel") |
529 | + onClicked: { |
530 | + PopupUtils.close(otherNetworkDialog); |
531 | + |
532 | + // If this dialog created the connection, |
533 | + // disconnect the device |
534 | + if (otherNetworkDialog.state === "CONNECTING") { |
535 | + DbusHelper.disconnectDevice(); |
536 | + } |
537 | + } |
538 | + } |
539 | + |
540 | + Button { |
541 | + id: connectButton |
542 | + objectName: "connect" |
543 | + Layout.fillWidth: true |
544 | + text: i18n.tr("Connect") |
545 | + enabled: connectAction.enabled |
546 | + action: connectAction |
547 | + Icon { |
548 | + height: parent.height - units.gu(1.5) |
549 | + width: parent.height - units.gu(1.5) |
550 | + anchors { |
551 | + centerIn: parent |
552 | + } |
553 | + name: "tick" |
554 | + color: "green" |
555 | + visible: successIndicator.running |
556 | + } |
557 | + ActivityIndicator { |
558 | + id: connectButtonIndicator |
559 | + running: false |
560 | + visible: running |
561 | + height: parent.height - units.gu(1.5) |
562 | + anchors { |
563 | + centerIn: parent |
564 | + } |
565 | + } |
566 | + } |
567 | + } |
568 | + |
569 | + Action { |
570 | + id: connectAction |
571 | + enabled: settingsValid() |
572 | + onTriggered: { |
573 | + DbusHelper.connect( |
574 | + networkname.text, |
575 | + securityList.selectedIndex, |
576 | + password.text); |
577 | + otherNetworkDialog.state = "CONNECTING"; |
578 | + } |
579 | + } |
580 | + |
581 | + /* Timer that shows a tick in the connect button once we have |
582 | + successfully connected. */ |
583 | + Timer { |
584 | + id: successIndicator |
585 | + interval: 2000 |
586 | + running: false |
587 | + repeat: false |
588 | + onTriggered: PopupUtils.close(otherNetworkDialog) |
589 | + } |
590 | + |
591 | + Connections { |
592 | + target: DbusHelper |
593 | + onDeviceStateChanged: { |
594 | + if (otherNetworkDialog.state === "FAILED") { |
595 | + /* Disconnect the device if it tries to reconnect after a |
596 | + connection failure */ |
597 | + if (newState === 40) { // 40 = NM_DEVICE_STATE_PREPARE |
598 | + DbusHelper.disconnectDevice(); |
599 | + } |
600 | + } |
601 | + |
602 | + /* We will only consider these cases if we are in |
603 | + the CONNECTING state. This means that this Dialog will not |
604 | + react to what other NetworkManager consumers do. |
605 | + */ |
606 | + if (otherNetworkDialog.state === "CONNECTING") { |
607 | + switch (newState) { |
608 | + case 120: |
609 | + feedback.text = common.reasonToString(reason); |
610 | + otherNetworkDialog.state = "FAILED"; |
611 | + break; |
612 | + case 100: |
613 | + /* connection succeeded only if it was us that |
614 | + created it */ |
615 | + otherNetworkDialog.state = "SUCCEEDED"; |
616 | + break; |
617 | } |
618 | } |
619 | } |
620 | } |
621 | } |
622 | } |
623 | + |
624 | |
625 | === modified file 'plugins/wifi/PageComponent.qml' |
626 | --- plugins/wifi/PageComponent.qml 2014-09-13 02:44:36 +0000 |
627 | +++ plugins/wifi/PageComponent.qml 2014-09-25 13:39:43 +0000 |
628 | @@ -18,11 +18,13 @@ |
629 | import SystemSettings 1.0 |
630 | import Ubuntu.Components 0.1 |
631 | import Ubuntu.Components.ListItems 0.1 as ListItem |
632 | +import Ubuntu.Components.Popups 0.1 |
633 | import Ubuntu.SystemSettings.Wifi 1.0 |
634 | import QMenuModel 0.1 |
635 | |
636 | ItemPage { |
637 | id: wifibase |
638 | + objectName: "wifiPage" |
639 | title: i18n.tr("Wi-Fi") |
640 | |
641 | UnityMenuModel { |
642 | @@ -105,7 +107,7 @@ |
643 | |
644 | if (item.hasOwnProperty("menuActivated")) { |
645 | item.menuActivated = Qt.binding(function() { |
646 | - return ListView.isCurrentItem; |
647 | + return ListView.isCurrentItem; |
648 | }); |
649 | item.selectMenu.connect(function() { |
650 | ListView.view.currentIndex = index; |
651 | @@ -132,10 +134,18 @@ |
652 | } |
653 | |
654 | ListItem.SingleValue { |
655 | - text: i18n.tr("Connect to hidden network") |
656 | + objectName: "connectToHiddenNetwork" |
657 | + text: i18n.tr("Connect to hidden network…") |
658 | progression: true |
659 | - onClicked: pageStack.push(Qt.resolvedUrl("OtherNetwork.qml")) |
660 | - visible : (actionGroup.actionObject.valid ? actionGroup.actionObject.state : false) |
661 | + onClicked: { |
662 | + otherNetworLoader.source = "OtherNetwork.qml"; |
663 | + PopupUtils.open(otherNetworLoader.item); |
664 | + } |
665 | + } |
666 | + |
667 | + Loader { |
668 | + id: otherNetworLoader |
669 | + asynchronous: false |
670 | } |
671 | } |
672 | |
673 | @@ -144,4 +154,5 @@ |
674 | Flickable.DragAndOvershootBounds : |
675 | Flickable.StopAtBounds |
676 | } |
677 | + |
678 | } |
679 | |
680 | === modified file 'plugins/wifi/nm_manager_proxy.h' |
681 | --- plugins/wifi/nm_manager_proxy.h 2014-06-18 14:16:53 +0000 |
682 | +++ plugins/wifi/nm_manager_proxy.h 2014-09-25 13:39:43 +0000 |
683 | @@ -108,7 +108,7 @@ |
684 | { |
685 | QList<QVariant> argumentList; |
686 | argumentList << QVariant::fromValue(connection) << QVariant::fromValue(device) << QVariant::fromValue(specific_object); |
687 | - return asyncCallWithArgumentList(QLatin1String("AddAndActivateConnection"), argumentList); |
688 | + return callWithArgumentList(QDBus::Block, QLatin1String("AddAndActivateConnection"), argumentList); |
689 | } |
690 | inline QDBusReply<QDBusObjectPath> AddAndActivateConnection(const QMap<QString, QVariantMap> &connection, const QDBusObjectPath &device, const QDBusObjectPath &specific_object, QDBusObjectPath &active_connection) |
691 | { |
692 | |
693 | === modified file 'plugins/wifi/wifidbushelper.cpp' |
694 | --- plugins/wifi/wifidbushelper.cpp 2014-09-04 00:58:34 +0000 |
695 | +++ plugins/wifi/wifidbushelper.cpp 2014-09-25 13:39:43 +0000 |
696 | @@ -31,6 +31,7 @@ |
697 | |
698 | #define NM_SERVICE "org.freedesktop.NetworkManager" |
699 | #define NM_PATH "/org/freedesktop/NetworkManager" |
700 | +#define NM_DEVICE_IFACE "org.freedesktop.NetworkManager.Device" |
701 | |
702 | typedef QMap<QString,QVariantMap> ConfigurationData; |
703 | Q_DECLARE_METATYPE(ConfigurationData) |
704 | @@ -96,9 +97,9 @@ |
705 | |
706 | QDBusObjectPath dev; |
707 | for (const auto &d : devices) { |
708 | - QDBusInterface iface("org.freedesktop.NetworkManager", |
709 | + QDBusInterface iface(NM_SERVICE, |
710 | d.path(), |
711 | - "org.freedesktop.NetworkManager.Device", |
712 | + NM_DEVICE_IFACE, |
713 | QDBusConnection::systemBus()); |
714 | |
715 | auto type_v = iface.property("DeviceType"); |
716 | @@ -110,14 +111,42 @@ |
717 | |
718 | if (dev.path().isEmpty()) { |
719 | // didn't find a wifi device |
720 | + qWarning() << "Could not find wifi device."; |
721 | return; |
722 | } |
723 | |
724 | + mgr.connection().disconnect( |
725 | + mgr.service(), |
726 | + dev.path(), |
727 | + NM_DEVICE_IFACE, |
728 | + "StateChanged", |
729 | + this, |
730 | + SLOT(nmDeviceStateChanged(uint, uint, uint))); |
731 | + |
732 | + mgr.connection().connect( |
733 | + mgr.service(), |
734 | + dev.path(), |
735 | + NM_DEVICE_IFACE, |
736 | + "StateChanged", |
737 | + this, |
738 | + SLOT(nmDeviceStateChanged(uint, uint, uint))); |
739 | + |
740 | QDBusObjectPath tmp; |
741 | auto reply2 = mgr.AddAndActivateConnection(configuration, |
742 | dev, |
743 | QDBusObjectPath("/"), |
744 | tmp); |
745 | + if(!reply2.isValid()) { |
746 | + qWarning() << "Could not connect: " << reply2.error().message() << "\n"; |
747 | + } |
748 | +} |
749 | + |
750 | +void WifiDbusHelper::nmDeviceStateChanged(uint newState, |
751 | + uint oldState, |
752 | + uint reason) |
753 | +{ |
754 | + Q_UNUSED (oldState); |
755 | + Q_EMIT (deviceStateChanged(newState, reason)); |
756 | } |
757 | |
758 | QString WifiDbusHelper::getWifiIpAddress() |
759 | @@ -138,11 +167,7 @@ |
760 | |
761 | QDBusObjectPath dev; |
762 | for (const auto &d : devices) { |
763 | - QDBusInterface iface("org.freedesktop.NetworkManager", |
764 | - d.path(), |
765 | - "org.freedesktop.NetworkManager.Device", |
766 | - m_systemBusConnection); |
767 | - |
768 | + QDBusInterface iface(NM_SERVICE, d.path(), NM_DEVICE_IFACE, m_systemBusConnection); |
769 | auto type_v = iface.property("DeviceType"); |
770 | if (type_v.toUInt() == 2 /* NM_DEVICE_TYPE_WIFI */) { |
771 | ip4addr = iface.property("Ip4Address").toInt(); |
772 | @@ -323,7 +348,7 @@ |
773 | QList<QStringList> networks; |
774 | |
775 | OrgFreedesktopNetworkManagerSettingsInterface foo |
776 | - ("org.freedesktop.NetworkManager", |
777 | + (NM_SERVICE, |
778 | "/org/freedesktop/NetworkManager/Settings", |
779 | QDBusConnection::systemBus()); |
780 | auto reply = foo.ListConnections(); |
781 | @@ -359,7 +384,7 @@ |
782 | |
783 | void WifiDbusHelper::forgetConnection(const QString dbus_path) { |
784 | OrgFreedesktopNetworkManagerSettingsConnectionInterface bar |
785 | - ("org.freedesktop.NetworkManager", |
786 | + (NM_SERVICE, |
787 | dbus_path, |
788 | QDBusConnection::systemBus()); |
789 | auto reply = bar.Delete(); |
790 | @@ -369,7 +394,7 @@ |
791 | } |
792 | } |
793 | |
794 | -bool WifiDbusHelper::deactivateConnection() { |
795 | +bool WifiDbusHelper::disconnectDevice() { |
796 | OrgFreedesktopNetworkManagerInterface mgr(NM_SERVICE, |
797 | NM_PATH, |
798 | m_systemBusConnection); |
799 | @@ -377,42 +402,27 @@ |
800 | auto reply1 = mgr.GetDevices(); |
801 | reply1.waitForFinished(); |
802 | if(!reply1.isValid()) { |
803 | - qWarning() << "deactivateConnection: Could not get network device: " << reply1.error().message() << "\n"; |
804 | + qWarning() << "disconnectDevice: Could not get network device: " << reply1.error().message() << "\n"; |
805 | return false; |
806 | } |
807 | auto devices = reply1.value(); |
808 | |
809 | - QDBusObjectPath activeConnection; |
810 | QDBusObjectPath dev; |
811 | for (const auto &d : devices) { |
812 | - QDBusInterface iface(NM_SERVICE, |
813 | - d.path(), |
814 | - "org.freedesktop.NetworkManager.Device", |
815 | - m_systemBusConnection); |
816 | + QDBusInterface iface(NM_SERVICE, d.path(), NM_DEVICE_IFACE, m_systemBusConnection); |
817 | |
818 | auto type_v = iface.property("DeviceType"); |
819 | if (type_v.toUInt() == 2 /* NM_DEVICE_TYPE_WIFI */) { |
820 | - activeConnection = qvariant_cast<QDBusObjectPath>(iface.property("ActiveConnection")); |
821 | - dev = d; |
822 | + if (d.path().isEmpty()) { |
823 | + // didn't find a wifi device |
824 | + qWarning() << "disconnectDevice: Could not find wifi device\n"; |
825 | + return false; |
826 | + } else { |
827 | + iface.call("Disconnect"); |
828 | + return true; |
829 | + } |
830 | break; |
831 | } |
832 | } |
833 | - |
834 | - if (dev.path().isEmpty()) { |
835 | - // didn't find a wifi device |
836 | - return false; |
837 | - } |
838 | - |
839 | - if (activeConnection.path().isEmpty()) { |
840 | - // no active connection |
841 | - return false; |
842 | - } |
843 | - |
844 | - auto reply = mgr.DeactivateConnection(activeConnection); |
845 | - reply.waitForFinished(); |
846 | - if(!reply.isValid()) { |
847 | - qWarning() << "Error deactivating connection: " << reply.error().message() << "\n"; |
848 | - return false; |
849 | - } |
850 | - return true; |
851 | + return false; |
852 | } |
853 | |
854 | === modified file 'plugins/wifi/wifidbushelper.h' |
855 | --- plugins/wifi/wifidbushelper.h 2014-09-04 00:58:34 +0000 |
856 | +++ plugins/wifi/wifidbushelper.h 2014-09-25 13:39:43 +0000 |
857 | @@ -40,10 +40,14 @@ |
858 | Q_INVOKABLE void connect(QString ssid, int security, QString password); |
859 | Q_INVOKABLE QList<QStringList> getPreviouslyConnectedWifiNetworks(); |
860 | Q_INVOKABLE void forgetConnection(const QString dbus_path); |
861 | - Q_INVOKABLE bool deactivateConnection(); |
862 | + Q_INVOKABLE bool disconnectDevice(); |
863 | + |
864 | +public Q_SLOTS: |
865 | + void nmDeviceStateChanged(uint, uint, uint); |
866 | |
867 | Q_SIGNALS: |
868 | void wifiIp4AddressChanged(QString wifiIp4Address); |
869 | + void deviceStateChanged(uint newState, uint reason); |
870 | |
871 | private: |
872 | QDBusConnection m_systemBusConnection; |
873 | |
874 | === modified file 'tests/autopilot/ubuntu_system_settings/__init__.py' |
875 | --- tests/autopilot/ubuntu_system_settings/__init__.py 2014-09-11 18:34:30 +0000 |
876 | +++ tests/autopilot/ubuntu_system_settings/__init__.py 2014-09-25 13:39:43 +0000 |
877 | @@ -27,7 +27,7 @@ |
878 | import autopilot.logging |
879 | import ubuntuuitoolkit |
880 | from autopilot import introspection, platform |
881 | - |
882 | +from ubuntu_system_settings.utils.i18n import ugettext as _ |
883 | |
884 | logger = logging.getLogger(__name__) |
885 | |
886 | @@ -110,6 +110,10 @@ |
887 | def go_to_language_page(self): |
888 | return self._go_to_page('entryComponent-language', 'languagePage') |
889 | |
890 | + @autopilot.logging.log_action(logger.debug) |
891 | + def go_to_wifi_page(self): |
892 | + return self._go_to_page('entryComponent-wifi', 'wifiPage') |
893 | + |
894 | def _go_to_page(self, item_object_name, page_object_name): |
895 | self.click_item(item_object_name) |
896 | page = self.wait_select_single(objectName=page_object_name) |
897 | @@ -181,6 +185,11 @@ |
898 | return self.select_single(objectName='aboutPage') |
899 | |
900 | @property |
901 | + def wifi_page(self): |
902 | + """ Return 'Wifi' page """ |
903 | + return self.select_single(objectName='wifiPage') |
904 | + |
905 | + @property |
906 | def _orientation_lock_switch(self): |
907 | return self.wait_select_single( |
908 | ubuntuuitoolkit.CheckBox, |
909 | @@ -655,3 +664,156 @@ |
910 | def _click_revert(self): |
911 | button = self.select_single('Button', objectName='revert') |
912 | self.pointing_device.click_object(button) |
913 | + |
914 | + |
915 | +class WifiPage(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
916 | + |
917 | + """Autopilot helper for the Sound page.""" |
918 | + |
919 | + @classmethod |
920 | + def validate_dbus_object(cls, path, state): |
921 | + name = introspection.get_classname_from_path(path) |
922 | + if name == b'ItemPage': |
923 | + if state['objectName'][1] == 'wifiPage': |
924 | + return True |
925 | + return False |
926 | + |
927 | + """Connects to hidden network |
928 | + |
929 | + :param name: Network name string (SSID) |
930 | + :kwarg security: A string that is either "none", "wpa" or "wep |
931 | + :kwarg password: A string/hex secret |
932 | + :kwarg cancel: A boolean deciding whether we press cancel or not |
933 | + |
934 | + :returns: If we are connecting, it returns the dialog, |
935 | + if we cancel, it returns itself |
936 | + |
937 | + """ |
938 | + @autopilot.logging.log_action(logger.debug) |
939 | + def connect_to_hidden_network(self, name, security="none", password=None, |
940 | + cancel=False, scroll_to_and_click=None): |
941 | + dialog = self._click_connect_to_hidden_network(scroll_to_and_click) |
942 | + dialog.enter_name(name) |
943 | + if security: |
944 | + dialog.set_security(security) |
945 | + if password: |
946 | + dialog.enter_password(password) |
947 | + |
948 | + if cancel: |
949 | + dialog.cancel() |
950 | + return self |
951 | + else: |
952 | + dialog.connect() |
953 | + return dialog |
954 | + |
955 | + @autopilot.logging.log_action(logger.debug) |
956 | + def _click_connect_to_hidden_network(self, scroll_to_and_click): |
957 | + |
958 | + # we can't mock the qunitymenu items, so we |
959 | + # have to wait for them to be built |
960 | + sleep(1) |
961 | + |
962 | + button = self.select_single('*', |
963 | + objectName='connectToHiddenNetwork') |
964 | + if (scroll_to_and_click): |
965 | + scroll_to_and_click(button) |
966 | + else: |
967 | + self.pointing_device.click_object(button) |
968 | + return self.get_root_instance().wait_select_single( |
969 | + objectName='otherNetworkDialog') |
970 | + |
971 | + |
972 | +class OtherNetwork( |
973 | + ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
974 | + |
975 | + """Autopilot helper for the Connect to Hidden Network dialog.""" |
976 | + |
977 | + @classmethod |
978 | + def validate_dbus_object(cls, path, state): |
979 | + name = introspection.get_classname_from_path(path) |
980 | + if name == b'Dialog': |
981 | + if state['objectName'][1] == 'otherNetworkDialog': |
982 | + return True |
983 | + return False |
984 | + |
985 | + @autopilot.logging.log_action(logger.debug) |
986 | + def enter_name(self, name): |
987 | + self._enter_name(name) |
988 | + |
989 | + @autopilot.logging.log_action(logger.debug) |
990 | + def _enter_name(self, name): |
991 | + namefield = self.select_single('TextField', |
992 | + objectName='networkname') |
993 | + namefield.write(name) |
994 | + |
995 | + @autopilot.logging.log_action(logger.debug) |
996 | + def set_security(self, security): |
997 | + """Sets the hidden network's security |
998 | + |
999 | + :param security: Either "none", "wpa" or "wep |
1000 | + |
1001 | + :returns: None |
1002 | + |
1003 | + """ |
1004 | + self._set_security(security) |
1005 | + |
1006 | + @autopilot.logging.log_action(logger.debug) |
1007 | + def _expand_security_list(self): |
1008 | + sec_list = self.select_single( |
1009 | + '*', objectName='securityList') |
1010 | + active_child = sec_list.select_single( |
1011 | + '*', objectName='listContainer') |
1012 | + self.pointing_device.click_object(active_child) |
1013 | + # wait for it to expand |
1014 | + sleep(0.5) |
1015 | + return sec_list |
1016 | + |
1017 | + @autopilot.logging.log_action(logger.debug) |
1018 | + def _set_security(self, security): |
1019 | + if security == 'none': |
1020 | + sec_list = self._expand_security_list() |
1021 | + item = sec_list.wait_select_single('*', |
1022 | + text=_('None')) |
1023 | + self.pointing_device.click_object(item) |
1024 | + elif security == 'wpa': |
1025 | + sec_list = self._expand_security_list() |
1026 | + item = sec_list.wait_select_single('*', |
1027 | + text=_('WPA & WPA2 Personal')) |
1028 | + self.pointing_device.click_object(item) |
1029 | + elif security == 'wep': |
1030 | + sec_list = self._expand_security_list() |
1031 | + item = sec_list.wait_select_single('*', |
1032 | + text=_('WEP')) |
1033 | + self.pointing_device.click_object(item) |
1034 | + elif security is not None: |
1035 | + raise ValueError('security type %s is not valid' % security) |
1036 | + # wait for ui to change |
1037 | + sleep(0.5) |
1038 | + |
1039 | + @autopilot.logging.log_action(logger.debug) |
1040 | + def enter_password(self, password): |
1041 | + self._enter_password(password) |
1042 | + |
1043 | + @autopilot.logging.log_action(logger.debug) |
1044 | + def _enter_password(self, password): |
1045 | + pwdfield = self.select_single('TextField', |
1046 | + objectName='password') |
1047 | + pwdfield.write(password) |
1048 | + |
1049 | + @autopilot.logging.log_action(logger.debug) |
1050 | + def cancel(self): |
1051 | + self._click_cancel() |
1052 | + |
1053 | + @autopilot.logging.log_action(logger.debug) |
1054 | + def _click_cancel(self): |
1055 | + button = self.select_single('Button', objectName='cancel') |
1056 | + self.pointing_device.click_object(button) |
1057 | + |
1058 | + @autopilot.logging.log_action(logger.debug) |
1059 | + def connect(self): |
1060 | + self._click_connect() |
1061 | + |
1062 | + @autopilot.logging.log_action(logger.debug) |
1063 | + def _click_connect(self): |
1064 | + button = self.select_single('Button', objectName='connect') |
1065 | + self.pointing_device.click_object(button) |
1066 | |
1067 | === modified file 'tests/autopilot/ubuntu_system_settings/tests/__init__.py' |
1068 | --- tests/autopilot/ubuntu_system_settings/tests/__init__.py 2014-09-11 18:34:30 +0000 |
1069 | +++ tests/autopilot/ubuntu_system_settings/tests/__init__.py 2014-09-25 13:39:43 +0000 |
1070 | @@ -13,15 +13,14 @@ |
1071 | import dbusmock |
1072 | import os |
1073 | import subprocess |
1074 | -from time import sleep |
1075 | - |
1076 | import ubuntuuitoolkit |
1077 | + |
1078 | from autopilot.matchers import Eventually |
1079 | +from dbusmock.templates.networkmanager import DEVICE_IFACE |
1080 | +from datetime import datetime |
1081 | from fixtures import EnvironmentVariable |
1082 | from testtools.matchers import Equals, NotEquals, GreaterThan |
1083 | - |
1084 | -from datetime import datetime |
1085 | - |
1086 | +from time import sleep |
1087 | from ubuntu_system_settings import SystemSettings |
1088 | |
1089 | ACCOUNTS_IFACE = 'org.freedesktop.Accounts' |
1090 | @@ -41,6 +40,9 @@ |
1091 | LM_SERVICE = 'org.freedesktop.login1' |
1092 | LM_PATH = '/org/freedesktop/login1' |
1093 | LM_IFACE = 'org.freedesktop.login1.Manager' |
1094 | +NM_SERVICE = 'org.freedesktop.NetworkManager' |
1095 | +NM_PATH = '/org/freedesktop/NetworkManager' |
1096 | +NM_IFACE = 'org.freedesktop.NetworkManager' |
1097 | |
1098 | |
1099 | class UbuntuSystemSettingsTestCase( |
1100 | @@ -737,3 +739,38 @@ |
1101 | self.mock_server.terminate() |
1102 | self.mock_server.wait() |
1103 | super(LanguageBaseTestCase, self).tearDown() |
1104 | + |
1105 | + |
1106 | +class WifiBaseTestCase(UbuntuSystemSettingsTestCase, |
1107 | + dbusmock.DBusTestCase): |
1108 | + """ Base class for wifi settings tests""" |
1109 | + |
1110 | + @classmethod |
1111 | + def setUpClass(cls): |
1112 | + cls.start_system_bus() |
1113 | + cls.dbus_con = cls.get_dbus(True) |
1114 | + # Add a mock NetworkManager environment so we get consistent results |
1115 | + (cls.p_mock, cls.obj_nm) = cls.spawn_server_template( |
1116 | + 'networkmanager', stdout=subprocess.PIPE) |
1117 | + cls.dbusmock = dbus.Interface(cls.obj_nm, dbusmock.MOCK_IFACE) |
1118 | + |
1119 | + def setUp(self, panel=None): |
1120 | + self.obj_nm.Reset() |
1121 | + device_path = self.obj_nm.AddWiFiDevice('test0', 'Barbaz', 1) |
1122 | + self.device_mock = dbus.Interface(self.dbus_con.get_object( |
1123 | + 'org.freedesktop.NetworkManager', device_path), |
1124 | + dbusmock.MOCK_IFACE) |
1125 | + |
1126 | + """A device should not just implement Device.Wireless/Device.Wired |
1127 | + interfaces, but also the Device interface. Since we want to test |
1128 | + the Disconnect method, we add it.""" |
1129 | + |
1130 | + try: |
1131 | + self.device_mock.AddMethod(DEVICE_IFACE, 'Disconnect', '', '', '') |
1132 | + except: |
1133 | + # it was already added |
1134 | + pass |
1135 | + |
1136 | + super(WifiBaseTestCase, self).setUp() |
1137 | + self.wifi_page = self.system_settings.\ |
1138 | + main_view.go_to_wifi_page() |
1139 | |
1140 | === added file 'tests/autopilot/ubuntu_system_settings/tests/test_wifi.py' |
1141 | --- tests/autopilot/ubuntu_system_settings/tests/test_wifi.py 1970-01-01 00:00:00 +0000 |
1142 | +++ tests/autopilot/ubuntu_system_settings/tests/test_wifi.py 2014-09-25 13:39:43 +0000 |
1143 | @@ -0,0 +1,135 @@ |
1144 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
1145 | +# Copyright 2014 Canonical |
1146 | +# |
1147 | +# This program is free software: you can redistribute it and/or modify it |
1148 | +# under the terms of the GNU General Public License version 3, as published |
1149 | +# by the Free Software Foundation. |
1150 | + |
1151 | +from __future__ import absolute_import |
1152 | +from autopilot.matchers import Eventually |
1153 | +from dbusmock.templates.networkmanager import DEVICE_IFACE |
1154 | +from testtools.matchers import Equals |
1155 | +from time import sleep |
1156 | +from ubuntu_system_settings.tests import WifiBaseTestCase |
1157 | +from ubuntu_system_settings.utils.i18n import ugettext as _ |
1158 | +from unittest import skip |
1159 | + |
1160 | + |
1161 | +class WifiTestCase(WifiBaseTestCase): |
1162 | + """Tests for Language Page""" |
1163 | + |
1164 | + def test_wifi_page_title_is_correct(self): |
1165 | + """Checks whether Wifi page is available""" |
1166 | + self.assertThat( |
1167 | + self.wifi_page.title, |
1168 | + Equals(_('Wi-Fi'))) |
1169 | + |
1170 | + def test_connect_to_hidden_network(self): |
1171 | + dialog = self.wifi_page.connect_to_hidden_network( |
1172 | + 'yeah', |
1173 | + scroll_to_and_click=self.system_settings.main_view |
1174 | + .scroll_to_and_click) |
1175 | + |
1176 | + # allow backend to set up listeners |
1177 | + sleep(0.3) |
1178 | + |
1179 | + """Mock a StateChanged signal on the Device, using a likely |
1180 | + scenario of a not found SSID: |
1181 | + newState = 120 # NM_DEVICE_STATE_FAILED |
1182 | + oldState = 0 # does not matter |
1183 | + reason = 53 # NM_DEVICE_STATE_REASON_SSID_NOT_FOUND |
1184 | + """ |
1185 | + |
1186 | + self.device_mock.EmitSignal( |
1187 | + DEVICE_IFACE, 'StateChanged', 'uuu', [100, 0, 0]) |
1188 | + |
1189 | + if dialog: |
1190 | + dialog.wait_until_destroyed() |
1191 | + |
1192 | + def test_connect_to_nonexistant_hidden_network(self): |
1193 | + |
1194 | + dialog = self.wifi_page.connect_to_hidden_network( |
1195 | + 'yeah', |
1196 | + scroll_to_and_click=self.system_settings.main_view |
1197 | + .scroll_to_and_click) |
1198 | + |
1199 | + # allow backend to set up listeners |
1200 | + sleep(0.3) |
1201 | + |
1202 | + """Mock a StateChanged signal on the Device, using a likely |
1203 | + scenario of a not found SSID: |
1204 | + newState = 120 # NM_DEVICE_STATE_FAILED |
1205 | + oldState = 0 # does not matter |
1206 | + reason = 53 # NM_DEVICE_STATE_REASON_SSID_NOT_FOUND |
1207 | + """ |
1208 | + |
1209 | + self.device_mock.EmitSignal( |
1210 | + DEVICE_IFACE, 'StateChanged', 'uuu', [120, 0, 53]) |
1211 | + |
1212 | + self.assertThat( |
1213 | + dialog.text, Eventually(Equals( |
1214 | + _('The Wi-Fi network could not be found')))) |
1215 | + |
1216 | + @skip('skipped due to bug 1337556') |
1217 | + def test_connect_to_hidden_network_using_secrets(self): |
1218 | + dialog = self.wifi_page.connect_to_hidden_network( |
1219 | + 'yeah', security='wpa', password='abcdefgh', |
1220 | + scroll_to_and_click=self.system_settings.main_view |
1221 | + .scroll_to_and_click) |
1222 | + |
1223 | + # allow backend to set up listeners |
1224 | + sleep(0.3) |
1225 | + |
1226 | + """Mock a StateChanged signal on the Device, which |
1227 | + lets the backend know it was the wrong secret: |
1228 | + newState = 100 # NM_DEVICE_STATE_ACTIVATED |
1229 | + oldState = 0 # does not matter |
1230 | + reason = 0 # does not matter |
1231 | + """ |
1232 | + |
1233 | + self.device_mock.EmitSignal( |
1234 | + DEVICE_IFACE, 'StateChanged', 'uuu', [100, 0, 0]) |
1235 | + |
1236 | + if dialog: |
1237 | + dialog.wait_until_destroyed() |
1238 | + |
1239 | + @skip('skipped due to bug 1337556') |
1240 | + def test_connect_to_hidden_network_using_incorrect_secrets(self): |
1241 | + dialog = self.wifi_page.connect_to_hidden_network( |
1242 | + 'yeah', security='wpa', password='abcdefgh', |
1243 | + scroll_to_and_click=self.system_settings.main_view |
1244 | + .scroll_to_and_click) |
1245 | + # allow backend to set up listeners |
1246 | + sleep(0.3) |
1247 | + |
1248 | + """Mock a StateChanged signal on the Device, which |
1249 | + lets the backend know it was the wrong secret: |
1250 | + newState = 120 # NM_DEVICE_STATE_FAILED |
1251 | + oldState = 0 # does not matter |
1252 | + reason = 7 # NM_DEVICE_STATE_REASON_NO_SECRETS |
1253 | + """ |
1254 | + |
1255 | + self.device_mock.EmitSignal( |
1256 | + DEVICE_IFACE, 'StateChanged', 'uuu', [120, 0, 7]) |
1257 | + |
1258 | + self.assertThat( |
1259 | + dialog.text, Eventually(Equals( |
1260 | + _('Your authentication details were incorrect')))) |
1261 | + |
1262 | + def test_connect_to_hidden_network_then_cancel(self): |
1263 | + |
1264 | + dialog = self.wifi_page.connect_to_hidden_network( |
1265 | + 'foo', |
1266 | + scroll_to_and_click=self.system_settings.main_view |
1267 | + .scroll_to_and_click) |
1268 | + |
1269 | + # allow backend to set up listeners |
1270 | + sleep(0.3) |
1271 | + |
1272 | + dialog.cancel() |
1273 | + |
1274 | + # check that Disconnect was called once |
1275 | + self.assertThat( |
1276 | + lambda: |
1277 | + len(self.device_mock.GetMethodCalls('Disconnect')), |
1278 | + Eventually(Equals(1))) |
FAILED: Continuous integration, rev:1037 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- ci/1488/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/4864/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- utopic/ 3554/console jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- utopic- i386-ci/ 680/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/6116/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/3861/ console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- system- settings- ci/1488/ rebuild
http://