Unity 8
Lockscreen.qml
1 /*
2  * Copyright (C) 2013 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.4
18 import Ubuntu.Components 1.3
19 import Ubuntu.Components.Popups 1.3
20 import Ubuntu.Telephony 0.1 as Telephony
21 
22 Showable {
23  id: root
24 
25  // Determine if a numeric or alphanumeric pad is used.
26  property bool alphaNumeric: false
27 
28  // Whether to show an emergency call button
29  property bool showEmergencyCallButton: true
30 
31  // Whether to show a cancel button (not all lockscreen types normally do anyway)
32  property bool showCancelButton: true
33 
34  // Informational text. (e.g. some text to tell which domain this is pin is entered for)
35  property string infoText: ""
36 
37  // Retries text (e.g. 3 retries left)
38  // (This is not currently used, but will be necessary for SIM unlock screen)
39  property string retryText: ""
40 
41  // The text to be displayed in case the login failed
42  property string errorText: ""
43 
44  // If > 0, a forced delay is happening
45  property int delayMinutes: 0
46 
47  // Set those to a value greater 0 to restrict the pin length.
48  // If both are unset, the Lockscreen will show a confirm button and allow typing any length of pin before
49  // confirming. If minPinLength is set to a value > 0, the confirm button will only become active when the
50  // entered pin is at least that long. If maxPinLength is set, the lockscreen won't allow entering any
51  // more numbers than that. If both are set to the same value, the lockscreen will enter auto confirming
52  // behavior, hiding the confirmation button and triggering that automatically when the entered pin reached
53  // that length. This is ignored by the alphaNumeric lockscreen as that one is always confirmed by pressing
54  // enter on the OSK.
55  property int minPinLength: -1
56  property int maxPinLength: -1
57 
58  property url background: ""
59  // Use this to put a black overlay above the background
60  // 0: normal background, 1: black background
61  property real darkenBackground: 0
62 
63  property color foregroundColor: "#f3f3e7"
64 
65  readonly property string passphrase: (pinPadLoader.item && pinPadLoader.item.passphrase) ? pinPadLoader.item.passphrase : ""
66 
67  signal entered(string passphrase)
68  signal cancel()
69  signal emergencyCall()
70  signal infoPopupConfirmed()
71 
72  onActiveFocusChanged: if (activeFocus && pinPadLoader.item) pinPadLoader.item.forceActiveFocus()
73 
74  function reset() {
75  // This causes the loader below to destry and recreate the source
76  pinPadLoader.resetting = true;
77  pinPadLoader.resetting = false;
78  }
79 
80  function clear(showAnimation) {
81  if (pinPadLoader.item) {
82  pinPadLoader.item.clear(showAnimation);
83  }
84  pinPadLoader.showWrongText = showAnimation
85  pinPadLoader.waiting = false
86  }
87 
88  function showInfoPopup(title, text) {
89  var popup = PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
90  // FIXME: SDK will do this internally soonish
91  popup.z = Number.MAX_VALUE
92  }
93 
94  function showText(text) {
95  // Programmatically enters the given text into the lockscreen
96  if (pinPadLoader.item) {
97  pinPadLoader.item.showText(text);
98  pinPadLoader.waiting = true;
99  }
100  }
101 
102  Rectangle {
103  // In case background fails to load
104  id: backgroundBackup
105  anchors.fill: parent
106  color: "black"
107  visible: root.background.toString() !== ""
108  }
109 
110  Image {
111  id: backgroundImage
112  objectName: "lockscreenBackground"
113  anchors {
114  fill: parent
115  }
116  // Limit how much memory we'll reserve for this image
117  sourceSize.height: height
118  sourceSize.width: width
119  source: root.required ? root.background : ""
120  fillMode: Image.PreserveAspectCrop
121  }
122 
123  // This is to
124  // a) align it with the greeter and
125  // b) keep the white fonts readable on bright backgrounds
126  Rectangle {
127  anchors.fill: parent
128  color: "black"
129  opacity: root.darkenBackground
130  }
131 
132  Loader {
133  id: pinPadLoader
134  objectName: "pinPadLoader"
135  anchors.fill: parent
136  property bool resetting: false
137  property bool waiting: false
138  property bool showWrongText: false
139  focus: true
140 
141  source: {
142  if (resetting || !root.required) {
143  return ""
144  } else if (root.delayMinutes > 0) {
145  return "DelayedLockscreen.qml"
146  } else if (root.alphaNumeric) {
147  return "PassphraseLockscreen.qml"
148  } else {
149  return "PinLockscreen.qml"
150  }
151  }
152  onSourceChanged: {
153  waiting = false
154  showWrongText = false
155  }
156 
157  Connections {
158  target: pinPadLoader.item
159 
160  onEntered: {
161  pinPadLoader.waiting = true
162  root.entered(passphrase);
163  }
164 
165  onCancel: {
166  root.cancel()
167  }
168  }
169 
170  Binding {
171  target: pinPadLoader.item
172  property: "minPinLength"
173  value: root.minPinLength
174  }
175  Binding {
176  target: pinPadLoader.item
177  property: "maxPinLength"
178  value: root.maxPinLength
179  }
180  Binding {
181  target: pinPadLoader.item
182  property: "infoText"
183  value: root.infoText
184  }
185  Binding {
186  target: pinPadLoader.item
187  property: "retryText"
188  value: root.retryText
189  }
190  Binding {
191  target: pinPadLoader.item
192  property: "errorText"
193  value: pinPadLoader.showWrongText ? root.errorText : ""
194  }
195  Binding {
196  target: pinPadLoader.item
197  property: "entryEnabled"
198  value: !pinPadLoader.waiting
199  }
200  Binding {
201  target: pinPadLoader.item
202  property: "alphaNumeric"
203  value: root.alphaNumeric
204  }
205  Binding {
206  target: pinPadLoader.item
207  property: "delayMinutes"
208  value: root.delayMinutes
209  }
210  Binding {
211  target: pinPadLoader.item
212  property: "showCancelButton"
213  value: root.showCancelButton
214  }
215  Binding {
216  target: pinPadLoader.item
217  property: "foregroundColor"
218  value: root.foregroundColor
219  }
220  }
221 
222  Item {
223  id: emergencyCallRow
224 
225  visible: showEmergencyCallButton
226 
227  anchors {
228  bottom: parent.bottom
229  bottomMargin: units.gu(7) + (Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0)
230  left: parent.left
231  right: parent.right
232  }
233 
234  Label {
235  id: emergencyCallLabel
236  objectName: "emergencyCallLabel"
237  anchors.horizontalCenter: parent.horizontalCenter
238 
239  text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency Call")
240  color: root.foregroundColor
241  }
242 
243  Icon {
244  id: emergencyCallIcon
245  anchors.left: emergencyCallLabel.right
246  anchors.leftMargin: units.gu(1)
247  width: emergencyCallLabel.height
248  height: emergencyCallLabel.height
249  name: "call-start"
250  color: root.foregroundColor
251  }
252 
253  MouseArea {
254  anchors.top: emergencyCallLabel.top
255  anchors.bottom: emergencyCallLabel.bottom
256  anchors.left: emergencyCallLabel.left
257  anchors.right: emergencyCallIcon.right
258  onClicked: root.emergencyCall()
259  }
260  }
261 
262  Component {
263  id: infoPopupComponent
264  ShellDialog {
265  id: dialog
266  objectName: "infoPopup"
267  property var dialogLoader // dummy to satisfy ShellDialog's context dependent prop
268 
269  Button {
270  objectName: "infoPopupOkButton"
271  text: i18n.tr("OK")
272  onClicked: {
273  PopupUtils.close(dialog)
274  root.infoPopupConfirmed();
275  }
276  }
277  }
278  }
279 }