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  Loader {
125  id: pinPadLoader
126  objectName: "pinPadLoader"
127  anchors.fill: parent
128  property bool resetting: false
129  property bool waiting: false
130  property bool showWrongText: false
131  focus: true
132 
133  source: {
134  if (resetting || !root.required) {
135  return ""
136  } else if (root.delayMinutes > 0) {
137  return "DelayedLockscreen.qml"
138  } else if (root.alphaNumeric) {
139  return "PassphraseLockscreen.qml"
140  } else {
141  return "PinLockscreen.qml"
142  }
143  }
144  onSourceChanged: {
145  waiting = false
146  showWrongText = false
147  }
148 
149  Connections {
150  target: pinPadLoader.item
151 
152  onEntered: {
153  pinPadLoader.waiting = true
154  root.entered(passphrase);
155  }
156 
157  onCancel: {
158  root.cancel()
159  }
160  }
161 
162  Binding {
163  target: pinPadLoader.item
164  property: "minPinLength"
165  value: root.minPinLength
166  }
167  Binding {
168  target: pinPadLoader.item
169  property: "maxPinLength"
170  value: root.maxPinLength
171  }
172  Binding {
173  target: pinPadLoader.item
174  property: "infoText"
175  value: root.infoText
176  }
177  Binding {
178  target: pinPadLoader.item
179  property: "retryText"
180  value: root.retryText
181  }
182  Binding {
183  target: pinPadLoader.item
184  property: "errorText"
185  value: pinPadLoader.showWrongText ? root.errorText : ""
186  }
187  Binding {
188  target: pinPadLoader.item
189  property: "entryEnabled"
190  value: !pinPadLoader.waiting
191  }
192  Binding {
193  target: pinPadLoader.item
194  property: "alphaNumeric"
195  value: root.alphaNumeric
196  }
197  Binding {
198  target: pinPadLoader.item
199  property: "delayMinutes"
200  value: root.delayMinutes
201  }
202  Binding {
203  target: pinPadLoader.item
204  property: "showCancelButton"
205  value: root.showCancelButton
206  }
207  Binding {
208  target: pinPadLoader.item
209  property: "foregroundColor"
210  value: root.foregroundColor
211  }
212  }
213 
214  Item {
215  id: emergencyCallRow
216 
217  visible: showEmergencyCallButton
218 
219  anchors {
220  bottom: parent.bottom
221  bottomMargin: units.gu(7) + (Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0)
222  left: parent.left
223  right: parent.right
224  }
225 
226  Label {
227  id: emergencyCallLabel
228  objectName: "emergencyCallLabel"
229  anchors.horizontalCenter: parent.horizontalCenter
230 
231  text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency Call")
232  color: root.foregroundColor
233  }
234 
235  Icon {
236  id: emergencyCallIcon
237  anchors.left: emergencyCallLabel.right
238  anchors.leftMargin: units.gu(1)
239  width: emergencyCallLabel.height
240  height: emergencyCallLabel.height
241  name: "call-start"
242  color: root.foregroundColor
243  }
244 
245  MouseArea {
246  anchors.top: emergencyCallLabel.top
247  anchors.bottom: emergencyCallLabel.bottom
248  anchors.left: emergencyCallLabel.left
249  anchors.right: emergencyCallIcon.right
250  onClicked: root.emergencyCall()
251  }
252  }
253 
254  Component {
255  id: infoPopupComponent
256  Dialog {
257  id: dialog
258  objectName: "infoPopup"
259  modal: true
260 
261  Button {
262  objectName: "infoPopupOkButton"
263  text: i18n.tr("OK")
264  onClicked: {
265  PopupUtils.close(dialog)
266  root.infoPopupConfirmed();
267  }
268  }
269  }
270  }
271 }