Merge lp:~jonas-drange/ubuntu-system-settings/hotspots-binding into lp:ubuntu-system-settings

Proposed by Jonas G. Drange
Status: Superseded
Proposed branch: lp:~jonas-drange/ubuntu-system-settings/hotspots-binding
Merge into: lp:ubuntu-system-settings
Diff against target: 3076 lines (+2449/-276)
16 files modified
plugins/cellular/CMakeLists.txt (+1/-0)
plugins/cellular/Common.qml (+97/-0)
plugins/cellular/Components/MultiSim.qml (+7/-2)
plugins/cellular/Components/SingleSim.qml (+6/-2)
plugins/cellular/Hotspot.qml (+39/-22)
plugins/cellular/HotspotSetup.qml (+301/-70)
plugins/cellular/hotspotmanager.cpp (+619/-159)
plugins/cellular/hotspotmanager.h (+147/-19)
plugins/system-update/system_update.cpp (+7/-0)
plugins/system-update/system_update.h (+2/-0)
plugins/system-update/update_manager.h (+4/-0)
tests/autopilot/ubuntu_system_settings/__init__.py (+132/-0)
tests/autopilot/ubuntu_system_settings/tests/__init__.py (+62/-1)
tests/autopilot/ubuntu_system_settings/tests/networkmanager.py (+902/-0)
tests/autopilot/ubuntu_system_settings/tests/test_cellular.py (+122/-1)
tests/plugins/system-update/fakesystemupdate.h (+1/-0)
To merge this branch: bzr merge lp:~jonas-drange/ubuntu-system-settings/hotspots-binding
Reviewer Review Type Date Requested Status
Ken VanDine Needs Fixing
PS Jenkins bot continuous-integration Approve
Mathieu Trudel-Lapierre (community) Abstain
Matthew Paul Thomas design Pending
Review via email: mp+252296@code.launchpad.net

This proposal has been superseded by a proposal from 2015-05-18.

Commit message

[cellular] ap support in binding and rewriting the API to make it easier to interact with

Description of the change

Changes
This modifies the current hotspotmanager binding to do AP and adhoc hotspots, but AP by default. It also mimics [1] in a lot of ways.

So, roughly it
* adds means to talk to URFKill and wpa_supplicant, to respectively soft block/unblock Wi-Fi, and change the interface driver if necessary (which it is on all hybris devices),
* uses NetworkManager events to be less racy,
* and checks for failures and reports them to the user.

The UI has been changed to use the new binding, albeit still hidden due to bug 1426923 bug 1429314 bug 1421671 and bug 1427358.

How to test
If libhybris device (krillin):
1. Edit /etc/dbus-1/system.d/wpa_supplicant.conf # so it looks like this: http://pastebin.ubuntu.com/10576889/
2. Confirm you can call $ gdbus call --system -d fi.w1.wpa_supplicant1 -o /fi/w1/wpa_supplicant1 -m fi.w1.wpa_supplicant1.SetInterfaceFirmware / ap

All devices:
1. Edit /usr/share/applications/ubuntu-system-settings.desktop
2. Change 'Exec' line to be Exec=env USS_SHOW_ALL_UI=1 system-settings %u or do $ initctl set-env USS_SHOW_ALL_UI=1

Checklist
 * Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)
    Yes

 * Did you build your software in a clean sbuild/pbuilder chroot or ppa?
    Yes

 * Did you build your software in a clean sbuild/pbuilder armhf chroot or ppa?
    Yes

 * Has your component "TestPlan” been executed successfully on emulator, N4?
    Yes (Krillin, Arale), not N4 due to bug from above.

 * Has a 5 minute exploratory testing run been executed on N4?
    No, see above.

 * If you changed the packaging (debian), did you subscribe a core-dev to this MP?
    N/A

 * If you changed the UI, did you subscribe the design-reviewers to this MP?
    Yes (mpt)

 * What components might get impacted by your changes?
    Cellular for Single and Multi-SIM

 * Have you requested review by the teams of these owning components?
    N/A

[1] http://bazaar.launchpad.net/~mathieu-tl/+junk/touch-hotspot/view/head:/hotspot.py

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ken VanDine (ken-vandine) wrote :

See a couple comments and questions inline.

review: Needs Information
Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Information given, but sat MP back to WIP to work on what Ken pointed out.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ken VanDine (ken-vandine) wrote :

In my testing I found that the ssidField which needs to be 8 or more characters only becomes valid when you enter the 9th character or the field loses focus. This MP is more about the backend it needs and the UI is still hidden. Not sure we want to block on that. However the hotspot I created on my mako appeared to work, but I couldn't make a successful connection to it from my laptop.

review: Needs Fixing
Revision history for this message
Mathieu Trudel-Lapierre (cyphermox) wrote :

I only reviewed the backend code but it looks fine to me; see one minor inline comment about wifi security.

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ken VanDine (ken-vandine) wrote :

Looks good, I pushed a fix to show the UI and disable predictive text in the password to another branch

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1369. By Jonas G. Drange

style

1370. By Jonas G. Drange

skip if wifi disabled

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ken VanDine (ken-vandine) wrote :

Please fix the indenting of the .cpp and .h files, you used 2 spaces instead of 4. Also see the comments inline in the diff.

review: Needs Fixing
1371. By Jonas G. Drange

start addressing ken's comments

1372. By Jonas G. Drange

four tests, fixing setup and teardown

1373. By Jonas G. Drange

fixing some test imports, indent now 4 spaces

1374. By Jonas G. Drange

merge trunk

1375. By Jonas G. Drange

merge prereq branch

1376. By Jonas G. Drange

hide if mako

1377. By Jonas G. Drange

add comment to import

1378. By Jonas G. Drange

hiding completely on mako

1379. By Jonas G. Drange

unhide for testing

1380. By Jonas G. Drange

remove enabledshim

1381. By Jonas G. Drange

using usc serverpropertysynchroniser

1382. By Jonas G. Drange

foo

1383. By Jonas G. Drange

let the checkbox render before starting hotspot

1384. By Jonas G. Drange

disable back button so as to ensure that the wifi is soft unblocked

1385. By Jonas G. Drange

sync trunk

1386. By Jonas G. Drange

sync with trunk

1387. By Jonas G. Drange

sync with trunk

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/cellular/CMakeLists.txt'
--- plugins/cellular/CMakeLists.txt 2015-03-26 21:57:53 +0000
+++ plugins/cellular/CMakeLists.txt 2015-05-18 15:06:15 +0000
@@ -6,6 +6,7 @@
6set(QML_SOURCES6set(QML_SOURCES
7 apn.js7 apn.js
8 carriers.js8 carriers.js
9 Common.qml
9 CustomApnEditor.qml10 CustomApnEditor.qml
10 PageChooseApn.qml11 PageChooseApn.qml
11 PageChooseCarrier.qml12 PageChooseCarrier.qml
1213
=== added file 'plugins/cellular/Common.qml'
--- plugins/cellular/Common.qml 1970-01-01 00:00:00 +0000
+++ plugins/cellular/Common.qml 2015-05-18 15:06:15 +0000
@@ -0,0 +1,97 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Jonas G. Drange <jonas.drange@canonical.com>
18 *
19*/
20import QtQuick 2.0
21
22Item {
23 /*
24 The mapping of code to string is taken from
25 http://bazaar.launchpad.net/~vcs-imports/
26 network-manager/trunk/view/head:/cli/src/common.c
27
28 NetworkManager documentation: https://developer.gnome.org/
29 NetworkManager/0.9/spec.html#type-NM_DEVICE_STATE_REASON
30 */
31 function reasonToString (reason) {
32 switch (reason) {
33 case 0:
34 return i18n.tr("Unknown error");
35 case 1:
36 return i18n.tr("No reason given");
37 case 2:
38 return i18n.tr("Device is now managed");
39 case 3:
40 return i18n.tr("Device is now unmanaged");
41 case 4:
42 return i18n.tr("The device could not be readied for configuration");
43 case 5:
44 return i18n.tr("IP configuration could not be reserved (no available address, timeout, etc.)");
45 case 6:
46 return i18n.tr("The IP configuration is no longer valid");
47 case 7:
48 return i18n.tr("Your authentication details were incorrect");
49 case 8:
50 return i18n.tr("802.1X supplicant disconnected");
51 case 9:
52 return i18n.tr("802.1X supplicant configuration failed");
53 case 10:
54 return i18n.tr("802.1X supplicant failed");
55 case 11:
56 return i18n.tr("802.1X supplicant took too long to authenticate");
57 case 15:
58 return i18n.tr("DHCP client failed to start");
59 case 16:
60 return i18n.tr("DHCP client error");
61 case 17:
62 return i18n.tr("DHCP client failed");
63 case 18:
64 return i18n.tr("Shared connection service failed to start");
65 case 19:
66 return i18n.tr("Shared connection service failed");
67 case 35:
68 return i18n.tr("Necessary firmware for the device may be missing");
69 case 36:
70 return i18n.tr("The device was removed");
71 case 37:
72 return i18n.tr("NetworkManager went to sleep");
73 case 38:
74 return i18n.tr("The device's active connection disappeared");
75 case 39:
76 return i18n.tr("Device disconnected by user or client");
77 case 41:
78 return i18n.tr("The device's existing connection was assumed");
79 case 42:
80 return i18n.tr("The supplicant is now available");
81 case 43:
82 return i18n.tr("The modem could not be found");
83 case 44:
84 return i18n.tr("The Bluetooth connection failed or timed out");
85 case 50:
86 return i18n.tr("A dependency of the connection failed");
87 case 52:
88 return i18n.tr("ModemManager is unavailable");
89 case 53:
90 return i18n.tr("The Wi-Fi network could not be found");
91 case 54:
92 return i18n.tr("A secondary connection of the base connection failed");
93 default:
94 return i18n.tr("Unknown");
95 }
96 }
97}
098
=== modified file 'plugins/cellular/Components/MultiSim.qml'
--- plugins/cellular/Components/MultiSim.qml 2015-01-21 20:44:20 +0000
+++ plugins/cellular/Components/MultiSim.qml 2015-05-18 15:06:15 +0000
@@ -22,6 +22,7 @@
22import SystemSettings 1.022import SystemSettings 1.0
23import Ubuntu.Components 0.123import Ubuntu.Components 0.1
24import Ubuntu.Components.ListItems 0.1 as ListItem24import Ubuntu.Components.ListItems 0.1 as ListItem
25import Ubuntu.SystemSettings.Update 1.0
2526
26Column {27Column {
27 objectName: "multiSim"28 objectName: "multiSim"
@@ -58,9 +59,13 @@
58 text: i18n.tr("Wi-Fi hotspot")59 text: i18n.tr("Wi-Fi hotspot")
59 progression: true60 progression: true
60 onClicked: {61 onClicked: {
61 pageStack.push(Qt.resolvedUrl("Hotspot.qml"))62 pageStack.push(Qt.resolvedUrl("../Hotspot.qml"))
62 }63 }
63 visible: showAllUI && (actionGroup.actionObject.valid ? actionGroup.actionObject.state : false)64 visible: (showAllUI &&
65 (actionGroup.actionObject.valid ?
66 actionGroup.actionObject.state : false) &&
67 UpdateManager.deviceName !== "mako")
68
64 }69 }
6570
66 ListItem.Standard {71 ListItem.Standard {
6772
=== modified file 'plugins/cellular/Components/SingleSim.qml'
--- plugins/cellular/Components/SingleSim.qml 2015-01-20 12:23:34 +0000
+++ plugins/cellular/Components/SingleSim.qml 2015-05-18 15:06:15 +0000
@@ -67,12 +67,16 @@
6767
68 ListItem.SingleValue {68 ListItem.SingleValue {
69 id: hotspotItem69 id: hotspotItem
70 objectName: "hotspotEntry"
70 text: i18n.tr("Wi-Fi hotspot")71 text: i18n.tr("Wi-Fi hotspot")
71 progression: true72 progression: true
72 onClicked: {73 onClicked: {
73 pageStack.push(Qt.resolvedUrl("Hotspot.qml"))74 pageStack.push(Qt.resolvedUrl("../Hotspot.qml"))
74 }75 }
75 visible: showAllUI && (actionGroup.actionObject.valid ? actionGroup.actionObject.state : false)76 visible: (showAllUI &&
77 (actionGroup.actionObject.valid ?
78 actionGroup.actionObject.state : false) &&
79 UpdateManager.deviceName !== "mako")
76 }80 }
7781
78 ListItem.Standard {82 ListItem.Standard {
7983
=== modified file 'plugins/cellular/Hotspot.qml'
--- plugins/cellular/Hotspot.qml 2014-07-29 15:39:08 +0000
+++ plugins/cellular/Hotspot.qml 2015-05-18 15:06:15 +0000
@@ -21,56 +21,73 @@
21import Ubuntu.Components 0.121import Ubuntu.Components 0.1
22import Ubuntu.Components.ListItems 0.1 as ListItem22import Ubuntu.Components.ListItems 0.1 as ListItem
23import Ubuntu.SystemSettings.Cellular 1.023import Ubuntu.SystemSettings.Cellular 1.0
24import Ubuntu.Components.Popups 0.1
2425
25ItemPage {26ItemPage {
2627
27 id: hotspot28 id: hotspot
29 objectName: "hotspotPage"
2830
29 title: i18n.tr("Wi-Fi hotspot")31 title: i18n.tr("Wi-Fi hotspot")
3032
31 HotspotManager {33 HotspotManager {
32 id: hotspotManager34 id: hotspotManager
35 // TODO(jgdx): Figure out why serverCheckedChanged is not fired
36 // automatically whenever hotspotManager.enabled changes.
37 onEnabledChanged: {
38 hotspotSwitch.serverChecked = enabled;
39 hotspotSwitch.serverCheckedChanged();
40 }
41 }
42
43 Loader {
44 id: setup
45 asynchronous: false
33 }46 }
3447
35 Column {48 Column {
3649
37 anchors.fill: parent50 anchors.fill: parent
51 spacing: units.gu(2)
3852
39 ListItem.Standard {53 ListItem.Standard {
40 text: i18n.tr("Hotspot")54 text: i18n.tr("Hotspot")
55 enabled: hotspotManager.stored
41 control: Switch {56 control: Switch {
42 id: hotspotSwitch57 id: hotspotSwitch
43 checked: hotspotManager.isHotspotActive()58 objectName: "hotspotSwitch"
44 onTriggered: {59 property bool serverChecked: hotspotManager.enabled
45 if(checked) {60 onServerCheckedChanged: checked = serverChecked
46 hotspotManager.enableHotspot()61 Component.onCompleted: checked = serverChecked
47 } else {62 onTriggered: hotspotManager.enabled = checked
48 hotspotManager.disableHotspot()
49 }
50 }
51 }63 }
52 }64 }
5365
54 Label {66 ListItem.Caption {
55 width: parent.width67 anchors {
56 wrapMode: Text.WordWrap68 left: parent.left
57 anchors.leftMargin: units.gu(2)69 right: parent.right
58 anchors.rightMargin: units.gu(2)70 leftMargin: units.gu(2)
59 text : hotspotSwitch.enabled ?71 rightMargin: units.gu(2)
72 }
73 text : hotspotSwitch.stored ?
60 i18n.tr("When hotspot is on, other devices can use your cellular data connection over Wi-Fi. Normal data charges apply.")74 i18n.tr("When hotspot is on, other devices can use your cellular data connection over Wi-Fi. Normal data charges apply.")
61 : i18n.tr("Other devices can use your cellular data connection over the Wi-Fi network. Normal data charges apply.") 75 : i18n.tr("Other devices can use your cellular data connection over the Wi-Fi network. Normal data charges apply.")
62 }76 }
6377
64 Button {78 Button {
65 text: i18n.tr("Set up hotspot")79 objectName: "hotspotSetupEntry"
66 anchors.left: parent.left80 anchors.horizontalCenter: parent.horizontalCenter
67 anchors.right: parent.right81 width: parent.width - units.gu(4)
68 anchors.leftMargin: units.gu(2)82 text: hotspotManager.stored ?
69 anchors.rightMargin: units.gu(2)83 i18n.tr("Change password/setup…") : i18n.tr("Set up hotspot…")
84
70 onClicked: {85 onClicked: {
71 pageStack.push(Qt.resolvedUrl("HotspotSetup.qml"), {hotspotManager: hotspotManager})86 setup.setSource(Qt.resolvedUrl("HotspotSetup.qml"));
87 PopupUtils.open(setup.item, hotspot, {
88 hotspotManager: hotspotManager
89 });
72 }90 }
73 }91 }
74
75 }92 }
76}93}
7794
=== modified file 'plugins/cellular/HotspotSetup.qml'
--- plugins/cellular/HotspotSetup.qml 2014-07-04 11:32:33 +0000
+++ plugins/cellular/HotspotSetup.qml 2015-05-18 15:06:15 +0000
@@ -22,82 +22,313 @@
22import Ubuntu.Components 0.122import Ubuntu.Components 0.1
23import Ubuntu.Components.ListItems 0.1 as ListItem23import Ubuntu.Components.ListItems 0.1 as ListItem
24import Ubuntu.SystemSettings.Cellular 1.024import Ubuntu.SystemSettings.Cellular 1.0
2525import Ubuntu.Components.Popups 0.1
26ItemPage {26
2727Component {
28 id: hotspotSetup28 id: hotspotSetup
29 title: i18n.tr("Change hotspot setup")29
3030 Dialog {
31 property var hotspotManager: null31 id: hotspotSetupDialog
3232 property var hotspotManager: null
3333
34 Column {34 /* hotspotManager.stored changes as soon as the user has added a
3535 hotspot, and we use this value when we choose between e.g. "Change" and
36 anchors.fill: parent36 "Setup". We'd like the narrative to be consistent, so we stick with
3737 what the stored value was at component completion.
38 ListItem.Standard {38 */
39 id: ssidLabel39 property bool stored: false
40 text: i18n.tr("Hotspot name")40 Component.onCompleted: stored = hotspotManager.stored;
41 }41
4242 objectName: "hotspotSetup"
43 TextField {43 anchorToKeyboard: true
44 id: ssidField44
45 text: hotspotManager.getHotspotName()45 function settingsValid() {
46 anchors.left: parent.left46 return ssidField.text != "" && passwordField.length >= 8;
47 anchors.right: parent.right47 }
48 anchors.leftMargin: units.gu(2)48
49 anchors.rightMargin: units.gu(2)49 title: stored ?
50 }50 i18n.tr("Change hotspot setup") : i18n.tr("Setup hotspot")
5151 text: feedback.enabled ? feedback.text : "";
52 ListItem.Standard {52
53 id: passwordLabel53 Common {
54 text: i18n.tr("Key (must be 8 characters or longer)")54 id: common
55 }55 }
5656
57 TextField {57 states: [
58 id: passwordField58 State {
59 text: hotspotManager.getHotspotPassword()59 name: "STARTING"
60 echoMode: passwordVisibleSwitch.checked ? TextInput.Normal : TextInput.Password60 PropertyChanges {
61 anchors.left: parent.left61 target: workingIndicator
62 anchors.right: parent.right62 running: true
63 anchors.leftMargin: units.gu(2)63 }
64 anchors.rightMargin: units.gu(2)64 PropertyChanges {
65 }65 target: ssidLabel
6666 opacity: 0.5
67 ListItem.Standard {67 }
68 text: i18n.tr("Show key")68 PropertyChanges {
69 id: passwordVisible69 target: ssidField
70 control: Switch {70 enabled: false
71 id: passwordVisibleSwitch71 }
72 PropertyChanges {
73 target: passwordLabel
74 opacity: 0.5
75 }
76 PropertyChanges {
77 target: passwordField
78 enabled: false
79 }
80 PropertyChanges {
81 target: feedback
82 enabled: true
83 }
84 PropertyChanges {
85 target: confirmButton
86 enabled: false
87 }
88 },
89
90 State {
91 name: "FAILED"
92 PropertyChanges {
93 target: feedback
94 enabled: true
95 }
96 PropertyChanges {
97 target: ssidField
98 errorHighlight: true
99 }
100 StateChangeScript {
101 script: ssidField.forceActiveFocus()
102 }
103 },
104
105 State {
106 name: "SUCCEEDED"
107 PropertyChanges {
108 target: successIcon
109 visible: true
110 }
111 PropertyChanges {
112 target: successIndicator
113 running: true
114 }
115 PropertyChanges {
116 target: ssidLabel
117 opacity: 0.5
118 }
119 PropertyChanges {
120 target: ssidField
121 enabled: false
122 }
123 PropertyChanges {
124 target: passwordLabel
125 opacity: 0.5
126 }
127 PropertyChanges {
128 target: passwordField
129 enabled: false
130 }
131 PropertyChanges {
132 target: confirmButton
133 enabled: false
134 }
72 }135 }
73 }136 ]
74137
75 RowLayout {138 Column {
76 anchors {139 anchors {
77 left: parent.left140 left: parent.left
78 right: parent.right141 right: parent.right
79 margins: units.gu(2)142 }
80 }143 spacing: units.gu(1)
81 144
82 Button {145 Label {
83 id: cancelButton146 property bool enabled: false
84 Layout.fillWidth: true147 id: feedback
85 text: i18n.tr("Cancel")148 horizontalAlignment: Text.AlignHCenter
86 onClicked: {149 height: contentHeight
87 pageStack.pop()150 wrapMode: Text.WordWrap
88 }151 visible: false
89 }152 }
90153
91 Button {154 Label {
92 id: connectButton155 id: ssidLabel
93 Layout.fillWidth: true156 text: i18n.tr("Hotspot name")
94 text: i18n.tr("Change")157 fontSize: "medium"
95 enabled: ssidField.text != "" && passwordField.length >= 8158 font.bold: true
96 onClicked: {159 color: Theme.palette.selected.backgroundText
97 hotspotManager.setupHotspot(ssidField.text, passwordField.text)160 elide: Text.ElideRight
98 pageStack.pop()161 }
99 }162
100 }163 TextField {
164 id: ssidField
165 objectName: "ssidField"
166 text: hotspotManager.ssid
167 inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
168 Component.onCompleted: forceActiveFocus()
169 width: parent.width
170 }
171
172 Label {
173 id: passwordLabel
174 text: i18n.tr("Key (must be 8 characters or longer)")
175 fontSize: "medium"
176 font.bold: true
177 color: Theme.palette.selected.backgroundText
178 wrapMode: Text.WordWrap
179 width: parent.width
180 }
181
182 TextField {
183 id: passwordField
184 objectName: "passwordField"
185 text: hotspotManager.password
186 echoMode: passwordVisibleSwitch.checked ?
187 TextInput.Normal : TextInput.Password
188 inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
189 width: parent.width
190 }
191
192 ListItem.Standard {
193 text: i18n.tr("Show key")
194 id: passwordVisible
195 onClicked: passwordVisibleSwitch.trigger()
196 control: Switch {
197 id: passwordVisibleSwitch
198 activeFocusOnPress: false
199 }
200 }
201
202 Row {
203
204 anchors {
205 left: parent.left
206 right: parent.right
207 }
208 width: parent.width
209 spacing: units.gu(2)
210
211 Button {
212 id: cancelButton
213 width: (parent.width / 2) - units.gu(1)
214 text: i18n.tr("Cancel")
215 activeFocusOnPress: false
216 onClicked: PopupUtils.close(hotspotSetupDialog)
217 }
218
219 Button {
220 id: confirmButton
221 objectName: "confirmButton"
222 width: (parent.width / 2) - units.gu(1)
223 text: hotspotSetupDialog.stored ? i18n.tr("Change") :
224 i18n.tr("Enable")
225 enabled: settingsValid()
226 activeFocusOnPress: false
227 onClicked: {
228 if (hotspotSetupDialog.stored) {
229 changeAction.trigger()
230 } else {
231 enableAction.trigger();
232 }
233 }
234
235 Icon {
236 id: successIcon
237 anchors.centerIn: parent
238 height: parent.height - units.gu(1.5)
239 width: parent.height - units.gu(1.5)
240 name: "tick"
241 color: "green"
242 visible: false
243 }
244
245 ActivityIndicator {
246 id: workingIndicator
247 anchors.centerIn: parent
248 running: false
249 visible: running
250 height: parent.height - units.gu(1.5)
251 }
252 }
253 }
254 }
255
256 Action {
257 id: enableAction
258 enabled: settingsValid()
259 onTriggered: {
260 hotspotSetupDialog.state = "STARTING";
261
262 function hotspotEnabledHandler (enabled) {
263 if (enabled) {
264 hotspotSetupDialog.state = "SUCCEEDED";
265 hotspotManager.enabledChanged.disconnect(
266 hotspotEnabledHandler);
267 }
268 }
269
270 hotspotManager.ssid = ssidField.text;
271 hotspotManager.password = passwordField.text;
272 hotspotManager.enabledChanged.connect(hotspotEnabledHandler);
273 hotspotManager.enabled = true;
274 }
275 }
276
277 Action {
278 id: changeAction
279 enabled: settingsValid()
280 onTriggered: {
281
282 function hotspotEnabledHandler (enabled) {
283 if (enabled) {
284 hotspotSetupDialog.state = "SUCCEEDED";
285 hotspotManager.enabledChanged.disconnect(
286 hotspotEnabledHandler);
287 }
288 }
289
290 function hotspotDisabledHandler (enabled) {
291 if (!enabled) {
292 hotspotManager.enabledChanged.connect(hotspotEnabledHandler);
293 hotspotManager.enabled = true;
294 hotspotManager.enabledChanged.disconnect(
295 hotspotDisabledHandler);
296 }
297 }
298
299 hotspotManager.ssid = ssidField.text;
300 hotspotManager.password = passwordField.text;
301
302 if (hotspotManager.enabled) {
303 hotspotSetupDialog.state = "STARTING";
304 hotspotManager.enabledChanged.connect(
305 hotspotDisabledHandler);
306 hotspotManager.enabled = false;
307 } else {
308 PopupUtils.close(hotspotSetupDialog);
309 }
310 }
311 }
312
313 /* Timer that shows a tick in the connect button once we have
314 successfully changed/started a hotspot. */
315 Timer {
316 id: successIndicator
317 interval: 2000
318 running: false
319 repeat: false
320 onTriggered: PopupUtils.close(hotspotSetupDialog)
321 }
322
323 Connections {
324 target: hotspotManager
325
326 onReportError: {
327 if (hotspotSetupDialog.state === "STARTING") {
328 hotspotSetupDialog.state = "FAILED";
329 feedback.text = common.reasonToString(reason);
330 }
331 }
101 }332 }
102 }333 }
103}334}
104335
=== modified file 'plugins/cellular/hotspotmanager.cpp'
--- plugins/cellular/hotspotmanager.cpp 2014-07-23 13:44:31 +0000
+++ plugins/cellular/hotspotmanager.cpp 2015-05-18 15:06:15 +0000
@@ -1,8 +1,9 @@
1/*1/*
2 * Copyright (C) 2014 Canonical, Ltd.2 * Copyright (C) 2014, 2015 Canonical, Ltd.
3 *3 *
4 * Authors:4 * Authors:
5 * Jussi Pakkanen <jussi.pakkanen@canonical.com>5 * Jussi Pakkanen <jussi.pakkanen@canonical.com>
6 * Jonas G. Drange <jonas.drange@canonical.com>
6 *7 *
7 * This program is free software: you can redistribute it and/or modify it8 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 3, as published9 * under the terms of the GNU General Public License version 3, as published
@@ -15,13 +16,9 @@
15 *16 *
16 * You should have received a copy of the GNU General Public License17 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */19*/
1920
20#include "hotspotmanager.h"21#include "hotspotmanager.h"
21
22#include "nm_manager_proxy.h"
23#include "nm_settings_proxy.h"
24#include "nm_settings_connection_proxy.h"
25#include <QStringList>22#include <QStringList>
26#include <QDBusReply>23#include <QDBusReply>
27#include <QtDebug>24#include <QtDebug>
@@ -31,31 +28,156 @@
31typedef QMap<QString, QVariantMap> nmConnectionArg;28typedef QMap<QString, QVariantMap> nmConnectionArg;
32Q_DECLARE_METATYPE(nmConnectionArg)29Q_DECLARE_METATYPE(nmConnectionArg)
3330
34namespace {31namespace { // wpa_supplicant interaction
32
33const QString wpa_supplicant_service("fi.w1.wpa_supplicant1");
34const QString wpa_supplicant_interface("fi.w1.wpa_supplicant1");
35const QString wpa_supplicant_path("/fi/w1/wpa_supplicant1");
36
37bool isHybrisWlan() {
38 QString program("getprop");
39 QStringList arguments;
40 arguments << "urfkill.hybris.wlan";
41
42 QProcess *getprop = new QProcess();
43 getprop->start(program, arguments);
44
45 if (!getprop->waitForFinished()) {
46 qCritical() << "getprop process failed:" << getprop->errorString();
47 delete getprop;
48 return false;
49 }
50
51 int index = getprop->readAllStandardOutput().indexOf("1");
52 delete getprop;
53
54 // A non-negative integer means getprop returned 1
55 return index >= 0;
56}
57
58// True if changed successfully, or there was no need. Otherwise false.
59// Supported modes are 'p2p', 'sta' and 'ap'.
60bool changeInterfaceFirmware(const QString interface, const QString mode) {
61 // Not supported.
62 if (mode == "adhoc") {
63 return true;
64 }
65
66 if (isHybrisWlan()) {
67 QDBusInterface wpasIface (
68 wpa_supplicant_service, wpa_supplicant_path, wpa_supplicant_interface,
69 QDBusConnection::systemBus());
70
71 const QDBusObjectPath interface_path(interface);
72
73 // TODO(jgdx): We need to guard against calling this
74 // when the interface is not soft blocked.
75 auto set_interface = wpasIface.call("SetInterfaceFirmware",
76 QVariant::fromValue(interface_path), QVariant(mode));
77
78 if (set_interface.type() == QDBusMessage::ErrorMessage) {
79 qCritical() << "Failed to change interface firmware:"
80 << set_interface.errorMessage();
81 return false;
82 } else {
83 return true;
84 }
85 }
86
87 // We had no need to change the firmware.
88 return true;
89}
90} // wpa_supplicant interaction
91
92namespace { // UrfKill interaction
93
94const QString urfkill_service("org.freedesktop.URfkill");
95const QString urfkill_interface("org.freedesktop.URfkill");
96const QString urfkill_path("/org/freedesktop/URfkill");
97
98// True if call went through and returned true.
99bool setWifiBlock(bool block) {
100 QDBusInterface urfkill_dbus_interface(urfkill_service, urfkill_path,
101 urfkill_interface, QDBusConnection::systemBus());
102
103 const unsigned int device_type = 1; /* wifi type */
104 auto reply = urfkill_dbus_interface.call("Block", device_type, block);
105
106 if (reply.type() == QDBusMessage::ErrorMessage) {
107 qCritical() << "Failed to block wifi" << reply.errorMessage();
108 return false;
109 }
110
111 // We got exactly one argument back, and it's not an error.
112 if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 1) {
113 // returned false from call
114 if (!qdbus_cast<bool>(reply.arguments().at(0))) {
115 qCritical() << "URfkill Block call did not succeed";
116 return false;
117 } else {
118 return true;
119 }
120 }
121 // We did not get what we wanted from dbus, so we treat that as failure.
122 return false;
123}
124} // UrfKill interaction
125
126namespace { // NetworkManager interaction
35127
36const QString nm_service("org.freedesktop.NetworkManager");128const QString nm_service("org.freedesktop.NetworkManager");
129const QString nm_object("/org/freedesktop/NetworkManager");
37const QString nm_settings_object("/org/freedesktop/NetworkManager/Settings");130const QString nm_settings_object("/org/freedesktop/NetworkManager/Settings");
38const QString nm_settings_interface("org.freedesktop.NetworkManager.Settings");131const QString nm_settings_interface("org.freedesktop.NetworkManager.Settings");
39const QString nm_connection_interface("org.freedesktop.NetworkManager.Settings.Connection");132const QString nm_connection_interface("org.freedesktop.NetworkManager.Settings.Connection");
40const QString nm_dbus_path("/org/freedesktop/NetworkManager");133const QString nm_connection_active_interface("org.freedesktop.NetworkManager.Connection.Active");
41const QString nm_device_interface("org.freedesktop.NetworkManager.Device");134const QString nm_device_interface("org.freedesktop.NetworkManager.Device");
42135const QString dbus_properties_interface("org.freedesktop.DBus.Properties");
43#define NM_METHOD_NAME "AddAndActivateConnection"136const QString connection_property("Connection");
44137
45void startAdhoc(const QByteArray &ssid, const QString &password, const QDBusObjectPath &devicePath) {138// NetworkManager dbus interface proxy we will use to query
139// against NetworkManager. See
140// https://developer.gnome.org/NetworkManager/0.9/spec.html
141// #org.freedesktop.NetworkManager
142OrgFreedesktopNetworkManagerInterface nm_manager(
143 nm_service, nm_object, QDBusConnection::systemBus());
144
145// NetworkManager Settings interface proxy we use to get
146// the list of connections, as well as adding connections.
147// See https://developer.gnome.org/NetworkManager/0.9/spec.html
148// #org.freedesktop.NetworkManager.Settings
149OrgFreedesktopNetworkManagerSettingsInterface nm_settings(
150 nm_service, nm_settings_object, QDBusConnection::systemBus());
151
152// Helper that maps QStrings to other QVariantMaps, i.e.
153// QMap<QString, QVariantMap>. QVariantMap is an alias for
154// QMap<QString, QVariant>.
155// See http://doc.qt.io/qt-5/qvariant.html#QVariantMap-typedef and
156// https://developer.gnome.org/NetworkManager/0.9/spec.html
157// #type-String_String_Variant_Map_Map
158nmConnectionArg createConnectionSettings(
159 const QByteArray &ssid, const QString &password,
160 const QDBusObjectPath &devicePath, QString mode, bool autoConnect = true) {
161 Q_UNUSED(devicePath);
46 nmConnectionArg connection;162 nmConnectionArg connection;
47163
48 QDBusObjectPath specific("/");164 QString s_ssid = QString::fromLatin1(ssid);
165 QString s_uuid = QUuid().createUuid().toString();
166 // Remove {} from the generated uuid.
167 s_uuid.remove(0, 1);
168 s_uuid.remove(s_uuid.size() - 1, 1);
49169
50 QVariantMap wireless;170 QVariantMap wireless;
51 wireless[QStringLiteral("security")] = QVariant(QStringLiteral("802-11-wireless-security"));171 wireless[QStringLiteral("security")] = QVariant(QStringLiteral("802-11-wireless-security"));
52 wireless[QStringLiteral("ssid")] = QVariant(ssid);172 wireless[QStringLiteral("ssid")] = QVariant(ssid);
53 wireless[QStringLiteral("mode")] = QVariant(QStringLiteral("adhoc"));173 wireless[QStringLiteral("mode")] = QVariant(mode);
174
54 connection["802-11-wireless"] = wireless;175 connection["802-11-wireless"] = wireless;
55176
56 QVariantMap connsettings;177 QVariantMap connsettings;
57 connsettings[QStringLiteral("autoconnect")] = QVariant(false);178 connsettings[QStringLiteral("autoconnect")] = QVariant(autoConnect);
58 connsettings[QStringLiteral("uuid")] = QVariant(QStringLiteral("aab22b5d-7342-48dc-8920-1b7da31d6829"));179 connsettings[QStringLiteral("id")] = QVariant(s_ssid);
180 connsettings[QStringLiteral("uuid")] = QVariant(s_uuid);
59 connsettings[QStringLiteral("type")] = QVariant(QStringLiteral("802-11-wireless"));181 connsettings[QStringLiteral("type")] = QVariant(QStringLiteral("802-11-wireless"));
60 connection["connection"] = connsettings;182 connection["connection"] = connsettings;
61183
@@ -66,6 +188,10 @@
66 ipv4[QStringLiteral("routes")] = QVariant(QStringList());188 ipv4[QStringLiteral("routes")] = QVariant(QStringList());
67 connection["ipv4"] = ipv4;189 connection["ipv4"] = ipv4;
68190
191 QVariantMap ipv6;
192 ipv6[QStringLiteral("method")] = QVariant(QStringLiteral("ignore"));
193 connection["ipv6"] = ipv6;
194
69 QVariantMap security;195 QVariantMap security;
70 security[QStringLiteral("proto")] = QVariant(QStringList{"rsn"});196 security[QStringLiteral("proto")] = QVariant(QStringList{"rsn"});
71 security[QStringLiteral("pairwise")] = QVariant(QStringList{"ccmp"});197 security[QStringLiteral("pairwise")] = QVariant(QStringList{"ccmp"});
@@ -74,176 +200,510 @@
74 security[QStringLiteral("psk")] = QVariant(password);200 security[QStringLiteral("psk")] = QVariant(password);
75 connection["802-11-wireless-security"] = security;201 connection["802-11-wireless-security"] = security;
76202
77 OrgFreedesktopNetworkManagerInterface mgr(nm_service,203 return connection;
78 nm_dbus_path,204}
79 QDBusConnection::systemBus());205
80 auto reply = mgr.AddAndActivateConnection(connection, devicePath, specific);206// Helper that returns a QMap<QString, QVariantMap> given a QDBusObjectPath.
81 reply.waitForFinished();207// See https://developer.gnome.org/NetworkManager/0.9/spec.html
82 if(!reply.isValid()) {208// #org.freedesktop.NetworkManager.Settings.Connection.GetSettings
83 qWarning() << "Failed to start adhoc network: " << reply.error().message() << "\n";209nmConnectionArg getConnectionSettings (QDBusObjectPath connection) {
84 }210 OrgFreedesktopNetworkManagerSettingsConnectionInterface conn(
85}211 nm_service, connection.path(), QDBusConnection::systemBus());
86212
87bool detectAdhoc(QString &dbusPath, QByteArray &ssid, QString &password, bool &isActive) {213 auto connection_settings = conn.GetSettings();
88 static const QString activeIface("org.freedesktop.NetworkManager.Connection.Active");214 connection_settings.waitForFinished();
89 static const QString connProp("Connection");215 return connection_settings.value();
90 OrgFreedesktopNetworkManagerInterface mgr(nm_service,216}
91 nm_dbus_path,217
92 QDBusConnection::systemBus());218
93 auto activeConnections = mgr.activeConnections();219// Helper that returns a QMap<QString, QVariantMap> given a QDBusObjectPath.
94 OrgFreedesktopNetworkManagerSettingsInterface settings(nm_service, nm_settings_object,220// See https://developer.gnome.org/NetworkManager/0.9/spec.html
95 QDBusConnection::systemBus());221// #org.freedesktop.NetworkManager.Settings.Connection.GetSettings
96 QSet<QDBusObjectPath> actives;222nmConnectionArg getConnectionSecrets (QDBusObjectPath connection,
97 auto r = settings.ListConnections();223 const QString key) {
98 r.waitForFinished();224 OrgFreedesktopNetworkManagerSettingsConnectionInterface conn(
99 for(const auto &conn : activeConnections) {225 nm_service, connection.path(), QDBusConnection::systemBus());
100 QDBusInterface iface(nm_service, conn.path(), "org.freedesktop.DBus.Properties",226 auto connection_secrets = conn.GetSecrets(key);
101 QDBusConnection::systemBus());227 connection_secrets.waitForFinished();
102 QDBusReply<QVariant> conname = iface.call("Get", activeIface, connProp);228 return connection_secrets.value();
103 if(!conname.isValid()) {229}
104 qWarning() << "Error getting connamd: " << conname.error().message() << "\n";230
231// Helper that adds a connection and returns the QDBusObjectPath
232// of the newly created connection.
233// See https://developer.gnome.org/NetworkManager/0.9/spec.html
234// #org.freedesktop.NetworkManager.Settings.AddConnection
235QDBusObjectPath addConnection(
236 const QByteArray &ssid, const QString &password,
237 const QDBusObjectPath &devicePath, QString mode) {
238 QDBusObjectPath invalid("");
239
240 nmConnectionArg connection = createConnectionSettings(ssid, password,
241 devicePath, mode);
242
243 auto add_connection_reply = nm_settings.AddConnection(connection);
244 add_connection_reply.waitForFinished();
245
246 if(!add_connection_reply.isValid()) {
247 qCritical() << "Failed to add connection: "
248 << add_connection_reply.error().message();
249 return invalid;
250 }
251 return add_connection_reply.argumentAt<0>();
252}
253
254// Returns a QDBusObjectPath of a hotspot given a mode.
255// Valid modes are 'p2p', 'ap' and 'adhoc'.
256QDBusObjectPath getHotspot(QString mode) {
257 const char wifi_key[] = "802-11-wireless";
258
259 auto listed_connections = nm_settings.ListConnections();
260 listed_connections.waitForFinished();
261
262 for(const auto &connection : listed_connections.value()) {
263 OrgFreedesktopNetworkManagerSettingsConnectionInterface conn(
264 nm_service, connection.path(), QDBusConnection::systemBus());
265
266 auto connection_settings = getConnectionSettings(connection);
267
268 if(connection_settings.find(wifi_key) != connection_settings.end()) {
269 auto wifi_setup = connection_settings[wifi_key];
270 QString wifi_mode = wifi_setup["mode"].toString();
271
272 if(wifi_mode == mode) {
273 return connection;
274 }
275 }
276 }
277 return QDBusObjectPath();
278}
279
280// Returns a QDBusObjectPath of a wireless device. For now
281// it returns the first device.
282QDBusObjectPath getWirelessDevice () {
283 // find the first wlan adapter for now
284 auto reply1 = nm_manager.GetDevices();
285 reply1.waitForFinished();
286
287 if(!reply1.isValid()) {
288 qCritical() << "Could not get network device: "
289 << reply1.error().message();
290 return QDBusObjectPath();
291 }
292 auto devices = reply1.value();
293
294 QDBusObjectPath dev;
295 for (const auto &d : devices) {
296 QDBusInterface iface(nm_service, d.path(), nm_device_interface,
297 QDBusConnection::systemBus());
298 auto type_v = iface.property("DeviceType");
299
300 if (type_v.toUInt() == 2 /* NM_DEVICE_TYPE_WIFI */) {
301 return d;
302 }
303 }
304 qCritical() << "Wireless device not found, hotspot functionality is inoperative.";
305 return dev;
306}
307
308// Helper to check if the hotspot on a given QDBusObjectPath is active
309// or not. It checks if the Connection.Active [1] for the given
310// path is in NetworkManager's ActiveConnections property [2].
311// [1] https://developer.gnome.org/NetworkManager/0.9/spec.html
312// #org.freedesktop.NetworkManager.Connection.Active
313// [2] https://developer.gnome.org/NetworkManager/0.9/spec.html
314// #org.freedesktop.NetworkManager
315bool isHotspotActive (QDBusObjectPath path) {
316 QSet<QDBusObjectPath> active_relevant_connections;
317 auto active_connections = nm_manager.activeConnections();
318 for(const auto &active_connection : active_connections) {
319
320 // Active connection interface proxy. It might have a connection
321 // property we can use to deduce if this active connection represents
322 // our active hotspot.
323 QDBusInterface active_connection_dbus_interface(
324 nm_service, active_connection.path(), dbus_properties_interface,
325 QDBusConnection::systemBus());
326
327 // Get the Connection property, if any.
328 QDBusReply<QVariant> connection_property =
329 active_connection_dbus_interface.call("Get",
330 nm_connection_active_interface, "Connection");
331
332 // The Connection property did not exist, so ignore this
333 // active connection.
334 if(!connection_property.isValid()) {
105 continue;335 continue;
106 }336 }
107 QDBusObjectPath mainConnection = qvariant_cast<QDBusObjectPath>(conname.value());337
108 actives.insert(mainConnection);338 // It does exist, cast it to a object path.
109 }339 QDBusObjectPath connection_path = qvariant_cast<QDBusObjectPath>(
110 const char wifiKey[] = "802-11-wireless";340 connection_property.value());
111 for(const auto &i : r.value()) {341
112 OrgFreedesktopNetworkManagerSettingsConnectionInterface conn(nm_service,342 // The object path is the same as the given hotspot path.
113 i.path(),343 if (path == connection_path) {
114 QDBusConnection::systemBus());344 return true;
115 auto reply = conn.GetSettings();
116 reply.waitForFinished();
117 auto s = reply.value();
118 if(s.find(wifiKey) != s.end()) {
119 auto wsetup = s[wifiKey];
120 if(wsetup["mode"] == "adhoc") {
121 dbusPath = i.path();
122 ssid = wsetup["ssid"].toByteArray();
123 auto pwdReply = conn.GetSecrets("802-11-wireless-security");
124 pwdReply.waitForFinished();
125 password = pwdReply.value()["802-11-wireless-security"]["psk"].toString();
126 isActive = false;
127 for(const auto &ac : actives) {
128 if(i == ac) {
129 isActive = true;
130 break;
131 }
132 }
133 return true;
134 }
135 }345 }
136 }346 }
347
348 // No active connection had a Connection property equal to the
349 // given path, so return false.
137 return false;350 return false;
138}351}
139352
140QDBusObjectPath detectWirelessDevice() {
141 OrgFreedesktopNetworkManagerInterface mgr(nm_service,
142 nm_dbus_path,
143 QDBusConnection::systemBus());
144 auto devices = mgr.GetDevices();
145 devices.waitForFinished();
146 for(const auto &dpath : devices.value()) {
147 QDBusInterface iface(nm_service, dpath.path(), "org.freedesktop.DBus.Properties",
148 QDBusConnection::systemBus());
149 QDBusReply<QVariant> typeReply = iface.call("Get", "org.freedesktop.NetworkManager.Device", "DeviceType");
150 auto typeInt = qvariant_cast<int>(typeReply.value());
151 if(typeInt == 2) {
152 return dpath; // Assumptions are that there is only one wifi device and it is not hotpluggable.
153 }
154 }
155 qWarning() << "Wireless device not found, hotspot functionality is inoperative.\n";
156 return QDBusObjectPath();
157}
158
159std::string generate_password() {353std::string generate_password() {
160 static const std::string items("abcdefghijklmnopqrstuvwxyz01234567890");354 static const std::string items("abcdefghijklmnopqrstuvwxyz01234567890");
161 const int passwordLength = 8;355 const int password_length = 8;
162 std::string result;356 std::string result;
163 for(int i=0; i<passwordLength; i++) {357
358 for(int i=0; i<password_length; i++) {
164 result.push_back(items[std::rand() % items.length()]);359 result.push_back(items[std::rand() % items.length()]);
165 }360 }
166 return result;361 return result;
167}362}
168363} // NetworkManager interaction
169}364
170365HotspotManager::HotspotManager(QObject *parent) :
171HotspotManager::HotspotManager(QObject *parent) : QObject(parent),366 QObject(parent), m_mode("ap"), m_enabled(false), m_stored(false),
172 m_devicePath(detectWirelessDevice()) {367 m_password(generate_password().c_str()), m_ssid(QByteArray("Ubuntu")),
368 m_device_path(getWirelessDevice()) {
173 static bool isRegistered = false;369 static bool isRegistered = false;
370
174 if(!isRegistered) {371 if(!isRegistered) {
175 qDBusRegisterMetaType<nmConnectionArg>();372 qDBusRegisterMetaType<nmConnectionArg>();
176 isRegistered = true;373 isRegistered = true;
177 }374 }
178 if(!detectAdhoc(m_settingsPath, m_ssid, m_password, m_isActive)) {375
179 m_settingsPath = "";376 // Stored is false if hotspot path is empty.
180 m_ssid = "Ubuntu hotspot";377 m_hotspot_path = getHotspot(m_mode);
181 m_password = generate_password().c_str();378 setStored(!m_hotspot_path.path().isEmpty());
182 m_isActive = false;379
183 }380 if (m_stored) {
184}381 updateSettingsFromDbus(m_hotspot_path);
185382 }
186QByteArray HotspotManager::getHotspotName() {383
384 // Watches for new connections added to NetworkManager's Settings
385 // interface.
386 nm_settings.connection().connect(
387 nm_settings.service(), nm_settings_object, nm_settings_interface,
388 "NewConnection", this, SLOT(onNewConnection(QDBusObjectPath)));
389
390 // Watches changes in NetworkManager.
391 nm_manager.connection().connect(
392 nm_manager.service(), nm_object, nm_service, "PropertiesChanged", this,
393 SLOT(onPropertiesChanged(QMap<QString, QVariant>)));
394}
395
396void HotspotManager::setEnabled(bool value) {
397 bool blocked = setWifiBlock(true);
398
399 // Failed to soft block, here we revert the enabled setting.
400 if (!blocked) {
401 // "The device could not be readied for configuration"
402 Q_EMIT reportError(5);
403 setEnable(false);
404 return;
405 }
406
407 // We are enabling a hotspot
408 if (value) {
409 // If the SSID is empty, we report an error. The UI should strive
410 // to prevent us from reaching this part of the code.
411 if (m_ssid.isEmpty()) {
412 Q_EMIT reportError(1);
413 setEnable(false);
414 return;
415 }
416
417 bool changed = changeInterfaceFirmware("/", m_mode);
418 if (!changed) {
419 // Necessary firmware for the device may be missing
420 Q_EMIT reportError(35);
421 setEnable(false);
422 setWifiBlock(false);
423 return;
424 }
425
426 if (m_stored) {
427 // we defer enabling until old hotspot is deleted
428 // if we can delete the old one
429 // If not, unset stored flag and call this method.
430 if (!destroy(m_hotspot_path)) {
431 setStored(false);
432 setEnabled(true);
433 setEnable(true);
434 }
435 } else {
436 // we defer enabling until new hotspot is created
437 m_hotspot_path = addConnection(m_ssid, m_password, m_device_path, m_mode);
438 if (m_hotspot_path.path().isEmpty()) {
439 // Emit "Unknown Error".
440 Q_EMIT reportError(0);
441 setEnable(false);
442 setWifiBlock(false);
443 }
444 }
445
446 } else {
447 // Disabling the hotspot.
448 disable();
449 setEnable(false);
450
451 bool unblocked = setWifiBlock(false);
452 if (!unblocked) {
453 // "The device could not be readied for configuration"
454 Q_EMIT reportError(5);
455 }
456 }
457}
458
459// Disables a hotspot.
460void HotspotManager::disable() {
461 QDBusObjectPath hotspot = getHotspot(m_mode);
462 if (hotspot.path().isEmpty()) {
463 qWarning() << "Could not find a hotspot setup to disable.\n";
464 return;
465 }
466
467 // Create Connection.Settings proxy for hotspot
468 OrgFreedesktopNetworkManagerSettingsConnectionInterface conn(
469 nm_service, hotspot.path(), QDBusConnection::systemBus());
470
471 // Get new settings
472 nmConnectionArg new_settings = createConnectionSettings(m_ssid, m_password,
473 m_device_path, m_mode, false);
474 auto updating = conn.Update(new_settings);
475 updating.waitForFinished();
476 if(!updating.isValid()) {
477 qCritical() << "Could not update connection with autoconnect=false: "
478 << updating.error().message();
479 }
480
481 auto active_connections = nm_manager.activeConnections();
482 for(const auto &active_connection : active_connections) {
483 // DBus Properties interface proxy of the active connection. We use
484 // this proxy to get to the Connection property.
485 QDBusInterface iface(
486 nm_service, active_connection.path(),
487 "org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
488
489 // Call to get the Connection property.
490 QDBusReply<QVariant> conname = iface.call(
491 "Get", nm_connection_active_interface, "Connection");
492
493 // Cast the property to a object path.
494 QDBusObjectPath backingConnection = qvariant_cast<QDBusObjectPath>(
495 conname.value());
496
497 // This active connection's Connection property was our hotspot,
498 // so we will deactivate it. Note that we do not remove the hotspot,
499 // as we are storing the ssid, password and mode on the connection.
500 if(backingConnection == m_hotspot_path) {
501 // Deactivate the connection.
502 auto deactivation = nm_manager.DeactivateConnection(active_connection);
503 deactivation.waitForFinished();
504 if(!deactivation.isValid()) {
505 qCritical() << "Could not get deactivate connection: "
506 << deactivation.error().message();
507 }
508 return;
509 }
510 }
511 return;
512}
513
514bool HotspotManager::enabled() const {
515 return m_enabled;
516}
517
518void HotspotManager::setEnable(bool value) {
519 if (m_enabled != value) {
520 m_enabled = value;
521 Q_EMIT enabledChanged(value);
522 }
523}
524
525bool HotspotManager::stored() const {
526 return m_stored;
527}
528
529void HotspotManager::setStored(bool value) {
530 if (m_stored != value) {
531 m_stored = value;
532 Q_EMIT storedChanged(value);
533 }
534}
535
536QByteArray HotspotManager::ssid() const {
187 return m_ssid;537 return m_ssid;
188}538}
189539
190QString HotspotManager::getHotspotPassword() {540void HotspotManager::setSsid(QByteArray value) {
541 if (m_ssid != value) {
542 m_ssid = value;
543 Q_EMIT ssidChanged(value);
544 }
545}
546
547QString HotspotManager::password() const {
191 return m_password;548 return m_password;
192}549}
193550
194void HotspotManager::setupHotspot(QByteArray ssid_, QString password_) {551void HotspotManager::setPassword(QString value) {
195 m_ssid = ssid_;552 if (m_password != value) {
196 m_password = password_;553 m_password = value;
197}554 Q_EMIT passwordChanged(value);
198555 }
199void HotspotManager::enableHotspot() {556}
200 if(!m_settingsPath.isEmpty()) {557
201 // Prints a warning message if the connection has disappeared already.558QString HotspotManager::mode() const {
202 destroyHotspot();559 return m_mode;
203 // NM returns from the dbus call immediately but only destroys the560}
204 // connection some time later. There is no callback for when this happens.561
205 // So this is the best we can do with reasonable effort.562void HotspotManager::setMode(QString value) {
206 QThread::sleep(1);563 if (m_mode != value) {
207 }564 m_mode = value;
208 startAdhoc(m_ssid, m_password, m_devicePath);565 Q_EMIT modeChanged(value);
209 detectAdhoc(m_settingsPath, m_ssid, m_password, m_isActive);566 }
210}567}
211568
212bool HotspotManager::isHotspotActive() {569void HotspotManager::onNewConnection(QDBusObjectPath path) {
213 return m_isActive;570 // The new connection is the same as the stored hotspot path.
214}571 if (path == m_hotspot_path) {
215572 // If a new hotspot was added, it is also given that
216void HotspotManager::disableHotspot() {573 // Wi-Fi has been soft blocked. We can now unblock Wi-Fi
217 static const QString activeIface("org.freedesktop.NetworkManager.Connection.Active");574 // and let NetworkManager pick up the newly created
218 static const QString connProp("Connection");575 // connection.
219 OrgFreedesktopNetworkManagerInterface mgr(nm_service,576 bool unblocked = setWifiBlock(false);
220 nm_dbus_path,577 if (!unblocked) {
221 QDBusConnection::systemBus());578 // "The device could not be readied for configuration"
222 auto activeConnections = mgr.activeConnections();579 Q_EMIT reportError(5);
223 for(const auto &aConn : activeConnections) {580 } else {
224 QDBusInterface iface(nm_service, aConn.path(), "org.freedesktop.DBus.Properties",581 // We successfully unblocked the Wi-Fi, so set m_enable to true.
225 QDBusConnection::systemBus());582 setEnable(true);
226 QDBusReply<QVariant> conname = iface.call("Get", activeIface, connProp);
227 QDBusObjectPath backingConnection = qvariant_cast<QDBusObjectPath>(conname.value());
228 if(backingConnection.path() == m_settingsPath) {
229 mgr.DeactivateConnection(aConn);
230 return;
231 }583 }
232 }584
233 qWarning() << "Could not find a hotspot setup to disable.\n";585 // This also mean we have successfully created a hotspot connection
234}586 // object in NetworkManager, so m_stored should now be true.
235587 setStored(true);
236void HotspotManager::destroyHotspot() {588 }
237 if(m_settingsPath.isEmpty()) {589}
238 qWarning() << "Tried to destroy nonexisting hotspot.\n";590
591
592bool HotspotManager::destroy(QDBusObjectPath path) {
593 if(path.path().isEmpty()) {
594 return false;
595 }
596
597 // Connection Settings interface proxy for the connection
598 // we are about to delete.
599 OrgFreedesktopNetworkManagerSettingsConnectionInterface conn(
600 nm_service, path.path(), QDBusConnection::systemBus());
601
602 // Subscribe to the connection proxy's Removed signal.
603 conn.connection().connect(conn.service(), path.path(), conn.interface(),
604 "Removed", this, SLOT(onRemoved()));
605
606 auto del = conn.Delete();
607 del.waitForFinished();
608 return del.isValid();
609}
610
611void HotspotManager::onRemoved() {
612 // The UI does not support direct deletion of a hotspot, and given how
613 // hotspots currently work, every time we want to re-use a hotspot, we
614 // delete it an add a new one.
615 // Thus, if a hotspot was deleted, we now create a new one.
616 m_hotspot_path = addConnection(m_ssid, m_password, m_device_path, m_mode);
617
618 // We could not add a connection, so report, disable and unblock.
619 if (m_hotspot_path.path().isEmpty()) {
620 // Emit "Unknown Error".
621 Q_EMIT reportError(0);
622 setEnable(false);
623 setWifiBlock(false);
624 }
625}
626
627void HotspotManager::onPropertiesChanged(QVariantMap properties) {
628 // If we have no hotspot path, ignore changes in NetworkManager.
629 if (m_hotspot_path.path().isEmpty()) {
239 return;630 return;
240 }631 }
241 QDBusInterface control(nm_service, m_settingsPath, nm_connection_interface,632
242 QDBusConnection::systemBus());633 // Set flag so we know that ActiveConnections changed.
243 QDBusReply<void> reply = control.call("Delete");634 bool active_connection_changed = false;
244 if(!reply.isValid()) {635
245 qWarning() << "Could not disconnect adhoc network: " << reply.error().message() << "\n";636 for(QVariantMap::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) {
246 } else {637 if (iter.key() == "ActiveConnections") {
247 m_isActive = false;638 active_connection_changed = true;
639
640 const QDBusArgument args = qvariant_cast<QDBusArgument>(iter.value());
641 if (args.currentType() == QDBusArgument::ArrayType) {
642 args.beginArray();
643
644 while (!args.atEnd()) {
645 QDBusObjectPath path = qdbus_cast<QDBusObjectPath>(args);
646
647 QDBusInterface active_connection_dbus_interface(
648 nm_service, path.path(), dbus_properties_interface,
649 QDBusConnection::systemBus());
650
651 QDBusReply<QVariant> connection_property = active_connection_dbus_interface.call(
652 "Get", nm_connection_active_interface, "Connection");
653
654 // Active connection did not have a connection property,
655 // so ignore it.
656 if(!connection_property.isValid()) {
657 continue;
658 }
659
660 QDBusObjectPath connection_path = qvariant_cast<QDBusObjectPath>(
661 connection_property.value());
662
663 // We see our connection as being active, so we emit that is
664 // enabled and return.
665 if (connection_path == m_hotspot_path) {
666 setEnable(true);
667 return;
668 }
669 }
670 args.endArray();
671 }
672 }
673 }
674
675 // At this point ActiveConnections changed, but
676 // our hotspot was not in that list.
677 if (active_connection_changed) {
678 setEnable(false);
679 }
680}
681
682void HotspotManager::updateSettingsFromDbus(QDBusObjectPath path) {
683 setEnable(isHotspotActive(m_hotspot_path));
684
685 nmConnectionArg settings = getConnectionSettings(path);
686 const char wifi_key[] = "802-11-wireless";
687 const char security_key[] = "802-11-wireless-security";
688
689 if (settings.find(wifi_key) != settings.end()) {
690 QByteArray ssid = settings[wifi_key]["ssid"].toByteArray();
691 if (!ssid.isEmpty()) {
692 setSsid(ssid);
693 }
694
695 QString mode = settings[wifi_key]["mode"].toString();
696 if (!mode.isEmpty()) {
697 setMode(mode);
698 }
699 }
700
701 nmConnectionArg secrets = getConnectionSecrets(path, security_key);
702
703 if (secrets.find(security_key) != secrets.end()) {
704 QString pwd = secrets[security_key]["psk"].toString();
705 if (!pwd.isEmpty()) {
706 setPassword(pwd);
707 }
248 }708 }
249}709}
250710
=== modified file 'plugins/cellular/hotspotmanager.h'
--- plugins/cellular/hotspotmanager.h 2014-07-23 13:44:31 +0000
+++ plugins/cellular/hotspotmanager.h 2015-05-18 15:06:15 +0000
@@ -1,8 +1,9 @@
1/*1/*
2 * Copyright (C) 2014 Canonical, Ltd.2 * Copyright (C) 2014, 2015 Canonical, Ltd.
3 *3 *
4 * Authors:4 * Authors:
5 * Jussi Pakkanen <jussi.pakkanen@canonical.com>5 * Jussi Pakkanen <jussi.pakkanen@canonical.com>
6 * Jonas G. Drange <jonas.drange@canonical.com>
6 *7 *
7 * This program is free software: you can redistribute it and/or modify it8 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 3, as published9 * under the terms of the GNU General Public License version 3, as published
@@ -15,39 +16,166 @@
15 *16 *
16 * You should have received a copy of the GNU General Public License17 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */19 *
20 *
21 * HotspotManager API
22 * ==============================
23 *
24 * Methods
25 *
26 * Signals
27 * enabledChanged(bool enabled)
28 * Signal that gets emitted when the hotspot is disabled or enabled.
29 *
30 * storedChanged(bool stored)
31 * Signal that gets emitted when a hotspot was stored.
32 *
33 * ssidChanged(QByteArray ssid)
34 * Signal that gets emitted when the ssid of the hotspot was changed.
35 *
36 * passwordChanged(QString password)
37 * Signal that gets emitted when the password of the hotspot was changed.
38 *
39 * modeChanged(QString mode)
40 * Signal that gets emitted when the mode was changed.
41 *
42 * authChanged(QString auth)
43 *
44 * Note that none of these signal will be emitted if a change to the hotspot
45 * was made by anyone else than the HotspotManager. Right now, the canonical
46 * way to edit a hotspot, is through the hotspot manager.
47 *
48 *
49 * reportError(int reason)
50 * The reasons correspond to https://developer.gnome.org/
51 * NetworkManager/0.9/spec.html#type-NM_DEVICE_STATE_REASON
52 *
53 * Properties
54 * bool enabled [readwrite]
55 * Whether or not the hotspot is enabled.
56 *
57 * bool stored [readonly]
58 * Whether or not a hotspot is known to the hotspotmanager.
59 *
60 * QByteArray ssid [readwrite]
61 * The current SSID of the hotspot.
62 *
63 * QString auth [readwrite]
64 * The current authentication of the hotspot. The default for this property
65 * is "wpa-psk" and is currently the only supported scheme. WEP is unsupported
66 * by design, as is no scheme at all.
67 *
68 * TODO: Check/add support for wpa-eap
69 *
70 * QString password [readwrite]
71 * The current Pre-Shared-Key for the hotspot. If the key is 64-characters
72 * long, it must contain only hexadecimal characters and is interpreted as a
73 * hexadecimal WPA key. Otherwise, the key must be between 8 and 63 ASCII
74 * characters and is interpreted as a WPA passphrase.
75 *
76 * QString mode [readwrite, optional]
77 * The current hotspot mode. The default of this value is "ap", but can be
78 * set to "p2p" or "adhoc". "p2p" and "adhoc" is currently not fully supported.
79 *
80 * TODO: Complete support for adhoc and p2p modes.
81*/
1982
20#ifndef CELLULAR_DBUS_HELPER83#ifndef HOTSPOTMANAGER_H
21#define CELLULAR_DBUS_HELPER84#define HOTSPOTMANAGER_H
2285
23#include <QObject>86#include <QObject>
24#include <QDBusObjectPath>87#include <QDBusObjectPath>
25/**88#include <QUuid>
26 * For exposing dbus data to Qml.89
27 */90#include "nm_manager_proxy.h"
91#include "nm_settings_proxy.h"
92#include "nm_settings_connection_proxy.h"
2893
29class HotspotManager : public QObject {94class HotspotManager : public QObject {
30 Q_OBJECT95 Q_OBJECT
96 Q_PROPERTY( bool enabled
97 READ enabled
98 WRITE setEnabled
99 NOTIFY enabledChanged)
100 Q_PROPERTY( QByteArray ssid
101 READ ssid
102 WRITE setSsid
103 NOTIFY ssidChanged)
104 Q_PROPERTY( QString auth
105 READ auth
106 WRITE setAuth
107 NOTIFY authChanged)
108 Q_PROPERTY( QString password
109 READ password
110 WRITE setPassword
111 NOTIFY passwordChanged)
112 Q_PROPERTY( QString mode
113 READ mode
114 WRITE setMode
115 NOTIFY modeChanged)
116 Q_PROPERTY( bool stored
117 READ stored
118 NOTIFY storedChanged)
31119
32public:120public:
33 explicit HotspotManager(QObject *parent = nullptr);121 explicit HotspotManager(QObject *parent = nullptr);
34 ~HotspotManager() {};122 ~HotspotManager() {};
35123
36 Q_INVOKABLE QByteArray getHotspotName();124 bool enabled() const;
37 Q_INVOKABLE QString getHotspotPassword();125 void setEnabled(bool);
38 Q_INVOKABLE void setupHotspot(QByteArray ssid, QString password);126 bool stored() const;
39 Q_INVOKABLE bool isHotspotActive();127
40 Q_INVOKABLE void enableHotspot();128 QByteArray ssid() const;
41 Q_INVOKABLE void disableHotspot();129 void setSsid(QByteArray);
42 void destroyHotspot();130
131 QString password() const;
132 void setPassword(QString);
133
134 QString mode() const;
135 void setMode(QString);
136
137 QString auth() const;
138 void setAuth(QString);
139
140Q_SIGNALS:
141 void enabledChanged(bool enabled);
142 void storedChanged(bool stored);
143 void ssidChanged(const QByteArray ssid);
144 void passwordChanged(const QString password);
145 void modeChanged(const QString mode);
146 void authChanged(const QString auth);
147
148 /*
149 The mapping of code to string is taken from
150 http://bazaar.launchpad.net/~vcs-imports/
151 network-manager/trunk/view/head:/cli/src/common.c
152
153 NetworkManager documentation: https://developer.gnome.org/
154 NetworkManager/0.9/spec.html#type-NM_DEVICE_STATE_REASON
155 */
156 void reportError(const int &reason);
157
158public Q_SLOTS:
159 void onNewConnection(const QDBusObjectPath);
160 void onRemoved();
161 void onPropertiesChanged(const QVariantMap);
43162
44private:163private:
164 QString m_mode;
165 bool m_enabled;
166 bool m_stored;
167 QString m_password;
45 QByteArray m_ssid;168 QByteArray m_ssid;
46 QString m_password;169 QDBusObjectPath m_device_path;
47 QString m_settingsPath;170 QDBusObjectPath m_hotspot_path;
48 QDBusObjectPath m_devicePath;171
49 bool m_isActive;172 void disable();
173
174 bool destroy(QDBusObjectPath);
175
176 void setStored(bool);
177 void setEnable(bool);
178 void updateSettingsFromDbus(QDBusObjectPath);
50};179};
51180
52
53#endif181#endif
54182
=== modified file 'plugins/system-update/system_update.cpp'
--- plugins/system-update/system_update.cpp 2014-10-28 17:49:47 +0000
+++ plugins/system-update/system_update.cpp 2015-05-18 15:06:15 +0000
@@ -105,6 +105,7 @@
105 reply.waitForFinished();105 reply.waitForFinished();
106 if (reply.isValid()) {106 if (reply.isValid()) {
107 m_currentBuildNumber = reply.argumentAt<0>();107 m_currentBuildNumber = reply.argumentAt<0>();
108 m_deviceName = reply.argumentAt<2>();
108 m_lastUpdateDate = QDateTime::fromString(reply.argumentAt<3>(), Qt::ISODate);109 m_lastUpdateDate = QDateTime::fromString(reply.argumentAt<3>(), Qt::ISODate);
109 m_detailedVersion = reply.argumentAt<4>();110 m_detailedVersion = reply.argumentAt<4>();
110 Q_EMIT versionChanged();111 Q_EMIT versionChanged();
@@ -129,6 +130,12 @@
129 return target > current;130 return target > current;
130}131}
131132
133QString SystemUpdate::deviceName() {
134 if (m_deviceName.isNull())
135 setCurrentDetailedVersion();
136
137 return m_deviceName;
138}
132139
133QDateTime SystemUpdate::lastUpdateDate() {140QDateTime SystemUpdate::lastUpdateDate() {
134 if (!m_lastUpdateDate.isValid())141 if (!m_lastUpdateDate.isValid())
135142
=== modified file 'plugins/system-update/system_update.h'
--- plugins/system-update/system_update.h 2014-09-26 20:14:54 +0000
+++ plugins/system-update/system_update.h 2015-05-18 15:06:15 +0000
@@ -48,6 +48,7 @@
48 int currentBuildNumber();48 int currentBuildNumber();
49 QString currentUbuntuBuildNumber();49 QString currentUbuntuBuildNumber();
50 QString currentDeviceBuildNumber();50 QString currentDeviceBuildNumber();
51 QString deviceName();
5152
52 void checkForUpdate();53 void checkForUpdate();
53 void downloadUpdate();54 void downloadUpdate();
@@ -80,6 +81,7 @@
80 QMap<QString, QString> m_detailedVersion;81 QMap<QString, QString> m_detailedVersion;
81 QDateTime m_lastUpdateDate;82 QDateTime m_lastUpdateDate;
82 int m_downloadMode;83 int m_downloadMode;
84 QString m_deviceName;
8385
84 QDBusConnection m_systemBusConnection;86 QDBusConnection m_systemBusConnection;
85 QString m_objectPath;87 QString m_objectPath;
8688
=== modified file 'plugins/system-update/update_manager.h'
--- plugins/system-update/update_manager.h 2015-03-16 13:51:36 +0000
+++ plugins/system-update/update_manager.h 2015-05-18 15:06:15 +0000
@@ -62,6 +62,8 @@
62 NOTIFY versionChanged)62 NOTIFY versionChanged)
63 Q_PROPERTY(QString currentDeviceBuildNumber READ currentDeviceBuildNumber63 Q_PROPERTY(QString currentDeviceBuildNumber READ currentDeviceBuildNumber
64 NOTIFY versionChanged)64 NOTIFY versionChanged)
65 Q_PROPERTY(QString deviceName READ deviceName
66 NOTIFY deviceNameChanged)
6567
66Q_SIGNALS:68Q_SIGNALS:
67 void checkFinished();69 void checkFinished();
@@ -78,6 +80,7 @@
78 void updateProcessFailed(QString message);80 void updateProcessFailed(QString message);
79 void systemUpdateFailed(int consecutiveFailureCount, QString lastReason);81 void systemUpdateFailed(int consecutiveFailureCount, QString lastReason);
80 void versionChanged();82 void versionChanged();
83 void deviceNameChanged();
81 void rebooting(bool status);84 void rebooting(bool status);
8285
83public:86public:
@@ -97,6 +100,7 @@
97 QDateTime lastUpdateDate() { return m_systemUpdate.lastUpdateDate(); }100 QDateTime lastUpdateDate() { return m_systemUpdate.lastUpdateDate(); }
98 QString currentUbuntuBuildNumber() { return m_systemUpdate.currentUbuntuBuildNumber(); }101 QString currentUbuntuBuildNumber() { return m_systemUpdate.currentUbuntuBuildNumber(); }
99 QString currentDeviceBuildNumber() { return m_systemUpdate.currentDeviceBuildNumber(); }102 QString currentDeviceBuildNumber() { return m_systemUpdate.currentDeviceBuildNumber(); }
103 QString deviceName() { return m_systemUpdate.deviceName(); }
100 bool checkTarget() { return m_systemUpdate.checkTarget(); }104 bool checkTarget() { return m_systemUpdate.checkTarget(); }
101105
102106
103107
=== modified file 'tests/autopilot/ubuntu_system_settings/__init__.py'
--- tests/autopilot/ubuntu_system_settings/__init__.py 2015-05-12 16:29:02 +0000
+++ tests/autopilot/ubuntu_system_settings/__init__.py 2015-05-18 15:06:15 +0000
@@ -306,6 +306,138 @@
306 field.write(name)306 field.write(name)
307 self.pointing_device.click_object(ok)307 self.pointing_device.click_object(ok)
308308
309 """
310 :returns: Whether or not hotspot can be used.
311 """
312 @autopilot.logging.log_action(logger.debug)
313 def have_hotspot(self):
314 return self.wait_select_single(objectName='hotspotEntry').visible
315
316 """
317 :param: Configuration with keys ssid and password.
318 :returns: Hotspot page.
319 """
320 @autopilot.logging.log_action(logger.debug)
321 def setup_hotspot(self, config=None):
322 hotspot_page = self._enter_hotspot()
323 hotspot_page.setup_hotspot(config)
324 return hotspot_page
325
326 """
327 Enables hotspot.
328 :returns: Hotspot page.
329 """
330 @autopilot.logging.log_action(logger.debug)
331 def enable_hotspot(self):
332 hotspot_page = self._enter_hotspot()
333 hotspot_page.enable_hotspot()
334 return hotspot_page
335
336 """
337 Disables hotspot.
338 :returns: Hotspot page.
339 """
340 @autopilot.logging.log_action(logger.debug)
341 def disable_hotspot(self):
342 hotspot_page = self._enter_hotspot()
343 hotspot_page.disable_hotspot()
344 return hotspot_page
345
346 @autopilot.logging.log_action(logger.debug)
347 def _enter_hotspot(self):
348 obj = self.wait_select_single(objectName="hotspotEntry")
349 self.pointing_device.click_object(obj)
350 return self.get_root_instance().wait_select_single(
351 objectName='hotspotPage')
352
353
354class Hotspot(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
355
356 """Autopilot helper for Hotspot page."""
357
358 @classmethod
359 def validate_dbus_object(cls, path, state):
360 name = introspection.get_classname_from_path(path)
361 if name == b'ItemPage':
362 if state['objectName'][1] == 'hotspotPage':
363 return True
364 return False
365
366 @property
367 def _switch(self):
368 return self.wait_select_single(
369 ubuntuuitoolkit.CheckBox,
370 objectName='hotspotSwitch')
371
372 @autopilot.logging.log_action(logger.debug)
373 def enable_hotspot(self):
374 self._switch.check()
375
376 @autopilot.logging.log_action(logger.debug)
377 def disable_hotspot(self):
378 self._switch.uncheck()
379
380 @autopilot.logging.log_action(logger.debug)
381 def setup_hotspot(self, config):
382 obj = self.select_single(objectName='hotspotSetupEntry')
383 self.pointing_device.click_object(obj)
384 setup = self.get_root_instance().wait_select_single(
385 objectName='hotspotSetup')
386 if config:
387 if 'ssid' in config:
388 setup.set_ssid(config['ssid'])
389 if 'password' in config:
390 setup.set_password(config['password'])
391 setup.enable()
392 if setup:
393 setup.wait_until_destroyed()
394
395 @autopilot.logging.log_action(logger.debug)
396 def get_hotspot_status(self):
397 return self._switch.checked
398
399
400class HotspotSetup(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
401
402 """Autopilot helper for Hotspot setup."""
403
404 @classmethod
405 def validate_dbus_object(cls, path, state):
406 name = introspection.get_classname_from_path(path)
407 if name == b'Dialog':
408 if state['objectName'][1] == 'hotspotSetup':
409 return True
410 return False
411
412 @property
413 def _ssid_field(self):
414 return self.wait_select_single(
415 ubuntuuitoolkit.TextField,
416 objectName='ssidField')
417
418 @property
419 def _password_field(self):
420 return self.wait_select_single(
421 ubuntuuitoolkit.TextField,
422 objectName='passwordField')
423
424 @property
425 def _enable_button(self):
426 return self.wait_select_single(
427 'Button', objectName='confirmButton')
428
429 @autopilot.logging.log_action(logger.debug)
430 def set_ssid(self, ssid):
431 self._ssid_field.write(ssid)
432
433 @autopilot.logging.log_action(logger.debug)
434 def set_password(self, password):
435 self._password_field.write(password)
436
437 @autopilot.logging.log_action(logger.debug)
438 def enable(self):
439 self.pointing_device.click_object(self._enable_button)
440
309441
310class BluetoothPage(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):442class BluetoothPage(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
311443
312444
=== modified file 'tests/autopilot/ubuntu_system_settings/tests/__init__.py'
--- tests/autopilot/ubuntu_system_settings/tests/__init__.py 2015-04-16 15:24:41 +0000
+++ tests/autopilot/ubuntu_system_settings/tests/__init__.py 2015-05-18 15:06:15 +0000
@@ -31,7 +31,6 @@
31from gi.repository import UPowerGlib31from gi.repository import UPowerGlib
32from testtools.matchers import Equals, NotEquals, GreaterThan32from testtools.matchers import Equals, NotEquals, GreaterThan
3333
34
35ACCOUNTS_IFACE = 'org.freedesktop.Accounts'34ACCOUNTS_IFACE = 'org.freedesktop.Accounts'
36ACCOUNTS_USER_IFACE = 'org.freedesktop.Accounts.User'35ACCOUNTS_USER_IFACE = 'org.freedesktop.Accounts.User'
37ACCOUNTS_OBJ = '/org/freedesktop/Accounts'36ACCOUNTS_OBJ = '/org/freedesktop/Accounts'
@@ -384,6 +383,68 @@
384 self.cellular_page = self.main_view.go_to_cellular_page()383 self.cellular_page = self.main_view.go_to_cellular_page()
385384
386385
386class HotspotBaseTestCase(CellularBaseTestCase):
387
388 @classmethod
389 def setUpClass(cls):
390 super(HotspotBaseTestCase, cls).setUpClass()
391 nm_tmpl = os.path.join(os.path.dirname(__file__), 'networkmanager.py')
392 (cls.n_mock, cls.obj_nm) = cls.spawn_server_template(
393 nm_tmpl, stdout=subprocess.PIPE)
394 (cls.u_mock, cls.obj_urf) = cls.spawn_server_template(
395 'urfkill', stdout=subprocess.PIPE)
396
397 @classmethod
398 def tearDownClass(cls):
399 cls.n_mock.terminate()
400 cls.n_mock.wait()
401 cls.u_mock.terminate()
402 cls.u_mock.wait()
403 super(HotspotBaseTestCase, cls).tearDownClass()
404
405 def tearDown(self):
406 self.obj_nm.Reset()
407 self.urfkill_mock.ClearCalls()
408 super(HotspotBaseTestCase, self).tearDown()
409
410 def setUp(self):
411 self.patch_environment("USS_SHOW_ALL_UI", "1")
412 self.nm_mock = dbus.Interface(self.obj_nm, dbusmock.MOCK_IFACE)
413 self.device_path = self.obj_nm.AddWiFiDevice('test0', 'Barbaz', 1)
414 self.device_mock = dbus.Interface(self.dbus_con.get_object(
415 NM_SERVICE, self.device_path),
416 'org.freedesktop.DBus.Properties')
417 self.urfkill_mock = dbus.Interface(self.obj_urf, dbusmock.MOCK_IFACE)
418 super(HotspotBaseTestCase, self).setUp()
419
420 def add_hotspot(self, name, password, secured=True, enabled=False):
421 settings = {
422 'connection': {
423 'id': dbus.String('Test AP', variant_level=1),
424 'type': dbus.String('802-11-wireless', variant_level=1), },
425 '802-11-wireless': {
426 'mode': dbus.String('ap', variant_level=1),
427 'ssid': dbus.String(name, variant_level=1),
428 }
429 }
430
431 if secured:
432 settings['802-11-wireless']['security'] = dbus.String(
433 '802-11-wireless-security', variant_level=1)
434 settings['802-11-wireless-security'] = {
435 'auth-alg': dbus.String('shared', variant_level=1),
436 'key-mgmt': dbus.String('wpa-psk', variant_level=1),
437 'psk': dbus.String(password, variant_level=1),
438 }
439
440 if enabled:
441 settings['connection']['autoconnect'] = True
442
443 connection_path = self.obj_nm.SettingsAddConnection(settings)
444
445 return connection_path
446
447
387class BluetoothBaseTestCase(UbuntuSystemSettingsTestCase):448class BluetoothBaseTestCase(UbuntuSystemSettingsTestCase):
388449
389 def setUp(self):450 def setUp(self):
390451
=== added file 'tests/autopilot/ubuntu_system_settings/tests/networkmanager.py'
--- tests/autopilot/ubuntu_system_settings/tests/networkmanager.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_system_settings/tests/networkmanager.py 2015-05-18 15:06:15 +0000
@@ -0,0 +1,902 @@
1'''NetworkManager mock template
2
3This creates the expected methods and properties of the main
4org.freedesktop.NetworkManager object, but no devices. You can specify any
5property such as 'NetworkingEnabled', or 'WirelessEnabled' etc. in
6"parameters".
7'''
8
9# This program is free software; you can redistribute it and/or modify it under
10# the terms of the GNU Lesser General Public License as published by the Free
11# Software Foundation; either version 3 of the License, or (at your option) any
12# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
13# of the license.
14
15__author__ = 'Iftikhar Ahmad'
16__email__ = 'iftikhar.ahmad@canonical.com'
17__copyright__ = '(c) 2012 Canonical Ltd.'
18__license__ = 'LGPL 3+'
19
20import dbus
21import uuid
22import binascii
23
24from dbusmock import MOCK_IFACE
25import dbusmock
26
27
28BUS_NAME = 'org.freedesktop.NetworkManager'
29MAIN_OBJ = '/org/freedesktop/NetworkManager'
30MAIN_IFACE = 'org.freedesktop.NetworkManager'
31SETTINGS_OBJ = '/org/freedesktop/NetworkManager/Settings'
32SETTINGS_IFACE = 'org.freedesktop.NetworkManager.Settings'
33DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
34WIRELESS_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
35ACCESS_POINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
36CSETTINGS_IFACE = 'org.freedesktop.NetworkManager.Settings.Connection'
37ACTIVE_CONNECTION_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
38SYSTEM_BUS = True
39
40
41class NMState:
42 '''Global state
43
44 As per https://developer.gnome.org/NetworkManager/unstable/spec.html#
45 type-NM_STATE
46 '''
47 NM_STATE_UNKNOWN = 0
48 NM_STATE_ASLEEP = 10
49 NM_STATE_DISCONNECTED = 20
50 NM_STATE_DISCONNECTING = 30
51 NM_STATE_CONNECTING = 40
52 NM_STATE_CONNECTED_LOCAL = 50
53 NM_STATE_CONNECTED_SITE = 60
54 NM_STATE_CONNECTED_GLOBAL = 70
55
56
57class NMConnectivityState:
58 '''Connectvity state
59
60 As per https://developer.gnome.org/NetworkManager/unstable/spec.html#
61 type-NM_CONNECTIVITY
62 '''
63 NM_CONNECTIVITY_UNKNOWN = 0
64 NM_CONNECTIVITY_NONE = 1
65 NM_CONNECTIVITY_PORTAL = 2
66 NM_CONNECTIVITY_LIMITED = 3
67 NM_CONNECTIVITY_FULL = 4
68
69
70class NMActiveConnectionState:
71 '''Active connection state
72
73 As per https://developer.gnome.org/NetworkManager/unstable/spec.html#
74 type-NM_ACTIVE_CONNECTION_STATE
75 '''
76 NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0
77 NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1
78 NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2
79 NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3
80 NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4
81
82
83class InfrastructureMode:
84 '''Infrastructure mode
85
86 As per https://developer.gnome.org/NetworkManager/unstable/spec.html#
87 type-NM_802_11_MODE
88 '''
89 NM_802_11_MODE_UNKNOWN = 0
90 NM_802_11_MODE_ADHOC = 1
91 NM_802_11_MODE_INFRA = 2
92 NM_802_11_MODE_AP = 3
93
94 NAME_MAP = {
95 NM_802_11_MODE_UNKNOWN: 'unknown',
96 NM_802_11_MODE_ADHOC: 'adhoc',
97 NM_802_11_MODE_INFRA: 'infrastructure',
98 NM_802_11_MODE_AP: 'access-point',
99 }
100
101
102class DeviceState:
103 '''Device states
104
105 As per https://developer.gnome.org/NetworkManager/unstable/spec.html#
106 type-NM_DEVICE_STATE
107 '''
108 UNKNOWN = 0
109 UNMANAGED = 10
110 UNAVAILABLE = 20
111 DISCONNECTED = 30
112 PREPARE = 40
113 CONFIG = 50
114 NEED_AUTH = 60
115 IP_CONFIG = 70
116 IP_CHECK = 80
117 SECONDARIES = 90
118 ACTIVATED = 100
119 DEACTIVATING = 110
120 FAILED = 120
121
122
123class NM80211ApSecurityFlags:
124 '''Security flags
125
126 As per https://developer.gnome.org/NetworkManager/unstable/spec.html#
127 type-NM_802_11_AP_SEC
128 '''
129 NM_802_11_AP_SEC_NONE = 0x00000000
130 NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001
131 NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002
132 NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004
133 NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008
134 NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010
135 NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020
136 NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040
137 NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080
138 NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100
139 NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200
140
141 NAME_MAP = {
142 NM_802_11_AP_SEC_KEY_MGMT_PSK: {
143 'key-mgmt': 'wpa-psk',
144 'auth-alg': 'open'
145 },
146 }
147
148
149class NM80211ApFlags:
150 '''Device flags
151
152 As per https://developer.gnome.org/NetworkManager/unstable/spec.html#
153 type-NM_802_11_AP_FLAGS
154 '''
155 NM_802_11_AP_FLAGS_NONE = 0x00000000
156 NM_802_11_AP_FLAGS_PRIVACY = 0x00000001
157
158
159def activate_connection(self, conn, dev, ap):
160 name = ap.rsplit('/', 1)[1]
161 RemoveActiveConnection(
162 self, dev, '/org/freedesktop/NetworkManager/ActiveConnection/' + name)
163
164 state = dbus.UInt32(
165 NMActiveConnectionState.NM_ACTIVE_CONNECTION_STATE_ACTIVATED)
166 active_conn = dbus.ObjectPath(
167 AddActiveConnection(self, [dev], conn, ap, name, state))
168
169 return active_conn
170
171
172def deactivate_connection(self, active_conn_path):
173 NM = dbusmock.get_object(MAIN_OBJ)
174
175 for dev_path in NM.GetDevices():
176 RemoveActiveConnection(self, dev_path, active_conn_path)
177
178
179def add_and_activate_connection(self, conn_conf, dev, ap):
180 name = ap.rsplit('/', 1)[1]
181 RemoveWifiConnection(
182 self, dev, '/org/freedesktop/NetworkManager/Settings/' + name)
183
184 raw_ssid = ''.join([
185 chr(byte) for byte in conn_conf["802-11-wireless"]["ssid"]])
186 wifi_conn = dbus.ObjectPath(
187 AddWiFiConnection(self, dev, name, raw_ssid, ""))
188
189 active_conn = activate_connection(self, wifi_conn, dev, ap)
190
191 return (wifi_conn, active_conn)
192
193
194def load(mock, parameters):
195 mock.activate_connection = activate_connection
196 mock.deactivate_connection = deactivate_connection
197 mock.add_and_activate_connection = add_and_activate_connection
198 mock.AddMethods(MAIN_IFACE, [
199 ('GetDevices', '', 'ao',
200 'ret = [k for k in objects.keys() if "/Devices" in k]'),
201 ('GetPermissions', '', 'a{ss}', 'ret = {}'),
202 ('state', '', 'u', "ret = self.Get('%s', 'State')" % MAIN_IFACE),
203 (
204 'CheckConnectivity', '', 'u',
205 "ret = self.Get('%s', 'Connectivity')" % MAIN_IFACE),
206 (
207 'ActivateConnection', 'ooo', 'o',
208 "ret = self.activate_connection(self, args[0], args[1], args[2])"),
209 (
210 'DeactivateConnection', 'o', '',
211 "self.deactivate_connection(self, args[0])"),
212 (
213 'AddAndActivateConnection', 'a{sa{sv}}oo', 'oo',
214 "ret = self.add_and_activate_connection("
215 "self, args[0], args[1], args[2])"),
216 ])
217
218 mock.AddProperties(
219 '',
220 {
221 'ActiveConnections': dbus.Array([], signature='o'),
222 'Devices': dbus.Array([], signature='o'),
223 'NetworkingEnabled': parameters.get('NetworkingEnabled', True),
224 'Connectivity': parameters.get(
225 'Connectivity',
226 dbus.UInt32(NMConnectivityState.NM_CONNECTIVITY_FULL)),
227 'State': parameters.get(
228 'State', dbus.UInt32(NMState.NM_STATE_CONNECTED_GLOBAL)),
229 'Startup': False,
230 'Version': parameters.get('Version', '0.9.6.0'),
231 'WimaxEnabled': parameters.get('WimaxEnabled', True),
232 'WimaxHardwareEnabled': parameters.get(
233 'WimaxHardwareEnabled', True),
234 'WirelessEnabled': parameters.get('WirelessEnabled', True),
235 'WirelessHardwareEnabled': parameters.get(
236 'WirelessHardwareEnabled', True),
237 'WwanEnabled': parameters.get('WwanEnabled', False),
238 'WwanHardwareEnabled': parameters.get('WwanHardwareEnabled', True)
239 })
240
241 settings_props = {'Hostname': 'hostname',
242 'CanModify': True,
243 'Connections': dbus.Array([], signature='o')}
244 settings_methods = [(
245 'ListConnections', '', 'ao',
246 "ret = self.Get('%s', 'Connections')" %
247 SETTINGS_IFACE),
248 ('GetConnectionByUuid', 's', 'o', ''),
249 (
250 'AddConnection', 'a{sa{sv}}', 'o',
251 'ret = self.SettingsAddConnection(args[0])'),
252 ('SaveHostname', 's', '', '')]
253 mock.AddObject(SETTINGS_OBJ,
254 SETTINGS_IFACE,
255 settings_props,
256 settings_methods)
257
258
259@dbus.service.method(MOCK_IFACE,
260 in_signature='sssv', out_signature='')
261def SetProperty(self, path, iface, name, value):
262 obj = dbusmock.get_object(path)
263 obj.Set(iface, name, value)
264 obj.EmitSignal(iface, 'PropertiesChanged', 'a{sv}', [{name: value}])
265
266
267@dbus.service.method(MOCK_IFACE,
268 in_signature='u', out_signature='')
269def SetGlobalConnectionState(self, state):
270 self.SetProperty(MAIN_OBJ, MAIN_IFACE, 'State',
271 dbus.UInt32(state, variant_level=1))
272 self.EmitSignal(MAIN_IFACE, 'StateChanged', 'u', [state])
273
274
275@dbus.service.method(MOCK_IFACE,
276 in_signature='u', out_signature='')
277def SetConnectivity(self, connectivity):
278 self.SetProperty(MAIN_OBJ, MAIN_IFACE, 'Connectivity',
279 dbus.UInt32(connectivity, variant_level=1))
280
281
282@dbus.service.method(MOCK_IFACE,
283 in_signature='ss', out_signature='')
284def SetDeviceActive(self, device_path, active_connection_path):
285 dev_obj = dbusmock.get_object(device_path)
286 dev_obj.Set(DEVICE_IFACE, 'ActiveConnection',
287 dbus.ObjectPath(active_connection_path))
288 old_state = dev_obj.Get(DEVICE_IFACE, 'State')
289 dev_obj.Set(DEVICE_IFACE, 'State', dbus.UInt32(DeviceState.ACTIVATED))
290
291 dev_obj.EmitSignal(DEVICE_IFACE, 'StateChanged', 'uuu', [
292 dbus.UInt32(DeviceState.ACTIVATED), old_state, dbus.UInt32(1)])
293
294
295@dbus.service.method(MOCK_IFACE,
296 in_signature='s', out_signature='')
297def SetDeviceDisconnected(self, device_path):
298 dev_obj = dbusmock.get_object(device_path)
299 dev_obj.Set(DEVICE_IFACE, 'ActiveConnection', dbus.ObjectPath('/'))
300 old_state = dev_obj.Get(DEVICE_IFACE, 'State')
301 dev_obj.Set(DEVICE_IFACE, 'State', dbus.UInt32(DeviceState.DISCONNECTED))
302
303 dev_obj.EmitSignal(DEVICE_IFACE, 'StateChanged', 'uuu', [
304 dbus.UInt32(DeviceState.DISCONNECTED), old_state, dbus.UInt32(1)])
305
306
307@dbus.service.method(MOCK_IFACE,
308 in_signature='ssi', out_signature='s')
309def AddEthernetDevice(self, device_name, iface_name, state):
310 '''Add an ethernet device.
311
312 You have to specify device_name, device interface name (e. g. eth0), and
313 state. You can use the predefined DeviceState values (e. g.
314 DeviceState.ACTIVATED) or supply a numeric value. For valid state values
315 please visit
316 http://projects.gnome.org/NetworkManager/developers/api/09/spec.html#
317 type-NM_DEVICE_STATE
318
319 Please note that this does not set any global properties.
320
321 Returns the new object path.
322 '''
323 path = '/org/freedesktop/NetworkManager/Devices/' + device_name
324 wired_props = {'Carrier': False,
325 'HwAddress': dbus.String('78:DD:08:D2:3D:43'),
326 'PermHwAddress': dbus.String('78:DD:08:D2:3D:43'),
327 'Speed': dbus.UInt32(0)}
328 self.AddObject(path,
329 'org.freedesktop.NetworkManager.Device.Wired',
330 wired_props,
331 [])
332
333 props = {'DeviceType': dbus.UInt32(1),
334 'State': dbus.UInt32(state),
335 'Interface': iface_name,
336 'AvailableConnections': dbus.Array([], signature='o'),
337 'IpInterface': ''}
338
339 obj = dbusmock.get_object(path)
340 obj.AddProperties(DEVICE_IFACE, props)
341
342 devices = self.Get(MAIN_IFACE, 'Devices')
343 devices.append(path)
344 self.Set(MAIN_IFACE, 'Devices', devices)
345
346 self.EmitSignal('org.freedesktop.NetworkManager', 'DeviceAdded', 'o',
347 [path])
348
349 return path
350
351
352@dbus.service.method(MOCK_IFACE,
353 in_signature='ssi', out_signature='s')
354def AddWiFiDevice(self, device_name, iface_name, state):
355 '''Add a WiFi Device.
356
357 You have to specify device_name, device interface name (e. g. wlan0) and
358 state. You can use the predefined DeviceState values (e. g.
359 DeviceState.ACTIVATED) or supply a numeric value. For valid state values,
360 please visit
361 http://projects.gnome.org/NetworkManager/developers/api/09/spec.html#
362 type-NM_DEVICE_STATE
363
364 Please note that this does not set any global properties.
365
366 Returns the new object path.
367 '''
368
369 path = '/org/freedesktop/NetworkManager/Devices/' + device_name
370 self.AddObject(path,
371 WIRELESS_DEVICE_IFACE,
372 {
373 'HwAddress': dbus.String('11:22:33:44:55:66'),
374 'PermHwAddress': dbus.String('11:22:33:44:55:66'),
375 'Bitrate': dbus.UInt32(5400),
376 'Mode': dbus.UInt32(2),
377 'WirelessCapabilities': dbus.UInt32(255),
378 'AccessPoints': dbus.Array([], signature='o'),
379 },
380 [
381 ('GetAccessPoints', '', 'ao',
382 'ret = self.access_points'),
383 ('GetAllAccessPoints', '', 'ao',
384 'ret = self.access_points'),
385 ('RequestScan', 'a{sv}', '', ''),
386 ])
387
388 dev_obj = dbusmock.get_object(path)
389 dev_obj.access_points = []
390 dev_obj.AddProperties(DEVICE_IFACE,
391 {
392 'ActiveConnection': dbus.ObjectPath('/'),
393 'AvailableConnections':
394 dbus.Array([], signature='o'),
395 'AutoConnect': False,
396 'Managed': True,
397 'Driver': 'dbusmock',
398 'DeviceType': dbus.UInt32(2),
399 'State': dbus.UInt32(state),
400 'Interface': iface_name,
401 'IpInterface': iface_name,
402 })
403
404 devices = self.Get(MAIN_IFACE, 'Devices')
405 devices.append(path)
406 self.Set(MAIN_IFACE, 'Devices', devices)
407
408 self.EmitSignal('org.freedesktop.NetworkManager', 'DeviceAdded', 'o',
409 [path])
410
411 return path
412
413
414@dbus.service.method(MOCK_IFACE,
415 in_signature='ssssuuuyu', out_signature='s')
416def AddAccessPoint(self, dev_path, ap_name, ssid, hw_address,
417 mode, frequency, rate, strength, security):
418 '''Add an access point to an existing WiFi device.
419
420 You have to specify WiFi Device path, Access Point object name,
421 ssid, hw_address, mode, frequency, rate, strength and security.
422 For valid access point property values, please visit
423 http://projects.gnome.org/NetworkManager/developers/api/09/spec.html#
424 org.freedesktop.NetworkManager.AccessPoint
425
426 Please note that this does not set any global properties.
427
428 Returns the new object path.
429 '''
430 dev_obj = dbusmock.get_object(dev_path)
431 ap_path = '/org/freedesktop/NetworkManager/AccessPoint/' + ap_name
432 if ap_path in dev_obj.access_points:
433 raise dbus.exceptions.DBusException(
434 'Access point %s on device %s already exists' % (ap_name,
435 dev_path),
436 name=MAIN_IFACE + '.AlreadyExists')
437
438 flags = NM80211ApFlags.NM_802_11_AP_FLAGS_PRIVACY
439 if security == NM80211ApSecurityFlags.NM_802_11_AP_SEC_NONE:
440 flags = NM80211ApFlags.NM_802_11_AP_FLAGS_NONE
441
442 self.AddObject(ap_path,
443 ACCESS_POINT_IFACE,
444 {'Ssid': dbus.ByteArray(ssid.encode('UTF-8')),
445 'HwAddress': dbus.String(hw_address),
446 'Flags': dbus.UInt32(flags),
447 'LastSeen': dbus.Int32(1),
448 'Frequency': dbus.UInt32(frequency),
449 'MaxBitrate': dbus.UInt32(rate),
450 'Mode': dbus.UInt32(mode),
451 'RsnFlags': dbus.UInt32(security),
452 'WpaFlags': dbus.UInt32(security),
453 'Strength': dbus.Byte(strength)},
454 [])
455
456 dev_obj.access_points.append(ap_path)
457
458 aps = dev_obj.Get(WIRELESS_DEVICE_IFACE, 'AccessPoints')
459 aps.append(ap_path)
460 dev_obj.Set(WIRELESS_DEVICE_IFACE, 'AccessPoints', aps)
461
462 dev_obj.EmitSignal(WIRELESS_DEVICE_IFACE, 'AccessPointAdded', 'o',
463 [ap_path])
464
465 return ap_path
466
467
468@dbus.service.method(MOCK_IFACE,
469 in_signature='ssss', out_signature='s')
470def AddWiFiConnection(self, dev_path, connection_name, ssid_name, key_mgmt):
471 '''Add an available connection to an existing WiFi device and access point.
472
473 You have to specify WiFi Device path, Connection object name,
474 SSID and key management.
475
476 The SSID must match one of the previously created access points.
477
478 Please note that this does not set any global properties.
479
480 Returns the new object path.
481 '''
482
483 dev_obj = dbusmock.get_object(dev_path)
484 connection_path = ('/org/freedesktop/NetworkManager/Settings/%s' %
485 connection_name)
486 connections = dev_obj.Get(DEVICE_IFACE, 'AvailableConnections')
487
488 settings_obj = dbusmock.get_object(SETTINGS_OBJ)
489 main_connections = settings_obj.ListConnections()
490
491 ssid = ssid_name.encode('UTF-8')
492
493 # Find the access point by ssid
494 access_point = None
495 access_points = dev_obj.access_points
496 for ap_path in access_points:
497 ap = dbusmock.get_object(ap_path)
498 if ap.Get(ACCESS_POINT_IFACE, 'Ssid') == ssid:
499 access_point = ap
500 break
501
502 if not access_point:
503 raise dbus.exceptions.DBusException(
504 'Access point with SSID [%s] could not be found' % (ssid_name),
505 name=MAIN_IFACE + '.DoesNotExist')
506
507 hw_address = access_point.Get(ACCESS_POINT_IFACE, 'HwAddress')
508 mode = access_point.Get(ACCESS_POINT_IFACE, 'Mode')
509 security = access_point.Get(ACCESS_POINT_IFACE, 'WpaFlags')
510
511 if connection_path in connections or connection_path in main_connections:
512 raise dbus.exceptions.DBusException(
513 'Connection %s on device %s already exists' % (
514 connection_name, dev_path),
515 name=MAIN_IFACE + '.AlreadyExists')
516
517 # Parse mac address string into byte array
518 mac_bytes = binascii.unhexlify(hw_address.replace(':', ''))
519
520 settings = {
521 '802-11-wireless': {
522 'seen-bssids': [hw_address],
523 'ssid': dbus.ByteArray(ssid),
524 'mac-address': dbus.ByteArray(mac_bytes),
525 'mode': InfrastructureMode.NAME_MAP[mode]
526 },
527 'connection': {
528 'timestamp': dbus.UInt64(1374828522),
529 'type': '802-11-wireless',
530 'id': ssid_name,
531 'uuid': str(uuid.uuid4())
532 },
533 }
534
535 if security != NM80211ApSecurityFlags.NM_802_11_AP_SEC_NONE:
536 settings['802-11-wireless']['security'] = '802-11-wireless-security'
537 sec = NM80211ApSecurityFlags.NAME_MAP[security]
538 settings['802-11-wireless-security'] = sec
539
540 self.AddObject(connection_path,
541 CSETTINGS_IFACE,
542 {
543 'Settings': dbus.Dictionary(
544 settings, signature='sa{sv}'),
545 'Secrets': dbus.Dictionary({}, signature='sa{sv}'),
546 },
547 [
548 (
549 'Delete', '', '',
550 'self.ConnectionDelete("%s")' % connection_path),
551 (
552 'GetSettings', '', 'a{sa{sv}}',
553 "ret = self.Get('%s', 'Settings')" %
554 CSETTINGS_IFACE),
555 (
556 'GetSecrets', 's', 'a{sa{sv}}',
557 "ret = self.Get('%s', 'Secrets')" %
558 CSETTINGS_IFACE),
559 (
560 'Update', 'a{sa{sv}}', '',
561 'self.ConnectionUpdate("%s", args[0])' %
562 connection_path),
563 ])
564
565 connections.append(dbus.ObjectPath(connection_path))
566 dev_obj.Set(DEVICE_IFACE, 'AvailableConnections', connections)
567
568 main_connections.append(connection_path)
569 settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
570
571 settings_obj.EmitSignal(SETTINGS_IFACE, 'NewConnection', 'o', [ap_path])
572
573 return connection_path
574
575
576@dbus.service.method(MOCK_IFACE,
577 in_signature='assssu', out_signature='s')
578def AddActiveConnection(self, devices, connection_device, specific_object,
579 name, state):
580 '''Add an active connection to an existing WiFi device.
581
582 You have to a list of the involved WiFi devices, the connection path,
583 the access point path, ActiveConnection object name and connection
584 state.
585
586 Please note that this does not set any global properties.
587
588 Returns the new object path.
589 '''
590
591 conn_obj = dbusmock.get_object(connection_device)
592 settings = conn_obj.Get(CSETTINGS_IFACE, 'Settings')
593 conn_uuid = settings['connection']['uuid']
594
595 device_objects = [dbus.ObjectPath(dev) for dev in devices]
596
597 active_connection_path = ('/org/freedesktop/NetworkManager/'
598 'ActiveConnection/%s' % name)
599 self.AddObject(active_connection_path,
600 ACTIVE_CONNECTION_IFACE,
601 {
602 'Devices': device_objects,
603 'Default6': False,
604 'Default': True,
605 'Vpn': False,
606 'Connection': dbus.ObjectPath(connection_device),
607 'Master': dbus.ObjectPath('/'),
608 'SpecificObject': dbus.ObjectPath(specific_object),
609 'Uuid': conn_uuid,
610 'State': state,
611 },
612 [])
613
614 for dev_path in devices:
615 self.SetDeviceActive(dev_path, active_connection_path)
616
617 active_connections = self.Get(MAIN_IFACE, 'ActiveConnections')
618 active_connections.append(dbus.ObjectPath(active_connection_path))
619 self.SetProperty(MAIN_OBJ, MAIN_IFACE, 'ActiveConnections',
620 active_connections)
621
622 return active_connection_path
623
624
625@dbus.service.method(MOCK_IFACE,
626 in_signature='ss', out_signature='')
627def RemoveAccessPoint(self, dev_path, ap_path):
628 '''Remove the specified access point.
629
630 You have to specify the device to remove the access point from, and the
631 path of the access point.
632
633 Please note that this does not set any global properties.
634 '''
635
636 dev_obj = dbusmock.get_object(dev_path)
637
638 aps = dev_obj.Get(WIRELESS_DEVICE_IFACE, 'AccessPoints')
639 aps.remove(ap_path)
640 dev_obj.Set(WIRELESS_DEVICE_IFACE, 'AccessPoints', aps)
641
642 dev_obj.access_points.remove(ap_path)
643
644 dev_obj.EmitSignal(WIRELESS_DEVICE_IFACE, 'AccessPointRemoved', 'o',
645 [ap_path])
646
647 self.RemoveObject(ap_path)
648
649
650@dbus.service.method(MOCK_IFACE,
651 in_signature='ss', out_signature='')
652def RemoveWifiConnection(self, dev_path, connection_path):
653 '''Remove the specified WiFi connection.
654
655 You have to specify the device to remove the connection from, and the
656 path of the Connection.
657
658 Please note that this does not set any global properties.
659 '''
660
661 dev_obj = dbusmock.get_object(dev_path)
662 settings_obj = dbusmock.get_object(SETTINGS_OBJ)
663
664 connections = dev_obj.Get(DEVICE_IFACE, 'AvailableConnections')
665 main_connections = settings_obj.ListConnections()
666
667 if (connection_path not in connections and
668 connection_path not in main_connections):
669 return
670
671 connections.remove(dbus.ObjectPath(connection_path))
672 dev_obj.Set(DEVICE_IFACE, 'AvailableConnections', connections)
673
674 main_connections.remove(connection_path)
675 settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
676
677 settings_obj.EmitSignal(SETTINGS_IFACE, 'ConnectionRemoved', 'o',
678 [connection_path])
679
680 connection_obj = dbusmock.get_object(connection_path)
681 connection_obj.EmitSignal(CSETTINGS_IFACE, 'Removed', '', [])
682
683 self.RemoveObject(connection_path)
684
685
686@dbus.service.method(MOCK_IFACE,
687 in_signature='ss', out_signature='')
688def RemoveActiveConnection(self, dev_path, active_connection_path):
689 '''Remove the specified ActiveConnection.
690
691 You have to specify the device to remove the connection from, and the
692 path of the ActiveConnection.
693
694 Please note that this does not set any global properties.
695 '''
696 self.SetDeviceDisconnected(dev_path)
697
698 active_connections = self.Get(MAIN_IFACE, 'ActiveConnections')
699
700 if active_connection_path not in active_connections:
701 return
702
703 active_connections.remove(dbus.ObjectPath(active_connection_path))
704 self.SetProperty(MAIN_OBJ, MAIN_IFACE, 'ActiveConnections',
705 active_connections)
706
707 self.RemoveObject(active_connection_path)
708
709
710@dbus.service.method(SETTINGS_IFACE,
711 in_signature='a{sa{sv}}', out_signature='o')
712def SettingsAddConnection(self, connection_settings):
713 '''Add a connection.
714
715 connection_settings is a String String Variant Map Map. See
716 https://developer.gnome.org/NetworkManager/0.9/spec.html
717 #type-String_String_Variant_Map_Map
718
719 If you omit uuid, this method adds one for you.
720 '''
721
722 if 'uuid' not in connection_settings['connection']:
723 connection_settings['connection']['uuid'] = str(uuid.uuid4())
724
725 NM = dbusmock.get_object(MAIN_OBJ)
726 settings_obj = dbusmock.get_object(SETTINGS_OBJ)
727 main_connections = settings_obj.ListConnections()
728
729 # Mimic how NM names connections
730 connection_name = str(len(main_connections))
731
732 connection_path = SETTINGS_OBJ + '/' + connection_name
733
734 if connection_path in main_connections:
735 raise dbus.exceptions.DBusException(
736 'Connection %s already exists' % connection_path,
737 name=MAIN_IFACE + '.AlreadyExists',)
738
739 self.AddObject(connection_path,
740 CSETTINGS_IFACE,
741 {
742 'Settings': dbus.Dictionary(connection_settings,
743 signature='sa{sv}'),
744 'Secrets': dbus.Dictionary({}, signature='sa{sv}'),
745 },
746 [
747 (
748 'Delete', '', '',
749 'self.ConnectionDelete("%s")' % connection_path),
750 (
751 'GetSettings', '', 'a{sa{sv}}',
752 "ret = self.Get('%s', 'Settings')" %
753 CSETTINGS_IFACE),
754 (
755 'GetSecrets', 's', 'a{sa{sv}}',
756 "ret = self.Get('%s', 'Secrets')" %
757 CSETTINGS_IFACE),
758 (
759 'Update', 'a{sa{sv}}', '',
760 'self.ConnectionUpdate("%s", args[0])' %
761 connection_path),
762 ])
763
764 main_connections.append(connection_path)
765 settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
766
767 settings_obj.EmitSignal(SETTINGS_IFACE, 'NewConnection', 'o',
768 [connection_path])
769
770 auto_connect = False
771 if 'autoconnect' in connection_settings['connection']:
772 auto_connect = connection_settings['connection']['autoconnect']
773
774 if auto_connect:
775 dev = None
776 devices = NM.GetDevices()
777
778 # Grab the first device.
779 if len(devices) > 0:
780 dev = devices[0]
781
782 if dev:
783 activate_connection(NM, connection_path, dev, connection_path)
784
785 return connection_path
786
787
788@dbus.service.method(CSETTINGS_IFACE,
789 in_signature='oa{sa{sv}}', out_signature='')
790def ConnectionUpdate(self, connection_path, settings):
791 '''Update settings on a connection.
792
793 settings is a String String Variant Map Map. See
794 https://developer.gnome.org/NetworkManager/0.9/spec.html
795 #type-String_String_Variant_Map_Map
796 '''
797 NM = dbusmock.get_object(MAIN_OBJ)
798 settings_obj = dbusmock.get_object(SETTINGS_OBJ)
799 conn_obj = dbusmock.get_object(connection_path)
800
801 main_connections = settings_obj.ListConnections()
802
803 if connection_path not in main_connections:
804 raise dbus.exceptions.DBusException(
805 'Connection %s does not exist' % connection_path,
806 name=MAIN_IFACE + '.DoesNotExist',)
807
808 conn_settings = conn_obj.Get(CSETTINGS_IFACE, 'Settings')
809 changed_settings = {}
810 for key, value in settings.items():
811 for k, v in value.items():
812 changed_settings[k] = v
813
814 if key not in conn_settings:
815 conn_settings[key] = dbus.Dictionary({}, signature='sv')
816
817 conn_settings[key][k] = v
818
819 conn_obj.Set(CSETTINGS_IFACE, 'Settings', conn_settings)
820
821 settings_obj.EmitSignal(CSETTINGS_IFACE, 'PropertiesChanged', 'a{sv}',
822 [changed_settings])
823 settings_obj.EmitSignal(CSETTINGS_IFACE, 'Updated', '', [])
824
825 auto_connect = False
826 if 'autoconnect' in settings['connection']:
827 auto_connect = settings['connection']['autoconnect']
828
829 if auto_connect:
830 dev = None
831 devices = NM.GetDevices()
832
833 # Grab the first device.
834 if len(devices) > 0:
835 dev = devices[0]
836
837 if dev:
838 activate_connection(NM, connection_path, dev, connection_path)
839
840 return connection_path
841
842
843@dbus.service.method(CSETTINGS_IFACE,
844 in_signature='o', out_signature='')
845def ConnectionDelete(self, connection_path):
846 '''Deletes a connection.
847
848 This also
849 * removes the deleted connection from any device,
850 * removes any active connection(s) it might be associated with,
851 * removes it from the Settings interface,
852 * as well as deletes the object from the mock.
853
854 Note: If this was the only active connection, we change the global
855 connection state.
856 '''
857 NM = dbusmock.get_object(MAIN_OBJ)
858 settings_obj = dbusmock.get_object(SETTINGS_OBJ)
859
860 # Find the associated active connection(s).
861 active_connections = NM.Get(MAIN_IFACE, 'ActiveConnections')
862 associated_active_connections = []
863 for ac in active_connections:
864 ac_obj = dbusmock.get_object(ac)
865 ac_con = ac_obj.Get(ACTIVE_CONNECTION_IFACE, 'Connection')
866 if ac_con == connection_path:
867 associated_active_connections.append(ac)
868
869 # We found that the connection we are deleting are associated to all
870 # active connections and subsequently set the global state to
871 # disconnected.
872 if len(active_connections) == len(associated_active_connections):
873 self.SetGlobalConnectionState(NMState.NM_STATE_DISCONNECTED)
874
875 # Remove the connection from all associated devices.
876 # We also remove all associated active connections.
877 for dev_path in NM.GetDevices():
878 dev_obj = dbusmock.get_object(dev_path)
879 connections = dev_obj.Get(DEVICE_IFACE, 'AvailableConnections')
880
881 for ac in associated_active_connections:
882 NM.RemoveActiveConnection(dev_path, ac)
883
884 if connection_path not in connections:
885 continue
886
887 connections.remove(dbus.ObjectPath(connection_path))
888 dev_obj.Set(DEVICE_IFACE, 'AvailableConnections', connections)
889
890 # Remove the connection from the settings interface
891 main_connections = settings_obj.ListConnections()
892 if connection_path not in main_connections:
893 return
894 main_connections.remove(connection_path)
895 settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
896 settings_obj.EmitSignal(SETTINGS_IFACE, 'ConnectionRemoved', 'o',
897 [connection_path])
898
899 # Remove the connection from the mock
900 connection_obj = dbusmock.get_object(connection_path)
901 connection_obj.EmitSignal(CSETTINGS_IFACE, 'Removed', '', [])
902 self.RemoveObject(connection_path)
0903
=== modified file 'tests/autopilot/ubuntu_system_settings/tests/test_cellular.py'
--- tests/autopilot/ubuntu_system_settings/tests/test_cellular.py 2014-10-29 15:51:17 +0000
+++ tests/autopilot/ubuntu_system_settings/tests/test_cellular.py 2015-05-18 15:06:15 +0000
@@ -5,6 +5,7 @@
5# under the terms of the GNU General Public License version 3, as published5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.6# by the Free Software Foundation.
77
8import dbus
8from gi.repository import Gio, GLib9from gi.repository import Gio, GLib
9from time import sleep10from time import sleep
1011
@@ -13,7 +14,14 @@
13from testtools.matchers import Equals, raises, StartsWith14from testtools.matchers import Equals, raises, StartsWith
1415
15from ubuntu_system_settings.tests import (16from ubuntu_system_settings.tests import (
16 CellularBaseTestCase, CONNMAN_IFACE, RDO_IFACE, NETREG_IFACE)17 CellularBaseTestCase, HotspotBaseTestCase, CONNMAN_IFACE, RDO_IFACE,
18 NETREG_IFACE)
19
20from ubuntu_system_settings.tests.networkmanager import (
21 CSETTINGS_IFACE, MAIN_OBJ as NM_PATH, MAIN_IFACE as NM_IFACE,
22)
23
24DEV_IFACE = 'org.freedesktop.NetworkManager.Device'
1725
1826
19class CellularTestCase(CellularBaseTestCase):27class CellularTestCase(CellularBaseTestCase):
@@ -288,3 +296,116 @@
288 lambda:296 lambda:
289 gsettings.get_value('default-sim-for-messages').get_string(),297 gsettings.get_value('default-sim-for-messages').get_string(),
290 Eventually(Equals('/ril_1')))298 Eventually(Equals('/ril_1')))
299
300
301class HotspotTestCase(HotspotBaseTestCase):
302
303 def test_setup(self):
304 if not self.cellular_page.have_hotspot():
305 self.skipTest('Cannot test hotspot since wifi is disabled.')
306
307 ssid = 'Ubuntu'
308 password = 'abcdefgh'
309 config = {'password': password}
310 active_con_path = NM_PATH + '/ActiveConnection/0'
311 con_path = NM_PATH + '/Settings/0'
312
313 hotspot_page = self.cellular_page.setup_hotspot(config)
314
315 # Assert that the switch is on.
316 self.assertTrue(hotspot_page.get_hotspot_status())
317
318 # Assert that Block on Urfkill is called twice.
319 self.assertThat(
320 lambda: len(self.urfkill_mock.GetMethodCalls('Block')),
321 Eventually(Equals(2))
322 )
323
324 # Assert that we get one active connection.
325 self.assertThat(
326 lambda: len(self.obj_nm.GetAll(NM_IFACE)['ActiveConnections']),
327 Eventually(Equals(1))
328 )
329
330 # Assert that the active connection has a certain path.
331 self.assertThat(
332 lambda: self.obj_nm.GetAll(NM_IFACE)['ActiveConnections'][0],
333 Eventually(Equals(active_con_path))
334 )
335
336 # Assert the device's active connection
337 self.assertThat(
338 lambda: self.device_mock.Get(DEV_IFACE, 'ActiveConnection'),
339 Eventually(Equals(active_con_path))
340 )
341
342 connection_mock = dbus.Interface(self.dbus_con.get_object(
343 NM_IFACE, con_path), CSETTINGS_IFACE)
344
345 settings = connection_mock.GetSettings()
346
347 # Assert that autoconnect is true, that ssid and password is what we
348 # expect them to be.
349 self.assertTrue(settings['connection']['autoconnect'])
350
351 s_ssid = bytearray(settings['802-11-wireless']['ssid']).decode('utf-8')
352 self.assertEqual(s_ssid, ssid)
353 self.assertEqual(settings['802-11-wireless-security']['psk'], password)
354
355 def test_enabling(self):
356 if not self.cellular_page.have_hotspot():
357 self.skipTest('Cannot test hotspot since wifi is disabled.')
358
359 self.add_hotspot('foo', 'abcdefgh', enabled=False)
360
361 self.assertThat(
362 lambda: len(self.obj_nm.GetAll(NM_IFACE)['ActiveConnections']),
363 Eventually(Equals(0))
364 )
365
366 self.cellular_page.enable_hotspot()
367
368 self.assertThat(
369 lambda: len(self.obj_nm.GetAll(NM_IFACE)['ActiveConnections']),
370 Eventually(Equals(1))
371 )
372
373 def test_disabling(self):
374 if not self.cellular_page.have_hotspot():
375 self.skipTest('Cannot test hotspot since wifi is disabled.')
376
377 self.add_hotspot('foo', 'abcdefgh', enabled=True)
378
379 self.assertThat(
380 lambda: len(self.obj_nm.GetAll(NM_IFACE)['ActiveConnections']),
381 Eventually(Equals(1))
382 )
383
384 self.cellular_page.disable_hotspot()
385
386 self.assertThat(
387 lambda: len(self.obj_nm.GetAll(NM_IFACE)['ActiveConnections']),
388 Eventually(Equals(0))
389 )
390
391 def test_changing(self):
392 if not self.cellular_page.have_hotspot():
393 self.skipTest('Cannot test hotspot since wifi is disabled.')
394
395 con_path = self.add_hotspot('foo', 'abcdefgh', enabled=True)
396
397 ssid = 'bar'
398 password = 'zomgzomg'
399 config = {'ssid': ssid, 'password': password}
400 self.cellular_page.setup_hotspot(config)
401
402 con_path = NM_PATH + '/Settings/0'
403
404 con_mock = dbus.Interface(self.dbus_con.get_object(
405 NM_IFACE, con_path), CSETTINGS_IFACE)
406
407 settings = con_mock.GetSettings()
408
409 s_ssid = bytearray(settings['802-11-wireless']['ssid']).decode('utf-8')
410 self.assertEqual(s_ssid, ssid)
411 self.assertEqual(settings['802-11-wireless-security']['psk'], password)
291412
=== modified file 'tests/plugins/system-update/fakesystemupdate.h'
--- tests/plugins/system-update/fakesystemupdate.h 2014-10-24 20:06:13 +0000
+++ tests/plugins/system-update/fakesystemupdate.h 2015-05-18 15:06:15 +0000
@@ -38,6 +38,7 @@
38 int currentBuildNumber() { return 123;}38 int currentBuildNumber() { return 123;}
39 QString currentUbuntuBuildNumber() { return QString("20140927");}39 QString currentUbuntuBuildNumber() { return QString("20140927");}
40 QString currentDeviceBuildNumber() { return QString("20140927");}40 QString currentDeviceBuildNumber() { return QString("20140927");}
41 QString deviceName() { return QString("mako");}
41 QDateTime lastUpdateDate() { return QDateTime::currentDateTime(); }42 QDateTime lastUpdateDate() { return QDateTime::currentDateTime(); }
4243
43 void checkForUpdate() {}44 void checkForUpdate() {}

Subscribers

People subscribed via source and target branches