@@ -14,36 +14,38 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17−import QtQuick 2.0
17+import QtQuick 2.3
18−import Ubuntu.Components 0.1
18+import AccountsService 0.1
19−import Ubuntu.Gestures 0.1
20import LightDM 0.1 as LightDM
19import LightDM 0.1 as LightDM
20+import Ubuntu.Components 1.1
21import "../Components"
21import "../Components"
24 id: greeter
24 id: greeter
26 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
25 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
28− x: launcherOffsetProxy + dragOffset
30 property url background
27 property url background
31− property bool loadContent: required
33 // How far to offset the top greeter layer during a launcher left-drag
29 // How far to offset the top greeter layer during a launcher left-drag
34 property real launcherOffset
30 property real launcherOffset
36 // 1 when fully shown and 0 when fully hidden
32 // 1 when fully shown and 0 when fully hidden
37− property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
33+ property real showProgress: MathUtils.clamp((width - Math.abs(greeterContentLoader.x)) / width, 0, 1)
35+ // True when the greeter is waiting for PAM or other setup process
36+ property bool waiting: true
39 showAnimation: StandardAnimation { property: "dragOffset"; to: 0; duration: UbuntuAnimation.FastDuration }
38 showAnimation: StandardAnimation { property: "dragOffset"; to: 0; duration: UbuntuAnimation.FastDuration }
40 hideAnimation: __leftHideAnimation
39 hideAnimation: __leftHideAnimation
42− property alias dragHandleWidth: dragHandle.width
41+ property alias lockscreen: lockscreen
43− property alias model: greeterContentLoader.model
42+
44− property bool locked: true
43+ readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock
44+ property bool forcedUnlock
45+ onForcedUnlockChanged: if (forcedUnlock) lockscreen.hide()
47+ property bool tabletMode
46− readonly property bool narrowMode: !multiUser && height > width
48+ readonly property bool narrowMode: !multiUser && !tabletMode
47 readonly property bool multiUser: LightDM.Users.count > 1
49 readonly property bool multiUser: LightDM.Users.count > 1
49 readonly property int currentIndex: greeterContentLoader.currentIndex
51 readonly property int currentIndex: greeterContentLoader.currentIndex
@@ -82,13 +84,13 @@ Showable {
84 function tryToUnlock() {
86 function tryToUnlock() {
85− if (created) {
87+ if (greeterContentLoader.item) {
86 greeterContentLoader.item.tryToUnlock()
88 greeterContentLoader.item.tryToUnlock()
90 function reset() {
92 function reset() {
91− if (created) {
93+ if (greeterContentLoader.item) {
92 greeterContentLoader.item.reset()
94 greeterContentLoader.item.reset()
@@ -109,74 +111,188 @@ Showable {
112− // Bi-directional revealer
114+ onShownChanged: {
113− DraggingArea {
115+ if (shown) {
114− id: dragHandle
116+ waiting = true;
115− anchors.fill: parent
116− enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled && greeter.shown
117− orientation: Qt.Horizontal
118− propagateComposedEvents: true
120− Component.onCompleted: {
118+ if (narrowMode) {
121− // set evaluators to baseline of dragValue == 0
119+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
122− leftEvaluator.reset()
121+ reset();
123− rightEvaluator.reset()
122+ }
130+ objectName: "lockscreen"
133+ showAnimation: StandardAnimation { property: "opacity"; to: 1 }
134+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
135+ anchors.fill: parent
137+ background: greeter.background
138+ darkenBackground: 0.4
139+ alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
143+ property string promptText
144+ infoText: promptText !== "" ? i18n.tr("Enter %1").arg(promptText) :
145+ alphaNumeric ? i18n.tr("Enter passphrase") :
146+ i18n.tr("Enter passcode")
147+ errorText: promptText !== "" ? i18n.tr("Sorry, incorrect %1").arg(promptText) :
148+ alphaNumeric ? i18n.tr("Sorry, incorrect passphrase") + "\n" +
149+ i18n.tr("Please re-enter") :
150+ i18n.tr("Sorry, incorrect passcode")
152+ // FIXME: We *should* show emergency dialer if there is a SIM present,
153+ // regardless of whether the side stage is enabled. But right now,
154+ // the assumption is that narrow screens are phones which have SIMs
155+ // and wider screens are tablets which don't. When we do allow this
156+ // on devices with a side stage and a SIM, work should be done to
157+ // ensure that the main stage is disabled while the dialer is present
158+ // in the side stage. See the FIXME in the stage loader in Shell.qml.
159+ showEmergencyCallButton: !greeter.tabletMode
161+ onEntered: LightDM.Greeter.respond(passphrase);
162+ onCancel: greeter.show()
163+ onEmergencyCall: startLockedApp("dialer-app")
165+ onShownChanged: if (shown) greeter.lockedApp = ""
126− function maybeTease() {
167+ function maybeShow() {
127− if (!greeter.locked || greeter.narrowMode)
168+ if (!greeter.forcedUnlock) {
128− greeter.tease();
169+ show();
131− onClicked: maybeTease()
173+ Timer {
132− onDragStart: maybeTease()
174+ id: forcedDelayTimer
133− onPressAndHold: {} // eat event, but no need to tease, as drag will cover it
175+ interval: 1000 * 60
177+ if (lockscreen.delayMinutes > 0) {
178+ lockscreen.delayMinutes -= 1
179+ if (lockscreen.delayMinutes > 0) {
135− onDragEnd: {
186+ Component.onCompleted: {
136− if (greeter.dragOffset > 0 && rightEvaluator.shouldAutoComplete()) {
187+ if (greeter.narrowMode) {
137− greeter.hideRight()
188+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
138− } else if (greeter.dragOffset < 0 && leftEvaluator.shouldAutoComplete()) {
141− greeter.show(); // undo drag
194+ target: LightDM.Greeter
145− onDragValueChanged: {
196+ onShowGreeter: greeter.show()
146− // dragValue is kept as a "step" value since we do this adjusting on the fly
197+ onHideGreeter: greeter.login()
147− greeter.dragOffset += dragValue;
198+
202+ if (!LightDM.Greeter.active) {
203+ return; // could happen if hideGreeter() comes in before we prompt
206+ if (greeter.narrowMode) {
207+ lockscreen.promptText = isDefaultPrompt ? "" : text.toLowerCase();
208+ lockscreen.maybeShow();
150− EdgeDragEvaluator {
212+ onPromptlessChanged: {
151− id: rightEvaluator
213+ if (!LightDM.Greeter.active) {
152− trackedPosition: dragHandle.dragValue + greeter.dragOffset
214+ return; // could happen if hideGreeter() comes in before we prompt
153− maxDragDistance: parent.width
215+ }
154− direction: Direction.Rightwards
216+ if (greeter.narrowMode) {
217+ if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
221+ lockscreen.maybeShow();
157− EdgeDragEvaluator {
226+ onAuthenticationComplete: {
158− id: leftEvaluator
227+ waiting = false;
159− trackedPosition: dragHandle.dragValue + greeter.dragOffset
228+ if (LightDM.Greeter.authenticated) {
160− maxDragDistance: parent.width
229+ AccountsService.failedLogins = 0
161− direction: Direction.Leftwards
230+ }
231+ // Else only penalize user for a failed login if they actually were
232+ // prompted for a password. We do this below after the promptless
235+ if (LightDM.Greeter.promptless) {
239+ if (LightDM.Greeter.authenticated) {
242+ AccountsService.failedLogins++
243+ if (maxFailedLogins >= 2) { // require at least a warning
244+ if (AccountsService.failedLogins === maxFailedLogins - 1) {
245+ var title = lockscreen.alphaNumeric ?
246+ i18n.tr("Sorry, incorrect passphrase.") :
247+ i18n.tr("Sorry, incorrect passcode.")
248+ var text = i18n.tr("This will be your last attempt.") + " " +
249+ (lockscreen.alphaNumeric ?
250+ i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
251+ i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
252+ lockscreen.showInfoPopup(title, text)
253+ } else if (AccountsService.failedLogins >= maxFailedLogins) {
254+ SystemImage.factoryReset() // Ouch!
257+ if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
258+ lockscreen.delayMinutes = failedLoginsDelayMinutes
259+ forcedDelayTimer.start()
262+ lockscreen.clear(true);
263+ if (greeter.narrowMode) {
264+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
165− targetItem: dragHandle
270+ Binding {
271+ target: LightDM.Greeter
273+ value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
166− anchors.fill: targetItem
277+ anchors.fill: parent
167− enabled: targetItem.enabled
278+ color: "black"
279+ opacity: greeter.showProgress * 0.8
171 id: greeterContentLoader
283 id: greeterContentLoader
172 objectName: "greeterContentLoader"
284 objectName: "greeterContentLoader"
173− anchors.fill: parent
285+
286+ x: launcherOffsetProxy + dragOffset
288+ height: parent.height
174 property var model: LightDM.Users
290 property var model: LightDM.Users
175 property int currentIndex: 0
291 property int currentIndex: 0
176 property var infographicModel: LightDM.Infographic
292 property var infographicModel: LightDM.Infographic
177 readonly property int backgroundTopMargin: -greeter.y
293 readonly property int backgroundTopMargin: -greeter.y
179− source: loadContent ? "GreeterContent.qml" : ""
295+ source: (greeter.required || lockscreen.required) ? "GreeterContent.qml" : ""
181 onLoaded: {
297 onLoaded: {
182 selected(currentIndex);
298 selected(currentIndex);
@@ -190,59 +306,7 @@ Showable {
190 greeterContentLoader.currentIndex = uid;
306 greeterContentLoader.currentIndex = uid;
192 onUnlocked: greeter.unlocked(uid);
308 onUnlocked: greeter.unlocked(uid);
309+ onTease: greeter.tease()
196− onTease: showLabelAnimation.start()
200− visible: greeter.shown
201− property real baseOpacity: 0.5
203− anchors.horizontalCenter: parent.horizontalCenter
204− anchors.bottom: parent.bottom
205− anchors.bottomMargin: units.gu(5)
206− text: "《 " + i18n.tr("Unlock") + " 》"
208− font.weight: Font.Light
210− SequentialAnimation on opacity {
211− id: showLabelAnimation
217− to: swipeHint.baseOpacity
218− duration: UbuntuAnimation.SleepyDuration
220− PauseAnimation { duration: UbuntuAnimation.BriskDuration }
222− from: swipeHint.baseOpacity
224− duration: UbuntuAnimation.SleepyDuration
229− // right side shadow
231− anchors.left: parent.right
232− anchors.top: parent.top
233− anchors.bottom: parent.bottom
234− visible: parent.required
235− fillMode: Image.Tile
236− source: "../graphics/dropshadow_right.png"
241− anchors.right: parent.left
242− anchors.top: parent.top
243− anchors.bottom: parent.bottom
244− visible: parent.required
245− fillMode: Image.Tile
246− source: "../graphics/dropshadow_left.png"