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