on xenial help sign in
Allow running the dialer-app in emergency mode when the screen is locked.

Approved by: Nick Dedekind, Seth Arnold

commit27c1c3c756c9dbdd3687fc5770391579da25962b authorMichael Terry <michael.terry@canonical.com> dateMon 21 Jul 2014, 14:56 (12 years ago) parent70f90d117002e2
9 files changed+342−47
qml/Components/Lockscreen.qml+17−5 qml/Greeter/Greeter.qml+1−1 qml/Shell.qml+84−27 qml/Stages/PhoneStage.qml+13−1 tests/mocks/LightDM/single-pin/GreeterPrivate.cpp+1−9 tests/qmltests/CMakeLists.txt+3−3 tests/qmltests/Greeter/tst_Lockscreen.qml+1−1 tests/qmltests/tst_Shell.qml+19 tests/qmltests/tst_ShellWithPin.qml+203
qml/Components/Lockscreen.qml+17−5
@@ -186,6 +186,17 @@ Showable {
186186 }
187187
188188 Column {
189+ id: emergencyCallColumn
190+
191+ // FIXME: We *should* show emergency dialer if there is a SIM present,
192+ // regardless of whether the side stage is enabled. But right now,
193+ // the assumption is that narrow screens are phones which have SIMs
194+ // and wider screens are tablets which don't. When we do allow this
195+ // on devices with a side stage and a SIM, work should be done to
196+ // ensure that the main stage is disabled while the dialer is present
197+ // in the side stage.
198+ visible: !shell.sideStageEnabled
199+
189200 anchors {
190201 left: parent.left
191202 bottom: parent.bottom
@@ -203,11 +214,6 @@ Showable {
203214 name: "phone-app-call-symbolic"
204215 color: "#f3f3e7"
205216 opacity: 0.6
206−
207− MouseArea {
208− anchors.fill: parent
209− onClicked: root.emergencyCall()
210− }
211217 }
212218
213219 Label {
@@ -219,6 +225,12 @@ Showable {
219225 }
220226 }
221227
228+ MouseArea {
229+ anchors.fill: emergencyCallColumn
230+ onClicked: root.emergencyCall()
231+ enabled: emergencyCallColumn.visible
232+ }
233+
222234 Component {
223235 id: infoPopupComponent
224236 Dialog {
qml/Greeter/Greeter.qml+1−1
@@ -70,7 +70,7 @@ Showable {
7070 DraggingArea {
7171 id: dragHandle
7272 anchors.fill: parent
73− enabled: greeter.narrowMode || !greeter.locked
73+ enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled
7474 orientation: Qt.Horizontal
7575 propagateComposedEvents: true
7676
qml/Shell.qml+84−27
@@ -137,7 +137,7 @@ FocusScope {
137137 id: dash
138138 objectName: "dash"
139139
140− available: !greeter.shown && !lockscreen.shown
140+ available: !LightDM.Greeter.active
141141 hides: [stages, launcher, panel.indicators]
142142 shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
143143 enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
@@ -200,7 +200,7 @@ FocusScope {
200200
201201 x: {
202202 if (shown) {
203− if (overlayMode || locked) {
203+ if (overlayMode || locked || greeter.fakeActiveForApp !== "") {
204204 return 0;
205205 }
206206 return launcher.progress
@@ -245,10 +245,17 @@ FocusScope {
245245 target: ApplicationManager
246246
247247 onFocusRequested: {
248+ if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
249+ lockscreen.show();
250+ }
251+ greeter.hide();
248252 stages.show(true);
249253 }
250254
251255 onFocusedApplicationIdChanged: {
256+ if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
257+ lockscreen.show();
258+ }
252259 if (ApplicationManager.focusedApplicationId.length > 0) {
253260 stages.show(false);
254261 } else {
@@ -439,6 +446,11 @@ FocusScope {
439446
440447 source: shell.sideStageEnabled ? "Stages/StageWithSideStage.qml" : "Stages/PhoneStage.qml"
441448
449+ Binding {
450+ target: applicationsDisplayLoader.item
451+ property: "objectName"
452+ value: "stage"
453+ }
442454 Binding {
443455 target: applicationsDisplayLoader.item
444456 property: "moving"
@@ -454,6 +466,11 @@ FocusScope {
454466 property: "dragAreaWidth"
455467 value: shell.edgeSize
456468 }
469+ Binding {
470+ target: applicationsDisplayLoader.item
471+ property: "spreadEnabled"
472+ value: greeter.fakeActiveForApp === "" // to support emergency dialer hack
473+ }
457474 }
458475 }
459476
@@ -478,6 +495,13 @@ FocusScope {
478495
479496 onEntered: LightDM.Greeter.respond(passphrase);
480497 onCancel: greeter.show()
498+ onEmergencyCall: {
499+ greeter.fakeActiveForApp = "dialer-app"
500+ shell.activateApplication("dialer-app")
501+ lockscreen.hide()
502+ }
503+
504+ onShownChanged: if (shown) greeter.fakeActiveForApp = ""
481505
482506 Component.onCompleted: {
483507 if (LightDM.Users.count == 1) {
@@ -510,6 +534,7 @@ FocusScope {
510534 }
511535 if (LightDM.Greeter.authenticated) {
512536 lockscreen.hide();
537+ greeter.login();
513538 } else {
514539 lockscreen.clear(true);
515540 }
@@ -519,7 +544,7 @@ FocusScope {
519544 Binding {
520545 target: LightDM.Greeter
521546 property: "active"
522− value: greeter.shown || lockscreen.shown
547+ value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
523548 }
524549
525550 Rectangle {
@@ -542,11 +567,16 @@ FocusScope {
542567 }
543568
544569 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
570+ onShowProgressChanged: if (LightDM.Greeter.promptless && showProgress === 0) greeter.login()
545571
546572 Greeter {
547573 id: greeter
548574 objectName: "greeter"
549575
576+ signal sessionStarted() // helpful for tests
577+
578+ property string fakeActiveForApp: ""
579+
550580 available: true
551581 hides: [launcher, panel.indicators]
552582 shown: true
@@ -558,6 +588,16 @@ FocusScope {
558588
559589 dragHandleWidth: shell.edgeSize
560590
591+ function login() {
592+ enabled = false;
593+ LightDM.Greeter.startSessionSync();
594+ sessionStarted();
595+ greeter.hide();
596+ lockscreen.hide();
597+ launcher.hide();
598+ enabled = true;
599+ }
600+
561601 onShownChanged: {
562602 if (shown) {
563603 lockscreen.reset();
@@ -569,6 +609,7 @@ FocusScope {
569609 if (LightDM.Users.count == 1) {
570610 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
571611 }
612+ greeter.fakeActiveForApp = "";
572613 greeter.forceActiveFocus();
573614 }
574615 }
@@ -618,12 +659,40 @@ FocusScope {
618659 }
619660
620661 function showHome() {
621− var animate = !greeter.shown && !stages.shown
622− greeter.hide()
662+ if (edgeDemo.running) {
663+ return
664+ }
665+
666+ if (LightDM.Greeter.active) {
667+ if (!LightDM.Greeter.promptless) {
668+ lockscreen.show()
669+ }
670+ greeter.hide()
671+ }
672+
673+ var animate = !LightDM.Greeter.active && !stages.shown
623674 dash.setCurrentScope("clickscope", animate, false)
624675 stages.hide()
625676 }
626677
678+ function showDash() {
679+ if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
680+ return;
681+ }
682+
683+ if (stages.shown && !stages.overlayMode && !stages.locked) {
684+ stages.hide();
685+ launcher.fadeOut();
686+ } else {
687+ launcher.switchToNextState("visible");
688+ }
689+
690+ if (greeter.shown) {
691+ greeter.hideRight();
692+ launcher.fadeOut();
693+ }
694+ }
695+
627696 Item {
628697 id: overlay
629698
@@ -631,17 +700,18 @@ FocusScope {
631700
632701 Panel {
633702 id: panel
703+ objectName: "panel"
634704 anchors.fill: parent //because this draws indicator menus
635705 indicators {
636706 hides: [launcher]
637− available: edgeDemo.panelEnabled
707+ available: edgeDemo.panelEnabled && greeter.fakeActiveForApp === ""
638708 contentEnabled: edgeDemo.panelContentEnabled
639709 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
640710 panelHeight: units.gu(3)
641711 }
642712 property string focusedAppId: ApplicationManager.focusedApplicationId
643713 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
644− fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown
714+ fullscreenMode: (focusedApplication && stages.fullscreen && !LightDM.Greeter.active) || greeter.fakeActiveForApp !== ""
645715
646716 InputFilterArea {
647717 anchors {
@@ -666,6 +736,7 @@ FocusScope {
666736
667737 Launcher {
668738 id: launcher
739+ objectName: "launcher"
669740
670741 readonly property bool dashSwipe: progress > 0
671742
@@ -673,29 +744,15 @@ FocusScope {
673744 anchors.bottom: parent.bottom
674745 width: parent.width
675746 dragAreaWidth: shell.edgeSize
676− available: edgeDemo.launcherEnabled
747+ available: edgeDemo.launcherEnabled && greeter.fakeActiveForApp === ""
677748
678− onShowDashHome: {
679− if (edgeDemo.running)
680− return;
681−
682− showHome()
683− }
684− onDash: {
685− if (stages.shown && !stages.overlayMode && !stages.locked) {
686− stages.hide();
687− launcher.fadeOut();
688− } else {
689− launcher.switchToNextState("visible");
690− }
691−
692− if (greeter.shown) {
693− greeter.hideRight();
694− launcher.fadeOut();
695− }
696− }
749+ onShowDashHome: showHome()
750+ onDash: showDash()
697751 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
698752 onLauncherApplicationSelected: {
753+ if (greeter.fakeActiveForApp !== "") {
754+ lockscreen.show()
755+ }
699756 if (!edgeDemo.running)
700757 shell.activateApplication(appId)
701758 }
qml/Stages/PhoneStage.qml+13−1
@@ -18,6 +18,7 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Ubuntu.Gestures 0.1
2020import Unity.Application 0.1
21+import LightDM 0.1 as LightDM
2122import Utils 0.1
2223import "../Components"
2324
@@ -33,6 +34,7 @@ Item {
3334 readonly property bool painting: mainScreenshotImage.visible || fadeInScreenshotImage.visible || appSplash.visible || spreadView.visible
3435 property bool fullscreen: priv.focusedApplication ? priv.focusedApplication.fullscreen : false
3536 property bool locked: spreadView.visible
37+ property bool spreadEnabled: true
3638
3739 // Not used for PhoneStage, only useful for SideStage and similar
3840 property bool overlayMode: false
@@ -131,6 +133,11 @@ Item {
131133 mainScreenshotImage.visible = true;
132134 } else if (priv.secondApplicationStarting && priv.waitingForScreenshot) {
133135 applicationSwitchingAnimation.start();
136+ if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
137+ // When greeter is up, no fancy animations, since user may
138+ // glimpse an app they shouldn't
139+ applicationSwitchingAnimation.complete();
140+ }
134141 }
135142 waitingForScreenshot = false;
136143 }
@@ -145,6 +152,11 @@ Item {
145152 priv.newFocusedAppId = appId;
146153 root.fullscreen = ApplicationManager.findApplication(appId).fullscreen;
147154 applicationSwitchingAnimation.start();
155+ if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
156+ // When greeter is up, no fancy animations, since user may
157+ // glimpse an app they shouldn't
158+ applicationSwitchingAnimation.complete();
159+ }
148160 } else {
149161 ApplicationManager.focusApplication(appId);
150162 }
@@ -244,7 +256,7 @@ Item {
244256 EdgeDragArea {
245257 id: spreadDragArea
246258 direction: Direction.Leftwards
247− enabled: ApplicationManager.count > 1 && spreadView.phase != 2
259+ enabled: ApplicationManager.count > 1 && spreadView.phase != 2 && root.spreadEnabled
248260
249261 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
250262 width: root.dragAreaWidth
tests/mocks/LightDM/single-pin/GreeterPrivate.cpp+1−9
@@ -19,8 +19,6 @@
1919#include "../Greeter.h"
2020#include "../GreeterPrivate.h"
2121
22−#include <QDebug>
23−
2422namespace QLightDM
2523{
2624
@@ -34,19 +32,13 @@ GreeterPrivate::GreeterPrivate(Greeter* parent)
3432void GreeterPrivate::handleAuthenticate()
3533{
3634 Q_Q(Greeter);
37−
38− qDebug() << "handleAuthentication called!" << authenticationUser;
39−
40− Q_EMIT q->showPrompt("PIN:", Greeter::PromptTypeSecret);
35+ Q_EMIT q->showPrompt("PIN", Greeter::PromptTypeSecret);
4136}
4237
4338void GreeterPrivate::handleRespond(const QString &response)
4439{
4540 Q_Q(Greeter);
46−
47−
4841 authenticated = (response == "1234");
49− qDebug() << "responding" << response << authenticated;
5042 Q_EMIT q->authenticationComplete();
5143}
5244
tests/qmltests/CMakeLists.txt+3−3
@@ -19,8 +19,8 @@ set(qmltest_DEFAULT_TARGETS qmluitests)
1919set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
2020set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
2121
22−add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
23− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
22+add_qml_test(. Shell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
23+add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single-pin")
2424add_qml_test(Components Carousel)
2525add_qml_test(Components DraggingArea)
2626add_qml_test(Components EdgeDemoOverlay)
@@ -75,4 +75,4 @@ add_qml_test(Panel/Indicators DefaultIndicatorPage ENVIRONMENT "LD_LIBRARY_PATH=
7575# These MenuItemFactory tests need the test/mocks/ to come before plugins/
7676add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
7777add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
78−add_qml_test(Stages PhoneStage)
78+add_qml_test(Stages PhoneStage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
tests/qmltests/Greeter/tst_Lockscreen.qml+1−1
@@ -57,7 +57,7 @@ Rectangle {
5757 target: LightDM.Greeter
5858
5959 onShowPrompt: {
60− if (text.indexOf("PIN") >= 0) {
60+ if (text === "PIN") {
6161 pinPadCheckBox.checked = false
6262 } else {
6363 pinPadCheckBox.checked = true
tests/qmltests/tst_Shell.qml+19
@@ -51,6 +51,11 @@ Item {
5151 id: shell
5252 }
5353
54+ SignalSpy {
55+ id: sessionSpy
56+ signalName: "sessionStarted"
57+ }
58+
5459 UT.UnityTestCase {
5560 name: "Shell"
5661 when: windowShown
@@ -92,6 +97,8 @@ Item {
9297 verify(ok);
9398
9499 swipeAwayGreeter();
100+
101+ sessionSpy.target = findChild(shell, "greeter")
95102 }
96103
97104 function cleanup() {
@@ -528,5 +535,17 @@ Item {
528535 LightDM.Greeter.showGreeter()
529536 tryCompare(greeter, "showProgress", 1)
530537 }
538+
539+ function test_login() {
540+ sessionSpy.clear()
541+
542+ var greeter = findChild(shell, "greeter")
543+ greeter.show()
544+ tryCompare(greeter, "showProgress", 1)
545+
546+ tryCompare(sessionSpy, "count", 0)
547+ swipeAwayGreeter()
548+ tryCompare(sessionSpy, "count", 1)
549+ }
531550 }
532551}
tests/qmltests/tst_ShellWithPin.qmlnew file+203
@@ -0,0 +1,203 @@
1+/*
2+ * Copyright (C) 2014 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 QtTest 1.0
19+import GSettings 1.0
20+import LightDM 0.1 as LightDM
21+import Unity.Application 0.1
22+import Unity.Test 0.1 as UT
23+import Powerd 0.1
24+
25+import "../../qml"
26+
27+Item {
28+ width: shell.width
29+ height: shell.height
30+
31+ QtObject {
32+ id: applicationArguments
33+
34+ function hasGeometry() {
35+ return false;
36+ }
37+
38+ function width() {
39+ return 0;
40+ }
41+
42+ function height() {
43+ return 0;
44+ }
45+ }
46+
47+ Shell {
48+ id: shell
49+ }
50+
51+ SignalSpy {
52+ id: sessionSpy
53+ signalName: "sessionStarted"
54+ }
55+
56+ UT.UnityTestCase {
57+ name: "ShellWithPin"
58+ when: windowShown
59+
60+ function initTestCase() {
61+ var ok = false;
62+ var attempts = 0;
63+ var maxAttempts = 1000;
64+
65+ // Qt loads a qml scene asynchronously. So early on, some findChild() calls made in
66+ // tests may fail because the desired child item wasn't loaded yet.
67+ // Thus here we try to ensure the scene has been fully loaded before proceeding with the tests.
68+ // As I couldn't find an API in QQuickView & friends to tell me that the scene is 100% loaded
69+ // (all items instantiated, etc), I resort to checking the existence of some key items until
70+ // repeatedly until they're all there.
71+ do {
72+ var dashContentList = findChild(shell, "dashContentList");
73+ waitForRendering(dashContentList);
74+ var homeLoader = findChild(dashContentList, "clickscope loader");
75+ ok = homeLoader !== null
76+ && homeLoader.item !== undefined;
77+
78+ var greeter = findChild(shell, "greeter");
79+ ok &= greeter !== null;
80+
81+ var launcherPanel = findChild(shell, "launcherPanel");
82+ ok &= launcherPanel !== null;
83+
84+ attempts++;
85+ if (!ok) {
86+ console.log("Attempt " + attempts + " failed. Waiting a bit before trying again.");
87+ // wait a bit before retrying
88+ wait(100);
89+ } else {
90+ console.log("All seem fine after " + attempts + " attempts.");
91+ }
92+ } while (!ok && attempts <= maxAttempts);
93+
94+ verify(ok);
95+
96+ sessionSpy.target = findChild(shell, "greeter")
97+ }
98+
99+ function init() {
100+ swipeAwayGreeter()
101+ }
102+
103+ function cleanup() {
104+ LightDM.Greeter.showGreeter()
105+ var greeter = findChild(shell, "greeter")
106+ tryCompare(greeter, "showProgress", 1)
107+
108+ // kill all (fake) running apps
109+ killApps()
110+ }
111+
112+ function killApps() {
113+ while (ApplicationManager.count > 0) {
114+ ApplicationManager.stopApplication(ApplicationManager.get(0).appId)
115+ }
116+ compare(ApplicationManager.count, 0)
117+ }
118+
119+ function swipeAwayGreeter() {
120+ var greeter = findChild(shell, "greeter");
121+ tryCompare(greeter, "showProgress", 1);
122+
123+ var touchX = shell.width - (shell.edgeSize / 2);
124+ var touchY = shell.height / 2;
125+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
126+
127+ // wait until the animation has finished
128+ tryCompare(greeter, "showProgress", 0);
129+
130+ // and for pin to be ready
131+ var lockscreen = findChild(shell, "lockscreen");
132+ var pinPadLoader = findChild(lockscreen, "pinPadLoader");
133+ tryCompare(pinPadLoader, "status", Loader.Ready)
134+ waitForRendering(lockscreen)
135+ }
136+
137+ function enterPin(pin) {
138+ var inputField = findChild(shell, "pinentryField")
139+ for (var i = 0; i < pin.length; ++i) {
140+ var character = pin.charAt(i)
141+ var button = findChild(shell, "pinPadButton" + character)
142+ mouseClick(button, units.gu(1), units.gu(1))
143+ }
144+ }
145+
146+ function test_login() {
147+ tryCompare(sessionSpy, "count", 0)
148+ enterPin("1234")
149+ tryCompare(sessionSpy, "count", 1)
150+ }
151+
152+ function test_emergencyCall() {
153+ var greeter = findChild(shell, "greeter")
154+ var lockscreen = findChild(shell, "lockscreen")
155+ var emergencyButton = findChild(lockscreen, "emergencyCallIcon")
156+ var panel = findChild(shell, "panel")
157+ var indicators = findChild(shell, "indicators")
158+ var launcher = findChild(shell, "launcher")
159+ var stage = findChild(shell, "stage")
160+
161+ mouseClick(emergencyButton, units.gu(1), units.gu(1))
162+
163+ tryCompare(greeter, "fakeActiveForApp", "dialer-app")
164+ tryCompare(lockscreen, "shown", false)
165+ tryCompare(panel, "fullscreenMode", true)
166+ tryCompare(indicators, "available", false)
167+ tryCompare(launcher, "available", false)
168+ tryCompare(stage, "spreadEnabled", false)
169+
170+ // Cancel emergency mode, and go back to normal
171+ waitForRendering(greeter)
172+ LightDM.Greeter.showGreeter()
173+
174+ tryCompare(greeter, "shown", true)
175+ tryCompare(greeter, "fakeActiveForApp", "")
176+ tryCompare(lockscreen, "shown", true)
177+ tryCompare(panel, "fullscreenMode", false)
178+ tryCompare(indicators, "available", true)
179+ tryCompare(launcher, "available", true)
180+ tryCompare(stage, "spreadEnabled", true)
181+ }
182+
183+ function test_emergencyCallCrash() {
184+ var lockscreen = findChild(shell, "lockscreen")
185+ var emergencyButton = findChild(lockscreen, "emergencyCallIcon")
186+ mouseClick(emergencyButton, units.gu(1), units.gu(1))
187+
188+ tryCompare(lockscreen, "shown", false)
189+ killApps() // kill dialer-app, as if it crashed
190+ tryCompare(lockscreen, "shown", true)
191+ }
192+
193+ function test_emergencyCallAppLaunch() {
194+ var lockscreen = findChild(shell, "lockscreen")
195+ var emergencyButton = findChild(lockscreen, "emergencyCallIcon")
196+ mouseClick(emergencyButton, units.gu(1), units.gu(1))
197+
198+ tryCompare(lockscreen, "shown", false)
199+ ApplicationManager.startApplication("gallery-app", ApplicationManager.NoFlag)
200+ tryCompare(lockscreen, "shown", true)
201+ }
202+ }
203+}