@@ -54,6 +54,7 @@ Showable {
5454 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
5555 property int failedLoginsDelayAttempts: 7 // number of failed logins
5656 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
57+ property int failedFingerprintLoginsDisableAttempts: 3 // number of failed fingerprint logins
5758
5859 readonly property bool animating: loader.item ? loader.item.animating : false
5960
@@ -62,6 +63,9 @@ Showable {
6263 signal emergencyCall()
6364
6465 function forceShow() {
66+ if (!active) {
67+ d.isLockscreen = true;
68+ }
6569 forcedUnlock = false;
6670 if (!required) {
6771 showNow(); // loader.onLoaded will select a user
@@ -121,7 +125,11 @@ Showable {
121125 readonly property bool multiUser: lightDM.users.count > 1
122126 property int currentIndex
123127 property bool waiting
124− property int fingerprintFailureCount
128+ property bool isLockscreen // true when we are locking an active session, rather than first user login
129+ readonly property bool allowFingerprint: isLockscreen &&
130+ AccountsService.failedFingerprintLogins <
131+ root.failedFingerprintLoginsDisableAttempts
132+ readonly property bool alphanumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
125133
126134 // We want 'launcherOffset' to animate down to zero. But not to animate
127135 // while being dragged. So ideally we change this only when the user
@@ -137,16 +145,8 @@ Showable {
137145 UbuntuNumberAnimation {}
138146 }
139147
140− onFingerprintFailureCountChanged: {
141− if (d.fingerprintFailureCount >= 3) {
142− d.startUnlock(false /* toTheRight */);
143− d.fingerprintFailureCount = 0;
144− }
145− }
146−
147148 function selectUser(uid, reset) {
148149 d.waiting = true;
149− d.fingerprintFailureCount = 0;
150150 if (reset) {
151151 loader.item.reset();
152152 }
@@ -199,6 +199,13 @@ Showable {
199199 onForcedUnlockChanged: d.checkForcedUnlock(false /* hideNow */)
200200 Component.onCompleted: d.checkForcedUnlock(true /* hideNow */)
201201
202+ onLockedChanged: {
203+ if (!locked) {
204+ AccountsService.failedLogins = 0;
205+ AccountsService.failedFingerprintLogins = 0;
206+ }
207+ }
208+
202209 onRequiredChanged: {
203210 if (required) {
204211 d.waiting = true;
@@ -360,7 +367,7 @@ Showable {
360367 Binding {
361368 target: loader.item
362369 property: "alphanumeric"
363− value: AccountsService.passwordDisplayHint === AccountsService.Keyboard
370+ value: d.alphanumeric
364371 }
365372
366373 Binding {
@@ -419,7 +426,6 @@ Showable {
419426 d.waiting = false;
420427
421428 if (lightDM.greeter.authenticated) {
422− AccountsService.failedLogins = 0;
423429 d.login();
424430 if (!lightDM.greeter.promptless) {
425431 loader.item.hide();
@@ -515,10 +521,16 @@ Showable {
515521
516522 function failOperation(reason) {
517523 console.log("Failed to identify user by fingerprint:", reason);
518− d.fingerprintFailureCount++;
519524 restartOperation();
520− if (loader.item)
521− loader.item.showErrorMessage(i18n.tr("Try again"));
525+ if (!allowFingerprint) {
526+ d.startUnlock(false /* toTheRight */);
527+ }
528+ if (loader.item) {
529+ var msg = d.allowFingerprint ? i18n.tr("Try again")
530+ d.alphanumeric ? i18n.tr("Use passphrase")
531+ : i18n.tr("Use passcode");
532+ loader.item.showErrorMessage(msg);
533+ }
522534 }
523535
524536 Component.onCompleted: restartOperation()
@@ -526,17 +538,28 @@ Showable {
526538 onIdEnabledChanged: restartOperation()
527539
528540 onSucceeded: {
541+ if (!d.allowFingerprint) {
542+ failOperation("too many failures");
543+ return;
544+ }
529545 if (result !== lightDM.users.data(d.currentIndex, lightDM.userRoles.UidRole)) {
546+ AccountsService.failedFingerprintLogins++;
530547 failOperation("not the selected user");
531548 return;
532549 }
533550 console.log("Identified user by fingerprint:", result);
534− d.fingerprintFailureCount = 0;
535551 if (loader.item)
536552 loader.item.notifyAuthenticationSucceeded(true /* showFakePassword */);
537553 if (root.active)
538554 root.forcedUnlock = true;
539555 }
540− onFailed: failOperation(reason)
556+ onFailed: {
557+ if (!d.allowFingerprint) {
558+ failOperation("too many failures");
559+ } else {
560+ AccountsService.failedFingerprintLogins++;
561+ failOperation(reason);
562+ }
563+ }
541564 }
542565}