Merge lp:~ken-vandine/ubuntu-system-settings/security_panel into lp:ubuntu-system-settings

Proposed by Ken VanDine
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
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

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

Improved handling of zero sim

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

cleaned up debug output

Revision history for this message
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?

review: Needs Fixing
932. By Ken VanDine

merged prereq

Revision history for this message
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?

review: Needs Fixing
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

Revision history for this message
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!

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

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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+ )

Subscribers

People subscribed via source and target branches