@@ -19,26 +19,42 @@ import QtQuick.Layouts 1.1
19import QtTest 1.0
19import QtTest 1.0
20import Unity.Test 0.1
20import Unity.Test 0.1
21import Ubuntu.Components 1.3
21import Ubuntu.Components 1.3
22+import Ubuntu.Components.ListItems 1.3 as ListItem
22import Unity.Application 0.1
23import Unity.Application 0.1
23−import Unity.Indicators 0.1 as Indicators
24+import QMenuModel 0.1
24import Ubuntu.Telephony 0.1 as Telephony
25import Ubuntu.Telephony 0.1 as Telephony
26+import AccountsService 0.1
27+import Unity.InputInfo 0.1
25import "../../../qml/Panel"
28import "../../../qml/Panel"
26import "../../../qml/Components/PanelState"
29import "../../../qml/Components/PanelState"
28−IndicatorTest {
33+PanelTest {
30− width: units.gu(100)
35+ width: units.gu(120)
31 height: units.gu(71)
36 height: units.gu(71)
32 color: "black"
37 color: "black"
34− Component.onCompleted: theme.name = "Ubuntu.Components.Themes.SuruDark"
39+ Binding {
41+ property: "keyboardAttached"
42+ value: keyboardAttached.checked
36− SurfaceManager {}
45+ SurfaceManager { id: sMgr }
46+ ApplicationMenuDataLoader {
38− Binding {
51+ Component.onCompleted: {
39− target: mouseEmulation
52+ theme.name = "Ubuntu.Components.Themes.SuruDark"
40− property: "checked"
53+ }
41− value: !windowControlsCB.checked
54+
44 RowLayout {
60 RowLayout {
@@ -61,12 +77,23 @@ IndicatorTest {
63 anchors.fill: parent
79 anchors.fill: parent
80+ mode: modeSelector.model[modeSelector.selectedIndex]
82+ indicatorMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
83+ applicationMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
86+ model: UnityMenuModel {
87+ modelData: appMenuData.generateTestData(5, 4, 2, 3, "menu")
64− indicators {
90+ hides: [ panel.indicators ]
65− width: parent.width > units.gu(60) ? units.gu(40) : parent.width
66− indicatorsModel: root.indicatorsModel
69− property real panelAndSeparatorHeight: panel.indicators.minimizedPanelHeight
93+ indicators {
94+ model: root.indicatorsModel
95+ hides: [ panel.applicationMenus ]
@@ -75,6 +102,18 @@ IndicatorTest {
75 Layout.alignment: Qt.AlignTop
102 Layout.alignment: Qt.AlignTop
76 Layout.fillWidth: false
103 Layout.fillWidth: false
105+ ListItem.ItemSelector {
107+ anchors { left: parent.left; right: parent.right }
108+ activeFocusOnPress: false
110+ model: ["staged", "windowed" ]
111+ onSelectedIndexChanged: {
112+ panel.mode = model[selectedIndex];
113+ keyboardAttached.checked = panel.mode == "windowed"
79 Layout.fillWidth: true
118 Layout.fillWidth: true
80 text: panel.indicators.shown ? "Hide" : "Show"
119 text: panel.indicators.shown ? "Hide" : "Show"
@@ -109,25 +148,22 @@ IndicatorTest {
109 Layout.fillWidth: true
148 Layout.fillWidth: true
110 CheckBox {
149 CheckBox {
111 id: windowControlsCB
150 id: windowControlsCB
112− onClicked: PanelState.buttonsVisible = checked
151+ onClicked: PanelState.decorationsVisible = checked
115− text: "Show window controls"
154+ text: "Show window decorations"
119 RowLayout {
159 RowLayout {
120 Layout.fillWidth: true
160 Layout.fillWidth: true
121 CheckBox {
161 CheckBox {
122− onClicked: {
162+ onClicked: PanelState.title = checked ? "Fake window title" : ""
124− PanelState.title = "Fake window title"
126− PanelState.title = ""
130 text: "Show fake window title"
165 text: "Show fake window title"
@@ -137,6 +173,12 @@ IndicatorTest {
137 color: "black"
173 color: "black"
177+ Layout.preferredHeight: units.dp(1);
178+ Layout.fillWidth: true;
140 Repeater {
182 Repeater {
141 model: root.originalModelData
183 model: root.originalModelData
142 RowLayout {
184 RowLayout {
@@ -147,6 +189,7 @@ IndicatorTest {
148 Layout.fillWidth: true
190 Layout.fillWidth: true
149 text: modelData["identifier"]
191 text: modelData["identifier"]
152 CheckBox {
195 CheckBox {
@@ -155,6 +198,7 @@ IndicatorTest {
157 text: "visible"
200 text: "visible"
@@ -165,7 +209,22 @@ IndicatorTest {
165 color: "black"
209 color: "black"
168− MouseTouchEmulationCheckbox { id: mouseEmulation }
212+ MouseTouchEmulationCheckbox {
215+ checked: panel.mode == "staged"
219+ Layout.fillWidth: true
221+ id: keyboardAttached
224+ text: "Keyboard Attached"
@@ -191,22 +250,31 @@ IndicatorTest {
193 function init() {
252 function init() {
253+ panel.mode = "staged";
254+ mouseEmulation.checked = true;
194 panel.fullscreenMode = false;
255 panel.fullscreenMode = false;
195 callManager.foregroundCall = null;
256 callManager.foregroundCall = null;
197− panel.indicators.hide();
258+ PanelState.title = "";
198− // Wait for animation to complete
259+ PanelState.decorationsVisible = false;
199− tryCompare(panel.indicators.hideAnimation, "running", false);
201 // Wait for the indicators to get into position.
261 // Wait for the indicators to get into position.
202 // (switches between normal and fullscreen modes are animated)
262 // (switches between normal and fullscreen modes are animated)
203− var indicatorArea = findChild(panel, "indicatorArea");
263+ var panelArea = findChild(panel, "panelArea");
204− tryCompare(indicatorArea, "y", 0);
264+ tryCompare(panelArea, "y", 0);
206 backgroundPressedSpy.clear();
266 backgroundPressedSpy.clear();
207 compare(backgroundPressedSpy.valid, true);
267 compare(backgroundPressedSpy.valid, true);
208 windowControlButtonsSpy.clear();
268 windowControlButtonsSpy.clear();
209 compare(windowControlButtonsSpy.valid, true);
269 compare(windowControlButtonsSpy.valid, true);
271+ waitForRendering(panel);
274+ function cleanup() {
275+ panel.indicators.hide();
276+ panel.applicationMenus.hide();
277+ waitForAllAnimationToComplete("initial");
212 function get_indicator_item(index) {
280 function get_indicator_item(index) {
@@ -216,8 +284,28 @@ IndicatorTest {
216 return indicatorItem;
284 return indicatorItem;
287+ function waitForAllAnimationToComplete(state) {
289+ waitUntilTransitionsEnd(panel);
290+ tryCompare(panel.indicators.hideAnimation, "running", false);
291+ tryCompare(panel.indicators.showAnimation, "running", false);
292+ tryCompare(panel.indicators, "state", state);
294+ for (var i = 0; i < root.originalModelData.length; i++) {
295+ var indicatorItem = get_indicator_item(i);
297+ var itemState = findInvisibleChild(indicatorItem, "indicatorItemState");
298+ verify(itemState !== null);
300+ waitUntilTransitionsEnd(itemState);
303+ tryCompare(panel.applicationMenus.hideAnimation, "running", false);
304+ tryCompare(panel.applicationMenus, "state", state);
219 function pullDownIndicatorsMenu() {
307 function pullDownIndicatorsMenu() {
220− var showDragHandle = findChild(panel, "showDragHandle");
308+ var showDragHandle = findChild(panel.indicators, "showDragHandle");
221 touchFlick(showDragHandle,
309 touchFlick(showDragHandle,
222 showDragHandle.width / 2,
310 showDragHandle.width / 2,
223 showDragHandle.height / 2,
311 showDragHandle.height / 2,
@@ -226,16 +314,22 @@ IndicatorTest {
226 tryCompare(panel.indicators, "fullyOpened", true);
314 tryCompare(panel.indicators, "fullyOpened", true);
229− function test_drag_show_data() {
317+ function pullDownApplicationsMenu() {
318+ var showDragHandle = findChild(panel.applicationMenus, "showDragHandle");
319+ touchFlick(showDragHandle,
320+ showDragHandle.width / 2,
321+ showDragHandle.height / 2,
322+ showDragHandle.width / 2,
323+ showDragHandle.height / 2 + (showDragHandle.autoCompleteDragThreshold * 1.1));
324+ tryCompare(panel.applicationMenus, "fullyOpened", true);
327+ function test_drag_indicator_item_down_shows_menu_data() {
231− { tag: "pinned", fullscreen: false, call: null,
329+ { tag: "pinned", fullscreen: false, call: null, y: 0 },
233− { tag: "fullscreen", fullscreen: true, call: null,
330+ { tag: "fullscreen", fullscreen: true, call: null, y: -panel.minimizedPanelHeight },
234− indicatorY: -panel.panelAndSeparatorHeight },
235− { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
331+ { tag: "pinned-callActive", fullscreen: false, call: phoneCall, y: 0},
237− { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
332+ { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall, y: -panel.minimizedPanelHeight }
238− indicatorY: -panel.panelAndSeparatorHeight }
@@ -243,24 +337,26 @@ IndicatorTest {
243 // indicators, first by running the hint animation, then after dragging down will
337 // indicators, first by running the hint animation, then after dragging down will
244 // expose more of the panel, binding it to the selected indicator and opening it's menu.
338 // expose more of the panel, binding it to the selected indicator and opening it's menu.
245 // Tested from first Y pixel to check for swipe from offscreen.
339 // Tested from first Y pixel to check for swipe from offscreen.
246− function test_drag_show(data) {
340+ function test_drag_indicator_item_down_shows_menu(data) {
247 panel.fullscreenMode = data.fullscreen;
341 panel.fullscreenMode = data.fullscreen;
248 callManager.foregroundCall = data.call;
342 callManager.foregroundCall = data.call;
250− var indicatorRow = findChild(panel.indicators, "indicatorItemRow");
344+ var panelRow = findChild(panel.indicators, "panelItemRow");
251− verify(indicatorRow !== null);
345+ verify(panelRow !== null);
253 var menuContent = findChild(panel.indicators, "menuContent");
347 var menuContent = findChild(panel.indicators, "menuContent");
254 verify(menuContent !== null);
348 verify(menuContent !== null);
256− var indicatorArea = findChild(panel, "indicatorArea");
350+ var panelArea = findChild(panel, "panelArea");
257− verify(indicatorArea !== null);
351+ verify(panelArea !== null);
259 // Wait for the indicators to get into position.
353 // Wait for the indicators to get into position.
260 // (switches between normal and fullscreen modes are animated)
354 // (switches between normal and fullscreen modes are animated)
261− tryCompareFunction(function() { return indicatorArea.y }, data.indicatorY);
355+ tryCompareFunction(function() { return panelArea.y }, data.y);
263 for (var i = 0; i < root.originalModelData.length; i++) {
357 for (var i = 0; i < root.originalModelData.length; i++) {
358+ waitForAllAnimationToComplete("initial");
264 var indicatorItem = get_indicator_item(i);
360 var indicatorItem = get_indicator_item(i);
266 var startXPosition = panel.mapFromItem(indicatorItem, indicatorItem.width / 2, 0).x;
362 var startXPosition = panel.mapFromItem(indicatorItem, indicatorItem.width / 2, 0).x;
@@ -268,7 +364,7 @@ IndicatorTest {
268 touchFlick(panel,
364 touchFlick(panel,
269 startXPosition, 0,
365 startXPosition, 0,
270 startXPosition, panel.height,
366 startXPosition, panel.height,
271− true /* beginTouch */, false /* endTouch */, units.gu(5), 15);
367+ true /* beginTouch */, false /* endTouch */, 1, 15);
273 // Indicators height should follow the drag, and therefore increase accordingly.
369 // Indicators height should follow the drag, and therefore increase accordingly.
274 // They should be at least half-way through the screen
370 // They should be at least half-way through the screen
@@ -278,105 +374,152 @@ IndicatorTest {
279 touchRelease(panel, startXPosition, panel.height);
375 touchRelease(panel, startXPosition, panel.height);
281− compare(indicatorRow.currentItemIndex, i, "Indicator item should be activated at position " + i);
377+ tryCompare(panelRow, "currentItemIndex", i, undefined, "Indicator item should be activated at position " + i);
282 compare(menuContent.currentMenuIndex, i, "Menu conetent should be activated for item at position " + i);
378 compare(menuContent.currentMenuIndex, i, "Menu conetent should be activated for item at position " + i);
284 // init for next indicatorItem
380 // init for next indicatorItem
285 panel.indicators.hide();
381 panel.indicators.hide();
286− tryCompare(panel.indicators.hideAnimation, "running", false);
287− tryCompare(panel.indicators, "state", "initial");
291− function test_drag_hide_data() {
385+ function test_drag_panel_handle_up_hides_menu_data() {
293− { tag: "pinned", fullscreen: false, call: null,
387+ { tag: "indicators-pinned", section: panel.indicators, fullscreen: false, call: null },
295− { tag: "fullscreen", fullscreen: true, call: null,
388+ { tag: "indicators-fullscreen", section: panel.indicators, fullscreen: true, call: null },
296− indicatorY: -panel.panelAndSeparatorHeight },
389+ { tag: "indicators-pinned-callActive", section: panel.indicators, fullscreen: false, call: phoneCall },
297− { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
390+ { tag: "indicators-fullscreen-callActive", section: panel.indicators, fullscreen: true, call: phoneCall },
298− indicatorY: 0},
391+ { tag: "appMenus-pinned", section: panel.applicationMenus, fullscreen: false, call: null },
392+ { tag: "appMenus-fullscreen", section: panel.applicationMenus, fullscreen: true, call: null },
299− { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
393+ { tag: "appMenus-pinned-callActive", section: panel.applicationMenus, fullscreen: false, call: phoneCall },
300− indicatorY: -panel.panelAndSeparatorHeight }
394+ { tag: "appMenus-fullscreen-callActive", section: panel.applicationMenus, fullscreen: true, call: phoneCall }
304 // Dragging the shown indicators up from bottom of panel will hide the indicators
398 // Dragging the shown indicators up from bottom of panel will hide the indicators
305 // Tested from last Y pixel to check for swipe from offscreen.
399 // Tested from last Y pixel to check for swipe from offscreen.
306− function test_drag_hide(data) {
400+ function test_drag_panel_handle_up_hides_menu(data) {
307 panel.fullscreenMode = data.fullscreen;
401 panel.fullscreenMode = data.fullscreen;
308 callManager.foregroundCall = data.call;
402 callManager.foregroundCall = data.call;
310− var indicatorRow = findChild(panel.indicators, "indicatorItemRow");
404+ var panelRow = findChild(data.section, "panelItemRow");
311− verify(indicatorRow !== null);
405+ verify(panelRow !== null);
313− var menuContent = findChild(panel.indicators, "menuContent");
407+ var panelArea = findChild(panel, "panelArea");
314− verify(menuContent !== null);
408+ verify(panelArea !== null);
316− var indicatorArea = findChild(panel, "indicatorArea");
317− verify(indicatorArea !== null);
319 // Wait for the indicators to get into position.
410 // Wait for the indicators to get into position.
320 // (switches between normal and fullscreen modes are animated)
411 // (switches between normal and fullscreen modes are animated)
321− tryCompareFunction(function() { return indicatorArea.y }, data.indicatorY);
412+ tryCompareFunction(function() { return panelArea.y }, data.fullscreen ? -panel.minimizedPanelHeight : 0);
323− panel.indicators.show();
414+ data.section.show();
324− tryCompare(panel.indicators.showAnimation, "running", false);
415+ tryCompare(data.section.showAnimation, "running", false);
325− tryCompare(panel.indicators, "unitProgress", 1);
416+ tryCompare(data.section, "unitProgress", 1);
327− touchFlick(panel.indicators,
418+ touchFlick(data.section,
328− panel.indicators.width / 2, panel.height,
419+ data.section.width / 2, panel.height,
329− panel.indicators.width / 2, 0,
420+ data.section.width / 2, 0,
330 true /* beginTouch */, false /* endTouch */, units.gu(5), 15);
421 true /* beginTouch */, false /* endTouch */, units.gu(5), 15);
332 // Indicators height should follow the drag, and therefore increase accordingly.
423 // Indicators height should follow the drag, and therefore increase accordingly.
333 // They should be at least half-way through the screen
424 // They should be at least half-way through the screen
334 tryCompareFunction(
425 tryCompareFunction(
335− function() {return panel.indicators.height <= panel.height * 0.5},
426+ function() {return data.section.height <= panel.height * 0.5},
338− touchRelease(panel.indicators, panel.indicators.width / 2, 0);
429+ touchRelease(data.section, data.section.width / 2, 0);
340− tryCompare(panel.indicators.hideAnimation, "running", true);
431+ tryCompare(data.section.hideAnimation, "running", true);
341− tryCompare(panel.indicators.hideAnimation, "running", false);
432+ tryCompare(data.section.hideAnimation, "running", false);
342− tryCompare(panel.indicators, "state", "initial");
433+ tryCompare(data.section, "state", "initial");
345 function test_hint_data() {
436 function test_hint_data() {
347− { tag: "normal", fullscreen: false, call: null, hintExpected: true},
438+ { tag: "indicators-normal", section: panel.indicators, fullscreen: false, call: null, hintExpected: true},
348− { tag: "fullscreen", fullscreen: true, call: null, hintExpected: false},
439+ { tag: "indicators-fullscreen", section: panel.indicators, fullscreen: true, call: null, hintExpected: false},
440+ { tag: "indicators-callActive", section: panel.indicators, fullscreen: false, call: phoneCall, hintExpected: false},
441+ { tag: "appMenus-normal", section: panel.applicationMenus, fullscreen: false, call: null, hintExpected: true},
442+ { tag: "appMenus-fullscreen", section: panel.applicationMenus, fullscreen: true, call: null, hintExpected: false},
349− { tag: "call hint", fullscreen: false, call: phoneCall, hintExpected: false},
443+ { tag: "appMenus-callActive", section: panel.applicationMenus, fullscreen: false, call: phoneCall, hintExpected: false},
353 function test_hint(data) {
447 function test_hint(data) {
448+ PanelState.title = "Fake Title"
354 panel.fullscreenMode = data.fullscreen;
449 panel.fullscreenMode = data.fullscreen;
355 callManager.foregroundCall = data.call;
450 callManager.foregroundCall = data.call;
357 if (data.fullscreen) {
452 if (data.fullscreen) {
358 // Wait for the indicators to get into position.
453 // Wait for the indicators to get into position.
359 // (switches between normal and fullscreen modes are animated)
454 // (switches between normal and fullscreen modes are animated)
360− var indicatorArea = findChild(panel, "indicatorArea");
455+ var panelArea = findChild(panel, "panelArea");
361− tryCompare(indicatorArea, "y", -panel.panelHeight);
456+ tryCompare(panelArea, "y", -panel.minimizedPanelHeight);
364− var indicatorItem = get_indicator_item(0);
365− var mappedPosition = root.mapFromItem(indicatorItem, indicatorItem.width / 2, indicatorItem.height / 2);
459+ var mappedPosition = root.mapFromItem(data.section,
460+ data.section.barWidth / 2, data.section.minimizedPanelHeight / 2);
462+ touchPress(panel, mappedPosition.x, panel.minimizedPanelHeight / 2);
367− touchPress(panel, mappedPosition.x, panel.indicators.minimizedPanelHeight / 2);
464+ var showDragHandle = findChild(data.section, "showDragHandle")
465+ var hintingAnimation = findInvisibleChild(showDragHandle, "hintingAnimation");
466+ verify(hintingAnimation);
369− // Give some time for a hint animation to change things, if any
468+ compare(hintingAnimation.running, data.hintExpected)
370− wait(500);
469+ tryCompare(hintingAnimation, "running", false); // wait till animation completes
372 // no hint animation when fullscreen
471 // no hint animation when fullscreen
373− compare(panel.indicators.fullyClosed, !data.hintExpected, "Indicator should be fully closed");
374− compare(panel.indicators.partiallyOpened, data.hintExpected, "Indicator should be partialy opened");
472+ compare(data.section.partiallyOpened, data.hintExpected, "Indicator should be partialy opened");
375− compare(panel.indicators.fullyOpened, false, "Indicator should not be fully opened");
473+ compare(data.section.fullyOpened, false, "Indicator should not be fully opened");
377 touchRelease(panel, mappedPosition.x, panel.minimizedPanelHeight / 2);
475 touchRelease(panel, mappedPosition.x, panel.minimizedPanelHeight / 2);
478+ function test_drag_applicationMenu_down_shows_menu_data() {
480+ { tag: "normal", fullscreen: false, call: null, hintExpected: true},
481+ { tag: "fullscreen", fullscreen: true, call: null, hintExpected: false},
482+ { tag: "callActive", fullscreen: false, call: phoneCall, hintExpected: false}
486+ // Dragging the application menu will gradually expose the
487+ // menus, first by running the hint animation, then after dragging down will
488+ // expose more of the panel. Releasing the touch will complete the show.
489+ function test_drag_applicationMenu_down_shows_menu(data) {
490+ PanelState.title = "Fake Title";
491+ panel.fullscreenMode = data.fullscreen;
492+ callManager.foregroundCall = data.call;
494+ var panelRow = findChild(panel.indicators, "panelItemRow");
495+ verify(panelRow !== null);
497+ var menuContent = findChild(panel.indicators, "menuContent");
498+ verify(menuContent !== null);
500+ var panelArea = findChild(panel, "panelArea");
501+ verify(panelArea !== null);
503+ // Wait for the indicators to get into position.
504+ // (switches between normal and fullscreen modes are animated)
505+ tryCompareFunction(function() { return panelArea.y }, data.fullscreen ? -panel.minimizedPanelHeight : 0);
509+ units.gu(1), panel.height,
510+ true /* beginTouch */, false /* endTouch */, units.gu(5), 15);
512+ // Indicators height should follow the drag, and therefore increase accordingly.
513+ // They should be at least half-way through the screen
515+ function() {return panel.applicationMenus.height >= panel.height * 0.5},
518+ touchRelease(panel, units.gu(1), panel.height);
520+ tryCompare(panel.applicationMenus, "fullyOpened", true)
380 /* Checks that no input reaches items behind the indicator bar.
523 /* Checks that no input reaches items behind the indicator bar.
381 Ie., the indicator bar should eat all input events that hit it.
524 Ie., the indicator bar should eat all input events that hit it.
@@ -385,20 +528,20 @@ IndicatorTest {
385 // that it doesn't have a "weak spot" from where taps pass through.
528 // that it doesn't have a "weak spot" from where taps pass through.
386 var numTaps = 5;
529 var numTaps = 5;
387 var stepLength = (panel.width / (numTaps + 1));
530 var stepLength = (panel.width / (numTaps + 1));
388− var tapY = panel.indicators.minimizedPanelHeight / 2;
531+ var tapY = panel.minimizedPanelHeight / 2;
389 for (var i = 1; i <= numTaps; ++i) {
532 for (var i = 1; i <= numTaps; ++i) {
390 tap(panel, stepLength * i, tapY);
533 tap(panel, stepLength * i, tapY);
391 tryCompare(panel.indicators, "fullyClosed", true);
534 tryCompare(panel.indicators, "fullyClosed", true);
395− function test_darkenedAreaEatsAllEvents() {
538+ function test_darkenedAreaEatsAllIndicatorEvents() {
397 // The center of the area not covered by the indicators menu
540 // The center of the area not covered by the indicators menu
398 // Ie, the visible darkened area behind the menu
541 // Ie, the visible darkened area behind the menu
399 var touchPosX = (panel.width - panel.indicators.width) / 2
542 var touchPosX = (panel.width - panel.indicators.width) / 2
400− var touchPosY = panel.indicators.minimizedPanelHeight +
543+ var touchPosY = panel.minimizedPanelHeight +
401− ((panel.height - panel.indicators.minimizedPanelHeight) / 2)
544+ ((panel.height - panel.minimizedPanelHeight) / 2)
403 // input goes through while the indicators menu is closed
546 // input goes through while the indicators menu is closed
404 tryCompare(panel.indicators, "fullyClosed", true);
547 tryCompare(panel.indicators, "fullyClosed", true);
@@ -434,6 +577,50 @@ IndicatorTest {
434 compare(backgroundPressedSpy.count, 2);
577 compare(backgroundPressedSpy.count, 2);
580+ function test_darkenedAreaEatsAllApplicationMenuEvents() {
581+ PanelState.title = "Fake Title"
583+ // The center of the area not covered by the indicators menu
584+ // Ie, the visible darkened area behind the menu
585+ var touchPosX = panel.applicationMenus.width + (panel.width - panel.applicationMenus.width) / 2
586+ var touchPosY = panel.minimizedPanelHeight +
587+ ((panel.height - panel.minimizedPanelHeight) / 2)
589+ // input goes through while the indicators menu is closed
590+ tryCompare(panel.applicationMenus, "fullyClosed", true);
591+ compare(backgroundPressedSpy.count, 0);
592+ tap(panel, touchPosX, touchPosY);
593+ compare(backgroundPressedSpy.count, 2);
595+ pullDownApplicationsMenu();
597+ // Darkened area eats input when the indicators menu is fully opened
598+ tap(panel, touchPosX, touchPosY);
599+ compare(backgroundPressedSpy.count, 2);
600+ backgroundPressedSpy.clear();
602+ // And should continue to eat inpunt until the indicators menu is fully closed
604+ while (!panel.applicationMenus.fullyClosed) {
605+ tap(panel, touchPosX, touchPosY);
607+ // it could have got fully closed during the tap
608+ // so we have to double check here
609+ if (!panel.applicationMenus.fullyClosed) {
610+ compare(backgroundPressedSpy.count, 0);
613+ // let the animation go a bit further
617+ // Now that's fully closed, input should go through again
618+ backgroundPressedSpy.clear();
619+ tap(panel, touchPosX, touchPosY);
620+ compare(backgroundPressedSpy.count, 2);
438 Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1439318
625 Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1439318
439 When the panel is in fullscreen mode and the user taps near the top edge,
626 When the panel is in fullscreen mode and the user taps near the top edge,
@@ -441,14 +628,12 @@ IndicatorTest {
443 function test_tapNearTopEdgeWithPanelInFullscreenMode() {
630 function test_tapNearTopEdgeWithPanelInFullscreenMode() {
444− var indicatorArea = findChild(panel, "indicatorArea");
631+ var panelArea = findChild(panel, "panelArea");
445− verify(indicatorArea);
446− var panelPriv = findInvisibleChild(panel, "panelPriv");
447− verify(panelPriv);
632+ verify(panelArea);
449 panel.fullscreenMode = true;
634 panel.fullscreenMode = true;
450 // wait until if finishes hiding itself
635 // wait until if finishes hiding itself
451− tryCompare(indicatorArea, "y", -panelPriv.indicatorHeight);
636+ tryCompare(panelArea, "y", -panel.minimizedPanelHeight);
453 compare(panel.indicators.shown, false);
638 compare(panel.indicators.shown, false);
454 verify(panel.indicators.fullyClosed);
639 verify(panel.indicators.fullyClosed);
@@ -479,7 +664,7 @@ IndicatorTest {
480 mouseClick(panel.indicators,
665 mouseClick(panel.indicators,
481 panel.indicators.width / 2,
666 panel.indicators.width / 2,
482− panel.indicators.minimizedPanelHeight / 2);
667+ panel.minimizedPanelHeight / 2);
484 compare(panel.indicators.shown, false);
669 compare(panel.indicators.shown, false);
485 verify(panel.indicators.fullyClosed);
670 verify(panel.indicators.fullyClosed);
@@ -494,7 +679,7 @@ IndicatorTest {
495 mouseClick(panel.indicators,
680 mouseClick(panel.indicators,
496 panel.indicators.width / 2,
681 panel.indicators.width / 2,
497− panel.indicators.minimizedPanelHeight / 2);
682+ panel.minimizedPanelHeight / 2);
499 compare(panel.indicators.shown, true);
684 compare(panel.indicators.shown, true);
500 tryCompare(panel.indicators, "fullyOpened", true);
685 tryCompare(panel.indicators, "fullyOpened", true);
@@ -510,13 +695,109 @@ IndicatorTest {
511 // https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1611959
696 // https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1611959
512 function test_windowControlButtonsFittsLaw() {
697 function test_windowControlButtonsFittsLaw() {
513− var buttonsVisible = PanelState.buttonsVisible;
698+ panel.mode = "windowed";
699+ var windowControlArea = findChild(panel, "windowControlArea");
700+ verify(windowControlArea, "Window control area should have been created in windowed mode")
514− PanelState.buttonsVisible = true;
702+ PanelState.decorationsVisible = true;
515 // click in very topleft corner and verify the close button got clicked too
703 // click in very topleft corner and verify the close button got clicked too
516 mouseMove(panel, 0, 0);
704 mouseMove(panel, 0, 0);
517 mouseClick(panel, 0, 0, undefined /*button*/, undefined /*modifiers*/, 100 /*short delay*/);
705 mouseClick(panel, 0, 0, undefined /*button*/, undefined /*modifiers*/, 100 /*short delay*/);
518 compare(windowControlButtonsSpy.count, 1);
706 compare(windowControlButtonsSpy.count, 1);
519− PanelState.buttonsVisible = buttonsVisible;
707+ }
709+ function test_hidingKeyboardIndicator_data() {
711+ { tag: "No keyboard, no keymap", keyboard: false, keymaps: [], hidden: true },
712+ { tag: "No keyboard, one keymap", keyboard: false, keymaps: ["us"], hidden: true },
713+ { tag: "No keyboard, 2 keymaps", keyboard: false, keymaps: ["us", "cs"], hidden: true },
714+ { tag: "Keyboard, no keymap", keyboard: true, keymaps: [], hidden: true },
715+ { tag: "Keyboard, one keymap", keyboard: true, keymaps: ["us"], hidden: true },
716+ { tag: "Keyboard, 2 keymaps", keyboard: true, keymaps: ["us", "cs"], hidden: false }
720+ function test_hidingKeyboardIndicator(data) {
721+ var item = findChild(panel, "indicator-keyboard-panelItem");
722+ AccountsService.keymaps = data.keymaps;
723+ if (data.keyboard) {
724+ MockInputDeviceBackend.addMockDevice("/indicator_kbd0", InputInfo.Keyboard);
726+ MockInputDeviceBackend.removeDevice("/indicator_kbd0");
729+ compare(item.hidden, data.hidden);
732+ function test_visibleIndicators_data() {
734+ { visible: [true, false, true, false, true, true, false, true] },
735+ { visible: [false, false, false, false, false, false, true, false] }
739+ function test_visibleIndicators(data) {
740+ for (var i = 0; i < data.visible.length; i++) {
741+ var visible = data.visible[i];
742+ root.setIndicatorVisible(i, visible);
744+ var dataItem = findChild(panel, root.originalModelData[i]["identifier"] + "-panelItem");
745+ tryCompare(dataItem, "opacity", visible ? 1.0 : 0.0);
746+ tryCompareFunction(function() { return dataItem.width > 0.0; }, visible);
749+ panel.indicators.show();
750+ tryCompare(panel.indicators.showAnimation, "running", false);
751+ tryCompare(panel.indicators, "unitProgress", 1);
753+ for (var i = 0; i < data.visible.length; i++) {
754+ root.setIndicatorVisible(i, data.visible[i]);
756+ var dataItem = findChild(panel, root.originalModelData[i]["identifier"] + "-panelItem");
757+ tryCompareFunction(function() { return dataItem.opacity > 0.0; }, true);
758+ tryCompareFunction(function() { return dataItem.width > 0.0; }, true);
762+ function test_stagedApplicationMenuBarShowOnMouseHover() {
763+ PanelState.title = "Fake Title";
764+ panel.mode = "staged";
765+ mouseEmulation.checked = false;
767+ var appTitle = findChild(panel.applicationMenus, "panelTitle"); verify(appTitle);
768+ var appMenuRow = findChild(panel.applicationMenus, "panelRow"); verify(appMenuRow);
769+ var appMenuBar = findChild(panel, "menuBar"); verify(appMenuBar);
771+ tryCompare(appTitle, "visible", true, undefined, "App title should be visible");
772+ tryCompare(appMenuBar, "visible", false, undefined, "App menu bar should not be visible");
774+ mouseMove(panel, panel.width/2, panel.panelHeight);
776+ tryCompare(appTitle, "visible", false, undefined, "App title should not be visible on mouse hover");
777+ tryCompare(appMenuBar, "visible", true, undefined, "App menu bar should be visible on mouse hover");
780+ function test_windowedApplicationMenuShowOnMouseHoverWhenDecorationsShown() {
781+ PanelState.title = "Fake Title";
782+ panel.mode = "windowed";
783+ mouseEmulation.checked = false;
785+ var appTitle = findChild(panel.applicationMenus, "panelTitle"); verify(appTitle);
786+ var appMenuRow = findChild(panel.applicationMenus, "panelRow"); verify(appMenuRow);
787+ var appMenuBar = findChild(panel, "menuBar"); verify(appMenuBar);
789+ tryCompare(appTitle, "visible", true, undefined, "App title should be visible");
790+ tryCompare(appMenuBar, "visible", false, undefined, "App menu bar should not be visible");
792+ mouseMove(panel, panel.width/2, panel.panelHeight);
794+ tryCompare(appTitle, "visible", true, undefined, "App title should still be visible on mouse hover when panel decorations are not visible");
795+ tryCompare(appMenuBar, "visible", false, undefined, "App menu bar should be visible on mouse hover when panel decorations are not visible");
797+ PanelState.decorationsVisible = true;
799+ tryCompare(appTitle, "visible", false, undefined, "App title should still be visible on mouse hover when panel decorations are visible");
800+ tryCompare(appMenuBar, "visible", true, undefined, "App menu bar should be visible on mouse hover when panel decorations not visible");