@@ -47,6 +47,7 @@ Rectangle {
4747 }
4848
4949 Item {
50+ id: shellContainer
5051 anchors.left: root.left
5152 anchors.right: controls.left
5253 anchors.top: root.top
@@ -66,6 +67,11 @@ Rectangle {
6667 width: units.gu(40)
6768 height: units.gu(71)
6869 }
70+ StateChangeScript {
71+ script: {
72+ GSettingsController.setUsageMode("Staged")
73+ }
74+ }
6975 },
7076 State {
7177 name: "tablet"
@@ -74,6 +80,28 @@ Rectangle {
7480 width: units.gu(100)
7581 height: units.gu(71)
7682 }
83+ StateChangeScript {
84+ script: {
85+ GSettingsController.setUsageMode("Staged")
86+ }
87+ }
88+ },
89+ State {
90+ name: "desktop"
91+ PropertyChanges {
92+ target: shellLoader
93+ width: shellContainer.width
94+ height: shellContainer.height
95+ }
96+ PropertyChanges {
97+ target: mouseEmulation
98+ checked: false
99+ }
100+ StateChangeScript {
101+ script: {
102+ GSettingsController.setUsageMode("Windowed")
103+ }
104+ }
77105 }
78106 ]
79107
@@ -81,6 +109,7 @@ Rectangle {
81109 property bool itemDestroyed: false
82110 sourceComponent: Component {
83111 Shell {
112+ id: __shell
84113 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
85114 orientation: Qt.PortraitOrientation
86115 primaryOrientation: Qt.PortraitOrientation
@@ -88,6 +117,10 @@ Rectangle {
88117 Component.onDestruction: {
89118 shellLoader.itemDestroyed = true;
90119 }
120+ Component.onCompleted: {
121+ var keyMapper = testCase.findChild(__shell, "physicalKeysMapper");
122+ keyMapper.controlInsteadOfAlt = true;
123+ }
91124 }
92125 }
93126 }
@@ -112,16 +145,32 @@ Rectangle {
112145 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
113146 spacing: units.gu(1)
114147
115− Button {
116− text: "Show Greeter"
117− activeFocusOnPress: false
118− onClicked: {
119− if (shellLoader.status !== Loader.Ready)
120− return;
121−
122− var greeter = testCase.findChild(shellLoader.item, "greeter");
123− if (!greeter.shown) {
124− LightDM.Greeter.showGreeter();
148+ Row {
149+ spacing: units.gu(1)
150+ Button {
151+ text: "Show Greeter"
152+ activeFocusOnPress: false
153+ onClicked: {
154+ if (shellLoader.status !== Loader.Ready)
155+ return;
156+
157+ var greeter = testCase.findChild(shellLoader.item, "greeter");
158+ if (!greeter.shown) {
159+ LightDM.Greeter.showGreeter();
160+ }
161+ }
162+ }
163+ Button {
164+ text: "Hide Greeter"
165+ activeFocusOnPress: false
166+ onClicked: {
167+ if (shellLoader.status !== Loader.Ready)
168+ return;
169+
170+ var greeter = testCase.findChild(shellLoader.item, "greeter");
171+ if (greeter.shown) {
172+ greeter.hide()
173+ }
125174 }
126175 }
127176 }
@@ -141,7 +190,7 @@ Rectangle {
141190 anchors { left: parent.left; right: parent.right }
142191 activeFocusOnPress: false
143192 text: "Size"
144− model: ["phone", "tablet"]
193+ model: ["phone", "tablet", "desktop"]
145194 onSelectedIndexChanged: {
146195 shellLoader.active = false;
147196 shellLoader.state = model[selectedIndex];
@@ -163,6 +212,17 @@ Rectangle {
163212
164213 Label { text: "Applications"; font.bold: true }
165214
215+ Button {
216+ text: "Start all apps"
217+ width: parent.width
218+ onClicked: {
219+ for (var i = 0; i < ApplicationManager.availableApplications.length; i++) {
220+ var appId = ApplicationManager.availableApplications[i];
221+ ApplicationManager.startApplication(appId)
222+ }
223+ }
224+ }
225+
166226 Repeater {
167227 id: appRepeater
168228 model: ApplicationManager.availableApplications
@@ -226,6 +286,12 @@ Rectangle {
226286 signalName: "actionInvoked"
227287 }
228288
289+ SignalSpy {
290+ id: appRemovedSpy
291+ target: ApplicationManager
292+ signalName: "applicationRemoved"
293+ }
294+
229295 Telephony.CallEntry {
230296 id: phoneCall
231297 phoneNumber: "+447812221111"
@@ -248,6 +314,7 @@ Rectangle {
248314 }
249315
250316 function cleanup() {
317+ mouseEmulation.checked = true;
251318 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
252319 tearDown();
253320 GSettingsController.setUsageMode("Staged");
@@ -269,6 +336,20 @@ Rectangle {
269336 waitForGreeterToStabilize();
270337 }
271338
339+ function loadDesktopShellWithApps() {
340+ loadShell("desktop");
341+ shell.usageScenario = "desktop"
342+ waitForRendering(root)
343+ var app1 = ApplicationManager.startApplication("dialer-app")
344+ var app2 = ApplicationManager.startApplication("webbrowser-app")
345+ var app3 = ApplicationManager.startApplication("camera-app")
346+ var app4 = ApplicationManager.startApplication("facebook-webapp")
347+ var app5 = ApplicationManager.startApplication("calendar-app")
348+ var app6 = ApplicationManager.startApplication("gallery-app")
349+ var app7 = ApplicationManager.startApplication("camera-app")
350+ waitUntilAppWindowIsFullyLoaded(app7);
351+ }
352+
272353 function waitForGreeterToStabilize() {
273354 var greeter = findChild(shell, "greeter");
274355 verify(greeter);
@@ -472,6 +553,41 @@ Rectangle {
472553 confirmLoggedIn(data.loggedIn)
473554 }
474555
556+ function test_longLeftEdgeSwipeTakesToAppsAndResetSearchString() {
557+ loadShell("phone");
558+ swipeAwayGreeter();
559+ dragLauncherIntoView();
560+ dashCommunicatorSpy.clear();
561+
562+ tapOnAppIconInLauncher();
563+ waitUntilApplicationWindowIsFullyVisible();
564+
565+ verify(ApplicationManager.focusedApplicationId !== "unity8-dash")
566+
567+ //Long left swipe
568+ swipeFromLeftEdge(units.gu(30));
569+
570+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
571+
572+ compare(dashCommunicatorSpy.count, 1);
573+ }
574+
575+ function test_ClickUbuntuIconInLauncherTakesToAppsAndResetSearchString() {
576+ loadShell("phone");
577+ swipeAwayGreeter();
578+ dragLauncherIntoView();
579+ dashCommunicatorSpy.clear();
580+
581+ var launcher = findChild(shell, "launcher");
582+ var dashIcon = findChild(launcher, "dashItem");
583+ verify(dashIcon != undefined);
584+ mouseClick(dashIcon);
585+
586+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
587+
588+ compare(dashCommunicatorSpy.count, 1);
589+ }
590+
475591 function test_suspend() {
476592 loadShell("phone");
477593 swipeAwayGreeter();
@@ -724,7 +840,7 @@ Rectangle {
724840
725841 // check that the desktop stage and window have been loaded
726842 {
727− var desktopWindow = findChild(shell, "decoratedWindow_webbrowser-app");
843+ var desktopWindow = findChild(shell, "appWindow_webbrowser-app");
728844 verify(desktopWindow);
729845 }
730846
@@ -1082,6 +1198,8 @@ Rectangle {
10821198 }
10831199
10841200 function test_tapUbuntuIconInLauncherOverAppSpread() {
1201+ launcherShowDashHomeSpy.clear();
1202+
10851203 loadShell("phone");
10861204 swipeAwayGreeter();
10871205
@@ -1228,5 +1346,228 @@ Rectangle {
12281346 var launcher = findChild(shell, "launcher");
12291347 compare(launcher.inverted, data.launcherInverted);
12301348 }
1349+
1350+ function test_altTabSwitchesFocus() {
1351+ loadShell("desktop");
1352+ shell.usageScenario = "desktop"
1353+ waitForRendering(root)
1354+
1355+ var desktopStage = findChild(shell, "stage");
1356+ verify(desktopStage != null)
1357+
1358+ var app1 = ApplicationManager.startApplication("dialer-app")
1359+ waitUntilAppWindowIsFullyLoaded(app1);
1360+ var app2 = ApplicationManager.startApplication("webbrowser-app")
1361+ waitUntilAppWindowIsFullyLoaded(app2);
1362+ var app3 = ApplicationManager.startApplication("camera-app")
1363+ waitUntilAppWindowIsFullyLoaded(app3);
1364+
1365+ // Do a quick alt-tab and see if focus changes
1366+ tryCompare(app3.session.surface, "activeFocus", true)
1367+ keyClick(Qt.Key_Tab, Qt.ControlModifier)
1368+ tryCompare(app2.session.surface, "activeFocus", true)
1369+
1370+
1371+ tryCompare(desktopStage, "state", "")
1372+
1373+ // Just press Alt, make sure the spread comes up
1374+ keyPress(Qt.Key_Control);
1375+ keyClick(Qt.Key_Tab);
1376+ tryCompare(desktopStage, "state", "altTab")
1377+
1378+ // Release control, check if spread disappears
1379+ keyRelease(Qt.Key_Control)
1380+ tryCompare(desktopStage, "state", "")
1381+
1382+ // Focus should have switched back now
1383+ tryCompare(app3.session.surface, "activeFocus", true)
1384+ }
1385+
1386+ function test_altTabWrapAround() {
1387+ loadDesktopShellWithApps();
1388+
1389+ var desktopStage = findChild(shell, "stage");
1390+ verify(desktopStage !== null)
1391+
1392+ var appContainer = findInvisibleChild(shell, "appContainer")
1393+ verify(appContainer !== null)
1394+
1395+ var appRepeater = findInvisibleChild(shell, "appRepeater")
1396+ verify(appRepeater !== null)
1397+
1398+ // remember the focused appId
1399+ var focused = ApplicationManager.get(ApplicationManager.findApplication(ApplicationManager.focusedApplicationId));
1400+
1401+ tryCompare(desktopStage, "state", "")
1402+
1403+ // Just press Alt, make sure the spread comes up
1404+ keyPress(Qt.Key_Control);
1405+ keyClick(Qt.Key_Tab);
1406+ tryCompare(desktopStage, "state", "altTab")
1407+ tryCompare(appRepeater, "highlightedIndex", 1)
1408+ waitForRendering(shell)
1409+
1410+ // Now press and hold Tab, make sure the highlight moves all the way but stops at the last one
1411+ // We can't simulate a pressed key with keyPress() currently, so let's inject the events
1412+ // at API level. Jump for 10 times, verify that it's still at the last one and didn't wrap around.
1413+ for (var i = 0; i < 10; i++) {
1414+ appContainer.selectNext(true); // true == isAutoRepeat
1415+ wait(0); // Trigger the event loop to make sure all the things happen
1416+ }
1417+ tryCompare(appRepeater, "highlightedIndex", 6)
1418+
1419+ // Now release it once, and verify that it does wrap around with an additional Tab press
1420+ keyRelease(Qt.Key_Tab);
1421+ keyClick(Qt.Key_Tab);
1422+ tryCompare(appRepeater, "highlightedIndex", 0)
1423+
1424+ // Release control, check if spread disappears
1425+ keyRelease(Qt.Key_Control)
1426+ tryCompare(desktopStage, "state", "")
1427+
1428+ // Make sure that after wrapping around once, we have the same one focused as at the beginning
1429+ tryCompare(focused.session.surface, "activeFocus", true)
1430+ }
1431+
1432+ function test_altBackTabNavigation() {
1433+ loadDesktopShellWithApps();
1434+
1435+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1436+ verify(appRepeater !== null);
1437+
1438+ keyPress(Qt.Key_Control)
1439+ keyClick(Qt.Key_Tab);
1440+ tryCompare(appRepeater, "highlightedIndex", 1);
1441+
1442+ keyClick(Qt.Key_Tab);
1443+ tryCompare(appRepeater, "highlightedIndex", 2);
1444+
1445+ keyClick(Qt.Key_Tab);
1446+ tryCompare(appRepeater, "highlightedIndex", 3);
1447+
1448+ keyClick(Qt.Key_Tab);
1449+ tryCompare(appRepeater, "highlightedIndex", 4);
1450+
1451+ keyClick(Qt.Key_Backtab);
1452+ tryCompare(appRepeater, "highlightedIndex", 3);
1453+
1454+ keyClick(Qt.Key_Backtab);
1455+ tryCompare(appRepeater, "highlightedIndex", 2);
1456+
1457+ keyClick(Qt.Key_Backtab);
1458+ tryCompare(appRepeater, "highlightedIndex", 1);
1459+
1460+ keyRelease(Qt.Key_Control);
1461+ }
1462+
1463+ function test_highlightFollowsMouse() {
1464+ loadDesktopShellWithApps()
1465+
1466+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1467+ verify(appRepeater !== null);
1468+
1469+ keyPress(Qt.Key_Control)
1470+ keyClick(Qt.Key_Tab);
1471+
1472+ tryCompare(appRepeater, "highlightedIndex", 1);
1473+
1474+ var x = 0;
1475+ var y = shell.height * .75;
1476+ mouseMove(shell, x, y)
1477+
1478+ for (var i = 0; i < 7; i++) {
1479+ while (appRepeater.highlightedIndex != i && x <= 4000) {
1480+ x+=10;
1481+ mouseMove(shell, x, y)
1482+ waitForRendering(shell)
1483+ }
1484+ }
1485+
1486+ verify(y < 4000);
1487+
1488+ keyRelease(Qt.Key_Control);
1489+ }
1490+
1491+ function test_closeFromSpread() {
1492+ loadDesktopShellWithApps()
1493+
1494+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1495+ verify(appRepeater !== null);
1496+
1497+ keyPress(Qt.Key_Control)
1498+ keyClick(Qt.Key_Tab);
1499+
1500+ appRemovedSpy.clear();
1501+
1502+ var closedAppId = ApplicationManager.get(2).appId;
1503+ var appDelegate2 = appRepeater.itemAt(2);
1504+ var closeMouseArea = findChild(appDelegate2, "closeMouseArea");
1505+
1506+ // Move the mosue over tile 2 and verify the close button becomes visible
1507+ var x = 0;
1508+ var y = shell.height * .5;
1509+ mouseMove(shell, x, y)
1510+ while (appRepeater.highlightedIndex !== 2 && x <= 4000) {
1511+ x+=10;
1512+ mouseMove(shell, x, y)
1513+ waitForRendering(shell)
1514+ }
1515+ tryCompare(closeMouseArea, "enabled", true)
1516+
1517+ // Close the app using the close button
1518+ mouseClick(closeMouseArea, closeMouseArea.width / 2, closeMouseArea.height / 2)
1519+
1520+ // Verify applicationRemoved has been emitted correctly
1521+ tryCompare(appRemovedSpy, "count", 1)
1522+ compare(appRemovedSpy.signalArguments[0][0], closedAppId);
1523+
1524+ keyRelease(Qt.Key_Control);
1525+ }
1526+
1527+ function test_selectFromSpreadWithMouse_data() {
1528+ return [
1529+ {tag: "click on tileInfo", tileInfo: true },
1530+ {tag: "click on surface", tileInfo: false },
1531+ ]
1532+ }
1533+
1534+ function test_selectFromSpreadWithMouse(data) {
1535+ loadDesktopShellWithApps()
1536+
1537+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1538+ verify(appRepeater !== null);
1539+
1540+ keyPress(Qt.Key_Control)
1541+ keyClick(Qt.Key_Tab);
1542+
1543+ appRemovedSpy.clear();
1544+
1545+ var focusAppId = ApplicationManager.get(2).appId;
1546+ var appDelegate2 = appRepeater.itemAt(2);
1547+ var decoratedWindow = findChild(appDelegate2, "decoratedWindow");
1548+ var stage = findChild(shell, "stage");
1549+
1550+ tryCompare(stage, "state", "altTab");
1551+
1552+ // Move the mouse over tile 2 and verify the highlight becomes visible
1553+ var x = 0;
1554+ var y = shell.height * (data.tileInfo ? .5 : 0.95)
1555+ mouseMove(shell, x, y)
1556+ while (appRepeater.highlightedIndex !== 2 && x <= 4000) {
1557+ x+=10;
1558+ mouseMove(shell, x, y)
1559+ waitForRendering(shell)
1560+ }
1561+ tryCompare(decoratedWindow, "highlightShown", true);
1562+
1563+ // Click the tile
1564+ mouseClick(decoratedWindow, decoratedWindow.width / 2, decoratedWindow.height / 2)
1565+
1566+ // Verify that we left the spread and app2 is the focused one now
1567+ tryCompare(stage, "state", "");
1568+ tryCompare(ApplicationManager, "focusedApplicationId", focusAppId);
1569+
1570+ keyRelease(Qt.Key_Control);
1571+ }
12311572 }
12321573}