on xenial help sign in
allow variable pin length for SIM PIN lockscreen
7f29b04Michael Zanetti
Components/PinPadButton.qml+40−13
@@ -21,24 +21,51 @@ Item {
21 id: root
21 id: root
22
22
23 property alias text: label.text
23 property alias text: label.text
24− property alias iconName: icon.name
24+ property alias subText: subTextLabel.text
25+ property string iconName
25
26
26 signal clicked()
27 signal clicked()
27
28
28− Label {
29+ Column {
29− id: label
30 anchors.centerIn: parent
30 anchors.centerIn: parent
31− color: "#f3f3e7"
31+ width: parent.width
32− fontSize: "large"
32+ height: childrenRect.height
33− font.weight: Font.DemiBold
34− }
35
33
34+ Item {
35+ anchors {
36+ left: parent.left
37+ right: parent.right
38+ }
39+ height: label.visible || icon.visible ? Math.max(label.height, icon.height) : 0
40+
41+ Label {
42+ id: label
43+ anchors.centerIn: parent
44+ width: parent.width
45+ horizontalAlignment: Text.AlignHCenter
46+ color: "#f3f3e7"
47+ fontSize: "large"
48+ font.weight: Font.DemiBold
49+ visible: text.length > 0
50+ }
51+
36− Icon {
52+ Icon {
37− id: icon
53+ id: icon
38− height: units.gu(3)
54+ height: units.gu(3)
39− width: height
55+ width: height
40− anchors.centerIn: parent
56+ anchors.centerIn: parent
57+ name: root.iconName
41− color: "#f3f3e7"
58+ color: "#f3f3e7"
59+ visible: name.length > 0
60+ }
61+ }
62+ Label {
63+ id: subTextLabel
64+ fontSize: "small"
65+ color: "grey"
66+ anchors.horizontalCenter: parent.horizontalCenter
67+ visible: text.length > 0
68+ }
42 }
69 }
43
70
44 MouseArea {
71 MouseArea {
Greeter/PinLockscreen.qml+33−4
@@ -27,7 +27,7 @@ Column {
27 property alias placeholderText: pinentryField.placeholderText
27 property alias placeholderText: pinentryField.placeholderText
28 property int padWidth: units.gu(34)
28 property int padWidth: units.gu(34)
29 property int padHeight: units.gu(28)
29 property int padHeight: units.gu(28)
30− property int pinLength: 4
30+ property int pinLength: -1
31
31
32 signal entered(string passphrase)
32 signal entered(string passphrase)
33 signal cancel()
33 signal cancel()
@@ -65,6 +65,9 @@ Column {
65 Label {
65 Label {
66 id: pinentryFieldLabel
66 id: pinentryFieldLabel
67 anchors.centerIn: parent
67 anchors.centerIn: parent
68+ width: parent.width - (backspaceIcon.width + backspaceIcon.anchors.rightMargin) * 2
69+ elide: Text.ElideMiddle
70+ horizontalAlignment: Text.AlignHCenter
68 font.pixelSize: units.dp(44)
71 font.pixelSize: units.dp(44)
69 color: "#f3f3e7"
72 color: "#f3f3e7"
70 opacity: 0.6
73 opacity: 0.6
@@ -76,6 +79,25 @@ Column {
76 text: parent.placeholderText
79 text: parent.placeholderText
77 visible: pinentryFieldLabel.text.length == 0
80 visible: pinentryFieldLabel.text.length == 0
78 }
81 }
82+
83+ Icon {
84+ id: backspaceIcon
85+ anchors {
86+ top: parent.top
87+ topMargin: units.gu(1)
88+ right: parent.right
89+ rightMargin: units.gu(2)
90+ bottom: parent.bottom
91+ bottomMargin: units.gu(1)
92+ }
93+ visible: root.pinLength == -1
94+ width: height
95+ name: "erase"
96+ MouseArea {
97+ anchors.fill: parent
98+ onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
99+ }
100+ }
79 }
101 }
80
102
81 UbuntuShape {
103 UbuntuShape {
@@ -154,7 +176,7 @@ Column {
154 objectName: "pinPadButtonBack"
176 objectName: "pinPadButtonBack"
155 width: root.padWidth / 3
177 width: root.padWidth / 3
156 height: root.padHeight / 4
178 height: root.padHeight / 4
157− iconName: "back"
179+ subText: "CANCEL"
158 onClicked: root.cancel();
180 onClicked: root.cancel();
159 }
181 }
160
182
@@ -171,8 +193,15 @@ Column {
171 objectName: "pinPadButtonErase"
193 objectName: "pinPadButtonErase"
172 width: root.padWidth / 3
194 width: root.padWidth / 3
173 height: root.padHeight / 4
195 height: root.padHeight / 4
174− iconName: "erase"
196+ iconName: root.pinLength == -1 ? "" : "erase"
197+ subText: root.pinLength == -1 ? "DONE" : ""
198+ onClicked: {
199+ if (root.pinLength !== -1) {
175− onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
200+ pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
201+ } else {
202+ root.entered(pinentryField.text);
203+ }
204+ }
176 enabled: entryEnabled
205 enabled: entryEnabled
177 }
206 }
178 }
207 }
Notifications/NotificationMenuItemFactory.qml−5
@@ -78,11 +78,6 @@ Loader {
78 PinLockscreen {
78 PinLockscreen {
79 anchors.left: parent.left; anchors.right: parent.right
79 anchors.left: parent.left; anchors.right: parent.right
80
80
81− Component.onCompleted: {
82− menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-pin-length': 'int'});
83− pinLength = menuData.ext.xCanonicalPinLength;
84− }
85−
86 onEntered: {
81 onEntered: {
87 menuModel.changeState(menuIndex, passphrase);
82 menuModel.changeState(menuIndex, passphrase);
88 entryEnabled = false;
83 entryEnabled = false;
tests/qmltests/Greeter/tst_Lockscreen.qml+11−4
@@ -176,15 +176,17 @@ Rectangle {
176
176
177 function test_unlock_data() {
177 function test_unlock_data() {
178 return [
178 return [
179− {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", unlockedSignal: true},
179+ {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", unlockedSignal: true, pinLength: 4},
180− {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", unlockedSignal: true},
180+ {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", unlockedSignal: true, pinLength: -1},
181− {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", unlockedSignal: false},
181+ {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", unlockedSignal: false, pinLength: 4},
182− {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", unlockedSignal: false},
182+ {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", unlockedSignal: false, pinLength: -1},
183+ {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", unlockedSignal: true, pinLength: -1},
183 ]
184 ]
184 }
185 }
185
186
186 function test_unlock(data) {
187 function test_unlock(data) {
187 unlockedCheckBox.checked = false
188 unlockedCheckBox.checked = false
189+ pinLengthTextField.text = data.pinLength
188 LightDM.Greeter.authenticate(data.username)
190 LightDM.Greeter.authenticate(data.username)
189 waitForRendering(lockscreen)
191 waitForRendering(lockscreen)
190
192
@@ -199,7 +201,12 @@ Rectangle {
199 var button = findChild(lockscreen, "pinPadButton" + character)
201 var button = findChild(lockscreen, "pinPadButton" + character)
200 mouseClick(button, units.gu(1), units.gu(1))
202 mouseClick(button, units.gu(1), units.gu(1))
201 }
203 }
204+ if (data.pinLength == -1) {
205+ var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
206+ mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
207+ }
202 }
208 }
209+
203 tryCompare(unlockedCheckBox, "checked", data.unlockedSignal)
210 tryCompare(unlockedCheckBox, "checked", data.unlockedSignal)
204 if (!data.unlockedSignal) {
211 if (!data.unlockedSignal) {
205 // make sure the input is cleared on wrong input
212 // make sure the input is cleared on wrong input