@@ -23,25 +23,34 @@ import LightDM 0.1 as LightDM
2323import Unity.Test 0.1 as UT
2424
2525Rectangle {
26− width: units.gu(60)
26+ id: root
27+ width: units.gu(80)
2728 height: units.gu(80)
2829 color: "orange"
2930
3031 Lockscreen {
3132 id: lockscreen
3233 anchors.fill: parent
33− anchors.rightMargin: units.gu(18)
34+ anchors.rightMargin: units.gu(30)
3435 placeholderText: "Please enter your PIN"
36+ wrongPlaceholderText: "Incorrect PIN"
37+ retryText: retryCountTextField.text
3538 alphaNumeric: pinPadCheckBox.checked
36− pinLength: pinLengthTextField.text
39+ minPinLength: minPinLengthTextField.text
40+ maxPinLength: maxPinLengthTextField.text
3741 username: "Lola"
42+ background: "../../../qml/graphics/phone_background.jpg"
43+ infoText: infoTextTextField.text
3844 }
3945
4046 Connections {
4147 target: lockscreen
4248
4349 onEmergencyCall: emergencyCheckBox.checked = true
44− onEntered: enteredLabel.text = passphrase
50+ onEntered: {
51+ enteredLabel.text = passphrase
52+ lockscreen.clear(true)
53+ }
4554 }
4655
4756 Connections {
@@ -49,9 +58,9 @@ Rectangle {
4958
5059 onShowPrompt: {
5160 if (text.indexOf("PIN") >= 0) {
52− lockscreen.alphaNumeric = false
61+ pinPadCheckBox.checked = false
5362 } else {
54− lockscreen.alphaNumeric = true
63+ pinPadCheckBox.checked = true
5564 }
5665 lockscreen.placeholderText = text;
5766 }
@@ -65,6 +74,7 @@ Rectangle {
6574 Column {
6675 anchors.fill: parent
6776 anchors.margins: units.gu(1)
77+ spacing: units.gu(1)
6878
6979 Row {
7080 CheckBox {
@@ -86,12 +96,32 @@ Rectangle {
8696 }
8797 Row {
8898 TextField {
89− id: pinLengthTextField
99+ id: minPinLengthTextField
90100 width: units.gu(7)
91101 text: "4"
92102 }
93103 Label {
94− text: "PIN length"
104+ text: "Min PIN length"
105+ }
106+ }
107+ Row {
108+ TextField {
109+ id: maxPinLengthTextField
110+ width: units.gu(7)
111+ text: "4"
112+ }
113+ Label {
114+ text: "Max PIN length"
115+ }
116+ }
117+ Row {
118+ TextField {
119+ id: retryCountTextField
120+ width: units.gu(7)
121+ text: "3 retries left"
122+ }
123+ Label {
124+ text: "Retries left"
95125 }
96126 }
97127 Label {
@@ -108,12 +138,40 @@ Rectangle {
108138 }
109139 Button {
110140 text: "start auth (1234)"
141+ width: parent.width
111142 onClicked: LightDM.Greeter.authenticate("has-pin")
112143 }
113144 Button {
114145 text: "start auth (password)"
146+ width: parent.width
115147 onClicked: LightDM.Greeter.authenticate("has-password")
116148 }
149+
150+ TextField {
151+ id: infoTextTextField
152+ width: parent.width
153+ placeholderText: "Infotext"
154+ text: "+49 179 3253553"
155+ }
156+
157+ TextField {
158+ id: infoPopupTitleTextField
159+ width: parent.width
160+ placeholderText: "Popup title"
161+ text: "This will be the last attempt"
162+ }
163+
164+ TextArea {
165+ id: infoPopupTextArea
166+ width: parent.width
167+ text: "If the SIM PIN is entered incorrectly, your SIM will be blocked and would require the PUK code to unlock."
168+ }
169+
170+ Button {
171+ text: "open info popup"
172+ width: parent.width
173+ onClicked: lockscreen.showInfoPopup(infoPopupTitleTextField.text, infoPopupTextArea.text)
174+ }
117175 }
118176 }
119177
@@ -121,6 +179,16 @@ Rectangle {
121179 name: "Lockscreen"
122180 when: windowShown
123181
182+ function cleanup() {
183+ lockscreen.clear(false);
184+ }
185+
186+ function waitForLockscreenReady() {
187+ var pinPadLoader = findChild(lockscreen, "pinPadLoader");
188+ tryCompare(pinPadLoader, "status", Loader.Ready)
189+ waitForRendering(lockscreen)
190+ }
191+
124192 function test_loading_data() {
125193 return [
126194 {tag: "numeric", alphanumeric: false, pinPadAvailable: true },
@@ -129,8 +197,8 @@ Rectangle {
129197 }
130198
131199 function test_loading(data) {
132− lockscreen.alphaNumeric = data.alphanumeric
133− waitForRendering(lockscreen)
200+ pinPadCheckBox.checked = data.alphanumeric
201+ waitForLockscreenReady();
134202 if (data.pinPadAvailable) {
135203 compare(findChild(lockscreen, "pinPadButton8").text, "8", "Could not find number 8 on PinPad")
136204 } else {
@@ -147,8 +215,8 @@ Rectangle {
147215
148216 function test_emergency_call(data) {
149217 emergencyCheckBox.checked = false
150− lockscreen.alphaNumeric = data.alphanumeric
151− waitForRendering(lockscreen)
218+ pinPadCheckBox.checked = data.alphanumeric
219+ waitForLockscreenReady();
152220 var emergencyButton = findChild(lockscreen, "emergencyCallIcon")
153221 mouseClick(emergencyButton, units.gu(1), units.gu(1))
154222 tryCompare(emergencyCheckBox, "checked", true)
@@ -163,9 +231,9 @@ Rectangle {
163231 }
164232
165233 function test_labels(data) {
166− lockscreen.alphaNumeric = data.alphanumeric
234+ pinPadCheckBox.checked = data.alphanumeric
167235 lockscreen.placeholderText = data.placeholderText
168− waitForRendering(lockscreen)
236+ waitForLockscreenReady();
169237 compare(findChild(lockscreen, "pinentryField").placeholderText, data.placeholderText, "Placeholdertext is not what it should be")
170238 if (data.alphanumeric) {
171239 compare(findChild(lockscreen, "greeterLabel").text, "Hello " + data.username, "Greeter is not set correctly")
@@ -175,23 +243,25 @@ Rectangle {
175243
176244 function test_unlock_data() {
177245 return [
178− {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", pinLength: 4},
179− {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", pinLength: -1},
180− {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", pinLength: 4},
181− {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", pinLength: -1},
182− {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", pinLength: -1},
246+ {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", minPinLength: 4, maxPinLength: 4},
247+ {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", minPinLength: -1, maxPinLength: -1},
248+ {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", minPinLength: 4, maxPinLength: 4},
249+ {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", minPinLength: -1, maxPinLength: -1},
250+ {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", minPinLength: -1, maxPinLength: -1},
183251 ]
184252 }
185253
186254 function test_unlock(data) {
187255 enteredLabel.text = ""
188− pinLengthTextField.text = data.pinLength
256+ minPinLengthTextField.text = data.minPinLength
257+ maxPinLengthTextField.text = data.maxPinLength
189258 LightDM.Greeter.authenticate(data.username)
190− waitForRendering(lockscreen)
259+ waitForLockscreenReady();
191260
192261 var inputField = findChild(lockscreen, "pinentryField")
193262 if (data.alphanumeric) {
194263 mouseClick(inputField, units.gu(1), units.gu(1))
264+ tryCompare(inputField, "focus", true);
195265 typeString(data.password)
196266 keyClick(Qt.Key_Enter)
197267 } else {
@@ -200,7 +270,7 @@ Rectangle {
200270 var button = findChild(lockscreen, "pinPadButton" + character)
201271 mouseClick(button, units.gu(1), units.gu(1))
202272 }
203− if (data.pinLength == -1) {
273+ if (data.minPinLength !== data.maxPinLength || data.minPinLength == -1) {
204274 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
205275 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
206276 }
@@ -219,11 +289,12 @@ Rectangle {
219289
220290 function test_clear(data) {
221291 pinPadCheckBox.checked = data.alphanumeric
222− waitForRendering(lockscreen)
292+ waitForLockscreenReady();
223293
224294 var inputField = findChild(lockscreen, "pinentryField")
225295 if (data.alphanumeric) {
226296 mouseClick(inputField, units.gu(1), units.gu(1))
297+ tryCompare(inputField, "activeFocus", true);
227298 typeString("1")
228299 } else {
229300 var button = findChild(lockscreen, "pinPadButton1")
@@ -239,6 +310,16 @@ Rectangle {
239310
240311 wait(0) // Trigger event loop to make sure the animation would start running
241312 compare(animation.running, data.animation)
313+ if (data.animation) {
314+ if (data.alphanumeric) {
315+ tryCompare(inputField, "placeholderText", lockscreen.wrongPlaceholderText)
316+ tryCompare(inputField, "placeholderText", lockscreen.placeholderText)
317+ } else {
318+ var label = findChild(lockscreen, "pinentryFieldPlaceHolder");
319+ tryCompare(label, "text", lockscreen.wrongPlaceholderText)
320+ tryCompare(label, "text", lockscreen.placeholderText)
321+ }
322+ }
242323
243324 // wait for animation to finish to not disturb other tests
244325 tryCompare(animation, "running", false)
@@ -246,33 +327,130 @@ Rectangle {
246327
247328 function test_backspace_data() {
248329 return [
249− {tag: "fixed length", pinLength: 4},
250− {tag: "variable length", pinLength: -1}
330+ {tag: "fixed length", minPinLength: 4, maxPinLength: 4},
331+ {tag: "variable undefined length", minPinLength: -1, maxPinLength: -1},
332+ {tag: "variable restricted length", minPinLength: 4, maxPinLength: 8}
251333 ];
252334 }
253335
254336 function test_backspace(data) {
255337 pinPadCheckBox.checked = false
256− pinLengthTextField.text = data.pinLength
257− waitForRendering(lockscreen);
338+ minPinLengthTextField.text = data.minPinLength
339+ maxPinLengthTextField.text = data.maxPinLength
340+ waitForLockscreenReady();
258341
259342 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
260343 var backspaceIcon = findChild(lockscreen, "backspaceIcon");
261344 var pinEntryField = findChild(lockscreen, "pinentryField");
262345
263− compare(pinPadButtonErase.iconName, data.pinLength == -1 ? "" : "erase");
264− compare(backspaceIcon.visible, data.pinLength == -1);
346+ var autoConfirmEnabled = data.minPinLength === data.maxPinLength && data.minPinLength !== -1;
347+ compare(pinPadButtonErase.iconName, autoConfirmEnabled ? "erase" : "");
348+ compare(backspaceIcon.visible, !autoConfirmEnabled);
265349
266350 var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
267351 mouseClick(pinPadButton5, units.gu(1), units.gu(1));
268352 compare(pinEntryField.text, "5");
269353
270− if (data.pinLength == -1) {
354+ if (data.minPinLength !== data.maxPinLength) {
271355 mouseClick(backspaceIcon, units.gu(1), units.gu(1));
272356 } else {
273357 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
274358 }
275359 compare(pinEntryField.text, "");
276360 }
361+
362+ function test_minMaxLength_data() {
363+ return [
364+ {tag: "undefined", minPinLength: -1, maxPinLength: -1},
365+ {tag: "fixed", minPinLength: 4, maxPinLength: 4},
366+ {tag: "variable, limited", minPinLength: 4, maxPinLength: 8},
367+ ];
368+ }
369+
370+ function test_minMaxLength(data) {
371+ pinPadCheckBox.checked = false
372+ minPinLengthTextField.text = data.minPinLength
373+ maxPinLengthTextField.text = data.maxPinLength
374+ waitForLockscreenReady();
375+
376+ var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
377+ var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
378+ var inputField = findChild(lockscreen, "pinentryField")
379+
380+ for (var i = 0; i < 10; i++) {
381+ mouseClick(pinPadButton5, units.gu(1), units.gu(1));
382+
383+ if (data.minPinLength == data.maxPinLength && data.minPinLength != -1) {
384+ // auto confirm mode...
385+ compare(inputField.text.length, (i+1) % data.minPinLength);
386+ } else {
387+ // manual confirm mode
388+ tryCompare(pinPadButtonErase, "enabled", (i+1) >= data.minPinLength)
389+ if (data.maxPinLength == -1) {
390+ compare(inputField.text.length, i+1);
391+ } else {
392+ compare(inputField.text.length, Math.min(data.maxPinLength, i+1));
393+ }
394+
395+ }
396+ }
397+ }
398+
399+ function test_retryDisplay_data() {
400+ return [
401+ {tag: "empty", retryText: "", shown: false},
402+ {tag: "3 retries left", retryText: "3 retries left", shown: true},
403+ ]
404+ }
405+
406+ function test_retryDisplay(data) {
407+ pinPadCheckBox.checked = false
408+ waitForLockscreenReady();
409+
410+ retryCountTextField.text = data.retryText;
411+ var label = findChild(lockscreen, "retryCountLabel")
412+ compare(label.visible, data.shown);
413+ }
414+
415+ function test_infoPopup() {
416+ verify(findChild(root, "infoPopup") === null);
417+ lockscreen.showInfoPopup("foo", "bar");
418+ tryCompareFunction(function() { return findChild(root, "infoPopup") !== null}, true);
419+
420+ var infoPopup = findChild(root, "infoPopup");
421+ compare(infoPopup.title, "foo");
422+ compare(infoPopup.text, "bar");
423+
424+ signalSpy.signalName = "infoPopupConfirmed"
425+ signalSpy.clear();
426+
427+ var okButton = findChild(root, "infoPopupOkButton");
428+ mouseClick(okButton, okButton.width / 2, okButton.height / 2);
429+
430+ tryCompareFunction(function() { return findChild(root, "infoPopup") === null}, true);
431+
432+ tryCompare(signalSpy, "count", 1);
433+ }
434+
435+ function test_infoTextDisplay_data() {
436+ return [
437+ {tag: "empty string", text: "", shown: false},
438+ {tag: "hello world", text: "hello world", shown: true},
439+ ]
440+ }
441+
442+ function test_infoTextDisplay(data) {
443+ pinPadCheckBox.checked = false
444+ waitForLockscreenReady();
445+
446+ infoTextTextField.text = data.text;
447+ var label = findChild(lockscreen, "infoTextLabel")
448+ compare(label.visible, data.shown);
449+ }
450+ }
451+
452+ SignalSpy {
453+ id: signalSpy
454+ target: lockscreen
277455 }
278456}