@@ -15,7 +15,9 @@
1515 */
1616
1717import QtQuick 2.4
18+import QtQuick.Window 2.2
1819import Ubuntu.Components 1.3
20+import Ubuntu.Telephony 0.1 as Telephony
1921import "../Components"
2022
2123FocusScope {
@@ -23,13 +25,13 @@ FocusScope {
2325
2426 property alias dragHandleLeftMargin: coverPage.dragHandleLeftMargin
2527 property alias launcherOffset: coverPage.launcherOffset
26− property int currentIndex // unused
27− property alias delayMinutes: lockscreen.delayMinutes
28+ property alias currentIndex: loginList.currentIndex
29+ property alias delayMinutes: delayedLockscreen.delayMinutes
2830 property alias backgroundTopMargin: coverPage.backgroundTopMargin
2931 property url background
3032 property bool locked
31− property bool alphanumeric
32− property var userModel // unused
33+ property alias alphanumeric: loginList.alphanumeric
34+ property alias userModel: loginList.model
3335 property alias infographicModel: coverPage.infographicModel
3436 property string sessionToStart
3537 property bool waiting
@@ -37,21 +39,25 @@ FocusScope {
3739 readonly property bool required: coverPage.required || lockscreen.required
3840 readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
3941
40− signal selected(int index) // unused
42+ // so that it can be replaced in tests with a mock object
43+ property var inputMethod: Qt.inputMethod
44+
45+ signal selected(int index)
4146 signal responded(string response)
4247 signal tease()
4348 signal emergencyCall()
4449
4550 function showMessage(html) {
46− // TODO
51+ loginList.showMessage(html);
4752 }
4853
4954 function showPrompt(text, isSecret, isDefaultPrompt) {
50− lockscreen.promptText = isDefaultPrompt ? "" : text.toLowerCase();
51− lockscreen.maybeShow();
55+ loginList.showPrompt(text, isSecret, isDefaultPrompt);
5256 }
5357
5458 function showLastChance() {
59+ /* TODO: when we finish support for resetting device after too many
60+ failed logins, we should re-add this popup.
5561 var title = lockscreen.alphaNumeric ?
5662 i18n.tr("Sorry, incorrect passphrase.") :
5763 i18n.tr("Sorry, incorrect passcode.");
@@ -60,6 +66,7 @@ FocusScope {
6066 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
6167 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."));
6268 lockscreen.showInfoPopup(title, text);
69+ */
6370 }
6471
6572 function hide() {
@@ -68,27 +75,24 @@ FocusScope {
6875 }
6976
7077 function notifyAuthenticationSucceeded(showFakePassword) {
71− // When using an alternate log in mechanism like fingerprints, the
72− // design is it looks like the user entered a passcode.
73− if (!alphanumeric && showFakePassword) {
74− lockscreen.showText("...."); // actual text doesn't matter, we show bullets
78+ if (showFakePassword) {
79+ loginList.showFakePassword();
7580 }
7681 }
7782
7883 function notifyAuthenticationFailed() {
79− lockscreen.customError = "";
80− lockscreen.clear(true);
84+ loginList.showError();
8185 }
8286
8387 function showErrorMessage(msg) {
8488 coverPage.showErrorMessage(msg);
85− lockscreen.customError = msg ? msg : " "; // avoid default message
86− lockscreen.clear(true);
8789 }
8890
89− function reset() {
90− lockscreen.customError = "";
91− coverPage.show();
91+ function reset(forceShow) {
92+ loginList.reset();
93+ if (forceShow) {
94+ coverPage.show();
95+ }
9296 }
9397
9498 function tryToUnlock(toTheRight) {
@@ -110,48 +114,62 @@ FocusScope {
110114 }
111115 }
112116
113− Lockscreen {
117+ Showable {
114118 id: lockscreen
115119 objectName: "lockscreen"
116−
120+ anchors.fill: parent
117121 shown: false
122+
118123 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
119124 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
120− anchors.fill: parent
121− visible: required
122− enabled: !coverPage.shown
123− background: root.background
124− darkenBackground: 0.4
125− alphaNumeric: root.alphanumeric
126− minPinLength: 4
127− maxPinLength: 4
128−
129− property string promptText
130− infoText: promptText !== "" ? i18n.tr("Enter %1").arg(promptText) :
131− alphaNumeric ? i18n.tr("Enter passphrase") :
132− i18n.tr("Enter passcode")
133−
134− property string customError
135− errorText: customError !== "" ? customError :
136− promptText !== "" ? i18n.tr("Sorry, incorrect %1").arg(promptText) :
137− alphaNumeric ? i18n.tr("Sorry, incorrect passphrase") + "\n" +
138− i18n.ctr("passphrase", "Please re-enter") :
139− i18n.tr("Sorry, incorrect passcode")
140−
141− onEntered: root.responded(passphrase)
142− onCancel: coverPage.show()
143− onEmergencyCall: root.emergencyCall()
144−
145− onEnabledChanged: {
146− if (enabled) {
147− lockscreen.forceActiveFocus();
125+
126+ CrossFadeImage {
127+ id: lockscreenBackground
128+ objectName: "lockscreenBackground"
129+ anchors {
130+ fill: parent
131+ topMargin: root.backgroundTopMargin
148132 }
133+ source: root.background
134+ fillMode: Image.PreserveAspectCrop
135+ // Limit how much memory we'll reserve for this image
136+ sourceSize.height: Math.max(Screen.width, Screen.height)
137+ sourceSize.width: 0
149138 }
150139
151− onVisibleChanged: {
152− if (visible) {
153− lockscreen.forceActiveFocus();
140+ // Darken background to match CoverPage
141+ Rectangle {
142+ anchors.fill: parent
143+ color: "black"
144+ opacity: 0.4
145+ }
146+
147+ LoginList {
148+ id: loginList
149+ objectName: "loginList"
150+
151+ anchors {
152+ horizontalCenter: parent.horizontalCenter
153+ top: parent.top
154+ bottom: parent.bottom
154155 }
156+ width: units.gu(40)
157+ boxVerticalOffset: units.gu(14)
158+ enabled: !coverPage.shown && visible
159+ visible: !delayedLockscreen.visible
160+
161+ locked: root.locked
162+
163+ onSelected: if (enabled) root.selected(index)
164+ onResponded: root.responded(response)
165+ }
166+
167+ DelayedLockscreen {
168+ id: delayedLockscreen
169+ objectName: "delayedLockscreen"
170+ anchors.fill: parent
171+ visible: delayMinutes > 0
172+ alphaNumeric: loginList.alphanumeric
155173 }
156174
157175 function maybeShow() {
@@ -179,15 +197,9 @@ FocusScope {
179197
180198 onShowProgressChanged: {
181199 if (showProgress === 1) {
182− lockscreen.reset();
183− }
184−
185− if (showProgress === 0) {
186− if (root.locked) {
187− lockscreen.clear(false); // to reset focus if necessary
188− } else {
189− root.responded("");
190− }
200+ loginList.reset();
201+ } else if (showProgress === 0) {
202+ loginList.tryToUnlock();
191203 }
192204 }
193205
@@ -199,4 +211,78 @@ FocusScope {
199211 }
200212 }
201213 }
214+
215+ StyledItem {
216+ id: bottomBar
217+ visible: lockscreen.shown
218+ height: units.gu(4)
219+
220+ anchors.left: parent.left
221+ anchors.right: parent.right
222+ anchors.top: parent.bottom
223+ anchors.topMargin: - height * (1 - coverPage.showProgress)
224+ - (inputMethod && inputMethod.visible ?
225+ inputMethod.keyboardRectangle.height : 0)
226+
227+ Rectangle {
228+ color: UbuntuColors.porcelain // matches OSK background
229+ anchors.fill: parent
230+ }
231+
232+ Label {
233+ text: i18n.tr("Cancel")
234+ anchors.left: parent.left
235+ anchors.leftMargin: units.gu(2)
236+ anchors.top: parent.top
237+ anchors.bottom: parent.bottom
238+ verticalAlignment: Text.AlignVCenter
239+ font.weight: Font.Light
240+ fontSize: "small"
241+ color: UbuntuColors.slate
242+
243+ AbstractButton {
244+ anchors.fill: parent
245+ anchors.leftMargin: -units.gu(2)
246+ anchors.rightMargin: -units.gu(2)
247+ onClicked: coverPage.show()
248+ }
249+ }
250+
251+ Label {
252+ objectName: "emergencyCallLabel"
253+ text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency")
254+ anchors.right: parent.right
255+ anchors.rightMargin: units.gu(2)
256+ anchors.top: parent.top
257+ anchors.bottom: parent.bottom
258+ verticalAlignment: Text.AlignVCenter
259+ font.weight: Font.Light
260+ fontSize: "small"
261+ color: UbuntuColors.slate
262+ // TODO: uncomment once bug 1616538 is fixed
263+ // visible: telepathyHelper.ready && telepathyHelper.emergencyCallsAvailable
264+ enabled: visible
265+
266+ AbstractButton {
267+ anchors.fill: parent
268+ anchors.leftMargin: -units.gu(2)
269+ anchors.rightMargin: -units.gu(2)
270+ onClicked: root.emergencyCall()
271+ }
272+ }
273+ }
274+
275+ // FIXME: It's difficult to keep something tied closely to the OSK (bug
276+ // 1616163). But as a hack to avoid the background peeking out,
277+ // we add an extra Rectangle that just serves to hide the background
278+ // during OSK animations.
279+ Rectangle {
280+ visible: bottomBar.visible
281+ height: inputMethod && inputMethod.visible ?
282+ inputMethod.keyboardRectangle.height : 0
283+ anchors.bottom: parent.bottom
284+ anchors.left: parent.left
285+ anchors.right: parent.right
286+ color: UbuntuColors.porcelain
287+ }
202288}