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.0
18 import Ubuntu.Components 1.0
19 import Ubuntu.Components.Popups 1.0
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  readonly property string passphrase: (pinPadLoader.item && pinPadLoader.item.passphrase) ? pinPadLoader.item.passphrase : ""
64 
65  signal entered(string passphrase)
66  signal cancel()
67  signal emergencyCall()
68  signal infoPopupConfirmed()
69 
70  onActiveFocusChanged: if (activeFocus && pinPadLoader.item) pinPadLoader.item.forceActiveFocus()
71 
72  function reset() {
73  // This causes the loader below to destry and recreate the source
74  pinPadLoader.resetting = true;
75  pinPadLoader.resetting = false;
76  }
77 
78  function clear(showAnimation) {
79  if (pinPadLoader.item) {
80  pinPadLoader.item.clear(showAnimation);
81  }
82  pinPadLoader.showWrongText = showAnimation
83  pinPadLoader.waiting = false
84  }
85 
86  function showInfoPopup(title, text) {
87  var popup = PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
88  // FIXME: SDK will do this internally soonish
89  popup.z = Number.MAX_VALUE
90  }
91 
92  Rectangle {
93  // In case background fails to load
94  id: backgroundBackup
95  anchors.fill: parent
96  color: "black"
97  visible: root.background.toString() !== ""
98  }
99 
100  Image {
101  id: backgroundImage
102  objectName: "lockscreenBackground"
103  anchors {
104  fill: parent
105  }
106  // Limit how much memory we'll reserve for this image
107  sourceSize.height: height
108  sourceSize.width: width
109  source: root.required ? root.background : ""
110  fillMode: Image.PreserveAspectCrop
111  }
112 
113  // This is to
114  // a) align it with the greeter and
115  // b) keep the white fonts readable on bright backgrounds
116  Rectangle {
117  anchors.fill: parent
118  color: "black"
119  opacity: root.darkenBackground
120  }
121 
122  MouseArea {
123  anchors.fill: root
124  onClicked: {
125  if (pinPadLoader.item)
126  pinPadLoader.item.forceActiveFocus()
127  }
128  }
129 
130  FocusScope {
131  id: loaderScope
132  anchors.fill: parent
133 
134  Loader {
135  id: pinPadLoader
136  objectName: "pinPadLoader"
137  anchors.fill: parent
138  property bool resetting: false
139  property bool waiting: false
140  property bool showWrongText: false
141 
142  source: {
143  if (resetting || !root.required) {
144  return ""
145  } else if (root.delayMinutes > 0) {
146  return "DelayedLockscreen.qml"
147  } else if (root.alphaNumeric) {
148  return "PassphraseLockscreen.qml"
149  } else {
150  return "PinLockscreen.qml"
151  }
152  }
153  onSourceChanged: {
154  waiting = false
155  showWrongText = false
156  if (loaderScope.activeFocus && pinPadLoader.item)
157  pinPadLoader.item.forceActiveFocus()
158  }
159 
160  Connections {
161  target: pinPadLoader.item
162 
163  onEntered: {
164  pinPadLoader.waiting = true
165  root.entered(passphrase);
166  }
167 
168  onCancel: {
169  root.cancel()
170  }
171  }
172 
173  Binding {
174  target: pinPadLoader.item
175  property: "minPinLength"
176  value: root.minPinLength
177  }
178  Binding {
179  target: pinPadLoader.item
180  property: "maxPinLength"
181  value: root.maxPinLength
182  }
183  Binding {
184  target: pinPadLoader.item
185  property: "infoText"
186  value: root.infoText
187  }
188  Binding {
189  target: pinPadLoader.item
190  property: "retryText"
191  value: root.retryText
192  }
193  Binding {
194  target: pinPadLoader.item
195  property: "errorText"
196  value: pinPadLoader.showWrongText ? root.errorText : ""
197  }
198  Binding {
199  target: pinPadLoader.item
200  property: "entryEnabled"
201  value: !pinPadLoader.waiting
202  }
203  Binding {
204  target: pinPadLoader.item
205  property: "alphaNumeric"
206  value: root.alphaNumeric
207  }
208  Binding {
209  target: pinPadLoader.item
210  property: "delayMinutes"
211  value: root.delayMinutes
212  }
213  }
214  Binding {
215  target: pinPadLoader.item
216  property: "showCancelButton"
217  value: root.showCancelButton
218  }
219  }
220 
221  Item {
222  id: emergencyCallRow
223 
224  visible: showEmergencyCallButton
225 
226  anchors {
227  bottom: parent.bottom
228  bottomMargin: units.gu(7) + (Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0)
229  left: parent.left
230  right: parent.right
231  }
232 
233  Label {
234  id: emergencyCallLabel
235  objectName: "emergencyCallLabel"
236  anchors.horizontalCenter: parent.horizontalCenter
237 
238  text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency Call")
239  color: "#f3f3e7"
240  }
241 
242  Icon {
243  id: emergencyCallIcon
244  anchors.left: emergencyCallLabel.right
245  anchors.leftMargin: units.gu(1)
246  width: emergencyCallLabel.height
247  height: emergencyCallLabel.height
248  name: "call-start"
249  color: "#f3f3e7"
250  }
251 
252  MouseArea {
253  anchors.top: emergencyCallLabel.top
254  anchors.bottom: emergencyCallLabel.bottom
255  anchors.left: emergencyCallLabel.left
256  anchors.right: emergencyCallIcon.right
257  onClicked: root.emergencyCall()
258  }
259  }
260 
261  Component {
262  id: infoPopupComponent
263  Dialog {
264  id: dialog
265  objectName: "infoPopup"
266  modal: true
267 
268  Button {
269  objectName: "infoPopupOkButton"
270  text: i18n.tr("OK")
271  onClicked: {
272  PopupUtils.close(dialog)
273  root.infoPopupConfirmed();
274  }
275  }
276  }
277  }
278 }