Merge lp:~ken-vandine/ubuntu-system-settings/security_panel into lp:ubuntu-system-settings
- security_panel
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ken VanDine |
Approved revision: | 934 |
Merged at revision: | 954 |
Proposed branch: | lp:~ken-vandine/ubuntu-system-settings/security_panel |
Merge into: | lp:ubuntu-system-settings |
Prerequisite: | lp:~jonas-drange/ubuntu-system-settings/visual-feedback-in-grid |
Diff against target: |
924 lines (+743/-27) 9 files modified
plugins/security-privacy/CMakeLists.txt (+3/-0) plugins/security-privacy/Ofono.qml (+38/-0) plugins/security-privacy/PageComponent.qml (+52/-4) plugins/security-privacy/SimPin.qml (+358/-0) plugins/security-privacy/sims.js (+34/-0) src/qml/CategoryGrid.qml (+1/-0) tests/autopilot/ubuntu_system_settings/tests/__init__.py (+5/-22) tests/autopilot/ubuntu_system_settings/tests/ofono.py (+34/-0) tests/autopilot/ubuntu_system_settings/tests/test_security.py (+218/-1) |
To merge this branch: | bzr merge lp:~ken-vandine/ubuntu-system-settings/security_panel |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Jonas G. Drange (community) | Approve | ||
Review via email: mp+232478@code.launchpad.net |
This proposal supersedes a proposal from 2014-08-27.
Commit message
SIM PIN lock implementation
Description of the change
SIM PIN lock implementation
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:930
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal | # |
It works beautifully.
One small issue:
When changing the pin of a locked sim I get "undefined attempts remaining" – but it seems to work just fine. Skip "n attempts remaining" when locked?
Sebastien Bacher (seb128) wrote : Posted in a previous version of this proposal | # |
Thanks for the work, some issues
- you seem to have code for display effect on panel when clicked, merge error?
- clicking on the switch and doing "cancel" leads to the control going to "true", it should not
- it displays slots for non present SIMs
- toggling a SIM leads to a "Enter SIM PIN" titled dialog with a "Lock" button, the spec doesn't describe that case?
- 933. By Ken VanDine
-
ensure the checked state matches the locked state
- 934. By Ken VanDine
-
fixed title for unlock dialog to match design when unlocking
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal | # |
Retries seems broken on my SIM. I'll try to dig a bit deeper and report a bug against something.
Good stuff!
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:931
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Jonas G. Drange (jonas-drange) wrote : | # |
Retries seems broken on my SIM. I'll try to dig a bit deeper and report a bug against something.
Good stuff!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:932
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'plugins/security-privacy/CMakeLists.txt' | |||
2 | --- plugins/security-privacy/CMakeLists.txt 2014-08-11 11:05:58 +0000 | |||
3 | +++ plugins/security-privacy/CMakeLists.txt 2014-08-27 21:27:21 +0000 | |||
4 | @@ -22,8 +22,11 @@ | |||
5 | 22 | Dash.qml | 22 | Dash.qml |
6 | 23 | Location.qml | 23 | Location.qml |
7 | 24 | LockSecurity.qml | 24 | LockSecurity.qml |
8 | 25 | Ofono.qml | ||
9 | 25 | PageComponent.qml | 26 | PageComponent.qml |
10 | 26 | PhoneLocking.qml | 27 | PhoneLocking.qml |
11 | 28 | SimPin.qml | ||
12 | 29 | sims.js | ||
13 | 27 | ) | 30 | ) |
14 | 28 | 31 | ||
15 | 29 | set(PANEL_SOURCES | 32 | set(PANEL_SOURCES |
16 | 30 | 33 | ||
17 | === added file 'plugins/security-privacy/Ofono.qml' | |||
18 | --- plugins/security-privacy/Ofono.qml 1970-01-01 00:00:00 +0000 | |||
19 | +++ plugins/security-privacy/Ofono.qml 2014-08-27 21:27:21 +0000 | |||
20 | @@ -0,0 +1,38 @@ | |||
21 | 1 | /* | ||
22 | 2 | * Copyright (C) 2014 Canonical Ltd | ||
23 | 3 | * | ||
24 | 4 | * This program is free software: you can redistribute it and/or modify | ||
25 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
26 | 6 | * published by the Free Software Foundation. | ||
27 | 7 | * | ||
28 | 8 | * This program is distributed in the hope that it will be useful, | ||
29 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
30 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
31 | 11 | * GNU General Public License for more details. | ||
32 | 12 | * | ||
33 | 13 | * You should have received a copy of the GNU General Public License | ||
34 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
35 | 15 | * | ||
36 | 16 | * Authors: | ||
37 | 17 | * Jonas G. Drange <jonas.drange@canonical.com> | ||
38 | 18 | * | ||
39 | 19 | */ | ||
40 | 20 | import QtQuick 2.0 | ||
41 | 21 | import MeeGo.QOfono 0.2 | ||
42 | 22 | |||
43 | 23 | Item { | ||
44 | 24 | property alias simMng: simMng | ||
45 | 25 | property alias present: simMng.present | ||
46 | 26 | |||
47 | 27 | property string path | ||
48 | 28 | property string name | ||
49 | 29 | property string title: { | ||
50 | 30 | var number = simMng.subscriberNumbers[0] || simMng.subscriberIdentity; | ||
51 | 31 | return name + (number ? " (" + number + ")" : ""); | ||
52 | 32 | } | ||
53 | 33 | |||
54 | 34 | OfonoSimManager { | ||
55 | 35 | id: simMng | ||
56 | 36 | modemPath: path | ||
57 | 37 | } | ||
58 | 38 | } | ||
59 | 0 | 39 | ||
60 | === modified file 'plugins/security-privacy/PageComponent.qml' | |||
61 | --- plugins/security-privacy/PageComponent.qml 2014-08-26 00:54:38 +0000 | |||
62 | +++ plugins/security-privacy/PageComponent.qml 2014-08-27 21:27:21 +0000 | |||
63 | @@ -27,6 +27,8 @@ | |||
64 | 27 | import Ubuntu.SystemSettings.Battery 1.0 | 27 | import Ubuntu.SystemSettings.Battery 1.0 |
65 | 28 | import Ubuntu.SystemSettings.Diagnostics 1.0 | 28 | import Ubuntu.SystemSettings.Diagnostics 1.0 |
66 | 29 | import Ubuntu.SystemSettings.SecurityPrivacy 1.0 | 29 | import Ubuntu.SystemSettings.SecurityPrivacy 1.0 |
67 | 30 | import MeeGo.QOfono 0.2 | ||
68 | 31 | import "sims.js" as Sims | ||
69 | 30 | 32 | ||
70 | 31 | ItemPage { | 33 | ItemPage { |
71 | 32 | id: root | 34 | id: root |
72 | @@ -37,6 +39,18 @@ | |||
73 | 37 | 39 | ||
74 | 38 | property alias usePowerd: batteryBackend.powerdRunning | 40 | property alias usePowerd: batteryBackend.powerdRunning |
75 | 39 | property bool lockOnSuspend | 41 | property bool lockOnSuspend |
76 | 42 | property var modemsSorted: manager.modems.slice(0).sort() | ||
77 | 43 | property var sims | ||
78 | 44 | property int simsPresent: 0 | ||
79 | 45 | property int simsLoaded: 0 | ||
80 | 46 | property int simsLocked: { | ||
81 | 47 | var t = 0; | ||
82 | 48 | sims.forEach(function (sim) { | ||
83 | 49 | if (sim.simMng.lockedPins.length > 0) | ||
84 | 50 | t++; | ||
85 | 51 | }); | ||
86 | 52 | return t; | ||
87 | 53 | } | ||
88 | 40 | 54 | ||
89 | 41 | UbuntuDiagnostics { | 55 | UbuntuDiagnostics { |
90 | 42 | id: diagnosticsWidget | 56 | id: diagnosticsWidget |
91 | @@ -50,6 +64,33 @@ | |||
92 | 50 | id: batteryBackend | 64 | id: batteryBackend |
93 | 51 | } | 65 | } |
94 | 52 | 66 | ||
95 | 67 | OfonoManager { | ||
96 | 68 | id: manager | ||
97 | 69 | Component.onCompleted: { | ||
98 | 70 | // create ofono bindings for all modem paths | ||
99 | 71 | var component = Qt.createComponent("Ofono.qml"); | ||
100 | 72 | modemsSorted.forEach(function (path, index) { | ||
101 | 73 | var sim = component.createObject(root, { | ||
102 | 74 | path: path, | ||
103 | 75 | name: phoneSettings.simNames[path] ? | ||
104 | 76 | phoneSettings.simNames[path] : | ||
105 | 77 | "SIM " + (index + 1) | ||
106 | 78 | }); | ||
107 | 79 | if (sim === null) | ||
108 | 80 | console.warn('failed to create sim object'); | ||
109 | 81 | else | ||
110 | 82 | Sims.add(sim); | ||
111 | 83 | }); | ||
112 | 84 | root.sims = Sims.getAll(); | ||
113 | 85 | root.simsPresent = Sims.getPresentCount(); | ||
114 | 86 | } | ||
115 | 87 | } | ||
116 | 88 | |||
117 | 89 | GSettings { | ||
118 | 90 | id: phoneSettings | ||
119 | 91 | schema.id: "com.ubuntu.phone" | ||
120 | 92 | } | ||
121 | 93 | |||
122 | 53 | GSettings { | 94 | GSettings { |
123 | 54 | id: unitySettings | 95 | id: unitySettings |
124 | 55 | schema.id: "com.canonical.Unity.Lenses" | 96 | schema.id: "com.canonical.Unity.Lenses" |
125 | @@ -113,12 +154,19 @@ | |||
126 | 113 | } | 154 | } |
127 | 114 | ListItem.SingleValue { | 155 | ListItem.SingleValue { |
128 | 115 | id: simControl | 156 | id: simControl |
129 | 157 | objectName: "simControl" | ||
130 | 116 | text: i18n.tr("SIM PIN") | 158 | text: i18n.tr("SIM PIN") |
132 | 117 | value: "Off" | 159 | value: { |
133 | 160 | if (simsLoaded === 1 && simsLocked > 0) | ||
134 | 161 | return i18n.tr("On"); | ||
135 | 162 | else if (simsLoaded > 1 && simsLocked > 0) | ||
136 | 163 | return simsLocked + "/" + simsLoaded; | ||
137 | 164 | else | ||
138 | 165 | return i18n.tr("Off"); | ||
139 | 166 | } | ||
140 | 167 | visible: simsPresent > 0 | ||
141 | 118 | progression: true | 168 | progression: true |
145 | 119 | visible: showAllUI | 169 | onClicked: pageStack.push(Qt.resolvedUrl("SimPin.qml"), { sims: sims }) |
143 | 120 | /* Not implemented yet */ | ||
144 | 121 | //onClicked: pageStack.push(Qt.resolvedUrl("SimPin.qml")) | ||
146 | 122 | } | 170 | } |
147 | 123 | ListItem.Standard { | 171 | ListItem.Standard { |
148 | 124 | text: i18n.tr("Encryption") | 172 | text: i18n.tr("Encryption") |
149 | 125 | 173 | ||
150 | === added file 'plugins/security-privacy/SimPin.qml' | |||
151 | --- plugins/security-privacy/SimPin.qml 1970-01-01 00:00:00 +0000 | |||
152 | +++ plugins/security-privacy/SimPin.qml 2014-08-27 21:27:21 +0000 | |||
153 | @@ -0,0 +1,358 @@ | |||
154 | 1 | /* | ||
155 | 2 | * Copyright (C) 2014 Canonical Ltd. | ||
156 | 3 | * | ||
157 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
158 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
159 | 6 | * by the Free Software Foundation. | ||
160 | 7 | * | ||
161 | 8 | * This program is distributed in the hope that it will be useful, but | ||
162 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
163 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
164 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
165 | 12 | * | ||
166 | 13 | * You should have received a copy of the GNU General Public License along | ||
167 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
168 | 15 | * | ||
169 | 16 | * Authors: | ||
170 | 17 | * Ken VanDine <ken.vandine@canonical.com> | ||
171 | 18 | * | ||
172 | 19 | */ | ||
173 | 20 | |||
174 | 21 | import GSettings 1.0 | ||
175 | 22 | import QtQuick 2.0 | ||
176 | 23 | import QtQuick.Layouts 1.1 | ||
177 | 24 | import Ubuntu.Components 1.1 | ||
178 | 25 | import Ubuntu.Components.ListItems 0.1 as ListItem | ||
179 | 26 | import Ubuntu.Components.Popups 0.1 | ||
180 | 27 | import SystemSettings 1.0 | ||
181 | 28 | import MeeGo.QOfono 0.2 | ||
182 | 29 | import "sims.js" as Sims | ||
183 | 30 | |||
184 | 31 | |||
185 | 32 | ItemPage { | ||
186 | 33 | id: root | ||
187 | 34 | title: i18n.tr("SIM PIN") | ||
188 | 35 | |||
189 | 36 | property var sims | ||
190 | 37 | property var curSim | ||
191 | 38 | |||
192 | 39 | Component { | ||
193 | 40 | id: dialogComponent | ||
194 | 41 | |||
195 | 42 | Dialog { | ||
196 | 43 | id: changePinDialog | ||
197 | 44 | title: i18n.tr("Change SIM PIN") | ||
198 | 45 | |||
199 | 46 | property string errorText: i18n.tr( | ||
200 | 47 | "Incorrect PIN. %1 attempts remaining." | ||
201 | 48 | ).arg(curSim.pinRetries[OfonoSimManager.SimPin] || 3) | ||
202 | 49 | property int simMin: curSim.minimumPinLength(OfonoSimManager.SimPin) | ||
203 | 50 | property int simMax: curSim.maximumPinLength(OfonoSimManager.SimPin) | ||
204 | 51 | |||
205 | 52 | // This is a bit hacky, but the contents of this dialog get so tall | ||
206 | 53 | // that on a mako device, they don't fit with the OSK also visible. | ||
207 | 54 | // So we scrunch up spacing. | ||
208 | 55 | Binding { | ||
209 | 56 | target: __foreground | ||
210 | 57 | property: "itemSpacing" | ||
211 | 58 | value: units.gu(1) | ||
212 | 59 | } | ||
213 | 60 | |||
214 | 61 | Connections { | ||
215 | 62 | target: curSim | ||
216 | 63 | onChangePinComplete: { | ||
217 | 64 | if (error === OfonoSimManager.FailedError) { | ||
218 | 65 | console.warn("Change PIN failed with: " + error); | ||
219 | 66 | incorrect.visible = true; | ||
220 | 67 | changePinDialog.enabled = true; | ||
221 | 68 | currentInput.forceActiveFocus(); | ||
222 | 69 | currentInput.selectAll(); | ||
223 | 70 | return; | ||
224 | 71 | } | ||
225 | 72 | incorrect.visible = false; | ||
226 | 73 | changePinDialog.enabled = true; | ||
227 | 74 | PopupUtils.close(changePinDialog); | ||
228 | 75 | } | ||
229 | 76 | } | ||
230 | 77 | |||
231 | 78 | Label { | ||
232 | 79 | text: i18n.tr("Current PIN:") | ||
233 | 80 | } | ||
234 | 81 | |||
235 | 82 | TextField { | ||
236 | 83 | id: currentInput | ||
237 | 84 | echoMode: TextInput.Password | ||
238 | 85 | inputMethodHints: Qt.ImhDialableCharactersOnly | ||
239 | 86 | maximumLength: simMax | ||
240 | 87 | } | ||
241 | 88 | |||
242 | 89 | Label { | ||
243 | 90 | id: retries | ||
244 | 91 | text: i18n.tr("%1 attempts remaining").arg( | ||
245 | 92 | curSim.pinRetries[OfonoSimManager.SimPin] || 3) | ||
246 | 93 | visible: !incorrect.visible | ||
247 | 94 | } | ||
248 | 95 | |||
249 | 96 | Label { | ||
250 | 97 | id: incorrect | ||
251 | 98 | text: errorText | ||
252 | 99 | visible: false | ||
253 | 100 | color: "darkred" | ||
254 | 101 | } | ||
255 | 102 | |||
256 | 103 | Label { | ||
257 | 104 | text: i18n.tr("Choose new PIN:") | ||
258 | 105 | } | ||
259 | 106 | |||
260 | 107 | TextField { | ||
261 | 108 | id: newInput | ||
262 | 109 | echoMode: TextInput.Password | ||
263 | 110 | inputMethodHints: Qt.ImhDialableCharactersOnly | ||
264 | 111 | maximumLength: simMax | ||
265 | 112 | } | ||
266 | 113 | |||
267 | 114 | Label { | ||
268 | 115 | text: i18n.tr("Confirm new PIN:") | ||
269 | 116 | } | ||
270 | 117 | |||
271 | 118 | TextField { | ||
272 | 119 | id: confirmInput | ||
273 | 120 | echoMode: TextInput.Password | ||
274 | 121 | inputMethodHints: Qt.ImhDialableCharactersOnly | ||
275 | 122 | maximumLength: simMax | ||
276 | 123 | |||
277 | 124 | // Doesn't get updated if you set this in enabled of confirmButton | ||
278 | 125 | onTextChanged: confirmButton.enabled = | ||
279 | 126 | (acceptableInput && | ||
280 | 127 | text.length >= simMin && | ||
281 | 128 | (text === newInput.text)) | ||
282 | 129 | } | ||
283 | 130 | |||
284 | 131 | Label { | ||
285 | 132 | id: notMatching | ||
286 | 133 | wrapMode: Text.Wrap | ||
287 | 134 | text: i18n.tr("PINs don't match. Try again.") | ||
288 | 135 | visible: false | ||
289 | 136 | color: "darkred" | ||
290 | 137 | } | ||
291 | 138 | |||
292 | 139 | RowLayout { | ||
293 | 140 | spacing: units.gu(1) | ||
294 | 141 | |||
295 | 142 | Button { | ||
296 | 143 | Layout.fillWidth: true | ||
297 | 144 | color: UbuntuColors.lightGrey | ||
298 | 145 | text: i18n.tr("Cancel") | ||
299 | 146 | onClicked: PopupUtils.close(changePinDialog) | ||
300 | 147 | } | ||
301 | 148 | |||
302 | 149 | Button { | ||
303 | 150 | id: confirmButton | ||
304 | 151 | Layout.fillWidth: true | ||
305 | 152 | color: UbuntuColors.green | ||
306 | 153 | text: i18n.tr("Change") | ||
307 | 154 | enabled: false | ||
308 | 155 | onClicked: { | ||
309 | 156 | changePinDialog.enabled = false | ||
310 | 157 | var match = (newInput.text === confirmInput.text) | ||
311 | 158 | notMatching.visible = !match | ||
312 | 159 | if (!match) { | ||
313 | 160 | changePinDialog.enabled = true | ||
314 | 161 | newInput.forceActiveFocus() | ||
315 | 162 | newInput.selectAll() | ||
316 | 163 | return | ||
317 | 164 | } | ||
318 | 165 | curSim.changePin(OfonoSimManager.SimPin, currentInput.text, newInput.text); | ||
319 | 166 | } | ||
320 | 167 | } | ||
321 | 168 | } | ||
322 | 169 | } | ||
323 | 170 | } | ||
324 | 171 | |||
325 | 172 | Component { | ||
326 | 173 | id: lockDialogComponent | ||
327 | 174 | |||
328 | 175 | Dialog { | ||
329 | 176 | id: lockPinDialog | ||
330 | 177 | objectName: "lockDialogComponent" | ||
331 | 178 | title: curSim.lockedPins.length > 0 ? | ||
332 | 179 | i18n.tr("Enter SIM PIN") : | ||
333 | 180 | i18n.tr("Enter Previous SIM PIN") | ||
334 | 181 | |||
335 | 182 | property string errorText: i18n.tr( | ||
336 | 183 | "Incorrect PIN. %1 attempts remaining." | ||
337 | 184 | ).arg(curSim.pinRetries[OfonoSimManager.SimPin] || 3) | ||
338 | 185 | |||
339 | 186 | property int simMin: curSim.minimumPinLength(OfonoSimManager.SimPin) | ||
340 | 187 | property int simMax: curSim.maximumPinLength(OfonoSimManager.SimPin) | ||
341 | 188 | |||
342 | 189 | // This is a bit hacky, but the contents of this dialog get so tall | ||
343 | 190 | // that on a mako device, they don't fit with the OSK also visible. | ||
344 | 191 | // So we scrunch up spacing. | ||
345 | 192 | Binding { | ||
346 | 193 | target: __foreground | ||
347 | 194 | property: "itemSpacing" | ||
348 | 195 | value: units.gu(1) | ||
349 | 196 | } | ||
350 | 197 | |||
351 | 198 | Connections { | ||
352 | 199 | target: curSim | ||
353 | 200 | onLockPinComplete: { | ||
354 | 201 | if (error === OfonoSimManager.FailedError) { | ||
355 | 202 | console.warn("Lock PIN failed with: " + error); | ||
356 | 203 | incorrect.visible = true; | ||
357 | 204 | lockPinDialog.enabled = true; | ||
358 | 205 | prevInput.forceActiveFocus(); | ||
359 | 206 | prevInput.selectAll(); | ||
360 | 207 | return; | ||
361 | 208 | } | ||
362 | 209 | incorrect.visible = false; | ||
363 | 210 | lockPinDialog.enabled = true; | ||
364 | 211 | PopupUtils.close(lockPinDialog); | ||
365 | 212 | } | ||
366 | 213 | onUnlockPinComplete: { | ||
367 | 214 | if (error === OfonoSimManager.FailedError) { | ||
368 | 215 | console.warn("Unlock PIN failed with: " + error); | ||
369 | 216 | incorrect.visible = true; | ||
370 | 217 | lockPinDialog.enabled = true; | ||
371 | 218 | prevInput.forceActiveFocus(); | ||
372 | 219 | prevInput.selectAll(); | ||
373 | 220 | return; | ||
374 | 221 | } | ||
375 | 222 | incorrect.visible = false; | ||
376 | 223 | lockPinDialog.enabled = true; | ||
377 | 224 | PopupUtils.close(lockPinDialog); | ||
378 | 225 | } | ||
379 | 226 | } | ||
380 | 227 | |||
381 | 228 | TextField { | ||
382 | 229 | id: prevInput | ||
383 | 230 | objectName: "prevInput" | ||
384 | 231 | echoMode: TextInput.Password | ||
385 | 232 | inputMethodHints: Qt.ImhDialableCharactersOnly | ||
386 | 233 | maximumLength: simMax | ||
387 | 234 | |||
388 | 235 | // Doesn't get updated if you set this in enabled of confirmButton | ||
389 | 236 | onTextChanged: lockButton.enabled = | ||
390 | 237 | (acceptableInput && text.length >= simMin) | ||
391 | 238 | } | ||
392 | 239 | |||
393 | 240 | Label { | ||
394 | 241 | text: i18n.tr("%1 attempts remaining").arg( | ||
395 | 242 | curSim.pinRetries[OfonoSimManager.SimPin] || 3) | ||
396 | 243 | visible: !incorrect.visible | ||
397 | 244 | } | ||
398 | 245 | |||
399 | 246 | Label { | ||
400 | 247 | id: incorrect | ||
401 | 248 | text: errorText | ||
402 | 249 | visible: false | ||
403 | 250 | color: "darkred" | ||
404 | 251 | } | ||
405 | 252 | |||
406 | 253 | RowLayout { | ||
407 | 254 | spacing: units.gu(1) | ||
408 | 255 | |||
409 | 256 | Button { | ||
410 | 257 | objectName: "cancelButton" | ||
411 | 258 | Layout.fillWidth: true | ||
412 | 259 | color: UbuntuColors.lightGrey | ||
413 | 260 | text: i18n.tr("Cancel") | ||
414 | 261 | onClicked: { | ||
415 | 262 | if (curSim.lockedPins.length < 1) | ||
416 | 263 | caller.checked = false; | ||
417 | 264 | else | ||
418 | 265 | caller.checked = true; | ||
419 | 266 | PopupUtils.close(lockPinDialog); | ||
420 | 267 | } | ||
421 | 268 | } | ||
422 | 269 | |||
423 | 270 | Button { | ||
424 | 271 | id: lockButton | ||
425 | 272 | objectName: "lockButton" | ||
426 | 273 | Layout.fillWidth: true | ||
427 | 274 | color: UbuntuColors.green | ||
428 | 275 | |||
429 | 276 | text: curSim.lockedPins.length > 0 ? i18n.tr("Unlock") : i18n.tr("Lock") | ||
430 | 277 | enabled: false | ||
431 | 278 | onClicked: { | ||
432 | 279 | lockPinDialog.enabled = false; | ||
433 | 280 | if (curSim.lockedPins.length > 0) | ||
434 | 281 | curSim.unlockPin(OfonoSimManager.SimPin, prevInput.text); | ||
435 | 282 | else | ||
436 | 283 | curSim.lockPin(OfonoSimManager.SimPin, prevInput.text); | ||
437 | 284 | } | ||
438 | 285 | } | ||
439 | 286 | } | ||
440 | 287 | } | ||
441 | 288 | } | ||
442 | 289 | |||
443 | 290 | Column { | ||
444 | 291 | anchors.left: parent.left | ||
445 | 292 | anchors.right: parent.right | ||
446 | 293 | |||
447 | 294 | Repeater { | ||
448 | 295 | model: sims.length | ||
449 | 296 | Column { | ||
450 | 297 | anchors { | ||
451 | 298 | left: parent.left | ||
452 | 299 | right: parent.right | ||
453 | 300 | } | ||
454 | 301 | |||
455 | 302 | Connections { | ||
456 | 303 | target: sims[index].simMng | ||
457 | 304 | onLockedPinsChanged: { | ||
458 | 305 | simPinSwitch.checked = | ||
459 | 306 | sims[index].simMng.lockedPins.length > 0; | ||
460 | 307 | } | ||
461 | 308 | } | ||
462 | 309 | |||
463 | 310 | ListItem.Standard { | ||
464 | 311 | text: i18n.tr("%1").arg(sims[index].title) | ||
465 | 312 | visible: sims.length > 1 | ||
466 | 313 | } | ||
467 | 314 | |||
468 | 315 | ListItem.Standard { | ||
469 | 316 | text: i18n.tr("SIM PIN") | ||
470 | 317 | control: Switch { | ||
471 | 318 | id: simPinSwitch | ||
472 | 319 | objectName: "simPinSwitch" | ||
473 | 320 | checked: sims[index].simMng.lockedPins.length > 0 | ||
474 | 321 | onClicked: { | ||
475 | 322 | curSim = sims[index].simMng; | ||
476 | 323 | PopupUtils.open(lockDialogComponent, simPinSwitch); | ||
477 | 324 | } | ||
478 | 325 | } | ||
479 | 326 | showDivider: index < (sims.length - 1) && simPinSwitch.checked | ||
480 | 327 | } | ||
481 | 328 | |||
482 | 329 | ListItem.SingleControl { | ||
483 | 330 | id: changeControl | ||
484 | 331 | visible: sims[index].simMng.lockedPins.length > 0 | ||
485 | 332 | control: Button { | ||
486 | 333 | enabled: parent.visible | ||
487 | 334 | text: i18n.tr("Change PIN…") | ||
488 | 335 | width: parent.width - units.gu(4) | ||
489 | 336 | onClicked: { | ||
490 | 337 | curSim = sims[index].simMng; | ||
491 | 338 | PopupUtils.open(dialogComponent); | ||
492 | 339 | } | ||
493 | 340 | } | ||
494 | 341 | showDivider: false | ||
495 | 342 | } | ||
496 | 343 | ListItem.Divider { | ||
497 | 344 | visible: index < (sims.length - 1) | ||
498 | 345 | } | ||
499 | 346 | |||
500 | 347 | } | ||
501 | 348 | } | ||
502 | 349 | |||
503 | 350 | ListItem.Caption { | ||
504 | 351 | text: i18n.tr("When a SIM PIN is set, it must be entered to access cellular services after restarting the phone or swapping the SIM.") | ||
505 | 352 | } | ||
506 | 353 | |||
507 | 354 | ListItem.Caption { | ||
508 | 355 | text: i18n.tr("Entering an incorrect PIN repeatedly may lock the SIM permanently.") | ||
509 | 356 | } | ||
510 | 357 | } | ||
511 | 358 | } | ||
512 | 0 | 359 | ||
513 | === added file 'plugins/security-privacy/sims.js' | |||
514 | --- plugins/security-privacy/sims.js 1970-01-01 00:00:00 +0000 | |||
515 | +++ plugins/security-privacy/sims.js 2014-08-27 21:27:21 +0000 | |||
516 | @@ -0,0 +1,34 @@ | |||
517 | 1 | var sims = []; | ||
518 | 2 | |||
519 | 3 | function add (sim) { | ||
520 | 4 | sims.push(sim); | ||
521 | 5 | root.simsLoaded++; | ||
522 | 6 | } | ||
523 | 7 | |||
524 | 8 | function getAll () { | ||
525 | 9 | return sims; | ||
526 | 10 | } | ||
527 | 11 | |||
528 | 12 | function get (n) { | ||
529 | 13 | return getAll()[n]; | ||
530 | 14 | } | ||
531 | 15 | |||
532 | 16 | function getCount () { | ||
533 | 17 | return getAll().length; | ||
534 | 18 | } | ||
535 | 19 | |||
536 | 20 | function getPresent () { | ||
537 | 21 | var present = []; | ||
538 | 22 | getAll().forEach(function (sim) { | ||
539 | 23 | if (sim.present) { | ||
540 | 24 | present.push(sim); | ||
541 | 25 | } else { | ||
542 | 26 | return; | ||
543 | 27 | } | ||
544 | 28 | }); | ||
545 | 29 | return present; | ||
546 | 30 | } | ||
547 | 31 | |||
548 | 32 | function getPresentCount () { | ||
549 | 33 | return getPresent().length; | ||
550 | 34 | } | ||
551 | 0 | 35 | ||
552 | === modified file 'src/qml/CategoryGrid.qml' | |||
553 | --- src/qml/CategoryGrid.qml 2014-08-05 13:27:35 +0000 | |||
554 | +++ src/qml/CategoryGrid.qml 2014-08-27 21:27:21 +0000 | |||
555 | @@ -59,6 +59,7 @@ | |||
556 | 59 | pageStack.push(model.item.pageComponent, | 59 | pageStack.push(model.item.pageComponent, |
557 | 60 | { plugin: model.item, pluginManager: pluginManager }) | 60 | { plugin: model.item, pluginManager: pluginManager }) |
558 | 61 | } | 61 | } |
559 | 62 | loader.item.highlighted = false; | ||
560 | 62 | } | 63 | } |
561 | 63 | } | 64 | } |
562 | 64 | } | 65 | } |
563 | 65 | 66 | ||
564 | === modified file 'tests/autopilot/ubuntu_system_settings/tests/__init__.py' | |||
565 | --- tests/autopilot/ubuntu_system_settings/tests/__init__.py 2014-08-26 15:48:32 +0000 | |||
566 | +++ tests/autopilot/ubuntu_system_settings/tests/__init__.py 2014-08-27 21:27:21 +0000 | |||
567 | @@ -191,23 +191,6 @@ | |||
568 | 191 | "PropertyChanged", "sv", [args[0], args[1]])' | 191 | "PropertyChanged", "sv", [args[0], args[1]])' |
569 | 192 | .replace('IFACE', RDO_IFACE)), ]) | 192 | .replace('IFACE', RDO_IFACE)), ]) |
570 | 193 | 193 | ||
571 | 194 | def mock_sim_manager(self, modem, properties=None): | ||
572 | 195 | if not properties: | ||
573 | 196 | properties = { | ||
574 | 197 | 'SubscriberNumbers': ['123456', '234567'] | ||
575 | 198 | } | ||
576 | 199 | modem.AddProperties(SIM_IFACE, properties) | ||
577 | 200 | modem.AddProperty(SIM_IFACE, 'Present', True) | ||
578 | 201 | modem.AddMethods( | ||
579 | 202 | SIM_IFACE, | ||
580 | 203 | [('GetProperties', '', 'a{sv}', | ||
581 | 204 | 'ret = self.GetAll("%s")' % SIM_IFACE), | ||
582 | 205 | ('SetProperty', 'sv', '', | ||
583 | 206 | 'self.Set("IFACE", args[0], args[1]); ' | ||
584 | 207 | 'self.EmitSignal("IFACE",\ | ||
585 | 208 | "PropertyChanged", "sv", [args[0], args[1]])' | ||
586 | 209 | .replace('IFACE', SIM_IFACE)), ]) | ||
587 | 210 | |||
588 | 211 | def mock_call_forwarding(self, modem): | 194 | def mock_call_forwarding(self, modem): |
589 | 212 | modem.AddProperty( | 195 | modem.AddProperty( |
590 | 213 | CALL_FWD_IFACE, 'VoiceUnconditional', '') | 196 | CALL_FWD_IFACE, 'VoiceUnconditional', '') |
591 | @@ -241,7 +224,6 @@ | |||
592 | 241 | self.mock_carriers('ril_0') | 224 | self.mock_carriers('ril_0') |
593 | 242 | self.mock_radio_settings(self.modem_0) | 225 | self.mock_radio_settings(self.modem_0) |
594 | 243 | self.mock_connection_manager(self.modem_0) | 226 | self.mock_connection_manager(self.modem_0) |
595 | 244 | self.mock_sim_manager(self.modem_0) | ||
596 | 245 | self.mock_call_forwarding(self.modem_0) | 227 | self.mock_call_forwarding(self.modem_0) |
597 | 246 | self.mock_call_settings(self.modem_0) | 228 | self.mock_call_settings(self.modem_0) |
598 | 247 | 229 | ||
599 | @@ -276,9 +258,10 @@ | |||
600 | 276 | self.mock_call_forwarding(self.modem_1) | 258 | self.mock_call_forwarding(self.modem_1) |
601 | 277 | self.mock_call_settings(self.modem_1) | 259 | self.mock_call_settings(self.modem_1) |
602 | 278 | 260 | ||
606 | 279 | self.mock_sim_manager(self.modem_1, { | 261 | self.modem_1.Set( |
607 | 280 | 'SubscriberNumbers': ['08123', '938762783'] | 262 | SIM_IFACE, |
608 | 281 | }) | 263 | 'SubscriberNumbers', ['08123', '938762783'] |
609 | 264 | ) | ||
610 | 282 | 265 | ||
611 | 283 | @classmethod | 266 | @classmethod |
612 | 284 | def setUpClass(cls): | 267 | def setUpClass(cls): |
613 | @@ -679,7 +662,7 @@ | |||
614 | 679 | super(ResetBaseTestCase, self).tearDown() | 662 | super(ResetBaseTestCase, self).tearDown() |
615 | 680 | 663 | ||
616 | 681 | 664 | ||
618 | 682 | class SecurityBaseTestCase(UbuntuSystemSettingsTestCase): | 665 | class SecurityBaseTestCase(UbuntuSystemSettingsOfonoTestCase): |
619 | 683 | """ Base class for security and privacy settings tests""" | 666 | """ Base class for security and privacy settings tests""" |
620 | 684 | 667 | ||
621 | 685 | def setUp(self): | 668 | def setUp(self): |
622 | 686 | 669 | ||
623 | === modified file 'tests/autopilot/ubuntu_system_settings/tests/ofono.py' | |||
624 | --- tests/autopilot/ubuntu_system_settings/tests/ofono.py 2014-08-19 12:35:00 +0000 | |||
625 | +++ tests/autopilot/ubuntu_system_settings/tests/ofono.py 2014-08-27 21:27:21 +0000 | |||
626 | @@ -81,6 +81,7 @@ | |||
627 | 81 | ]) | 81 | ]) |
628 | 82 | obj = dbusmock.mockobject.objects[path] | 82 | obj = dbusmock.mockobject.objects[path] |
629 | 83 | obj.name = name | 83 | obj.name = name |
630 | 84 | add_simmanager_api(obj) | ||
631 | 84 | add_voice_call_api(obj) | 85 | add_voice_call_api(obj) |
632 | 85 | add_netreg_api(obj) | 86 | add_netreg_api(obj) |
633 | 86 | self.modems.append(path) | 87 | self.modems.append(path) |
634 | @@ -89,6 +90,39 @@ | |||
635 | 89 | return path | 90 | return path |
636 | 90 | 91 | ||
637 | 91 | 92 | ||
638 | 93 | def add_simmanager_api(mock): | ||
639 | 94 | '''Add org.ofono.SimManager API to a mock''' | ||
640 | 95 | |||
641 | 96 | iface = 'org.ofono.SimManager' | ||
642 | 97 | mock.AddProperties(iface, { | ||
643 | 98 | 'CardIdentifier': _parameters.get('CardIdentifier', 12345), | ||
644 | 99 | 'Present': _parameters.get('Present', dbus.Boolean(True)), | ||
645 | 100 | 'SubscriberNumbers': _parameters.get('SubscriberNumbers', | ||
646 | 101 | ['123456789', '234567890']), | ||
647 | 102 | 'SubscriberIdentity': _parameters.get('SubscriberIdentity', 23456), | ||
648 | 103 | 'LockedPins': _parameters.get('LockedPins', ['pin']), | ||
649 | 104 | 'Retries': _parameters.get('Retries', {'pin': dbus.Byte(3)}), | ||
650 | 105 | 'PinRequired': _parameters.get('PinRequired', 'none') | ||
651 | 106 | }) | ||
652 | 107 | |||
653 | 108 | mock.AddMethods(iface, [ | ||
654 | 109 | ('GetProperties', '', 'a{sv}', 'ret = self.GetAll("%s")' % iface), | ||
655 | 110 | ('SetProperty', 'sv', '', 'self.Set("%(i)s", args[0], args[1]); ' | ||
656 | 111 | 'self.EmitSignal("%(i)s", "PropertyChanged", "sv", [args[0], ' | ||
657 | 112 | 'args[1]])' % {'i': iface}), | ||
658 | 113 | ('ChangePin', 'sss', '', ''), | ||
659 | 114 | ('EnterPin', 'ss', '', ''), | ||
660 | 115 | ('ResetPin', 'sss', '', ''), | ||
661 | 116 | ('LockPin', 'ss', '', 'if args[1] == "2468": self.Set("%(i)s",' | ||
662 | 117 | '"LockedPins", dbus.Array(["pin"])); self.EmitSignal("%(i)s",' | ||
663 | 118 | '"PropertyChanged", "sv", ["LockedPins", self.Get("%(i)s", ' | ||
664 | 119 | '"LockedPins")])' % {'i': iface}), | ||
665 | 120 | ('UnlockPin', 'ss', '', 'if args[1] == "2468": self.Set("%(i)s",' | ||
666 | 121 | '"LockedPins", ""); self.EmitSignal("%(i)s", "PropertyChanged", "sv",' | ||
667 | 122 | ' ["LockedPins", self.Get("%(i)s", "LockedPins")])' % {'i': iface}) | ||
668 | 123 | ]) | ||
669 | 124 | |||
670 | 125 | |||
671 | 92 | def add_voice_call_api(mock): | 126 | def add_voice_call_api(mock): |
672 | 93 | '''Add org.ofono.VoiceCallManager API to a mock''' | 127 | '''Add org.ofono.VoiceCallManager API to a mock''' |
673 | 94 | 128 | ||
674 | 95 | 129 | ||
675 | === modified file 'tests/autopilot/ubuntu_system_settings/tests/test_security.py' | |||
676 | --- tests/autopilot/ubuntu_system_settings/tests/test_security.py 2014-08-21 21:08:31 +0000 | |||
677 | +++ tests/autopilot/ubuntu_system_settings/tests/test_security.py 2014-08-27 21:27:21 +0000 | |||
678 | @@ -7,10 +7,13 @@ | |||
679 | 7 | 7 | ||
680 | 8 | from gi.repository import Gio | 8 | from gi.repository import Gio |
681 | 9 | from time import sleep | 9 | from time import sleep |
682 | 10 | import unittest | ||
683 | 10 | from testtools.matchers import Equals, NotEquals | 11 | from testtools.matchers import Equals, NotEquals |
684 | 11 | from autopilot.matchers import Eventually | 12 | from autopilot.matchers import Eventually |
685 | 12 | 13 | ||
687 | 13 | from ubuntu_system_settings.tests import SecurityBaseTestCase | 14 | from ubuntu_system_settings.tests import ( |
688 | 15 | SecurityBaseTestCase, | ||
689 | 16 | SIM_IFACE) | ||
690 | 14 | 17 | ||
691 | 15 | from ubuntu_system_settings.utils.i18n import ugettext as _ | 18 | from ubuntu_system_settings.utils.i18n import ugettext as _ |
692 | 16 | from ubuntuuitoolkit import emulators as toolkit_emulators | 19 | from ubuntuuitoolkit import emulators as toolkit_emulators |
693 | @@ -21,6 +24,7 @@ | |||
694 | 21 | 24 | ||
695 | 22 | def setUp(self): | 25 | def setUp(self): |
696 | 23 | super(SecurityTestCase, self).setUp() | 26 | super(SecurityTestCase, self).setUp() |
697 | 27 | self.assertEqual(['pin'], self.modem_0.Get(SIM_IFACE, 'LockedPins')) | ||
698 | 24 | prps = self.system_settings.main_view.security_page.get_properties() | 28 | prps = self.system_settings.main_view.security_page.get_properties() |
699 | 25 | self.use_powerd = prps['usePowerd'] | 29 | self.use_powerd = prps['usePowerd'] |
700 | 26 | if self.use_powerd: | 30 | if self.use_powerd: |
701 | @@ -64,6 +68,12 @@ | |||
702 | 64 | ) | 68 | ) |
703 | 65 | self.system_settings.main_view.scroll_to_and_click(selector) | 69 | self.system_settings.main_view.scroll_to_and_click(selector) |
704 | 66 | 70 | ||
705 | 71 | def _go_to_sim_lock(self): | ||
706 | 72 | selector = self.security_page.select_single( | ||
707 | 73 | objectName="simControl" | ||
708 | 74 | ) | ||
709 | 75 | self.system_settings.main_view.scroll_to_and_click(selector) | ||
710 | 76 | |||
711 | 67 | def _go_to_sleep_values(self): | 77 | def _go_to_sleep_values(self): |
712 | 68 | self._go_to_phone_lock() | 78 | self._go_to_phone_lock() |
713 | 69 | selector = self.system_settings.main_view.select_single( | 79 | selector = self.system_settings.main_view.select_single( |
714 | @@ -171,3 +181,210 @@ | |||
715 | 171 | selected_delegate = selector.select_single( | 181 | selected_delegate = selector.select_single( |
716 | 172 | 'OptionSelectorDelegate', selected=True) | 182 | 'OptionSelectorDelegate', selected=True) |
717 | 173 | self.assertEquals(selected_delegate.text, 'After 4 minutes') | 183 | self.assertEquals(selected_delegate.text, 'After 4 minutes') |
718 | 184 | |||
719 | 185 | def test_sim_pin_control_value(self): | ||
720 | 186 | self.assertEqual('none', self.modem_0.Get(SIM_IFACE, 'PinRequired')) | ||
721 | 187 | self.assertEqual(['pin'], self.modem_0.Get(SIM_IFACE, 'LockedPins')) | ||
722 | 188 | |||
723 | 189 | sim_pin_value = self.security_page.select_single( | ||
724 | 190 | objectName='simControl').value | ||
725 | 191 | |||
726 | 192 | self.assertThat( | ||
727 | 193 | sim_pin_value, | ||
728 | 194 | Equals(_('On')) | ||
729 | 195 | ) | ||
730 | 196 | |||
731 | 197 | def test_sim_pin_lock_control(self): | ||
732 | 198 | self._go_to_sim_lock() | ||
733 | 199 | sim_lock_control = self.system_settings.main_view.select_single( | ||
734 | 200 | objectName='simPinSwitch') | ||
735 | 201 | locked = len(self.modem_0.Get(SIM_IFACE, 'LockedPins')) > 0 | ||
736 | 202 | self.assertEquals(locked, sim_lock_control.checked) | ||
737 | 203 | |||
738 | 204 | def test_sim_pin_lock_control_unlock(self): | ||
739 | 205 | self._go_to_sim_lock() | ||
740 | 206 | sim_lock_control = self.system_settings.main_view.select_single( | ||
741 | 207 | objectName='simPinSwitch') | ||
742 | 208 | |||
743 | 209 | self.assertTrue(sim_lock_control.checked) | ||
744 | 210 | |||
745 | 211 | self.system_settings.main_view.scroll_to_and_click(sim_lock_control) | ||
746 | 212 | |||
747 | 213 | lock_dialog = self.system_settings.main_view.select_single( | ||
748 | 214 | objectName='lockDialogComponent') | ||
749 | 215 | self.assertEqual( | ||
750 | 216 | lock_dialog.title, | ||
751 | 217 | _("Enter SIM PIN") | ||
752 | 218 | ) | ||
753 | 219 | |||
754 | 220 | prev_input = self.system_settings.main_view.select_single( | ||
755 | 221 | objectName='prevInput') | ||
756 | 222 | submit_button = self.system_settings.main_view.select_single( | ||
757 | 223 | objectName='lockButton') | ||
758 | 224 | |||
759 | 225 | self.assertEqual( | ||
760 | 226 | submit_button.text, | ||
761 | 227 | _("Unlock") | ||
762 | 228 | ) | ||
763 | 229 | |||
764 | 230 | self.assertFalse( | ||
765 | 231 | submit_button.get_properties()['enabled'] | ||
766 | 232 | ) | ||
767 | 233 | self.system_settings.main_view.scroll_to_and_click(prev_input) | ||
768 | 234 | self.keyboard.type("246") | ||
769 | 235 | self.assertFalse( | ||
770 | 236 | submit_button.get_properties()['enabled'] | ||
771 | 237 | ) | ||
772 | 238 | self.keyboard.type("8") | ||
773 | 239 | |||
774 | 240 | self.assertTrue( | ||
775 | 241 | submit_button.get_properties()['enabled'] | ||
776 | 242 | ) | ||
777 | 243 | |||
778 | 244 | self.system_settings.main_view.scroll_to_and_click(submit_button) | ||
779 | 245 | |||
780 | 246 | self.assertFalse(sim_lock_control.checked) | ||
781 | 247 | |||
782 | 248 | locked = len(self.modem_0.Get(SIM_IFACE, 'LockedPins')) > 0 | ||
783 | 249 | self.assertEquals(locked, sim_lock_control.checked) | ||
784 | 250 | |||
785 | 251 | @unittest.skip('skipped because the simPinSwitch state fails to update') | ||
786 | 252 | def test_sim_pin_lock_control_lock(self): | ||
787 | 253 | self.modem_0.Set(SIM_IFACE, 'LockedPins', "") | ||
788 | 254 | self._go_to_sim_lock() | ||
789 | 255 | sim_lock_control = self.system_settings.main_view.select_single( | ||
790 | 256 | objectName='simPinSwitch') | ||
791 | 257 | |||
792 | 258 | self.assertFalse(sim_lock_control.checked) | ||
793 | 259 | |||
794 | 260 | self.system_settings.main_view.scroll_to_and_click(sim_lock_control) | ||
795 | 261 | |||
796 | 262 | lock_dialog = self.system_settings.main_view.select_single( | ||
797 | 263 | objectName='lockDialogComponent') | ||
798 | 264 | self.assertEqual( | ||
799 | 265 | lock_dialog.title, | ||
800 | 266 | _("Enter SIM PIN") | ||
801 | 267 | ) | ||
802 | 268 | |||
803 | 269 | prev_input = self.system_settings.main_view.select_single( | ||
804 | 270 | objectName='prevInput') | ||
805 | 271 | submit_button = self.system_settings.main_view.select_single( | ||
806 | 272 | objectName='lockButton') | ||
807 | 273 | |||
808 | 274 | self.assertEqual( | ||
809 | 275 | submit_button.text, | ||
810 | 276 | _("Lock") | ||
811 | 277 | ) | ||
812 | 278 | |||
813 | 279 | self.assertFalse( | ||
814 | 280 | submit_button.get_properties()['enabled'] | ||
815 | 281 | ) | ||
816 | 282 | self.system_settings.main_view.scroll_to_and_click(prev_input) | ||
817 | 283 | self.keyboard.type("246") | ||
818 | 284 | self.assertFalse( | ||
819 | 285 | submit_button.get_properties()['enabled'] | ||
820 | 286 | ) | ||
821 | 287 | self.keyboard.type("8") | ||
822 | 288 | |||
823 | 289 | self.assertTrue( | ||
824 | 290 | submit_button.get_properties()['enabled'] | ||
825 | 291 | ) | ||
826 | 292 | |||
827 | 293 | self.system_settings.main_view.scroll_to_and_click(submit_button) | ||
828 | 294 | |||
829 | 295 | self.assertTrue(sim_lock_control.checked) | ||
830 | 296 | |||
831 | 297 | self.assertEqual(['pin'], self.modem_0.Get(SIM_IFACE, 'LockedPins')) | ||
832 | 298 | locked = len(self.modem_0.Get(SIM_IFACE, 'LockedPins')) > 0 | ||
833 | 299 | self.assertEquals(locked, sim_lock_control.checked) | ||
834 | 300 | |||
835 | 301 | def test_sim_pin_lock_control_unlock_fail(self): | ||
836 | 302 | self._go_to_sim_lock() | ||
837 | 303 | sim_lock_control = self.system_settings.main_view.select_single( | ||
838 | 304 | objectName='simPinSwitch') | ||
839 | 305 | |||
840 | 306 | self.assertTrue( | ||
841 | 307 | len(self.modem_0.Get(SIM_IFACE, 'LockedPins')) > 0 | ||
842 | 308 | ) | ||
843 | 309 | self.assertTrue(sim_lock_control.checked) | ||
844 | 310 | |||
845 | 311 | self.system_settings.main_view.scroll_to_and_click(sim_lock_control) | ||
846 | 312 | |||
847 | 313 | lock_dialog = self.system_settings.main_view.select_single( | ||
848 | 314 | objectName='lockDialogComponent') | ||
849 | 315 | self.assertEqual( | ||
850 | 316 | lock_dialog.title, | ||
851 | 317 | _("Enter SIM PIN") | ||
852 | 318 | ) | ||
853 | 319 | |||
854 | 320 | prev_input = self.system_settings.main_view.select_single( | ||
855 | 321 | objectName='prevInput') | ||
856 | 322 | submit_button = self.system_settings.main_view.select_single( | ||
857 | 323 | objectName='lockButton') | ||
858 | 324 | |||
859 | 325 | self.assertEqual( | ||
860 | 326 | submit_button.text, | ||
861 | 327 | _("Unlock") | ||
862 | 328 | ) | ||
863 | 329 | |||
864 | 330 | self.assertFalse( | ||
865 | 331 | submit_button.get_properties()['enabled'] | ||
866 | 332 | ) | ||
867 | 333 | self.system_settings.main_view.scroll_to_and_click(prev_input) | ||
868 | 334 | self.keyboard.type("1234") | ||
869 | 335 | |||
870 | 336 | self.assertTrue( | ||
871 | 337 | submit_button.get_properties()['enabled'] | ||
872 | 338 | ) | ||
873 | 339 | |||
874 | 340 | self.system_settings.main_view.scroll_to_and_click(submit_button) | ||
875 | 341 | |||
876 | 342 | self.assertTrue( | ||
877 | 343 | len(self.modem_0.Get(SIM_IFACE, 'LockedPins')) > 0 | ||
878 | 344 | ) | ||
879 | 345 | |||
880 | 346 | @unittest.skip('skipped because the simPinSwitch state fails to update') | ||
881 | 347 | def test_sim_pin_lock_control_lock_fail(self): | ||
882 | 348 | self.modem_0.Set(SIM_IFACE, 'LockedPins', "") | ||
883 | 349 | self._go_to_sim_lock() | ||
884 | 350 | sim_lock_control = self.system_settings.main_view.select_single( | ||
885 | 351 | objectName='simPinSwitch') | ||
886 | 352 | |||
887 | 353 | self.assertFalse( | ||
888 | 354 | len(self.modem_0.Get(SIM_IFACE, 'LockedPins')) > 0 | ||
889 | 355 | ) | ||
890 | 356 | |||
891 | 357 | self.system_settings.main_view.scroll_to_and_click(sim_lock_control) | ||
892 | 358 | |||
893 | 359 | lock_dialog = self.system_settings.main_view.select_single( | ||
894 | 360 | objectName='lockDialogComponent') | ||
895 | 361 | self.assertEqual( | ||
896 | 362 | lock_dialog.title, | ||
897 | 363 | _("Enter SIM PIN") | ||
898 | 364 | ) | ||
899 | 365 | |||
900 | 366 | prev_input = self.system_settings.main_view.select_single( | ||
901 | 367 | objectName='prevInput') | ||
902 | 368 | submit_button = self.system_settings.main_view.select_single( | ||
903 | 369 | objectName='lockButton') | ||
904 | 370 | |||
905 | 371 | self.assertEqual( | ||
906 | 372 | submit_button.text, | ||
907 | 373 | _("Lock") | ||
908 | 374 | ) | ||
909 | 375 | |||
910 | 376 | self.assertFalse( | ||
911 | 377 | submit_button.get_properties()['enabled'] | ||
912 | 378 | ) | ||
913 | 379 | self.system_settings.main_view.scroll_to_and_click(prev_input) | ||
914 | 380 | self.keyboard.type("1234") | ||
915 | 381 | |||
916 | 382 | self.assertTrue( | ||
917 | 383 | submit_button.get_properties()['enabled'] | ||
918 | 384 | ) | ||
919 | 385 | |||
920 | 386 | self.system_settings.main_view.scroll_to_and_click(submit_button) | ||
921 | 387 | |||
922 | 388 | self.assertFalse( | ||
923 | 389 | len(self.modem_0.Get(SIM_IFACE, 'LockedPins')) > 0 | ||
924 | 390 | ) |
PASSED: Continuous integration, rev:929 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- ci/1313/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/4134 jenkins. qa.ubuntu. com/job/ generic- mediumtests- utopic/ 3146 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- utopic- i386-ci/ 505 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/3964 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/5386 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/5386/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 12225 jenkins. qa.ubuntu. com/job/ autopilot- testrunner- otto-utopic/ 2571 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/3433 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/3433/ artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- system- settings- ci/1313/ rebuild
http://