on xenial help sign in
Improvements for the appdrawer

Allow cancelling of the reveal gesture move the app store uri to a gsetting (LP: #1648173) Approved by: Lukáš Tinkl, Unity8 CI Bot

commit13a79d1d5e11bf6dc17f5a4a4dd094f59583b767 authorMichael Zanetti <michael.zanetti@canonical.com> dateTue 24 Jan 2017, 07:42 (10 years ago) parente14a31ee3a0651
18 files changed+236−166
data/com.canonical.Unity8.gschema.xml+5 plugins/Utils/appdrawerproxymodel.cpp+1−1 qml/Launcher/Drawer.qml+78−5 qml/Launcher/DrawerGridView.qml+3−1 qml/Launcher/DrawerListView.qml+6 qml/Launcher/Launcher.qml+6−10 qml/Launcher/LauncherDelegate.qml+8−9 qml/Launcher/LauncherPanel.qml+11−6 qml/Launcher/MoreAppsHeader.qml+12−5 qml/Launcher/graphics/launcher-app-focus-ring.svg−12 qml/Shell.qml+16−4 tests/mocks/GSettings.1.0/fake_gsettings.cpp+14 tests/mocks/GSettings.1.0/fake_gsettings.h+7 tests/qmltests/Dash/tst_DashShell.qml−40 tests/qmltests/Launcher/tst_Drawer.qml+42−3 tests/qmltests/Launcher/tst_Launcher.qml+5−6 tests/qmltests/tst_Shell.qml+5−64 tests/qmltests/tst_ShellWithPin.qml+17
data/com.canonical.Unity8.gschema.xml+5
@@ -53,6 +53,11 @@
5353 <summary>Enable or disable the indicator pull down menus</summary>
5454 <description>Toggle the availability of the indicator pull down menus</description>
5555 </key>
56+ <key type="s" name="appstore-uri">
57+ <default>'scope://com.canonical.scopes.clickstore'</default>
58+ <summary>The uri to the app store</summary>
59+ <description>This will be used whenever the user triggers an action to open the app store.</description>
60+ </key>
5661 </schema>
5762
5863 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
plugins/Utils/appdrawerproxymodel.cpp+1−1
@@ -185,5 +185,5 @@ QString AppDrawerProxyModel::appId(int index) const
185185 return adpm->appId(sourceIndex.row());
186186 }
187187 }
188− return nullptr;
188+ return QString();
189189}
qml/Launcher/Drawer.qml+78−5
@@ -20,6 +20,7 @@ import Unity.Launcher 0.1
2020import Utils 0.1
2121import "../Components"
2222import Qt.labs.settings 1.0
23+import GSettings 1.0
2324
2425FocusScope {
2526 id: root
@@ -47,8 +48,10 @@ FocusScope {
4748 if (event.text.trim() !== "") {
4849 focusInput();
4950 searchField.text = event.text;
50− event.accepted = true;
5151 }
52+ // Catch all presses here in case the navigation lets something through
53+ // We never want to end up in the launcher with focus
54+ event.accepted = true;
5255 }
5356
5457 Settings {
@@ -88,6 +91,9 @@ FocusScope {
8891 anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
8992 placeholderText: i18n.tr("Search…")
9093 focus: true
94+
95+ KeyNavigation.down: sections
96+
9197 onAccepted: {
9298 if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
9399 root.applicationSelected(listLoader.item.getFirstAppId());
@@ -104,7 +110,14 @@ FocusScope {
104110
105111 Sections {
106112 id: sections
113+ objectName: "drawerSections"
107114 width: parent.width
115+
116+ KeyNavigation.up: searchField
117+ KeyNavigation.down: headerFocusScope
118+ KeyNavigation.backtab: searchField
119+ KeyNavigation.tab: headerFocusScope
120+
108121 actions: [
109122 Action {
110123 text: i18n.ctr("Apps sorted alphabetically", "A-Z")
@@ -124,9 +137,45 @@ FocusScope {
124137 }
125138 }
126139
140+ FocusScope {
141+ id: headerFocusScope
142+ objectName: "headerFocusScope"
143+ KeyNavigation.up: sections
144+ KeyNavigation.down: listLoader.item
145+ KeyNavigation.backtab: sections
146+ KeyNavigation.tab: listLoader.item
147+ activeFocusOnTab: true
148+
149+ GSettings {
150+ id: settings
151+ schema.id: "com.canonical.Unity8"
152+ }
153+
154+ Keys.onPressed: {
155+ switch (event.key) {
156+ case Qt.Key_Return:
157+ case Qt.Key_Enter:
158+ case Qt.Key_Space:
159+ trigger();
160+ event.accepted = true;
161+ }
162+ }
163+
164+ function trigger() {
165+ Qt.openUrlExternally(settings.appstoreUri)
166+ }
167+ }
168+
127169 Loader {
128170 id: listLoader
129− anchors { left: parent.left; top: sectionsContainer.bottom; right: parent.right; bottom: parent.bottom; leftMargin: units.gu(1); rightMargin: units.gu(1) }
171+ objectName: "drawerListLoader"
172+ anchors { left: parent.left; top: sectionsContainer.bottom; right: parent.right; bottom: parent.bottom }
173+
174+ KeyNavigation.up: headerFocusScope
175+ KeyNavigation.down: searchField
176+ KeyNavigation.backtab: headerFocusScope
177+ KeyNavigation.tab: searchField
178+
130179 sourceComponent: {
131180 switch (sections.selectedIndex) {
132181 case 0: return aToZComponent;
@@ -176,10 +225,13 @@ FocusScope {
176225 Component {
177226 id: mostUsedComponent
178227 DrawerListView {
228+ id: mostUsedListView
179229
180230 header: MoreAppsHeader {
181231 width: parent.width
182232 height: units.gu(6)
233+ highlighted: headerFocusScope.activeFocus
234+ onClicked: headerFocusScope.trigger();
183235 }
184236
185237 model: AppDrawerProxyModel {
@@ -189,7 +241,8 @@ FocusScope {
189241 }
190242
191243 delegate: UbuntuShape {
192− width: parent.width
244+ width: parent.width - units.gu(2)
245+ anchors.horizontalCenter: parent.horizontalCenter
193246 color: "#20ffffff"
194247 aspect: UbuntuShape.Flat
195248 // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
@@ -205,6 +258,9 @@ FocusScope {
205258 bottomMargin: units.gu(1)
206259 clip: true
207260
261+ interactive: true
262+ focus: index == mostUsedListView.currentIndex
263+
208264 model: sortProxyModel
209265
210266 delegateWidth: units.gu(8)
@@ -218,10 +274,13 @@ FocusScope {
218274 Component {
219275 id: aToZComponent
220276 DrawerListView {
277+ id: aToZListView
221278
222279 header: MoreAppsHeader {
223280 width: parent.width
224281 height: units.gu(6)
282+ highlighted: headerFocusScope.activeFocus
283+ onClicked: headerFocusScope.trigger();
225284 }
226285
227286 model: AppDrawerProxyModel {
@@ -231,7 +290,8 @@ FocusScope {
231290 }
232291
233292 delegate: UbuntuShape {
234− width: parent.width
293+ width: parent.width - units.gu(2)
294+ anchors.horizontalCenter: parent.horizontalCenter
235295 color: "#20ffffff"
236296 aspect: UbuntuShape.Flat
237297
@@ -253,7 +313,8 @@ FocusScope {
253313 anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
254314 height: rows * delegateHeight
255315
256− interactive: false
316+ interactive: true
317+ focus: index == aToZListView.currentIndex
257318
258319 model: AppDrawerProxyModel {
259320 id: categoryModel
@@ -272,10 +333,13 @@ FocusScope {
272333 Component {
273334 id: drawerDelegateComponent
274335 AbstractButton {
336+ id: drawerDelegate
275337 width: GridView.view.cellWidth
276338 height: units.gu(10)
277339 objectName: "drawerItem_" + model.appId
278340
341+ readonly property bool focused: index === GridView.view.currentIndex && GridView.view.activeFocus
342+
279343 onClicked: root.applicationSelected(model.appId)
280344
281345 Column {
@@ -299,6 +363,15 @@ FocusScope {
299363 source: model.icon
300364 }
301365 sourceFillMode: UbuntuShape.PreserveAspectCrop
366+
367+ StyledItem {
368+ styleName: "FocusShape"
369+ anchors.fill: parent
370+ StyleHints {
371+ visible: drawerDelegate.focused
372+ radius: units.gu(2.55)
373+ }
374+ }
302375 }
303376
304377 Label {
qml/Launcher/DrawerGridView.qml+3−1
@@ -17,7 +17,7 @@
1717import QtQuick 2.4
1818import "../Components"
1919
20−Item {
20+FocusScope {
2121 id: root
2222
2323 property int delegateWidth: units.gu(10)
@@ -25,6 +25,7 @@ Item {
2525 property alias delegate: gridView.delegate
2626 property alias model: gridView.model
2727 property alias interactive: gridView.interactive
28+ property alias currentIndex: gridView.currentIndex
2829
2930 property alias header: gridView.header
3031 property alias topMargin: gridView.topMargin
@@ -37,6 +38,7 @@ Item {
3738 id: gridView
3839 anchors.fill: parent
3940 leftMargin: spacing
41+ focus: true
4042
4143 readonly property int overflow: width - (root.columns * root.delegateWidth)
4244 readonly property real spacing: overflow / (root.columns)
qml/Launcher/DrawerListView.qml+6
@@ -25,6 +25,12 @@ ListView {
2525 bottomMargin: units.gu(1)
2626 spacing: units.gu(1)
2727 clip: true
28+ focus: true
29+
30+ onActiveFocusChanged: {
31+ currentIndex = -1;
32+ currentIndex = 0;
33+ }
2834
2935 function getFirstAppId() {
3036 return model.appId(0);
qml/Launcher/Launcher.qml+6−10
@@ -87,14 +87,14 @@ FocusScope {
8787 superPressTimer.stop();
8888 superLongPressTimer.stop();
8989 } else {
90+ switchToNextState("");
91+ root.focus = false;
9092 if (panel.highlightIndex == -1) {
91− showDashHome();
93+ root.showDashHome();
9294 } else if (panel.highlightIndex >= 0){
9395 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
9496 }
9597 panel.highlightIndex = -2;
96− switchToNextState("");
97− root.focus = false;
9898 }
9999 }
100100
@@ -210,7 +210,7 @@ FocusScope {
210210 case Qt.Key_Return:
211211 case Qt.Key_Space:
212212 if (panel.highlightIndex == -1) {
213− showDashHome();
213+ root.showDashHome();
214214 } else if (panel.highlightIndex >= 0) {
215215 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
216216 }
@@ -473,9 +473,7 @@ FocusScope {
473473 }
474474 onPassed: {
475475 if (root.drawerEnabled) {
476− root.switchToNextState("drawer");
477− root.focus = true;
478− drawer.focus = true;
476+ root.openDrawer()
479477 }
480478 }
481479
@@ -551,9 +549,7 @@ FocusScope {
551549 if (!dragging) {
552550 if (distance > panel.width / 2) {
553551 if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
554− root.switchToNextState("drawer");
555− root.focus = true;
556− drawer.focus = true;
552+ root.openDrawer(false)
557553 } else {
558554 root.switchToNextState("visible");
559555 }
qml/Launcher/LauncherDelegate.qml+8−9
@@ -124,15 +124,14 @@ Item {
124124 height: parent.itemHeight + units.gu(1)
125125 anchors.centerIn: parent
126126
127− Image {
128− objectName: "focusRing"
129− anchors.centerIn: iconShape
130− height: width * 15 / 16
131− width: iconShape.width + units.gu(1)
132− source: "graphics/launcher-app-focus-ring.svg"
133− sourceSize.width: width
134− sourceSize.height: height
135− visible: root.highlighted
127+ StyledItem {
128+ styleName: "FocusShape"
129+ anchors.fill: iconShape
130+ activeFocusOnTab: true
131+ StyleHints {
132+ visible: root.highlighted
133+ radius: units.gu(2.55)
134+ }
136135 }
137136
138137 ProportionalShape {
qml/Launcher/LauncherPanel.qml+11−6
@@ -80,6 +80,7 @@ Rectangle {
8080 }
8181
8282 Rectangle {
83+ id: bfb
8384 objectName: "buttonShowDashHome"
8485 width: parent.width
8586 height: width * .9
@@ -100,13 +101,15 @@ Rectangle {
100101 activeFocusOnPress: false
101102 onClicked: root.showDashHome()
102103 }
103− Rectangle {
104− objectName: "bfbFocusHighlight"
104+
105+ StyledItem {
106+ styleName: "FocusShape"
105107 anchors.fill: parent
106− border.color: "white"
107− border.width: units.dp(1)
108− color: "transparent"
109− visible: parent.highlighted
108+ anchors.margins: units.gu(.5)
109+ StyleHints {
110+ visible: bfb.highlighted
111+ radius: 0
112+ }
110113 }
111114 }
112115
@@ -788,6 +791,8 @@ Rectangle {
788791 quickList.model = launcherListView.model.get(index).quickList;
789792 quickList.appId = launcherListView.model.get(index).appId;
790793 quickList.state = "open";
794+ root.highlightIndex = index;
795+ quickList.forceActiveFocus();
791796 }
792797
793798 Item {
qml/Launcher/MoreAppsHeader.qml+12−5
@@ -4,17 +4,24 @@ import Ubuntu.Components 1.3
44AbstractButton {
55 id: root
66
7− onClicked: {
8− // TODO: Make this point to the snappy store as soon as we stop landing to vivid
9− Qt.openUrlExternally("scope://com.canonical.scopes.clickstore")
10− }
7+ property bool highlighted: false
118
129 UbuntuShape {
13− width: parent.width
10+ width: parent.width - units.gu(2)
11+ anchors.horizontalCenter: parent.horizontalCenter
1412 height: parent.height - units.gu(1)
1513 color: "#20ffffff"
1614 aspect: UbuntuShape.Flat
1715
16+ StyledItem {
17+ styleName: "FocusShape"
18+ anchors.fill: parent
19+ activeFocusOnTab: true
20+ StyleHints {
21+ visible: root.highlighted
22+ }
23+ }
24+
1825 Row {
1926 anchors.fill: parent
2027 anchors.margins: units.gu(1)
qml/Launcher/graphics/launcher-app-focus-ring.svgdeleted−12
@@ -1,12 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2−<svg width="172px" height="163px" viewBox="0 0 172 163" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
3− <!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
4− <title>Shape</title>
5− <desc>Created with Sketch.</desc>
6− <defs></defs>
7− <g id="•-Launcher" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
8− <g id="Artboard-9" sketch:type="MSArtboardGroup" transform="translate(-163.000000, -1436.000000)" fill="#E95420">
9− <path d="M221.983432,1440 L221.983432,1440 C195.6127,1440 184.708233,1442.4723 177.107949,1450.10734 C169.476819,1457.77336 167,1468.79245 167,1495.3481 L167,1538.9019 C167,1565.45755 169.476819,1576.47664 177.107949,1584.14266 C184.708233,1591.7777 195.6127,1594.25 221.983432,1594.25 L276.016868,1594.25 C302.387595,1594.25 313.291998,1591.77771 320.892221,1584.14264 C328.523252,1576.47663 331,1565.45769 331,1538.9019 L331,1495.3481 C331,1468.79231 328.523252,1457.77337 320.892221,1450.10736 C313.291998,1442.47229 302.387595,1440 276.016868,1440 L221.983432,1440 Z M221.983432,1436 L276.016868,1436 C302.345315,1436 314.848953,1438.36655 323.727108,1447.2854 C332.633306,1456.23243 335,1468.85167 335,1495.3481 L335,1538.9019 C335,1565.39833 332.633306,1578.01757 323.727108,1586.9646 C314.848953,1595.88345 302.345315,1598.25 276.016868,1598.25 L221.983432,1598.25 C195.654985,1598.25 183.151291,1595.88345 174.273077,1586.96463 C165.366772,1578.0176 163,1565.39822 163,1538.9019 L163,1495.3481 C163,1468.85178 165.366772,1456.2324 174.273077,1447.28537 C183.151291,1438.36655 195.654985,1436 221.983432,1436 L221.983432,1436 Z" id="Shape" sketch:type="MSShapeGroup"></path>
10− </g>
11− </g>
12−</svg>
qml/Shell.qml+16−4
@@ -344,6 +344,16 @@ StyledItem {
344344 onLoaded: {
345345 item.objectName = "greeter"
346346 }
347+ property bool openDrawerAfterUnlock: false
348+ Connections {
349+ target: greeter
350+ onActiveChanged: {
351+ if (!greeter.active && greeterLoader.openDrawerAfterUnlock) {
352+ launcher.openDrawer(false);
353+ greeterLoader.openDrawerAfterUnlock = false;
354+ }
355+ }
356+ }
347357 }
348358
349359 Component {
@@ -435,9 +445,11 @@ StyledItem {
435445 if (shell.mode === "greeter") {
436446 SessionBroadcast.requestHomeShown(AccountsService.user);
437447 } else {
438− var animate = !LightDMService.greeter.active && !stages.shown;
439− dash.setCurrentScope(0, animate, false);
440− ApplicationManager.requestFocusApplication("unity8-dash");
448+ if (!greeter.active) {
449+ launcher.openDrawer(false);
450+ } else {
451+ greeterLoader.openDrawerAfterUnlock = true;
452+ }
441453 }
442454 }
443455
@@ -513,7 +525,7 @@ StyledItem {
513525 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
514526 blurSource: greeter.shown ? greeter : stages
515527 topPanelHeight: panel.panelHeight
516− drawerEnabled: !greeter.shown
528+ drawerEnabled: !greeter.active
517529
518530 onShowDashHome: showHome()
519531 onLauncherApplicationSelected: {
tests/mocks/GSettings.1.0/fake_gsettings.cpp+14
@@ -29,6 +29,7 @@ GSettingsControllerQml::GSettingsControllerQml()
2929 , m_edgeDragWidth(2)
3030 , m_enableLauncher(true)
3131 , m_enableIndicatorMenu(true)
32+ , m_appstoreUri("http://uappexplorer.com")
3233{
3334}
3435
@@ -173,6 +174,11 @@ void GSettingsControllerQml::setEnableIndicatorMenu(bool enableIndicatorMenu)
173174 }
174175}
175176
177+QString GSettingsControllerQml::appstoreUri() const
178+{
179+ return m_appstoreUri;
180+}
181+
176182GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
177183}
178184
@@ -376,6 +382,14 @@ QVariant GSettingsQml::enableIndicatorMenu() const
376382 }
377383}
378384
385+QVariant GSettingsQml::appstoreUri() const
386+{
387+ if (m_valid && m_schema->id() == "com.canonical.Unity8") {
388+ return GSettingsControllerQml::instance()->appstoreUri();
389+ }
390+ return QVariant();
391+}
392+
379393void GSettingsQml::setLifecycleExemptAppids(const QVariant &appIds)
380394{
381395 if (m_valid && m_schema->id() == "com.canonical.qtmir") {
tests/mocks/GSettings.1.0/fake_gsettings.h+7
@@ -59,6 +59,7 @@ class GSettingsQml: public QObject, public QQmlParserStatus
5959 Q_PROPERTY(QVariant edgeDragWidth READ edgeDragWidth WRITE setEdgeDragWidth NOTIFY edgeDragWidthChanged)
6060 Q_PROPERTY(QVariant enableLauncher READ enableLauncher WRITE setEnableLauncher NOTIFY enableLauncherChanged)
6161 Q_PROPERTY(QVariant enableIndicatorMenu READ enableIndicatorMenu WRITE setEnableIndicatorMenu NOTIFY enableIndicatorMenuChanged)
62+ Q_PROPERTY(QVariant appstoreUri READ appstoreUri NOTIFY appstoreUriChanged)
6263
6364public:
6465 GSettingsQml(QObject *parent = nullptr);
@@ -77,6 +78,7 @@ public:
7778 QVariant edgeDragWidth() const;
7879 QVariant enableLauncher() const;
7980 QVariant enableIndicatorMenu() const;
81+ QVariant appstoreUri() const;
8082
8183 void setDisableHeight(const QVariant &val);
8284 void setPictureUri(const QVariant &str);
@@ -101,6 +103,7 @@ Q_SIGNALS:
101103 void edgeDragWidthChanged();
102104 void enableLauncherChanged();
103105 void enableIndicatorMenuChanged();
106+ void appstoreUriChanged();
104107
105108private:
106109 GSettingsSchemaQml* m_schema;
@@ -147,6 +150,8 @@ public:
147150 bool enableIndicatorMenu() const;
148151 Q_INVOKABLE void setEnableIndicatorMenu(bool enableIndicatorMenu);
149152
153+ QString appstoreUri() const;
154+
150155Q_SIGNALS:
151156 void disableHeightChanged();
152157 void pictureUriChanged(const QString&);
@@ -158,6 +163,7 @@ Q_SIGNALS:
158163 void edgeDragWidthChanged(uint edgeDragWidth);
159164 void enableLauncherChanged(bool enableLauncher);
160165 void enableIndicatorMenuChanged(bool enableIndicatorMenu);
166+ void appstoreUriChanged(const QString &appstoreUri);
161167
162168private:
163169 GSettingsControllerQml();
@@ -172,6 +178,7 @@ private:
172178 uint m_edgeDragWidth;
173179 bool m_enableLauncher;
174180 bool m_enableIndicatorMenu;
181+ QString m_appstoreUri;
175182
176183 static GSettingsControllerQml* s_controllerInstance;
177184 QList<GSettingsQml *> m_registeredGSettings;
tests/qmltests/Dash/tst_DashShell.qml−40
@@ -80,45 +80,5 @@ Item {
8080 true, 15000);
8181 waitForRendering(findChild(dash, "scopeLoader0").item);
8282 }
83−
84− function test_setShellHome() {
85− var dashContentList = findChild(dash, "dashContentList");
86− var startX = dash.width - units.gu(1);
87− var startY = dash.height / 2;
88− var stopX = units.gu(1)
89− var stopY = startY;
90− waitForRendering(dashContentList);
91− touchFlick(dash, startX, startY, stopX, stopY);
92− touchFlick(dash, startX, startY, stopX, stopY);
93− compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
94−
95− // Flick the greeter away
96− var startX = shell.width - units.gu(1);
97− var startY = shell.height / 2;
98− var stopX = units.gu(1)
99− var stopY = startY;
100− touchFlick(shell, startX, startY, stopX, stopY);
101−
102− var greeter = findChild(shell, "greeter");
103− tryCompare(greeter, "shown", false);
104−
105− // bring in the launcher
106− var startX = units.gu(1);
107− var startY = shell.height / 2;
108− var stopX = shell.width / 3;
109− var stopY = startY;
110− touchFlick(shell, startX, startY, stopX, stopY);
111−
112− var launcher = findChild(shell, "launcher");
113− var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
114− tryCompare(buttonShowDashHome, "enabled", true);
115− tryCompare(launcher, "visibleWidth", launcher.panelWidth);
116−
117− // Make sure that opening the launcher doesn't change the scope
118− compare(dashContentList.currentIndex, 2, "Opening the launcher changed the current scope");
119−
120− mouseClick(buttonShowDashHome);
121− tryCompare(dashContentList, "currentIndex", 0);
122− }
12383 }
12484}
tests/qmltests/Launcher/tst_Drawer.qml+42−3
@@ -136,6 +136,8 @@ StyledItem {
136136 launcher.hide();
137137 var drawer = findChild(launcher, "drawer");
138138 tryCompare(drawer, "x", -drawer.width);
139+ var searchField = findChild(drawer, "searchField");
140+ searchField.text = "";
139141 }
140142
141143 function test_revealByEdgeDrag() {
@@ -173,7 +175,7 @@ StyledItem {
173175 var drawer = dragDrawerIntoView();
174176 waitForRendering(launcher);
175177
176− mouseFlick(root, drawer.width - units.gu(1), drawer.height / 2, units.gu(2), drawer.height / 2, true, true);
178+ mouseFlick(root, drawer.width - units.gu(1), drawer.height / 2, units.gu(10), drawer.height / 2, true, true);
177179
178180 tryCompare(drawer.anchors, "rightMargin", 0);
179181 tryCompare(launcher, "state", data.endState);
@@ -263,8 +265,8 @@ StyledItem {
263265
264266 function test_searchDirectly() {
265267 var drawer = dragDrawerIntoView();
266− waitForRendering(drawer);
267− waitUntilTransitionsEnd(drawer);
268+ waitForRendering(launcher);
269+ waitUntilTransitionsEnd(launcher);
268270 tryCompare(drawer, "focus", true);
269271
270272 var searchField = findChild(drawer, "searchField");
@@ -272,5 +274,42 @@ StyledItem {
272274 typeString("cam");
273275 tryCompareFunction(function() { return searchField.displayText }, "cam");
274276 }
277+
278+ function test_kbdNavigation() {
279+ launcher.openDrawer(true);
280+ waitForRendering(launcher);
281+ waitUntilTransitionsEnd(launcher);
282+ compare(launcher.lastSelectedApplication, "");
283+
284+ var drawer = findChild(launcher, "drawer");
285+ var searchField = findChild(drawer, "searchField");
286+ var sections = findChild(drawer, "drawerSections");
287+ var header = findChild(drawer, "headerFocusScope");
288+ var listLoader = findChild(drawer, "drawerListLoader");
289+
290+ tryCompare(searchField, "activeFocus", true);
291+ // for some reason, even when the searchField has activeFocus already,
292+ // it won't react on key down events if they're coming in too early...
293+ // let's repeat the press for a bit before giving up
294+ tryCompareFunction(function() {
295+ wait(10)
296+ keyClick(Qt.Key_Down);
297+ return sections.activeFocus;
298+ }, true)
299+
300+ keyClick(Qt.Key_Down);
301+ tryCompare(header, "activeFocus", true);
302+
303+ keyClick(Qt.Key_Down);
304+ tryCompare(listLoader, "activeFocus", true);
305+
306+ keyClick(Qt.Key_Down);
307+ keyClick(Qt.Key_Left);
308+ tryCompare(listLoader, "activeFocus", true);
309+
310+ keyClick(Qt.Key_Enter);
311+
312+ compare(launcher.lastSelectedApplication, "calendar-app");
313+ }
275314 }
276315}
tests/qmltests/Launcher/tst_Launcher.qml+5−6
@@ -371,18 +371,17 @@ Rectangle {
371371 function assertFocusOnIndex(index) {
372372 var launcherPanel = findChild(launcher, "launcherPanel");
373373 var launcherListView = findChild(launcher, "launcherListView");
374− var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
374+ var bfb = findChild(launcher, "buttonShowDashHome");
375375
376376 waitForRendering(launcher);
377377 tryCompare(launcherPanel, "highlightIndex", index);
378− compare(bfbFocusHighlight.visible, index === -1);
378+ compare(bfb.highlighted, index === -1);
379379 for (var i = 0; i < launcherListView.count; i++) {
380380 var item = findChild(launcher, "launcherDelegate" + i);
381381 // Delegates might be destroyed when not visible. We can't check if they paint a focus highlight.
382382 // Make sure the requested index does have focus. for the others, try best effort to check if they don't
383383 if (index === i || item) {
384− var focusRing = findChild(item, "focusRing")
385− tryCompare(focusRing, "visible", index === i);
384+ tryCompare(item, "highlighted", index === i);
386385 }
387386 }
388387 }
@@ -1190,13 +1189,13 @@ Rectangle {
11901189 }
11911190
11921191 function test_keyboardNavigation(data) {
1193− var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
1192+ var bfb = findChild(launcher, "buttonShowDashHome");
11941193 var quickList = findChild(launcher, "quickList");
11951194 var launcherPanel = findChild(launcher, "launcherPanel");
11961195 var launcherListView = findChild(launcher, "launcherListView");
11971196 var last = launcherListView.count - 1;
11981197
1199− compare(bfbFocusHighlight.visible, false);
1198+ compare(bfb.highlighted, false);
12001199 launcher.openForKeyboardNavigation();
12011200 tryCompare(launcherPanel, "x", 0);
12021201 waitForRendering(launcher);
tests/qmltests/tst_Shell.qml+5−64
@@ -746,22 +746,6 @@ Rectangle {
746746 mockNotificationsModel.append(n)
747747 }
748748
749− function test_ClickUbuntuIconInLauncherTakesToAppsAndResetSearchString() {
750− loadShell("phone");
751− swipeAwayGreeter();
752− dragLauncherIntoView();
753− dashCommunicatorSpy.clear();
754−
755− var launcher = findChild(shell, "launcher");
756− var dashIcon = findChild(launcher, "dashItem");
757− verify(dashIcon != undefined);
758− mouseClick(dashIcon);
759−
760− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
761−
762− compare(dashCommunicatorSpy.count, 1);
763− }
764−
765749 function test_suspend() {
766750 loadShell("phone");
767751 swipeAwayGreeter();
@@ -1378,47 +1362,6 @@ Rectangle {
13781362 tryCompare(stage, "state", "spread");
13791363 }
13801364
1381− function test_tapUbuntuIconInLauncherOverAppSpread() {
1382− launcherShowDashHomeSpy.clear();
1383−
1384− loadShell("phone");
1385− swipeAwayGreeter();
1386−
1387− waitUntilFocusedApplicationIsShowingItsSurface();
1388−
1389− swipeFromRightEdgeToShowAppSpread();
1390−
1391− var launcher = findChild(shell, "launcher");
1392−
1393− dragLauncherIntoView();
1394−
1395− // Emulate a tap with a finger, where the touch position drifts during the tap.
1396− // This is to test the touch ownership changes. The tap is happening on the button
1397− // area but then drifting into the left edge drag area. This test makes sure
1398− // the touch ownership stays with the button and doesn't move over to the
1399− // left edge drag area.
1400− {
1401− var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
1402− touchFlick(buttonShowDashHome,
1403− buttonShowDashHome.width * 0.2, /* startPos.x */
1404− buttonShowDashHome.height * 0.8, /* startPos.y */
1405− buttonShowDashHome.width * 0.8, /* endPos.x */
1406− buttonShowDashHome.height * 0.2 /* endPos.y */);
1407− }
1408−
1409− compare(launcherShowDashHomeSpy.count, 1);
1410−
1411− // check that the stage has left spread mode.
1412− {
1413− var stage = findChild(shell, "stage");
1414− tryCompare(stage, "state", "staged");
1415− }
1416−
1417− // check that the launcher got dismissed
1418− var launcherPanel = findChild(shell, "launcherPanel");
1419− tryCompare(launcherPanel, "x", -launcherPanel.width);
1420− }
1421−
14221365 function test_physicalHomeKeyPressDoesNothingWithActiveGreeter() {
14231366 loadShell("phone");
14241367
@@ -1873,7 +1816,7 @@ Rectangle {
18731816 loadDesktopShellWithApps()
18741817 var launcher = findChild(shell, "launcher");
18751818 var stage = findChild(shell, "stage");
1876− var bfb = findChild(launcher, "buttonShowDashHome");
1819+ var app1 = findChild(launcher, "launcherDelegate0");
18771820
18781821 GSettingsController.setAutohideLauncher(!data.launcherLocked);
18791822 waitForRendering(shell);
@@ -1886,17 +1829,17 @@ Rectangle {
18861829 if (!data.launcherLocked) {
18871830 revealLauncherByEdgePushWithMouse();
18881831 tryCompare(launcher, "x", 0);
1889− mouseMove(bfb, bfb.width / 2, bfb.height / 2)
1832+ mouseMove(app1, app1.width / 2, app1.height / 2)
18901833 waitForRendering(shell)
18911834 }
18921835
1893− mouseClick(bfb, bfb.width / 2, bfb.height / 2)
1836+ mouseClick(app1, app1.width / 2, app1.height / 2)
18941837 if (!data.launcherLocked) {
18951838 tryCompare(launcher, "state", "")
18961839 }
18971840 tryCompare(stage, "state", "windowed")
18981841
1899− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash")
1842+ tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app")
19001843
19011844 keyRelease(Qt.Key_Alt);
19021845 }
@@ -2220,10 +2163,8 @@ Rectangle {
22202163 tryCompare(launcher, "state", "visible");
22212164 tryCompare(launcherPanel, "highlightIndex", -1);
22222165 keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2223− tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2166+ tryCompare(launcher, "state", "drawer");
22242167 tryCompare(launcherPanel, "highlightIndex", -2);
2225− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2226− tryCompare(stage, "focus", true)
22272168 }
22282169
22292170 function test_longpressSuperOpensLauncherAndShortcutsOverlay() {
tests/qmltests/tst_ShellWithPin.qml+17
@@ -550,5 +550,22 @@ Item {
550550 var lockscreen = findChild(shell, "lockscreen");
551551 verify(lockscreen.shown);
552552 }
553+
554+ function test_bfbOnLockedDevice() {
555+ var launcher = findChild(shell, "launcher");
556+ touchFlick(shell, units.gu(.5), shell.height / 2, units.gu(10), shell.height / 2);
557+
558+ tryCompare(launcher, "x", 0);
559+ tryCompare(launcher, "state", "visible");
560+
561+ waitForRendering(shell)
562+
563+ var bfb = findChild(launcher, "buttonShowDashHome");
564+ mouseClick(bfb, bfb.width / 2, bfb.height / 2);
565+
566+ enterPin("1234")
567+
568+ tryCompare(launcher, "state", "drawer");
569+ }
553570 }
554571}