@@ -60,7 +60,7 @@ Item {
61 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
61 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
62 property int failedLoginsDelayAttempts: 7 // number of failed logins
62 property int failedLoginsDelayAttempts: 7 // number of failed logins
63− property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting
63+ property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
65 property int orientation
65 property int orientation
66 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
66 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
@@ -87,9 +87,9 @@ Item {
90− function setFakeActiveForApp(app) {
90+ function setLockedApp(app) {
91 if (shell.locked) {
91 if (shell.locked) {
92− greeter.fakeActiveForApp = app
92+ greeter.lockedApp = app
93 lockscreen.hide()
93 lockscreen.hide()
@@ -128,6 +128,13 @@ Item {
128 objectName: "dashCommunicator"
128 objectName: "dashCommunicator"
132+ target: ApplicationManager
133+ property: "forceDashActive"
134+ value: launcher.shown || launcher.dashSwipe
131 WindowKeysFilter {
138 WindowKeysFilter {
132 // Handle but do not filter out volume keys
139 // Handle but do not filter out volume keys
133 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
140 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
@@ -162,32 +169,37 @@ Item {
162 Connections {
169 Connections {
163 target: ApplicationManager
170 target: ApplicationManager
164 onFocusRequested: {
171 onFocusRequested: {
172+ if (greeter.narrowMode) {
165− if (appId === "dialer-app") {
173+ if (appId === "dialer-app") {
166− // Always let the dialer-app through. Either user asked
174+ // Always let the dialer-app through. Either user asked
167− // for an emergency call or accepted an incoming call.
175+ // for an emergency call or accepted an incoming call.
168− setFakeActiveForApp(appId)
176+ setLockedApp(appId)
169− } else if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
177+ } else if (greeter.hasLockedApp && greeter.lockedApp !== appId) {
170− lockscreen.show();
178+ greeter.startUnlock()
182+ if (LightDM.Greeter.active) {
183+ greeter.startUnlock()
176 onFocusedApplicationIdChanged: {
188 onFocusedApplicationIdChanged: {
177− if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
189+ if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
178− lockscreen.show();
190+ greeter.startUnlock()
180 panel.indicators.hide();
192 panel.indicators.hide();
183 onApplicationAdded: {
195 onApplicationAdded: {
184 if (greeter.shown && appId != "unity8-dash") {
196 if (greeter.shown && appId != "unity8-dash") {
185− greeter.hide();
197+ greeter.startUnlock()
187− if (appId === "dialer-app") {
199+ if (greeter.narrowMode && appId === "dialer-app") {
188 // Always let the dialer-app through. Either user asked
200 // Always let the dialer-app through. Either user asked
189 // for an emergency call or accepted an incoming call.
201 // for an emergency call or accepted an incoming call.
190− setFakeActiveForApp(appId)
202+ setLockedApp(appId)
192 launcher.hide();
204 launcher.hide();
@@ -195,9 +207,19 @@ Item {
197 id: applicationsDisplayLoader
209 id: applicationsDisplayLoader
210+ objectName: "applicationsDisplayLoader"
198 anchors.fill: parent
211 anchors.fill: parent
213+ // When we have a locked app, we only want to show that one app.
214+ // FIXME: do this in a less traumatic way. We currently only allow
215+ // locked apps in phone mode (see FIXME in Lockscreen component in
216+ // this same file). When that changes, we need to do something
217+ // nicer here. But this code is currently just to prevent a
218+ // theoretical attack where user enters lockedApp mode, then makes
219+ // the screen larger (maybe connects to monitor) and tries to enter
221+ property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
200− source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
222+ source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
202 Binding {
224 Binding {
203 target: applicationsDisplayLoader.item
225 target: applicationsDisplayLoader.item
@@ -223,7 +245,7 @@ Item {
223 Binding {
245 Binding {
224 target: applicationsDisplayLoader.item
246 target: applicationsDisplayLoader.item
225 property: "spreadEnabled"
247 property: "spreadEnabled"
226− value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
248+ value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
228 Binding {
250 Binding {
229 target: applicationsDisplayLoader.item
251 target: applicationsDisplayLoader.item
@@ -278,8 +300,6 @@ Item {
278 id: lockscreen
300 id: lockscreen
279 objectName: "lockscreen"
301 objectName: "lockscreen"
281− readonly property int backgroundTopMargin: -panel.panelHeight
283 hides: [launcher, panel.indicators]
303 hides: [launcher, panel.indicators]
284 shown: false
304 shown: false
285 enabled: true
305 enabled: true
@@ -294,11 +314,33 @@ Item {
294 minPinLength: 4
314 minPinLength: 4
295 maxPinLength: 4
315 maxPinLength: 4
317+ // FIXME: We *should* show emergency dialer if there is a SIM present,
318+ // regardless of whether the side stage is enabled. But right now,
319+ // the assumption is that narrow screens are phones which have SIMs
320+ // and wider screens are tablets which don't. When we do allow this
321+ // on devices with a side stage and a SIM, work should be done to
322+ // ensure that the main stage is disabled while the dialer is present
323+ // in the side stage. See the FIXME in the stage loader in this file.
324+ showEmergencyCallButton: !shell.sideStageEnabled
297 onEntered: LightDM.Greeter.respond(passphrase);
326 onEntered: LightDM.Greeter.respond(passphrase);
298 onCancel: greeter.show()
327 onCancel: greeter.show()
299− onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
328+ onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter locked-app mode
301− onShownChanged: if (shown) greeter.fakeActiveForApp = ""
330+ onShownChanged: if (shown) greeter.lockedApp = ""
333+ id: forcedDelayTimer
336+ if (lockscreen.delayMinutes > 0) {
337+ lockscreen.delayMinutes -= 1
338+ if (lockscreen.delayMinutes > 0) {
303 Component.onCompleted: {
345 Component.onCompleted: {
304 if (greeter.narrowMode) {
346 if (greeter.narrowMode) {
@@ -317,14 +359,15 @@ Item {
317 if (greeter.narrowMode) {
359 if (greeter.narrowMode) {
318 if (isDefaultPrompt) {
360 if (isDefaultPrompt) {
319 if (lockscreen.alphaNumeric) {
361 if (lockscreen.alphaNumeric) {
320− lockscreen.infoText = i18n.tr("Enter your passphrase")
362+ lockscreen.infoText = i18n.tr("Enter passphrase")
321− lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
363+ lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase") + "\n" +
364+ i18n.tr("Please re-enter")
323− lockscreen.infoText = i18n.tr("Enter your passcode")
366+ lockscreen.infoText = i18n.tr("Enter passcode")
324 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
367 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
327− lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
370+ lockscreen.infoText = i18n.tr("Enter %1").arg(text.toLowerCase())
328 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
371 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
@@ -333,11 +376,13 @@ Item {
335 onPromptlessChanged: {
378 onPromptlessChanged: {
379+ if (greeter.narrowMode) {
336− if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
380+ if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
337− lockscreen.hide()
381+ lockscreen.hide()
338− } else {
382+ } else {
339− lockscreen.reset();
383+ lockscreen.reset();
340− lockscreen.show();
384+ lockscreen.show();
@@ -372,7 +417,8 @@ Item {
374 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
419 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
375− lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
420+ lockscreen.delayMinutes = failedLoginsDelayMinutes
421+ forcedDelayTimer.start()
378 lockscreen.clear(true);
424 lockscreen.clear(true);
@@ -386,7 +432,7 @@ Item {
386 Binding {
432 Binding {
387 target: LightDM.Greeter
433 target: LightDM.Greeter
388 property: "active"
434 property: "active"
389− value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
435+ value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
392 Rectangle {
438 Rectangle {
@@ -398,7 +444,8 @@ Item {
399 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
445 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
400 id: greeterWrapper
446 id: greeterWrapper
447+ objectName: "greeterWrapper"
401− x: launcher.progress
448+ x: greeter.narrowMode ? launcher.progress : 0
402 y: panel.panelHeight
449 y: panel.panelHeight
403 width: parent.width
450 width: parent.width
404 height: parent.height - panel.panelHeight
451 height: parent.height - panel.panelHeight
@@ -411,14 +458,22 @@ Item {
411 property bool fullyShown: showProgress === 1.0
458 property bool fullyShown: showProgress === 1.0
412 onFullyShownChanged: {
459 onFullyShownChanged: {
413 // Wait until the greeter is completely covering lockscreen before resetting it.
460 // Wait until the greeter is completely covering lockscreen before resetting it.
414− if (fullyShown && !LightDM.Greeter.authenticated) {
461+ if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
415 lockscreen.reset();
462 lockscreen.reset();
416 lockscreen.show();
463 lockscreen.show();
420 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
467 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
421− onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
468+ onShowProgressChanged: {
469+ if (showProgress === 0) {
470+ if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
472+ } else if (greeter.narrowMode) {
473+ lockscreen.clear(false) // to reset focus if necessary
423 Greeter {
478 Greeter {
424 id: greeter
479 id: greeter
@@ -426,13 +481,16 @@ Item {
427 signal sessionStarted() // helpful for tests
482 signal sessionStarted() // helpful for tests
429− property string fakeActiveForApp: ""
484+ property string lockedApp: ""
485+ property bool hasLockedApp: lockedApp !== ""
431 available: true
487 available: true
432 hides: [launcher, panel.indicators]
488 hides: [launcher, panel.indicators]
433 shown: true
489 shown: true
434 loadContent: required || lockscreen.required // keeps content in memory for quick show()
490 loadContent: required || lockscreen.required // keeps content in memory for quick show()
492+ locked: shell.locked
436 defaultBackground: shell.background
494 defaultBackground: shell.background
438 width: parent.width
496 width: parent.width
@@ -440,6 +498,18 @@ Item {
441 dragHandleWidth: shell.edgeSize
499 dragHandleWidth: shell.edgeSize
501+ function startUnlock() {
503+ if (!LightDM.Greeter.authenticated) {
443 function login() {
513 function login() {
444 enabled = false;
514 enabled = false;
445 if (LightDM.Greeter.startSessionSync()) {
515 if (LightDM.Greeter.startSessionSync()) {
@@ -455,8 +525,10 @@ Item {
455 if (shown) {
525 if (shown) {
456 if (greeter.narrowMode) {
526 if (greeter.narrowMode) {
457 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
527 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
459− greeter.fakeActiveForApp = "";
531+ greeter.lockedApp = "";
460 greeter.forceActiveFocus();
532 greeter.forceActiveFocus();
@@ -501,10 +573,7 @@ Item {
503 if (LightDM.Greeter.active) {
575 if (LightDM.Greeter.active) {
504− if (!LightDM.Greeter.authenticated) {
507− greeter.hide()
576+ greeter.startUnlock()
510 var animate = !LightDM.Greeter.active && !stages.shown
579 var animate = !LightDM.Greeter.active && !stages.shown
@@ -513,16 +582,20 @@ Item {
515 function showDash() {
584 function showDash() {
585+ if (greeter.hasLockedApp || // just in case user gets here
516− if (shell.locked) {
586+ (!greeter.narrowMode && shell.locked)) {
519 if (greeter.shown) {
590 if (greeter.shown) {
520 greeter.hideRight();
591 greeter.hideRight();
521 launcher.fadeOut();
592 launcher.fadeOut();
595+ if (ApplicationManager.focusedApplicationId != "unity8-dash") {
524− ApplicationManager.requestFocusApplication("unity8-dash")
596+ ApplicationManager.requestFocusApplication("unity8-dash")
525− launcher.fadeOut();
597+ launcher.fadeOut();
@@ -537,7 +610,7 @@ Item {
537 anchors.fill: parent //because this draws indicator menus
610 anchors.fill: parent //because this draws indicator menus
538 indicators {
611 indicators {
539 hides: [launcher]
612 hides: [launcher]
540− available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && greeter.fakeActiveForApp === ""
613+ available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
541 contentEnabled: edgeDemo.panelContentEnabled
614 contentEnabled: edgeDemo.panelContentEnabled
542 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
615 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
543 panelHeight: units.gu(3)
616 panelHeight: units.gu(3)
@@ -548,7 +621,7 @@ Item {
548 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
621 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
550 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
623 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
551− || greeter.fakeActiveForApp !== ""
624+ || greeter.hasLockedApp
554 Launcher {
627 Launcher {
@@ -561,26 +634,18 @@ Item {
561 anchors.bottom: parent.bottom
634 anchors.bottom: parent.bottom
562 width: parent.width
635 width: parent.width
563 dragAreaWidth: shell.edgeSize
636 dragAreaWidth: shell.edgeSize
564− available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && greeter.fakeActiveForApp === ""
637+ available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
566 onShowDashHome: showHome()
639 onShowDashHome: showHome()
568− if (ApplicationManager.focusedApplicationId != "unity8-dash") {
569− showDash()
640+ onDash: showDash()
571− if (greeter.shown) {
576 onDashSwipeChanged: {
641 onDashSwipeChanged: {
577 if (dashSwipe) {
642 if (dashSwipe) {
578 dash.setCurrentScope("clickscope", false, true)
643 dash.setCurrentScope("clickscope", false, true)
581 onLauncherApplicationSelected: {
646 onLauncherApplicationSelected: {
582− if (greeter.fakeActiveForApp !== "") {
647+ if (greeter.hasLockedApp) {
583− lockscreen.show()
648+ greeter.startUnlock()
585 if (!edgeDemo.running)
650 if (!edgeDemo.running)
586 shell.activateApplication(appId)
651 shell.activateApplication(appId)