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