@@ -19,15 +19,20 @@ import QtTest 1.0
1919import AccountsService 0.1
2020import IntegratedLightDM 0.1 as LightDM
2121import Ubuntu.Components 1.3
22+import Ubuntu.Components.ListItems 1.3
23+import Ubuntu.Telephony 0.1 as Telephony
2224import Unity.Application 0.1
2325import Unity.Test 0.1 as UT
26+import Utils 0.1
2427
2528import "../../../qml"
29+import "../../../qml/Components"
2630
27−Item {
31+Rectangle {
2832 id: root
29− width: shellLoader.width + buttons.width
30− height: shellLoader.height
33+ color: UbuntuColors.lightGrey
34+ width: units.gu(100) + buttons.width
35+ height: units.gu(71)
3136
3237 QtObject {
3338 id: applicationArguments
@@ -45,6 +50,11 @@ Item {
4550 }
4651 }
4752
53+ Telephony.CallEntry {
54+ id: phoneCall
55+ phoneNumber: "+447812221111"
56+ }
57+
4858 Component.onCompleted: {
4959 // must set the mock mode before loading the Shell
5060 LightDM.Greeter.mockMode = "single-pin";
@@ -52,21 +62,63 @@ Item {
5262 shellLoader.active = true;
5363 }
5464
55− Row {
56− spacing: 0
57− anchors.fill: parent
65+ Item {
66+ id: shellContainer
67+ anchors.left: root.left
68+ anchors.right: buttons.left
69+ anchors.top: root.top
70+ anchors.bottom: root.bottom
5871
5972 Loader {
6073 id: shellLoader
6174
6275 active: false
63− width: units.gu(40)
64− height: units.gu(71)
76+ anchors.horizontalCenter: parent.horizontalCenter
77+ anchors.top: parent.top
78+ anchors.bottom: parent.bottom
79+
80+ property int shellOrientation: Qt.PortraitOrientation
81+ property int nativeOrientation: Qt.PortraitOrientation
82+ property int primaryOrientation: Qt.PortraitOrientation
83+
84+ state: modeSelector.model[modeSelector.selectedIndex]
85+ states: [
86+ State {
87+ name: "phone"
88+ PropertyChanges {
89+ target: shellLoader
90+ width: units.gu(40)
91+ }
92+ },
93+ State {
94+ name: "tablet"
95+ PropertyChanges {
96+ target: shellLoader
97+ width: units.gu(100)
98+ shellOrientation: Qt.LandscapeOrientation
99+ nativeOrientation: Qt.LandscapeOrientation
100+ primaryOrientation: Qt.LandscapeOrientation
101+ }
102+ },
103+ State {
104+ name: "desktop"
105+ PropertyChanges {
106+ target: shellLoader
107+ width: units.gu(100)
108+ }
109+ }
110+ ]
65111
66112 property bool itemDestroyed: false
67113 sourceComponent: Component {
68114 Shell {
115+ usageScenario: shellLoader.state
69116 property string indicatorProfile: "phone"
117+ orientation: shellLoader.shellOrientation
118+ orientations: Orientations {
119+ native_: shellLoader.nativeOrientation
120+ primary: shellLoader.primaryOrientation
121+ }
70122
71123 Component.onDestruction: {
72124 shellLoader.itemDestroyed = true;
@@ -74,29 +126,92 @@ Item {
74126 }
75127 }
76128 }
129+ }
130+
131+ Rectangle {
132+ id: buttons
133+ color: UbuntuColors.darkGrey
134+ width: units.gu(30)
135+ anchors.top: root.top
136+ anchors.bottom: root.bottom
137+ anchors.right: root.right
138+
139+ Column {
140+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
141+ spacing: units.gu(1)
142+ Row {
143+ anchors { left: parent.left; right: parent.right }
144+ Button {
145+ text: "Hide Greeter"
146+ onClicked: {
147+ if (shellLoader.status !== Loader.Ready)
148+ return;
149+
150+ var greeter = testCase.findChild(shellLoader.item, "greeter");
151+ if (greeter.shown) {
152+ greeter.hide();
153+ }
154+ }
155+ }
156+ }
157+
158+ Row {
159+ anchors { left: parent.left; right: parent.right }
160+ Button {
161+ text: "Restart Tutorial"
162+ onClicked: {
163+ if (shellLoader.status !== Loader.Ready)
164+ return;
165+
166+ AccountsService.demoEdges = false;
167+ AccountsService.demoEdgesCompleted = [];
168+ AccountsService.demoEdges = true;
169+ }
170+ }
171+ }
77172
78− Rectangle {
79− id: buttons
80− color: "white"
81− width: units.gu(30)
82− height: shellLoader.height
83−
84− Column {
85− anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
86− spacing: units.gu(1)
87− Row {
88− anchors { left: parent.left; right: parent.right }
89− Button {
90− text: "Restart Tutorial"
91− onClicked: {
92− if (shellLoader.status !== Loader.Ready)
93− return;
94−
95− AccountsService.demoEdges = false;
96− AccountsService.demoEdges = true;
173+ Row {
174+ anchors { left: parent.left; right: parent.right }
175+ CheckBox {
176+ onCheckedChanged: {
177+ if (checked) {
178+ callManager.foregroundCall = phoneCall;
179+ } else {
180+ callManager.foregroundCall = null;
97181 }
98182 }
99183 }
184+ Label {
185+ text: "Active Call"
186+ anchors.verticalCenter: parent.verticalCenter
187+ }
188+ }
189+
190+ Row {
191+ anchors { left: parent.left; right: parent.right }
192+ CheckBox {
193+ activeFocusOnPress: false
194+ onCheckedChanged: {
195+ var surface = SurfaceManager.inputMethodSurface;
196+ if (checked) {
197+ surface.setState(Mir.RestoredState);
198+ } else {
199+ surface.setState(Mir.MinimizedState);
200+ }
201+ }
202+ }
203+ Label {
204+ text: "Input Method"
205+ anchors.verticalCenter: parent.verticalCenter
206+ }
207+ }
208+
209+ ItemSelector {
210+ id: modeSelector
211+ anchors { left: parent.left; right: parent.right }
212+ activeFocusOnPress: false
213+ text: "Mode"
214+ model: ["phone", "tablet", "desktop"]
100215 }
101216 }
102217 }
@@ -111,17 +226,21 @@ Item {
111226 property real halfHeight: shell ? shell.height / 2 : 0
112227
113228 function init() {
114− tryCompare(shell, "enabled", true); // enabled by greeter when ready
229+ prepareShell();
115230
116− AccountsService.demoEdges = false;
117− AccountsService.demoEdges = true;
118− swipeAwayGreeter();
231+ var tutorialLeft = findChild(shell, "tutorialLeft");
232+ tryCompare(tutorialLeft, "opacity", 1);
119233 }
120234
121235 function cleanup() {
236+ resetLoader("phone");
237+ }
238+
239+ function resetLoader(state) {
122240 shellLoader.itemDestroyed = false;
123241
124242 shellLoader.active = false;
243+ shellLoader.state = state;
125244
126245 tryCompare(shellLoader, "status", Loader.Null);
127246 tryCompare(shellLoader, "item", null);
@@ -143,6 +262,24 @@ Item {
143262 removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
144263 }
145264
265+ function prepareShell() {
266+ tryCompare(shell, "enabled", true); // enabled by greeter when ready
267+
268+ WindowStateStorage.clear();
269+ SurfaceManager.inputMethodSurface.setState(Mir.MinimizedState);
270+ callManager.foregroundCall = null;
271+ AccountsService.demoEdges = false;
272+ AccountsService.demoEdgesCompleted = [];
273+ AccountsService.demoEdges = true;
274+
275+ LightDM.Greeter.hideGreeter();
276+ }
277+
278+ function loadShell(state) {
279+ resetLoader(state);
280+ prepareShell();
281+ }
282+
146283 function killApps() {
147284 while (ApplicationManager.count > 1) {
148285 var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
@@ -163,234 +300,515 @@ Item {
163300 waitForRendering(greeter);
164301 }
165302
166− function waitForPage(name) {
167− waitForRendering(findChild(shell, name));
168− var page = findChild(shell, name);
169− tryCompare(page, "shown", true);
170− tryCompare(page.showAnimation, "running", false);
171− return page;
303+ function openTutorialTop() {
304+ var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
305+ var tutorialTop = findChild(shell, "tutorialTop");
306+ var tutorialTopTimer = findInvisibleChild(tutorialTop, "tutorialTopTimer");
307+
308+ tutorialTopTimer.interval = 1;
309+ AccountsService.demoEdgesCompleted = ["left", "left-long"];
310+
311+ tryCompare(tutorialLeftLoader, "active", false);
312+ tryCompare(tutorialTop, "shown", true);
313+ tryCompare(tutorialTop, "opacity", 1);
172314 }
173315
174− function checkTopEdge() {
175− touchFlick(shell, halfWidth, 0, halfWidth, halfHeight);
316+ function openTutorialRight() {
317+ var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
318+ var tutorialRight = findChild(shell, "tutorialRight");
176319
177− var panel = findChild(shell, "panel");
178− tryCompare(panel.indicators, "fullyClosed", true);
320+ AccountsService.demoEdgesCompleted = ["left", "left-long", "top"];
321+ ApplicationManager.startApplication("gallery-app");
322+ ApplicationManager.startApplication("facebook-webapp");
323+
324+ tryCompare(tutorialLeftLoader, "active", false);
325+ tryCompare(tutorialRight, "shown", true);
326+ tryCompare(tutorialRight, "opacity", 1);
179327 }
180328
181− function checkLeftEdge() {
182− touchFlick(shell, 0, halfHeight, halfWidth, halfHeight);
329+ function openTutorialBottom() {
330+ var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
331+ var tutorialBottom = findChild(shell, "tutorialBottom");
332+
333+ AccountsService.demoEdgesCompleted = ["left", "left-long", "top", "right"];
334+ tryCompare(tutorialLeftLoader, "active", false);
183335
336+ ApplicationManager.startApplication("dialer-app");
337+ ApplicationManager.requestFocusApplication("dialer-app");
338+
339+ tryCompare(tutorialBottom, "shown", true);
340+ tryCompare(tutorialBottom, "opacity", 1);
341+ }
342+
343+ function test_tutorialLeftEdges() {
344+ var tutorial = findChild(shell, "tutorial");
345+ var tutorialLeft = findChild(tutorial, "tutorialLeft");
184346 var launcher = findChild(shell, "launcher");
185− tryCompare(launcher, "state", "");
347+ var stage = findChild(shell, "stage");
348+ var panel = findChild(shell, "panel");
349+
350+ verify(tutorial.running);
351+ verify(tutorial.launcherEnabled);
352+ verify(!tutorial.spreadEnabled);
353+ verify(!tutorial.panelEnabled);
354+ verify(tutorialLeft.shown);
355+ verify(launcher.available);
356+ verify(!stage.spreadEnabled);
357+ verify(!panel.indicators.available);
186358 }
187359
188− function checkRightEdge() {
189− if (shell.usageScenario === "phone") {
190− touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight);
360+ function test_tutorialLeftFinish() {
361+ var tutorial = findChild(shell, "tutorial");
362+ var tutorialLeft = findChild(tutorial, "tutorialLeft");
363+ var launcher = findChild(shell, "launcher");
191364
192− var stage = findChild(shell, "stage");
193− var spreadView = findChild(stage, "spreadView");
194− tryCompare(spreadView, "phase", 0);
195− }
365+ touchFlick(shell, 0, halfHeight, halfWidth, halfHeight);
366+
367+ tryCompare(tutorialLeft, "shown", false);
368+ tryCompare(AccountsService, "demoEdgesCompleted", ["left"]);
369+ tryCompare(launcher, "state", "visible");
196370 }
197371
198− function checkBottomEdge() {
199− // Can't actually check effect of swipe, since dash isn't really loaded
200− var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader");
201− tryCompare(applicationsDisplayLoader, "interactive", false);
372+ function test_tutorialLeftShortDrag() {
373+ // Here we want to test just barely pulling the launcher out and
374+ // letting go (i.e. not triggering the "progress" property of
375+ // Launcher).
376+ var tutorialLeft = findChild(shell, "tutorialLeft");
377+ var launcher = findChild(shell, "launcher");
378+
379+ // Confirm fade during drag
380+ touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight, true, false);
381+ // compare opacity with a bound rather than hard 0.6 because progress doesn't
382+ // always match the drag perfectly (takes a moment for drag to kick in)
383+ tryCompareFunction(function() {
384+ return tutorialLeft.opacity >= 0.6 && tutorialLeft.opacity < 0.8;
385+ }, true);
386+ touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight, false, true);
387+
388+
389+ // Make sure we don't do anything if we don't pull the launcher
390+ // out much.
391+ touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight);
392+ tryCompare(launcher, "state", ""); // should remain hidden
393+ tryCompare(tutorialLeft, "shown", true); // and we should still be on left
394+
395+
396+ // Now drag out but not past launcher itself
397+ touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.9, halfHeight);
398+
399+ tryCompare(tutorialLeft, "shown", false);
400+ tryCompare(AccountsService, "demoEdgesCompleted", ["left"]);
401+ tryCompare(launcher, "state", "visible");
202402 }
203403
204− function checkFinished() {
205− tryCompare(AccountsService, "demoEdges", false);
404+ function test_tutorialLeftLongDrag() {
405+ // Just confirm that a long drag ("dash" drag) doesn't confuse us
206406
207− var tutorial = findChild(shell, "tutorial");
208− tryCompare(tutorial, "running", false);
407+ // So that we actually switch to dash and launcher hides
408+ ApplicationManager.startApplication("gallery-app");
209409
210410 var launcher = findChild(shell, "launcher");
211− tryCompare(launcher, "shown", false);
411+ var tutorialLeft = findChild(shell, "tutorialLeft");
412+ touchFlick(shell, 0, halfHeight, shell.width, halfHeight);
413+
414+ tryCompare(tutorialLeft, "shown", false);
415+ tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long"]);
212416 }
213417
214− function goToPage(name) {
215− var page = waitForPage("tutorialLeft");
216− checkTopEdge();
217− checkRightEdge();
218− checkBottomEdge();
219− if (name === "tutorialLeft") return page;
418+ function test_tutorialLeftAutoSkipped() {
419+ // Test that we skip the tutorial if user uses left edge themselves
420+
421+ var tutorialLeft = findChild(shell, "tutorialLeft");
422+ LightDM.Greeter.showGreeter();
423+ tryCompare(tutorialLeft, "visible", false);
424+ compare(AccountsService.demoEdgesCompleted, []);
425+
220426 touchFlick(shell, 0, halfHeight, halfWidth, halfHeight);
427+ tryCompare(AccountsService, "demoEdgesCompleted", ["left"]);
428+ }
221429
222− page = waitForPage("tutorialLeftFinish");
223− if (name === "tutorialLeftFinish") return page;
224− var tick = findChild(page, "tick");
225− tap(tick);
226−
227− page = waitForPage("tutorialRight");
228− checkTopEdge();
229− checkLeftEdge();
230− checkBottomEdge();
231− if (name === "tutorialRight") return page;
232− touchFlick(shell,
233− shell.width, halfHeight,
234− halfWidth, halfHeight,
235− true /* beginTouch */, true /* endTouch */,
236− 20 /* speed */, 50 /* iterations */);
237− var overlay = findChild(page, "overlay");
238− tryCompare(overlay, "shown", true);
239− var tick = findChild(page, "tick");
240− tap(tick);
241−
242− var page = waitForPage("tutorialBottom");
243− checkTopEdge();
244− checkLeftEdge();
245− checkRightEdge();
246− if (name === "tutorialBottom") return page;
247− touchFlick(shell, halfWidth, shell.height, halfWidth, halfHeight);
430+ function test_tutorialTopEdges() {
431+ var tutorial = findChild(shell, "tutorial");
432+ var tutorialTop = findChild(tutorial, "tutorialTop");
433+ var launcher = findChild(shell, "launcher");
434+ var stage = findChild(shell, "stage");
435+ var panel = findChild(shell, "panel");
248436
249− var page = waitForPage("tutorialBottomFinish");
250− checkTopEdge();
251− checkLeftEdge();
252− checkRightEdge();
253− checkBottomEdge();
254− if (name === "tutorialBottomFinish") return page;
255− var tick = findChild(page, "tick");
256− tap(tick);
437+ openTutorialTop();
257438
258− checkFinished();
259− return null;
439+ tryCompare(tutorial, "running", true);
440+ verify(!tutorial.launcherEnabled);
441+ verify(!tutorial.spreadEnabled);
442+ verify(tutorial.panelEnabled);
443+ verify(tutorialTop.shown);
444+ verify(!launcher.available);
445+ verify(!stage.spreadEnabled);
446+ verify(panel.indicators.available);
260447 }
261448
262− function test_walkthrough() {
263− goToPage(null);
449+ function test_tutorialTopFinish() {
450+ var tutorial = findChild(shell, "tutorial");
451+ var tutorialTop = findChild(tutorial, "tutorialTop");
452+ var panel = findChild(shell, "panel");
453+
454+ openTutorialTop();
455+ touchFlick(shell, halfWidth, 0, halfWidth, shell.height);
456+
457+ tryCompare(tutorialTop, "shown", false);
458+ tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top"]);
459+ tryCompare(panel.indicators, "fullyOpened", true);
264460 }
265461
266− function test_skipOnDesktop() {
462+ function test_tutorialTopShortDrag() {
267463 var tutorial = findChild(shell, "tutorial");
268− tryCompare(tutorial, "active", true);
269− tryCompare(tutorial, "running", true);
464+ var tutorialTop = findChild(tutorial, "tutorialTop");
465+ var panel = findChild(shell, "panel");
270466
271− shell.usageScenario = "desktop";
272− tryCompare(tutorial, "active", false);
273− tryCompare(tutorial, "running", false);
467+ openTutorialTop();
468+ touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, true, false);
469+ // compare opacity with a bound rather than hard 0.6 because progress doesn't
470+ // always match the drag perfectly (takes a moment for drag to kick in)
471+ tryCompareFunction(function() {
472+ return tutorialTop.opacity >= 0.6 && tutorialTop.opacity < 0.7;
473+ }, true);
474+ touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, false, true);
475+
476+ compare(tutorialTop.shown, true);
274477 }
275478
276− function test_launcherShortDrag() {
277− // goToPage does a normal launcher pull. But here we want to test
278− // just barely pulling the launcher out and letting go (i.e. not
279− // triggering the "progress" property of Launcher).
479+ function test_tutorialTopAutoSkipped() {
480+ // Test that we skip the tutorial if user uses top edge themselves
280481
281− var left = goToPage("tutorialLeft");
482+ var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
483+ var tutorialTop = findChild(shell, "tutorialTop");
484+ AccountsService.demoEdgesCompleted = ["left", "left-long"];
485+ tryCompare(tutorialLeftLoader, "active", false);
486+ verify(!tutorialTop.shown);
282487
283− // Make sure we don't do anything if we don't pull the launcher
284− // out much.
488+ touchFlick(shell, halfWidth, 0, halfWidth, shell.height);
489+ tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top"]);
490+ }
491+
492+ function test_tutorialRightEdges() {
493+ var tutorial = findChild(shell, "tutorial");
494+ var tutorialRight = findChild(tutorial, "tutorialRight");
285495 var launcher = findChild(shell, "launcher");
286− touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight);
287− tryCompare(launcher, "state", ""); // should remain hidden
288− tryCompare(left, "shown", true); // and we should still be on left
496+ var stage = findChild(shell, "stage");
497+ var panel = findChild(shell, "panel");
289498
290− // Now drag out but not past launcher itself
291− touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.9, halfHeight);
499+ openTutorialRight();
500+
501+ tryCompare(tutorial, "running", true);
502+ verify(!tutorial.launcherEnabled);
503+ verify(tutorial.spreadEnabled);
504+ verify(!tutorial.panelEnabled);
505+ verify(tutorialRight.shown);
506+ verify(!launcher.available);
507+ verify(stage.spreadEnabled);
508+ verify(!panel.indicators.available);
509+ }
510+
511+ function test_tutorialRightFinish() {
512+ var tutorial = findChild(shell, "tutorial");
513+ var tutorialRight = findChild(tutorial, "tutorialRight");
514+ var stage = findChild(shell, "stage");
515+
516+ openTutorialRight();
517+ touchFlick(shell, shell.width, halfHeight, 0, halfHeight);
518+
519+ tryCompare(tutorialRight, "shown", false);
520+ tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top", "right"]);
521+ }
522+
523+ function test_tutorialRightShortDrag() {
524+ var tutorial = findChild(shell, "tutorial");
525+ var tutorialRight = findChild(tutorial, "tutorialRight");
526+ var stage = findChild(shell, "stage");
527+
528+ openTutorialRight();
529+ touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, true, false);
530+ // compare opacity with a bound rather than hard 0.6 because progress doesn't
531+ // always match the drag perfectly (takes a moment for drag to kick in)
532+ tryCompareFunction(function() {
533+ return tutorialRight.opacity >= 0.6 && tutorialRight.opacity < 0.8;
534+ }, true);
535+ touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, false, true);
536+
537+ compare(tutorialRight.shown, true);
538+ }
292539
293− waitForPage("tutorialLeftFinish");
540+ function test_tutorialRightDelay() {
541+ // Test that if we exit the top tutorial, we don't immediately
542+ // jump into right tutorial.
543+ var tutorialRight = findChild(shell, "tutorialRight");
544+ var tutorialRightTimer = findInvisibleChild(tutorialRight, "tutorialRightInactivityTimer");
545+
546+ tutorialRightTimer.interval = 1;
547+ openTutorialTop();
548+ ApplicationManager.startApplication("gallery-app");
549+ ApplicationManager.startApplication("facebook-webapp");
550+ tryCompare(ApplicationManager, "count", 3);
551+
552+ AccountsService.demoEdgesCompleted = ["left", "left-long", "top"];
553+ verify(tutorialRightTimer.running, true);
554+ verify(!tutorialRight.shown);
555+ tryCompare(tutorialRight, "shown", true);
294556 }
295557
296− function test_launcherLongDrag() {
297− // goToPage does a normal launcher pull. But here we want to test
298− // a full pull across the page.
558+ function test_tutorialRightAutoSkipped() {
559+ // Test that we skip the tutorial if user uses right edge themselves
299560
300− var left = goToPage("tutorialLeft");
561+ var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
562+ AccountsService.demoEdgesCompleted = ["left", "left-long"];
563+ tryCompare(tutorialLeftLoader, "active", false);
301564
565+ touchFlick(shell, shell.width, halfHeight, 0, halfHeight);
566+ tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "right"]);
567+ }
568+
569+ function test_tutorialBottomEdges() {
570+ var tutorial = findChild(shell, "tutorial");
571+ var tutorialBottom = findChild(tutorial, "tutorialBottom");
572+ var tutorialLabel = findChild(tutorialBottom, "tutorialLabel");
302573 var launcher = findChild(shell, "launcher");
303− touchFlick(shell, 0, halfHeight, shell.width, halfHeight);
574+ var stage = findChild(shell, "stage");
575+ var panel = findChild(shell, "panel");
304576
305− var errorTextLabel = findChild(left, "errorTextLabel");
306− var errorTitleLabel = findChild(left, "errorTitleLabel");
307− tryCompare(launcher, "state", ""); // launcher goes away
308− tryCompare(left, "shown", true); // still on left page
309− tryCompare(errorTextLabel, "opacity", 1); // show error
310− tryCompare(errorTitleLabel, "opacity", 1); // show error
577+ openTutorialBottom();
578+
579+ tryCompare(tutorial, "running", true);
580+ verify(!tutorial.launcherEnabled);
581+ verify(!tutorial.spreadEnabled);
582+ verify(!tutorial.panelEnabled);
583+ verify(tutorialBottom.shown);
584+ verify(!launcher.available);
585+ verify(!stage.spreadEnabled);
586+ verify(!panel.indicators.available);
587+ compare(tutorialLabel.text, "Swipe up for recent calls");
311588 }
312589
313− function test_launcherDragBack() {
314− // goToPage does a full launcher pull. But here we test pulling
315− // all the way out, then dragging back into place.
590+ function test_tutorialBottomFinish() {
591+ var tutorial = findChild(shell, "tutorial");
592+ var tutorialBottom = findChild(tutorial, "tutorialBottom");
316593
317− var left = goToPage("tutorialLeft");
318− touchFlick(shell, 0, halfHeight, halfWidth, halfHeight, true, false);
319− touchFlick(shell, halfWidth, halfHeight, 0, halfHeight, false, true);
594+ openTutorialBottom();
595+ touchFlick(shell, halfWidth, shell.height, halfWidth, halfHeight);
320596
321− tryCompare(left, "shown", true); // and we should still be on left
597+ tryCompare(tutorialBottom, "shown", false);
598+ tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top", "right", "bottom-dialer-app"]);
599+
600+ // OK, we did one, just confirm that when all are done, we mark whole tutorial as done.
601+ verify(AccountsService.demoEdges);
602+ AccountsService.demoEdgesCompleted = ["left", "left-long", "top", "right",
603+ "bottom-address-book-app",
604+ "bottom-com.ubuntu.calculator_calculator",
605+ "bottom-dialer-app",
606+ "bottom-messaging-app"];
607+ verify(!AccountsService.demoEdges);
322608 }
323609
324− function test_launcherNoDragGap() {
325− // See bug 1454882, where if you dragged the launcher while it was
326− // visible, you could pull it further than the edge of the screen.
610+ function test_tutorialBottomAppearsBeforeRight() {
611+ // Confirm that if bottom edge and right edge would appear on the
612+ // the same app open, bottom edge appears first. (this is a lightly
613+ // edited version of openTutorialRight)
614+ var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
615+ var tutorialRight = findChild(shell, "tutorialRight");
616+ var tutorialBottom = findChild(shell, "tutorialBottom");
327617
328− var left = goToPage("tutorialLeft");
329− var launcher = findChild(shell, "launcher");
330− var teaseAnimation = findInvisibleChild(left, "teaseAnimation");
618+ AccountsService.demoEdgesCompleted = ["left", "left-long", "top"];
619+ ApplicationManager.startApplication("gallery-app");
620+ ApplicationManager.startApplication("dialer-app");
621+
622+ tryCompare(tutorialLeftLoader, "active", false);
623+ tryCompare(tutorialBottom, "shown", true);
624+ tryCompare(tutorialBottom, "opacity", 1);
625+ tryCompare(tutorialRight, "visible", false);
626+ }
331627
332− // Wait for launcher to be really out there
333− tryCompareFunction(function() {return launcher.x > teaseAnimation.maxBounce/2}, true);
334− verify(teaseAnimation.running);
628+ function test_tutorialBottomOnlyCoversSideStageOnTablet() {
629+ loadShell("tablet");
335630
336− // Start a drag, make sure animation stops
337− touchFlick(shell, 0, halfHeight, units.gu(4), halfHeight, true, false);
338− verify(!teaseAnimation.running);
339− verify(launcher.visibleWidth > 0);
340− verify(launcher.x > 0);
341− compare(launcher.x, teaseAnimation.bounce);
631+ var tutorialBottom = findChild(shell, "tutorialBottom");
632+ var targetHeight = shell.height - units.gu(4);
633+ var mainStageX = units.gu(20);
634+ var sideStageX = shell.width - units.gu(20);
342635
343− // Continue drag, make sure we don't create a gap on the left hand side
344− touchFlick(shell, units.gu(4), halfHeight, shell.width, halfHeight, false, false);
345− verify(!teaseAnimation.running);
346− compare(launcher.visibleWidth, launcher.panelWidth);
347− compare(launcher.x, 0);
636+ WindowStateStorage.saveStage("dialer-app", ApplicationInfoInterface.SideStage);
637+ openTutorialBottom();
348638
349− // Finish and make sure we continue animation
350− touchFlick(shell, shell.width, halfHeight, shell.width, halfHeight, false, true);
351− tryCompare(teaseAnimation, "running", true);
639+ touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, true, false);
640+ compare(tutorialBottom.opacity, 1);
641+ touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, false, true);
642+
643+ touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, true, false);
644+ verify(tutorialBottom.opacity < 1);
645+ touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, false, true);
352646 }
353647
354− function test_spread() {
355− // Unfortunately, most of what we want to test of the spread is
356− // "did it render correctly?" but that's hard to test. So instead,
357− // just poke and prod it a little bit to see if some of the values
358− // we'd expect to be correct, are so.
648+ function test_tutorialBottomOnlyCoversMainStageOnTablet() {
649+ loadShell("tablet");
359650
360− var right = goToPage("tutorialRight");
361− var stage = findChild(right, "stage");
362− var delegate0 = findChild(right, "appDelegate0");
651+ var tutorialBottom = findChild(shell, "tutorialBottom");
652+ var targetHeight = shell.height - units.gu(4);
653+ var mainStageX = units.gu(20);
654+ var sideStageX = shell.width - units.gu(20);
363655
364− tryCompare(stage, "dragProgress", 0);
365− touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, true, false);
366− verify(stage.dragProgress > 0);
367− compare(stage.dragProgress, -delegate0.xTranslate);
368− touchFlick(shell, shell.width * 0.8, halfHeight, shell.width, halfHeight, false, true);
369− tryCompare(stage, "dragProgress", 0);
656+ WindowStateStorage.saveStage("notes-app", ApplicationInfoInterface.SideStage);
657+ ApplicationManager.startApplication("notes-app");
370658
371− tryCompare(delegate0, "x", shell.width);
659+ openTutorialBottom();
372660
373− var screenshotImage = findChild(right, "screenshotImage");
374− tryCompare(screenshotImage, "source", Qt.resolvedUrl("../../../qml/Tutorial/graphics/facebook.png"));
375− tryCompare(screenshotImage, "visible", true);
661+ touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, true, false);
662+ compare(tutorialBottom.opacity, 1);
663+ touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, false, true);
664+
665+ touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, true, false);
666+ verify(tutorialBottom.opacity < 1);
667+ touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, false, true);
376668 }
377669
378− function test_bottomShortDrag() {
379− var bottom = goToPage("tutorialBottom");
670+ function test_activeCallInterruptsTutorial() {
671+ var tutorialLeft = findChild(shell, "tutorialLeft");
672+ verify(tutorialLeft.shown);
673+ verify(!tutorialLeft.paused);
380674
381− touchFlick(shell, halfWidth, shell.height, halfWidth, shell.height * 0.8);
675+ callManager.foregroundCall = phoneCall;
676+ verify(!tutorialLeft.shown);
677+ verify(tutorialLeft.paused);
678+ tryCompare(tutorialLeft, "visible", false);
382679
383− var errorTextLabel = findChild(bottom, "errorTextLabel");
384− var errorTitleLabel = findChild(bottom, "errorTitleLabel");
385− tryCompare(bottom, "shown", true); // still on bottom page
386− tryCompare(errorTextLabel, "opacity", 1); // show error
387− tryCompare(errorTitleLabel, "opacity", 1); // show error
680+ callManager.foregroundCall = null;
681+ tryCompare(tutorialLeft, "shown", true);
682+ verify(!tutorialLeft.paused);
388683 }
389684
390− function test_interrupted() {
391− goToPage("tutorialLeft");
685+ function test_dialerInterruptionWithNoOverlappingTutorials() {
686+ var tutorialLeft = findChild(shell, "tutorialLeft");
687+ var tutorialBottom = findChild(shell, "tutorialBottom");
688+ verify(tutorialLeft.shown);
689+
690+ // Start call, hiding left tutorial
691+ callManager.foregroundCall = phoneCall;
692+ tryCompare(tutorialLeft, "shown", false);
693+
694+ // Start dialer app
695+ ApplicationManager.startApplication("dialer-app");
696+ tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app");
697+ verify(!tutorialBottom.shown);
698+
699+ // Dismiss call, bottom tutorial should appear
700+ callManager.foregroundCall = null;
701+ tryCompare(tutorialBottom, "shown", true);
702+ verify(!tutorialLeft.shown);
703+
704+ // Get rid of bottom tutorial, left should now be shown
705+ touchFlick(shell, halfWidth, shell.height, halfWidth, halfHeight);
706+ tryCompare(tutorialBottom, "shown", false);
707+ tryCompare(tutorialLeft, "shown", true);
708+ }
709+
710+ function test_greeterInterruptsTutorial() {
711+ var tutorialLeft = findChild(shell, "tutorialLeft");
712+ verify(tutorialLeft.shown);
713+ verify(!tutorialLeft.paused);
714+
715+ LightDM.Greeter.showGreeter();
716+ verify(!tutorialLeft.shown);
717+ verify(tutorialLeft.paused);
718+ tryCompare(tutorialLeft, "visible", false);
719+
720+ LightDM.Greeter.hideGreeter();
721+ tryCompare(tutorialLeft, "shown", true);
722+ verify(!tutorialLeft.paused);
723+ }
724+
725+ function test_interruptionChecksReadyStateWhenDone() {
726+ // If we're done with an interruption (like active call), make sure
727+ // that we don't blindly resume the tutorial -- our trigger
728+ // conditions still need to be met. For example, there need to be
729+ // enough apps open for the right edge tutorial.
730+
731+ openTutorialRight();
732+
733+ var tutorialRight = findChild(shell, "tutorialRight");
734+ verify(tutorialRight.isReady);
735+ verify(tutorialRight.shown);
736+ verify(!tutorialRight.paused);
737+
738+ callManager.foregroundCall = phoneCall;
739+ killApps();
740+ callManager.foregroundCall = null;
741+
742+ verify(!tutorialRight.isReady);
743+ verify(!tutorialRight.shown);
744+ verify(!tutorialRight.paused);
745+ compare(AccountsService.demoEdgesCompleted, ["left", "left-long", "top"]);
746+ }
747+
748+ function test_desktopOnlyShowsTutorialRight() {
749+ loadShell("desktop");
750+
751+ var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
752+ var tutorialTopLoader = findChild(shell, "tutorialTopLoader");
753+ var tutorialRightLoader = findChild(shell, "tutorialRightLoader");
754+ var tutorialBottomLoader = findChild(shell, "tutorialBottomLoader");
755+ verify(!tutorialLeftLoader.active);
756+ verify(!tutorialTopLoader.active);
757+ verify(tutorialRightLoader.active);
758+ verify(!tutorialBottomLoader.active);
759+ compare(AccountsService.demoEdgesCompleted, []);
760+
392761 ApplicationManager.startApplication("dialer-app");
393− checkFinished();
762+ ApplicationManager.startApplication("camera-app");
763+ tryCompare(tutorialRightLoader.item, "isReady", true);
764+ tryCompare(tutorialRightLoader, "shown", true);
765+ }
766+
767+ function test_oskDoesNotHideTutorial() {
768+ var tutorialLeft = findChild(shell, "tutorialLeft");
769+ verify(tutorialLeft.shown);
770+
771+ var surface = SurfaceManager.inputMethodSurface;
772+ surface.setState(Mir.RestoredState);
773+
774+ var inputMethod = findInvisibleChild(shell, "inputMethod");
775+ tryCompare(inputMethod, "state", "shown");
776+
777+ verify(tutorialLeft.shown);
778+ }
779+
780+ function test_oskPreventsTutorial() {
781+ var surface = SurfaceManager.inputMethodSurface;
782+ var inputMethod = findInvisibleChild(shell, "inputMethod");
783+
784+ AccountsService.demoEdges = false;
785+ surface.setState(Mir.RestoredState);
786+ tryCompare(inputMethod, "state", "shown");
787+
788+ var tutorial = findChild(shell, "tutorial");
789+ tryCompare(tutorial, "keyboardVisible", true);
790+
791+ AccountsService.demoEdges = true;
792+ var tutorialLeft = findChild(shell, "tutorialLeft");
793+ verify(!tutorialLeft.shown);
794+
795+ surface.setState(Mir.MinimizedState);
796+ tryCompare(inputMethod, "state", "hidden");
797+ tryCompare(tutorialLeft, "shown", false);
798+ }
799+
800+ function test_accountsServiceSettings() {
801+ var tutorialLeft = findChild(shell, "tutorialLeft");
802+ verify(tutorialLeft != null);
803+ verify(tutorialLeft.shown);
804+
805+ AccountsService.demoEdges = false;
806+ verify(findChild(shell, "tutorialLeft") == null);
807+
808+ AccountsService.demoEdges = true;
809+ tutorialLeft = findChild(shell, "tutorialLeft");
810+ verify(tutorialLeft != null);
811+ tryCompare(tutorialLeft, "shown", true);
394812 }
395813 }
396814}