@@ -0,0 +1,1366 @@
2+ * Copyright 2014-2016 Canonical Ltd.
3+ * Copyright 2021 UBports Foundation
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; version 3.
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19+import QtQuick.Window 2.2
22+import "../../../qml/Greeter"
23+import LightDMController 0.1
24+import LightDM.FullLightDM 0.1 as LightDM
25+import Ubuntu.Components 1.3
26+import Ubuntu.Components.ListItems 1.3 as ListItem
27+import Ubuntu.Telephony 0.1 as Telephony
28+import Unity.Test 0.1 as UT
37+ theme.name: "Ubuntu.Components.Themes.Ambiance"
39+ Component.onCompleted: {
40+ // must set the mock mode before loading the Shell
41+ LightDMController.userMode = "single";
47+ width: root.width - controls.width
48+ height: parent.height
53+ anchors.horizontalCenter: parent.horizontalCenter
54+ anchors.verticalCenter: parent.verticalCenter
60+ height: parent.height
63+ property bool itemDestroyed: false
64+ sourceComponent: Component {
68+ background: "/usr/share/backgrounds/warty-final-ubuntu.png"
69+ backgroundSourceSize: width
70+ userModel: LightDM.Users
71+ infographicModel: LightDM.Infographic
73+ launcherOffset: parseFloat(launcherOffsetField.text)
74+ currentIndex: parseInt(currentIndexField.text, 10)
75+ delayMinutes: parseInt(delayMinutesField.text, 10)
76+ panelHeight: parseFloat(panelHeightField.text)
77+ locked: lockedCheckBox.checked
78+ inputMethodRect: fakeKeyboard.childrenRect
79+ property var testKeyboard: fakeKeyboard
81+ usageMode: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
82+ multiUser: multiUserCheckBox.checked
83+ orientation: orientationSelector.model[orientationSelector.selectedIndex] == "landscape" ? Qt.LandscapeOrientation : Qt.PortraitOrientation
85+ Component.onDestruction: {
86+ loader.itemDestroyed = true
91+ currentIndexField.text = index;
98+ anchors.bottom: view.bottom
100+ height: visible ? view.height * 0.6 : 0
101+ visible: keyboardVisibleCheckBox.checked
103+ text: "Keyboard Rectangle"
106+ fontSizeMode: Text.Fit
107+ minimumPixelSize: 10; font.pixelSize: 200
108+ verticalAlignment: Text.AlignVCenter
109+ x: (parent.width - width) / 2
110+ y: (parent.height - height) / 2
112+ height: parent.height
119+ state: loader.item ? loader.item.usageMode + "-" + (loader.item.isLandscape ? "landscape" : "portrait") : "phone-portrait"
123+ name: "phone-portrait"
125+ target: viewContainer
127+ height: units.gu(71)
131+ name: "phone-landscape"
133+ target: viewContainer
135+ height: units.gu(40)
139+ name: "tablet-landscape"
141+ target: viewContainer
142+ width: units.gu(100)
143+ height: units.gu(71)
147+ name: "tablet-portrait"
149+ target: viewContainer
151+ height: units.gu(100)
155+ name: "desktop-portrait"
157+ target: viewContainer
159+ height: parent.height
163+ name: "desktop-landscape"
165+ target: viewContainer
167+ height: parent.height
176+ color: theme.palette.normal.background
178+ height: parent.height
180+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
181+ spacing: units.gu(1)
185+ onClicked: loader.item.hide()
190+ text: "Show Message"
191+ onClicked: LightDMService.prompts.append(messageField.text, LightDMService.prompts.Message)
202+ onClicked: LightDMService.prompts.append(promptField.text, isSecretCheckBox.checked ? LightDMService.prompts.Secret : LightDMService.prompts.Question)
210+ id: isSecretCheckBox
218+ text: "Notify Auth Failure"
220+ loader.item.notifyAuthenticationFailed();
226+ text: "Try To Unlock"
227+ onClicked: loader.item.tryToUnlock(toTheRightCheckBox.checked)
230+ id: toTheRightCheckBox
237+ text: "Usage scenario"
240+ ListItem.ItemSelector {
241+ id: usageScenarioSelector
242+ anchors { left: parent.left; right: parent.right }
243+ activeFocusOnPress: false
244+ model: ["phone", "tablet", "desktop"]
250+ ListItem.ItemSelector {
251+ id: orientationSelector
252+ anchors { left: parent.left; right: parent.right }
253+ activeFocusOnPress: false
254+ model: ["portrait", "landscape"]
258+ id: launcherOffsetField
263+ text: "launcherOffset"
268+ id: currentIndexField
273+ text: "currentIndex"
278+ id: delayMinutesField
283+ text: "delayMinutes"
288+ id: panelHeightField
306+ id: multiUserCheckBox
309+ LightDMController.userMode = "full";
311+ LightDMController.userMode = "single";
315+ target: LightDMController
316+ onSessionModeChanged: {
317+ if (LightDMController.userMode === "full") {
318+ multipleSessionsCheckbox.checked = true;
320+ multipleSessionsCheckbox.checked = false;
331+ id: alphanumericCheckBox
335+ text: "alphanumeric"
340+ text: "selected: " + selectedSpy.count
345+ text: "responded: " + respondedSpy.count
350+ text: "teased: " + teaseSpy.count
355+ text: "emergency: " + emergencySpy.count
360+ text: "infographics: " + infographicDataChangedSpy.count
364+ id: multipleSessions
366+ id: multipleSessionsCheckbox
369+ LightDMController.sessionMode = "full";
371+ LightDMController.sessionMode = "single";
375+ target: LightDMController
376+ onSessionModeChanged: {
377+ if (LightDMController.sessionMode === "full") {
378+ multipleSessionsCheckbox.checked = true;
380+ multipleSessionsCheckbox.checked = false;
386+ text: "Multiple Sessions"
391+ id: numSessionsSlider
395+ maximumValue: LightDMController.numAvailableSessions
396+ value: LightDMController.numSessions
397+ visible: LightDMController.sessionMode === "full"
399+ target: LightDMController
400+ property: "numSessions"
401+ value: numSessionsSlider.value
405+ text: "Available Sessions"
412+ loader.active = false;
413+ loader.active = true;
419+ id: keyboardVisibleCheckBox
422+ text: "Keyboard Visible"
429+/* FIXME: infographic user is hardcoded to "has-password",
430+ * needs to be set to current user to test in multiUser mode
433+ target: LightDM.Infographic
434+ property: "username"
435+ value: "has-password"
441+ signalName: "selected"
447+ signalName: "responded"
459+ signalName: "emergencyCall"
463+ id: infographicDataChangedSpy
464+ target: LightDM.Infographic
465+ signalName: "dataChanged"
472+ property Item view: loader.status === Loader.Ready ? loader.item : null
473+ property url testIconDirectory: Qt.resolvedUrl("../../../qml/Greeter/graphics/session_icons")
476+ selectIndex(0); // break binding with text field
477+ tryCompare(LightDMService.prompts, "count", 1);
478+ selectedSpy.clear();
479+ respondedSpy.clear();
481+ emergencySpy.clear();
482+ infographicDataChangedSpy.clear();
483+ LightDMController.reset();
484+ LightDM.Sessions.iconSearchDirectories = [testIconDirectory];
486+ waitForRendering(view);
487+ var userList = findChild(view, "userList");
488+ tryCompare(userList, "movingInternally", false);
491+ function cleanup() {
492+ keyboardVisibleCheckBox.checked = false;
494+ loader.itemDestroyed = false;
495+ loader.active = false;
496+ tryCompare(loader, "status", Loader.Null);
497+ tryCompare(loader, "item", null);
498+ tryCompare(loader, "itemDestroyed", true);
499+ loader.active = true;
500+ tryCompare(loader, "status", Loader.Ready);
501+ removeTimeConstraintsFromSwipeAreas(loader.item);
502+ LightDMController.sessionMode = "single";
505+ function setLightDMMockMode(mode) {
506+ LightDMController.userMode = mode;
507+ waitForRendering(root);
510+ function setUsageMode(usageMode) {
511+ view.usageMode = usageMode;
512+ if (usageMode == "desktop") {
513+ view.multiUser = true;
514+ setLightDMMockMode("full");
515+ view.orientation = Qt.LandscapeOrientation;
516+ } else if (usageMode == "phone") {
517+ view.multiUser = false;
518+ setLightDMMockMode("single");
519+ view.orientation = Qt.PortraitOrientation;
520+ telepathyHelper.ready = true;
521+ telepathyHelper.emergencyCallsAvailable = true;
522+ LightDM.Greeter.authenticate("no-password");
523+ tryCompare(LightDMService.prompts, "count", 1);
527+ function swipeAwayCover(toTheRight) {
528+ if (toTheRight === undefined) {
532+ tryCompare(view, "fullyShown", true);
533+ var touchY = view.height / 2;
535+ touchFlick(view, 0, touchY, view.width, touchY);
537+ touchFlick(view, view.width, touchY, 0, touchY);
539+ var coverPage = findChild(view, "coverPage");
540+ tryCompare(coverPage, "showProgress", 0);
541+ waitForRendering(view);
544+ function getIndexOf(name) {
545+ for (var i = 0; i < LightDM.Users.count; i++) {
546+ if (name === LightDM.Users.data(i, LightDM.UserRoles.NameRole)) {
550+ fail("Didn't find name")
554+ function selectIndex(i) {
555+ var user = LightDM.Users.data(i, LightDM.UserRoles.NameRole);
556+ LightDM.Greeter.authenticate(user);
558+ var userList = findChild(view, "userList");
559+ var promptList = findChild(view, "promptList");
561+ view.currentIndex = i;
562+ tryCompare(promptList, "opacity", 1);
563+ tryCompare(userList, "movingInternally", false);
566+ function selectUser(name) {
567+ var i = getIndexOf(name);
572+/* Desktop view tests (multiuser) */
573+ function test_sessionless_user_is_still_valid() {
574+ setUsageMode("desktop");
575+ var loginList = findChild(view, "loginList")
578+ * If a user has never logged in before, or, for some reason
579+ * has no sessionHint, ensure that the model returns the default
580+ * session and that the view respects this
582+ selectUser("no-session");
583+ compare(LightDM.Users.data(loginList.currentIndex, LightDM.UserRoles.SessionRole), LightDM.Greeter.defaultSession);
585+ tryCompare(loginList, "currentSession", LightDM.Greeter.defaultSession);
588+ function test_changingSessionSticksToUser() {
589+ setUsageMode("desktop");
590+ var loginList = findChild(view, "loginList");
592+ selectUser("invalid-session");
593+ tryCompare(loginList, "currentSession", "invalid");
595+ selectUser("has-password");
596+ tryCompare(loginList, "currentSession", "ubuntu");
598+ selectUser("invalid-session")
599+ tryCompare(loginList, "currentSession", "invalid");
602+ function test_sessionIconsAreValid() {
603+ setUsageMode("desktop");
604+ LightDMController.sessionMode = "full";
605+ selectUser("has-password");
607+ // Test the login list icon is valid
608+ var sessionChooserButton = findChild(view, "sessionChooserButton");
609+ compare(sessionChooserButton.visible, true);
611+ var loginList = findChild(view, "loginList");
612+ var session = String(loginList.currentSession).toLowerCase();
613+ var icon = String(sessionChooserButton.icon);
614+ compare(icon.indexOf(session) > -1, true);
616+ // Test the session list icons are valid
617+ var lockscreen = findChild(view, "lockscreen");
618+ lockscreen.state = "SessionsList"
619+ var sessionsList = findChild(view, "sessionsList");
620+ tryCompare(sessionsList, "visible", true);
623+ function test_choosingNewSessionChangesLoginListIcon() {
624+ // Ensure the default session is selected (Ubuntu)
626+ setUsageMode("desktop");
629+ LightDMController.sessionMode = "full";
630+ selectUser("has-password");
632+ var sessionChooserButton = findChild(view, "sessionChooserButton");
633+ var icon = String(sessionChooserButton.icon);
634+ compare(icon.indexOf("ubuntu") > -1, true);
636+ tap(sessionChooserButton)
637+ for(var i = 0; i < LightDM.Sessions.count; i++) {
638+ var delegateName = "sessionDelegate" + String(i);
639+ var currentDelegate = findChild(view, delegateName);
640+ verify(currentDelegate);
641+ var sessionKey = LightDM.Sessions.data(i,LightDM.SessionRoles.KeyRole);
642+ if (sessionKey === "gnome-classic") {
643+ waitForRendering(currentDelegate);
644+ tap(currentDelegate);
645+ waitForRendering(sessionChooserButton);
650+ icon = String(sessionChooserButton.icon);
651+ compare(icon.indexOf("gnome") > -1, true,
652+ "Expected icon to contain gnome but it was " + icon);
655+ function test_noSessionsDoesntBreakView() {
656+ setUsageMode("desktop");
657+ LightDMController.sessionMode = "none";
658+ compare(LightDM.Sessions.count, 0)
661+ function test_sessionIconNotShownWithOneSession() {
662+ setUsageMode("desktop");
663+ LightDMController.sessionMode = "single";
664+ compare(LightDM.Sessions.count, 1);
666+ var sessionChooserButton = findChild(view, "sessionChooserButton");
667+ tryCompare(sessionChooserButton, "visible", false);
670+ function test_sessionIconNotShownWithActiveUser() {
671+ setUsageMode("desktop");
672+ selectUser("active");
674+ var sessionChooserButton = findChild(view, "sessionChooserButton");
675+ tryCompare(sessionChooserButton, "visible", false);
678+ function test_sessionIconShownWithMultipleSessions() {
679+ setUsageMode("desktop");
680+ LightDMController.sessionMode = "full";
681+ selectUser("has-password");
683+ var sessionChooserButton = findChild(view, "sessionChooserButton");
684+ tryCompare(sessionChooserButton, "visible", true);
687+ function test_selected() {
688+ setUsageMode("desktop");
690+ var delegate = findChild(view, "username2");
692+ compare(selectedSpy.count, 1);
693+ compare(selectedSpy.signalArguments[0][0], 2);
694+ compare(view.currentIndex, 0); // confirm we didn't change
697+ function test_customBackground() {
698+ setUsageMode("desktop");
699+ var lockscreen = findChild(view, "lockscreen");
700+ var backgroundShade = findChild(lockscreen, "backgroundShade");
702+ verify(!view.hasCustomBackground);
703+ verify(!backgroundShade.visible);
705+ view.hasCustomBackground = true;
706+ verify(backgroundShade.visible);
709+ function test_respondedWithPassword() {
710+ setUsageMode("desktop");
712+ selectUser("has-password");
713+ var greeterPrompt = findChild(view, "greeterPrompt0");
714+ verify(greeterPrompt.isSecret);
715+ typeString("password");
716+ keyClick(Qt.Key_Enter);
717+ compare(respondedSpy.count, 1);
718+ compare(respondedSpy.signalArguments[0][0], "password");
721+ function test_respondedWithNonSecret() {
722+ setUsageMode("desktop");
724+ selectUser("question-prompt");
725+ var greeterPrompt = findChild(view, "greeterPrompt0");
726+ verify(!greeterPrompt.isSecret);
728+ keyClick(Qt.Key_Enter);
729+ compare(respondedSpy.count, 1);
730+ compare(respondedSpy.signalArguments[0][0], "foo");
733+ function test_fullyShown_data() {
735+ {tag: "multiuser", multiUser: true, usageMode: "desktop", results: [true, true, true, true]},
736+ {tag: "singleuser", multiUser: false, usageMode: "desktop", results: [true, false, true, false]},
737+ {tag: "multiuser", multiUser: true, usageMode: "phone", results: [true, true, true, true]},
738+ {tag: "singleuser", multiUser: false, usageMode: "phone", results: [true, false, true, false]}
742+ function test_fullyShown(data) {
743+ setUsageMode(data.usageMode);
744+ view.multiUser = data.multiUser;
745+ tryCompare(view, "fullyShown", data.results[0]);
746+ tryCompare(view, "required", data.results[0]);
748+ tryCompare(view, "fullyShown", data.results[1]);
749+ tryCompare(view, "required", data.results[1]);
751+ tryCompare(view, "fullyShown", data.results[2]);
752+ tryCompare(view, "required", data.results[2]);
753+ view.locked = false;
754+ tryCompare(view, "fullyShown", data.results[3]);
755+ tryCompare(view, "required", data.results[3]);
758+ function test_infoPrompt() {
759+ setUsageMode("desktop");
760+ selectUser("info-prompt");
762+ var infoLabel = findChild(view, "infoLabel0");
763+ compare(infoLabel.text, "Welcome to Unity Greeter");
764+ compare(infoLabel.textFormat, Text.PlainText);
766+ verify(findChild(view, "greeterPrompt1") != null);
769+ function test_longInfoPrompt() {
770+ setUsageMode("desktop");
771+ selectUser("long-info-prompt");
773+ var infoLabel = findChild(view, "infoLabel0");
774+ compare(infoLabel.text, "Welcome to Unity Greeter\n\nWe like to annoy you with super ridiculously long messages.\nLike this one\n\nThis is the last line of a multiple line message.");
775+ verify(infoLabel.contentWidth > infoLabel.width);
777+ verify(findChild(view, "greeterPrompt1") != null);
780+ function test_multiInfoPrompt() {
781+ setUsageMode("desktop");
782+ selectUser("multi-info-prompt");
784+ var infoLabel0 = findChild(view, "infoLabel0");
785+ compare(infoLabel0.text, "Welcome to Unity Greeter");
787+ var infoLabel1 = findChild(view, "infoLabel1");
788+ compare(infoLabel1.text, "This is an error");
789+ compare(infoLabel1.color, theme.palette.normal.negative);
791+ var infoLabel2 = findChild(view, "infoLabel2");
792+ compare(infoLabel2.text, "You should have seen three messages");
794+ verify(findChild(view, "greeterPrompt3") != null);
797+ // Escape is used to reset the authentication, especially if PAM is unresponsive
798+ function test_escape() {
799+ setUsageMode("desktop");
801+ var index = selectUser("has-password");
802+ selectedSpy.clear();
804+ var promptField = findChild(view, "promptField");
806+ verify(promptField.activeFocus);
807+ compare(promptField.opacity, 1);
809+ typeString("password");
810+ keyClick(Qt.Key_Enter);
811+ verify(promptField.activeFocus);
812+ compare(promptField.opacity, 0); // hidden by fakeLabel
814+ compare(selectedSpy.count, 0);
815+ keyClick(Qt.Key_Escape);
816+ compare(selectedSpy.count, 1);
817+ compare(selectedSpy.signalArguments[0][0], index);
820+ var promptField = findChild(view, "promptField");
821+ verify(promptField.activeFocus);
822+ compare(promptField.opacity, 1);
825+ function test_unicode() {
826+ setUsageMode("desktop");
827+ var index = selectUser("unicode");
828+ var label = findChild(view, "username" + index);
829+ tryCompare(label, "text", "가나다라마");
832+ function test_authError() {
833+ setUsageMode("desktop");
835+ var index = selectUser("auth-error");
836+ var greeterPrompt = findChild(view, "greeterPrompt1"); // after error message
838+ compare(greeterPrompt.text, "Retry");
840+ compare(respondedSpy.count, 0);
841+ compare(selectedSpy.count, 1);
842+ compare(selectedSpy.signalArguments[0][0], index);
845+ function test_noPassword() {
846+ setUsageMode("desktop");
848+ selectUser("no-password");
849+ var greeterPrompt = findChild(view, "greeterPrompt0");
850+ compare(greeterPrompt.text, "Log In");
852+ compare(selectedSpy.count, 0);
853+ compare(respondedSpy.count, 1);
854+ compare(respondedSpy.signalArguments[0][0], "");
857+ function test_loginListNotCoveredByKeyboard() {
858+ setUsageMode("desktop");
859+ var loginList = findChild(view, "loginList");
860+ compare(loginList.height, view.height);
862+ // when the vkb shows up, loginList is moved up to remain fully uncovered
864+ keyboardVisibleCheckBox.checked = true;
866+ var halfway = (view.height - loginList.highlightedHeight) / 2;
867+ var halfwayWithOsk = halfway - view.inputMethodRect.height / 2;
868+ tryCompare(loginList, "boxVerticalOffset", halfwayWithOsk);
870+ var highlightItem = findChild(loginList, "highlightItem");
871+ tryCompareFunction( function() {
872+ var highlightRect = highlightItem.mapToItem(view, 0, 0, highlightItem.width, highlightItem.height);
873+ return highlightRect.y + highlightRect.height <= view.testKeyboard.y;
876+ // once the vkb goes away, loginList goes back to its full height
878+ keyboardVisibleCheckBox.checked = false;
880+ tryCompare(loginList, "boxVerticalOffset", halfway);
883+ function test_passphrase() {
884+ setUsageMode("desktop");
886+ var index = selectUser("has-password");
887+ var promptField = findChild(view, "promptField");
889+ verify(view.alphanumeric);
890+ compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, 0);
893+ compare(promptField.text, "d");
896+ function test_passcode() {
897+ setUsageMode("desktop");
899+ var index = selectUser("has-pin");
900+ view.alphanumeric = false;
902+ var promptField = findChild(view, "promptField");
903+ compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, Qt.ImhDigitsOnly);
906+ compare(promptField.text, "");
912+ compare(promptField.text, "0000");
914+ compare(respondedSpy.count, 1);
915+ compare(respondedSpy.signalArguments[0][0], "0000");
917+ compare(promptField.opacity, 0);
920+ function test_loginListMovement_data() {
922+ {tag: "up", key: Qt.Key_Up, result: 1},
923+ {tag: "down", key: Qt.Key_Down, result: 3},
927+ function test_loginListMovement(data) {
928+ setUsageMode("desktop");
931+ selectedSpy.clear();
934+ compare(selectedSpy.count, 1);
935+ compare(selectedSpy.signalArguments[0][0], data.result);
938+ function test_focusStaysActive() {
939+ setUsageMode("desktop");
941+ selectUser("no-password");
942+ var greeterPrompt = findChild(view, "greeterPrompt0");
943+ verify(greeterPrompt.activeFocus);
944+ keyClick(Qt.Key_Enter);
945+ compare(selectedSpy.count, 0);
946+ compare(respondedSpy.count, 1);
947+ compare(respondedSpy.signalArguments[0][0], "");
948+ verify(greeterPrompt.activeFocus);
949+ keyClick(Qt.Key_Enter);
950+ compare(respondedSpy.count, 1);
952+ selectUser("has-password");
953+ var greeterPrompt = findChild(view, "greeterPrompt0");
954+ verify(greeterPrompt.activeFocus);
956+ keyClick(Qt.Key_Enter);
957+ compare(selectedSpy.count, 0);
958+ compare(respondedSpy.count, 2);
959+ compare(respondedSpy.signalArguments[1][0], "d");
960+ verify(greeterPrompt.activeFocus);
961+ keyClick(Qt.Key_Enter);
962+ compare(respondedSpy.count, 2);
964+ var index = selectUser("no-password");
965+ var greeterPrompt = findChild(view, "greeterPrompt0");
967+ verify(greeterPrompt.activeFocus);
968+ keyClick(Qt.Key_Enter);
969+ compare(respondedSpy.count, 2);
970+ compare(selectedSpy.count, 1);
971+ compare(selectedSpy.signalArguments[0][0], index);
972+ verify(greeterPrompt.activeFocus);
973+ keyClick(Qt.Key_Enter);
974+ compare(selectedSpy.count, 1);
976+ selectUser("no-password");
977+ var greeterPrompt = findChild(view, "greeterPrompt0");
978+ verify(greeterPrompt.activeFocus);
981+ function test_scrollChangesIndex() {
982+ /* Check if the index of the current user gets changed
983+ * if we scroll through the list.
984+ * Expected result: the list has moved at least by one
985+ * user and the index of the user is reported using the
986+ * selected signal in LoginList.qml
987+ * https://github.com/ubports/unity8/issues/397
989+ setUsageMode("desktop");
991+ var loginList = findChild(view, "loginList");
992+ // FIXME: Fix scrolling sensitivity (scrolling by -1 shouldn't move more than one user down)
993+ mouseWheel( loginList, loginList.width / 2, loginList.height / 2, 0, -1, null );
995+ tryVerify(function(){ return selectedSpy.signalArguments[0][0] > 0 });
998+// function test_dragChangesIndex() {
999+// /* Check if the index of the current user gets changed
1000+// * if we drag the list or swipe.on it.
1001+// * Expected result: the list has moved at least by one
1002+// * user and the index of the user is reported using the
1003+// * selected signal in LoginList.qml
1004+// * https://github.com/ubports/unity8/issues/397
1006+// setUsageMode("desktop");
1007+// swipeAwayCover();
1008+// var loginList = findChild(view, "loginList");
1009+// // FIXME: Fix scrolling sensitivity (the number of scrolled users is randomly changing)
1010+// touchFlick(loginList, loginList.width/2, loginList.height/3, loginList.width/2, loginList.height/3 -units.gu(2.1));
1011+// selectedSpy.wait();
1012+// tryVerify(function(){ return selectedSpy.signalArguments[0][0] > 0 });
1015+/* Mobile view tests */
1016+ function test_tease_data() {
1018+ {tag: "left", x: 0, offset: 0, count: 1},
1019+ {tag: "leftWithOffsetPass", x: 10, offset: 10, count: 1},
1020+ {tag: "leftWithOffsetFail", x: 9, offset: 10, count: 0},
1021+ {tag: "right", x: view.width, offset: 0, count: 1},
1024+ function test_tease(data) {
1025+ view.dragHandleLeftMargin = data.offset;
1026+ tap(view, data.x, 0);
1027+ tryCompare(teaseSpy, "count", data.count);
1030+ function test_respondedWithPin() {
1031+ LightDM.Greeter.authenticate("has-pin");
1032+ view.locked = true;
1033+ view.alphanumeric = false;
1035+ typeString("1234");
1036+ respondedSpy.wait();
1037+ compare(respondedSpy.signalArguments[0][0], "1234");
1040+ function test_respondedWithPassphrase() {
1041+ LightDM.Greeter.authenticate("has-password");
1042+ view.locked = true;
1044+ typeString("test");
1045+ keyClick(Qt.Key_Enter);
1046+ compare(respondedSpy.count, 1);
1047+ compare(respondedSpy.signalArguments[0][0], "test");
1050+ function test_respondedWithSwipe_data() {
1052+ {tag: "left", toTheRight: false, hiddenX: -view.width},
1053+ {tag: "right", toTheRight: true, hiddenX: view.width},
1056+ function test_respondedWithSwipe(data) {
1057+ swipeAwayCover(data.toTheRight);
1058+ var coverPage = findChild(view, "coverPage");
1059+ compare(coverPage.x, data.hiddenX);
1060+ compare(respondedSpy.count, 1);
1061+ compare(respondedSpy.signalArguments[0][0], "");
1064+ function test_emergencyCall_data() {
1066+ {tag: "phone", available: true},
1067+ {tag: "desktop", available: false},
1070+ function test_emergencyCall(data) {
1071+ telepathyHelper.emergencyCallsAvailable = data.available;
1072+ view.locked = true;
1074+ var emergencyCallLabel = findChild(view, "emergencyCallLabel");
1075+ tap(emergencyCallLabel);
1076+ if (!data.available) {
1077+ expectFail("", "Bug 1616538 prevents us supporting conditional emergency button support");
1079+ compare(emergencyCallLabel.visible, data.available ? true : false);
1080+ compare(emergencySpy.count, data.available ? 1 : 0);
1083+ function test_emergencyCallAvailability() {
1084+ view.locked = true;
1085+ var emergencyCallLabel = findChild(view, "emergencyCallLabel");
1086+ verify(emergencyCallLabel.visible);
1088+ telepathyHelper.emergencyCallsAvailable = false;
1089+ telepathyHelper.ready = true;
1090+ expectFail("", "Bug 1616538 prevents us supporting conditional emergency button support");
1091+ verify(!emergencyCallLabel.visible);
1093+ telepathyHelper.emergencyCallsAvailable = true;
1094+ telepathyHelper.ready = false;
1095+ verify(!emergencyCallLabel.visible);
1098+ function test_tryToUnlock() {
1099+ var coverPage = findChild(view, "coverPage");
1100+ tryCompare(coverPage, "showProgress", 1);
1101+ compare(view.tryToUnlock(false), true);
1102+ tryCompare(coverPage, "showProgress", 0);
1103+ compare(view.tryToUnlock(false), false);
1107+ Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1388359
1108+ "User metrics can no longer be changed by double tap"
1110+ function test_doubleTapSwitchesToNextInfographic() {
1111+ setUsageMode("phone");
1112+ infographicDataChangedSpy.clear();
1113+ var coverPage = findChild(view, "coverPage");
1116+ var infographicPrivate = findInvisibleChild(coverPage, "infographicPrivate");
1117+ verify(infographicPrivate);
1119+ // wait for the UI to settle down before double tapping it
1120+ tryCompare(infographicPrivate, "animating", false);
1122+ var dataCircle = findChild(coverPage, "dataCircle");
1123+ verify(dataCircle);
1125+ mouseDoubleClickSequence(dataCircle);
1127+ tryCompare(infographicDataChangedSpy, "count", 1);
1130+ function test_movesBackIntoPlaceWhenNotDraggedFarEnough() {
1131+ var coverPage = findChild(view, "coverPage");
1133+ var dragEvaluator = findInvisibleChild(coverPage, "edgeDragEvaluator");
1134+ verify(dragEvaluator);
1136+ // Make it easier to get a rejection/rollback. Otherwise would have to inject
1137+ // a fake timer into dragEvaluator.
1138+ // Afterall, we are testing if the CoverPage indeed moves back on a
1139+ // rollback decision, not the drag evaluation itself.
1140+ dragEvaluator.minDragDistance = dragEvaluator.maxDragDistance / 2;
1142+ // it starts as fully shown
1143+ compare(coverPage.x, 0);
1145+ // then we drag it a bit
1146+ var startX = coverPage.width - 1;
1147+ var touchY = coverPage.height / 2;
1148+ var dragXDelta = -(dragEvaluator.minDragDistance * 0.3);
1149+ touchFlick(coverPage,
1150+ startX , touchY, // start pos
1151+ startX + dragXDelta, touchY, // end pos
1152+ true /* beginTouch */, false /* endTouch */);
1154+ // which should make it move a bit
1155+ tryCompareFunction(function() {return coverPage.x < 0;}, true);
1157+ // then we release it
1158+ touchRelease(coverPage, startX + dragXDelta, touchY);
1160+ // which should make it move back into its original position as it didn't move
1161+ // far enough to have it hidden
1162+ tryCompare(coverPage, "x", 0);
1165+ function test_dragToHide_data() {
1167+ {tag: "left", startX: view.width * 0.95, endX: view.width * 0.1, hiddenX: -view.width},
1168+ {tag: "right", startX: view.width * 0.1, endX: view.width * 0.95, hiddenX: view.width},
1171+ function test_dragToHide(data) {
1172+ var coverPage = findChild(view, "coverPage");
1173+ compare(coverPage.x, 0);
1174+ compare(coverPage.visible, true);
1175+ compare(coverPage.shown, true);
1176+ compare(coverPage.showProgress, 1);
1177+ compare(view.fullyShown, true);
1180+ data.startX, view.height / 2, // start pos
1181+ data.endX, view.height / 2); // end pos
1183+ tryCompare(coverPage, "x", data.hiddenX);
1184+ tryCompare(coverPage, "visible", false);
1185+ tryCompare(coverPage, "shown", false);
1186+ tryCompare(coverPage, "showProgress", 0);
1187+ compare(view.fullyShown, false);
1190+ function test_hiddenViewRemainsHiddenAfterResize_data() {
1192+ {tag: "left", startX: view.width * 0.95, endX: view.width * 0.1},
1193+ {tag: "right", startX: view.width * 0.1, endX: view.width * 0.95},
1196+ function test_hiddenViewRemainsHiddenAfterResize(data) {
1198+ data.startX, view.height / 2, // start pos
1199+ data.endX, view.height / 2); // end pos
1201+ var coverPage = findChild(view, "coverPage");
1202+ tryCompare(coverPage, "x", data.tag == "left" ? -view.width : view.width);
1203+ tryCompare(coverPage, "visible", false);
1204+ tryCompare(coverPage, "shown", false);
1205+ tryCompare(coverPage, "showProgress", 0);
1207+ // flip dimensions to simulate an orientation change
1208+ view.width = loader.height;
1209+ view.height = loader.width;
1211+ // All properties should remain consistent
1212+ tryCompare(coverPage, "x", data.tag == "left" ? -view.width : view.width);
1213+ tryCompare(coverPage, "visible", false);
1214+ tryCompare(coverPage, "shown", false);
1215+ tryCompare(coverPage, "showProgress", 0);
1218+ // Make sure that if user has a mouse, they can still get rid of cover page
1219+ function test_mouseClickHidesCoverPage() {
1220+ var coverPage = findChild(view, "coverPage");
1222+ verify(coverPage.shown);
1223+ mouseClick(coverPage, coverPage.width/2, coverPage.height - units.gu(2));
1224+ verify(!coverPage.shown);
1227+ function test_showErrorMessage() {
1228+ var coverPage = findChild(view, "coverPage");
1229+ var swipeHint = findChild(coverPage, "swipeHint");
1230+ var errorMessageAnimation = findInvisibleChild(coverPage, "errorMessageAnimation");
1232+ view.showErrorMessage("hello");
1233+ compare(swipeHint.text, "《 hello 》");
1234+ verify(errorMessageAnimation.running);
1235+ verify(swipeHint.opacityAnimation.running);
1237+ errorMessageAnimation.complete();
1238+ swipeHint.opacityAnimation.complete();
1239+ tryCompare(swipeHint, "text", "《 " + i18n.tr("Unlock") + " 》");
1242+ function test_keepPasswordOnRotation() {
1243+ /* Check if the password is kept when rotating
1244+ * the screen from portrait to landscape in mobile.
1246+ setUsageMode("phone");
1247+ LightDM.Greeter.authenticate("has-password");
1248+ view.locked = true;
1251+ let greeterPrompt = findChild(view, "greeterPrompt0");
1252+ tryCompare(greeterPrompt, "enteredText", "");
1253+ typeString("test");
1254+ tryCompare(greeterPrompt, "enteredText", "test");
1255+ view.orientation = Qt.LandscapeOrientation;
1256+ tryCompare(greeterPrompt, "enteredText", "test");
1259+ function test_infographicsShownOnRotation_data() {
1262+ tag: "phone-portrait-singleuser",
1264+ usageMode: "phone",
1265+ orientation: Qt.PortraitOrientation,
1270+ tag: "phone-portrait-multiuser",
1272+ usageMode: "phone",
1273+ orientation: Qt.PortraitOrientation,
1278+ tag: "phone-landscape-singleuser",
1280+ usageMode: "phone",
1281+ orientation: Qt.LandscapeOrientation,
1286+ tag: "phone-landscape-multiuser",
1288+ usageMode: "phone",
1289+ orientation: Qt.LandscapeOrientation,
1294+ tag: "tablet-landscape-singleuser",
1296+ usageMode: "tablet",
1297+ orientation: Qt.LandscapeOrientation,
1302+ tag: "tablet-landscape-multiuser",
1304+ usageMode: "tablet",
1305+ orientation: Qt.LandscapeOrientation,
1310+ tag: "tablet-portrait-singleuser",
1312+ usageMode: "tablet",
1313+ orientation: Qt.PortraitOrientation,
1318+ tag: "tablet-portrait-multiuser",
1320+ usageMode: "tablet",
1321+ orientation: Qt.PortraitOrientation,
1326+ tag: "desktop-singleuser",
1328+ usageMode: "desktop",
1329+ orientation: Qt.LandscapeOrientation,
1334+ tag: "desktop-multiuser",
1336+ usageMode: "desktop",
1337+ orientation: Qt.LandscapeOrientation,
1344+ function test_infographicsShownOnRotation(data) {
1345+ /* Check if infographics is shown in the correct
1346+ * places. This test runs in all the combinations
1347+ * of orientation and usage mode.
1349+ setUsageMode(data.usageMode);
1350+ view.orientation = data.orientation;
1351+ view.multiUser = data.multiUser;
1352+ view.locked = true;
1354+ let coverPage = findChild(view, "coverPage");
1355+ let lockscreen = findChild(view, "lockscreen");
1356+ let coverPageInfographics = findChild(coverPage, "infographicsLoader");
1357+ let lockscreenInfographics = findChild(lockscreen, "infographicsLoader");
1358+ verify(coverPageInfographics);
1359+ verify(lockscreenInfographics);
1361+ tryCompare(coverPageInfographics, "active", data.coverPage);
1363+ tryCompare(lockscreenInfographics, "active", data.lockscreen);