on xenial help sign in
Merge
commit035d9de215f9b7b116ebbb1e092d130179f54c72 authorAlbert Astals <albert.astals@canonical.com> dateMon 5 Aug 2013, 15:13 (13 years ago) parent5719a185da4ba4
29 files changed+602−77
Components/CrossFadeImage.qml+3−1 Greeter/Greeter.qml+2−3 Greeter/GreeterContent.qml−2 Shell.qml+54−32 debian/control+3−1 debian/unity8-private.install+1 plugins/CMakeLists.txt+1 plugins/Powerd/CMakeLists.txt+13 plugins/Powerd/Powerd.cpp+36 plugins/Powerd/Powerd.h+40 plugins/Powerd/plugin.cpp+36 plugins/Powerd/plugin.h+35 plugins/Powerd/qmldir+3 tests/autopilot/unity8/shell/emulators/greeter.py+4−1 tests/autopilot/unity8/shell/tests/test_hud.py+5−5 tests/autopilot/unity8/shell/tests/test_lock_screen.py+58−26 tests/data/unity/backgrounds/blue.png tests/data/unity/backgrounds/red.png tests/mocks/CMakeLists.txt+1 tests/mocks/GSettings/CMakeLists.txt+31 tests/mocks/GSettings/fake_gsettings.cpp+102 tests/mocks/GSettings/fake_gsettings.h+90 tests/mocks/GSettings/plugin.cpp+33 tests/mocks/GSettings/plugin.h+31 tests/mocks/GSettings/qmldir+2 tests/mocks/LightDM/single/GreeterPrivate.cpp+2−4 tests/qmltests/CMakeLists.txt+1−1 tests/qmltests/Dash/tst_FilterGrids.qml+1−1 tests/qmltests/tst_Shell.qml+14
Components/CrossFadeImage.qml+3−1
@@ -85,7 +85,7 @@ Item {
8585 Connections {
8686 target: __nextImage
8787 onStatusChanged: {
88− if (__nextImage.status == Image.Ready) {
88+ if (__nextImage.status == Image.Ready || __nextImage.status == Image.Error) {
8989 swapImages();
9090 }
9191 }
@@ -96,6 +96,7 @@ Item {
9696 anchors.fill: parent
9797 cache: false
9898 asynchronous: true
99+ fillMode: Image.PreserveAspectCrop
99100 z: 1
100101 }
101102
@@ -104,6 +105,7 @@ Item {
104105 anchors.fill: parent
105106 cache: false
106107 asynchronous: true
108+ fillMode: Image.PreserveAspectCrop
107109 z: 0
108110 }
109111
Greeter/Greeter.qml+2−3
@@ -34,7 +34,7 @@ Showable {
3434
3535 property alias dragHandleWidth: dragHandle.width
3636 property alias model: greeterContentLoader.model
37− property bool locked: shown && multiUser && !greeterContentLoader.promptless
37+ property bool locked: shown && !LightDM.Greeter.promptless
3838
3939 readonly property bool narrowMode: !multiUser && width <= units.gu(60)
4040 readonly property bool multiUser: LightDM.Users.count > 1
@@ -59,7 +59,6 @@ Showable {
5959 anchors.fill: parent
6060 property var model: LightDM.Users
6161 property int currentIndex: 0
62− property bool promptless: item ? item.promptless : false
6362 property var infographicModel: LightDM.Infographic
6463
6564 source: required ? "GreeterContent.qml" : ""
@@ -113,7 +112,7 @@ Showable {
113112 // UI element)
114113 distanceThreshold: 0
115114
116− enabled: !greeter.locked
115+ enabled: greeter.narrowMode || !greeter.locked
117116
118117 direction: Direction.Leftwards
119118 }
Greeter/GreeterContent.qml−2
@@ -23,7 +23,6 @@ MouseArea {
2323 id: root
2424 anchors.fill: parent
2525
26− property bool promptless: loginLoader.status == Loader.Ready && LightDM.Greeter.promptless
2726 property bool ready: wallpaper.status == Image.Ready
2827 property bool leftTeaserPressed: teasingMouseArea.pressed &&
2928 teasingMouseArea.mouseX < teasingMouseArea.width / 2
@@ -38,7 +37,6 @@ MouseArea {
3837
3938 source: shell.background
4039 anchors.fill: parent
41− crossFade: false
4240 fadeInFirst: false
4341 }
4442
Shell.qml+54−32
@@ -15,10 +15,12 @@
1515 */
1616
1717import QtQuick 2.0
18+import GSettings 1.0
1819import Ubuntu.Application 0.1
1920import Ubuntu.Components 0.1
2021import Ubuntu.Gestures 0.1
2122import LightDM 0.1 as LightDM
23+import Powerd 0.1
2224import "Dash"
2325import "Greeter"
2426import "Launcher"
@@ -40,8 +42,8 @@ FocusScope {
4042 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
4143
4244 property real edgeSize: units.gu(2)
43− property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
44− property url background: default_background
45+ property url defaultBackground: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
46+ property url background: backgroundSettings.pictureUri
4547 readonly property real panelHeight: panel.panelHeight
4648
4749 property bool dashShown: dash.shown
@@ -114,6 +116,11 @@ FocusScope {
114116 }
115117 }
116118
119+ GSettings {
120+ id: backgroundSettings
121+ schema.id: "org.gnome.desktop.background"
122+ }
123+
117124 VolumeControl {
118125 id: volumeControl
119126 }
@@ -121,12 +128,6 @@ FocusScope {
121128 Keys.onVolumeUpPressed: volumeControl.volumeUp()
122129 Keys.onVolumeDownPressed: volumeControl.volumeDown()
123130
124− Keys.onReleased: {
125− if (event.key == Qt.Key_PowerOff) {
126− greeter.show()
127− }
128− }
129−
130131 Item {
131132 id: underlay
132133 objectName: "underlay"
@@ -144,12 +145,16 @@ FocusScope {
144145 // through the translucent parts of the shell surface.
145146 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
146147
147− Image {
148+ CrossFadeImage {
148149 id: backgroundImage
150+ objectName: "backgroundImage"
149151 source: shell.background
150− sourceSize.width: parent.width
151− sourceSize.height: parent.height
152152 anchors.fill: parent
153+ onStatusChanged: {
154+ if (status == Image.Error) {
155+ backgroundSettings.pictureUri = shell.defaultBackground
156+ }
157+ }
153158 }
154159
155160 Rectangle {
@@ -194,7 +199,6 @@ FocusScope {
194199 }
195200 }
196201
197−
198202 Item {
199203 id: stagesOuterContainer
200204
@@ -259,7 +263,6 @@ FocusScope {
259263 ignoreUnknownSignals: true
260264 }
261265
262−
263266 Stage {
264267 id: mainStage
265268
@@ -420,9 +423,6 @@ FocusScope {
420423
421424 dragHandleWidth: shell.edgeSize
422425
423− property var previousMainApp: null
424− property var previousSideApp: null
425−
426426 onShownChanged: {
427427 if (shown) {
428428 lockscreen.reset();
@@ -432,27 +432,13 @@ FocusScope {
432432 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
433433 }
434434 greeter.forceActiveFocus();
435− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
436− // the stage was actually shown
437− if (mainStage.fullyShown) greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
438− if (sideStage.fullyShown) greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
439− applicationManager.unfocusCurrentApplication();
440− } else {
441− if (greeter.previousMainApp) {
442− applicationManager.focusApplication(greeter.previousMainApp);
443− greeter.previousMainApp = null;
444− }
445− if (greeter.previousSideApp) {
446− applicationManager.focusApplication(greeter.previousSideApp);
447− greeter.previousSideApp = null;
448− }
449435 }
450436 }
451437
452438 onUnlocked: greeter.hide()
453439 onSelected: {
454440 var bgPath = greeter.model.data(uid, LightDM.UserRoles.BackgroundPathRole)
455− shell.background = bgPath ? bgPath : default_background
441+ shell.background = bgPath ? bgPath : defaultBackground
456442 }
457443
458444 onLeftTeaserPressedChanged: {
@@ -467,6 +453,42 @@ FocusScope {
467453 blockInput: greeter.shown || lockscreen.shown
468454 }
469455
456+ Connections {
457+ id: powerConnection
458+ target: Powerd
459+
460+ property var previousMainApp: null
461+ property var previousSideApp: null
462+
463+ function setFocused(focused) {
464+ if (!focused) {
465+ // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
466+ // the stage was actually shown
467+ if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
468+ if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
469+ applicationManager.unfocusCurrentApplication();
470+ } else {
471+ if (powerConnection.previousMainApp) {
472+ applicationManager.focusApplication(powerConnection.previousMainApp);
473+ powerConnection.previousMainApp = null;
474+ }
475+ if (powerConnection.previousSideApp) {
476+ applicationManager.focusApplication(powerConnection.previousSideApp);
477+ powerConnection.previousSideApp = null;
478+ }
479+ }
480+ }
481+
482+ onPowerStateChange: {
483+ if (state == 0) { // suspend
484+ powerConnection.setFocused(false);
485+ greeter.show();
486+ } else if (state == 1) { // active
487+ powerConnection.setFocused(true);
488+ }
489+ }
490+ }
491+
470492 Item {
471493 id: overlay
472494
@@ -552,7 +574,7 @@ FocusScope {
552574 anchors.bottom: parent.bottom
553575 width: parent.width
554576 dragAreaWidth: shell.edgeSize
555− available: !greeter.locked
577+ available: !greeter.shown || greeter.narrowMode
556578 onDashItemSelected: {
557579 greeter.hide()
558580 // Animate if moving between application and dash
debian/control+3−1
@@ -56,8 +56,10 @@ Description: Indicators client test application
5656
5757Package: unity8
5858Architecture: any
59−Depends: qmenumodel-qml,
59+Depends: gsettings-desktop-schemas,
60+ qmenumodel-qml,
6061 qtdeclarative5-dee-plugin,
62+ qtdeclarative5-gsettings1.0,
6163 qtdeclarative5-ubuntu-ui-toolkit-plugin,
6264 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
6365 qtdeclarative5-xmllistmodel-plugin,
debian/unity8-private.install+1
@@ -1,6 +1,7 @@
11usr/lib/*/unity8/qml/HudClient
22usr/lib/*/unity8/qml/LightDM
33usr/lib/*/unity8/qml/ListViewWithPageHeader
4+usr/lib/*/unity8/qml/Powerd
45usr/lib/*/unity8/qml/Ubuntu
56usr/lib/*/unity8/qml/Unity
67usr/lib/*/unity8/qml/Utils
plugins/CMakeLists.txt+1
@@ -4,3 +4,4 @@ add_subdirectory(Unity)
44add_subdirectory(HudClient)
55add_subdirectory(LightDM)
66add_subdirectory(ListViewWithPageHeader)
7+add_subdirectory(Powerd)
plugins/Powerd/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(Powerd-qml MODULE
6+ plugin.cpp
7+ Powerd.cpp
8+ )
9+
10+qt5_use_modules(Powerd-qml DBus Qml)
11+
12+export_qmlfiles(Powerd Powerd)
13+export_qmlplugin(Powerd 0.1 Powerd TARGETS Powerd-qml)
plugins/Powerd/Powerd.cppnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "Powerd.h"
20+
21+Powerd::Powerd(QObject* parent)
22+ : QObject(parent),
23+ powerd(NULL)
24+{
25+ powerd = new QDBusInterface("com.canonical.powerd",
26+ "/com/canonical/powerd",
27+ "com.canonical.powerd",
28+ QDBusConnection::SM_BUSNAME(), this);
29+
30+ powerd->connection().connect("com.canonical.powerd",
31+ "/com/canonical/powerd",
32+ "com.canonical.powerd",
33+ "SysPowerStateChange",
34+ this,
35+ SIGNAL(powerStateChange(int)));
36+}
plugins/Powerd/Powerd.hnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_POWERD_H
21+#define UNITY_POWERD_H
22+
23+#include <QtCore/QObject>
24+#include <QtDBus/QDBusInterface>
25+
26+class Powerd: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit Powerd(QObject *parent = 0);
32+
33+Q_SIGNALS:
34+ void powerStateChange(int state);
35+
36+private:
37+ QDBusInterface *powerd;
38+};
39+
40+#endif
plugins/Powerd/plugin.cppnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "plugin.h"
21+#include "Powerd.h"
22+
23+#include <QtQml/QtQml>
24+
25+static QObject *powerd_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
26+{
27+ Q_UNUSED(engine)
28+ Q_UNUSED(scriptEngine)
29+ return new Powerd();
30+}
31+
32+void PowerdPlugin::registerTypes(const char *uri)
33+{
34+ Q_ASSERT(uri == QLatin1String("Powerd"));
35+ qmlRegisterSingletonType<Powerd>(uri, 0, 1, "Powerd", powerd_provider);
36+}
plugins/Powerd/plugin.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef POWER_PLUGIN_H
21+#define POWER_PLUGIN_H
22+
23+#include <QtQml/QQmlEngine>
24+#include <QtQml/QQmlExtensionPlugin>
25+
26+class PowerdPlugin : public QQmlExtensionPlugin
27+{
28+ Q_OBJECT
29+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30+
31+public:
32+ void registerTypes(const char *uri);
33+};
34+
35+#endif
plugins/Powerd/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Powerd
2+plugin Powerd-qml
3+typeinfo plugin.qmltypes
tests/autopilot/unity8/shell/emulators/greeter.py+4−1
@@ -25,7 +25,7 @@ class Greeter(UnityEmulatorBase):
2525
2626 """An emulator that understands the greeter screen."""
2727
28− def unlock(self):
28+ def swipe(self):
2929 """Swipe the greeter screen away."""
3030 self.created.wait_for(True)
3131 touch = Touch.create()
@@ -38,3 +38,6 @@ class Greeter(UnityEmulatorBase):
3838 touch.drag(start_x, start_y, stop_x, stop_y)
3939
4040 self.created.wait_for(False)
41+
42+ def get_prompt(self):
43+ return self.select_single("TextField", objectName="passwordInput")
tests/autopilot/unity8/shell/tests/test_hud.py+5−5
@@ -37,7 +37,7 @@ class TestHud(UnityTestCase):
3737
3838 """
3939 self.launch_unity()
40− self.main_window.get_greeter().unlock()
40+ self.main_window.get_greeter().swipe()
4141 window = self.main_window.get_qml_view()
4242 hud_show_button = self.main_window.get_hud_show_button()
4343 hud = self.main_window.get_hud()
@@ -58,7 +58,7 @@ class TestHud(UnityTestCase):
5858
5959 """
6060 self.launch_unity()
61− self.main_window.get_greeter().unlock()
61+ self.main_window.get_greeter().swipe()
6262 window = self.main_window.get_qml_view()
6363 hud_show_button = self.main_window.get_hud_show_button()
6464 hud = self.main_window.get_hud()
@@ -81,7 +81,7 @@ class TestHud(UnityTestCase):
8181 def test_hide_hud_click(self):
8282 """Tapping the close button of the Hud must dismiss it."""
8383 self.launch_unity()
84− self.main_window.get_greeter().unlock()
84+ self.main_window.get_greeter().swipe()
8585 hud = self.main_window.get_hud()
8686
8787 self._launch_test_app_from_app_screen()
@@ -97,7 +97,7 @@ class TestHud(UnityTestCase):
9797
9898 """
9999 self.launch_unity()
100− self.main_window.get_greeter().unlock()
100+ self.main_window.get_greeter().swipe()
101101 hud = self.main_window.get_hud()
102102 window = self.main_window.get_qml_view()
103103
@@ -114,7 +114,7 @@ class TestHud(UnityTestCase):
114114 def test_launcher_hides_hud(self):
115115 """Opening the Launcher while the Hud is active must close the Hud."""
116116 self.launch_unity()
117− self.main_window.get_greeter().unlock()
117+ self.main_window.get_greeter().swipe()
118118 hud = self.main_window.get_hud()
119119 launcher = self.main_window.get_launcher()
120120
tests/autopilot/unity8/shell/tests/test_lock_screen.py+58−26
@@ -40,52 +40,68 @@ class TestLockscreen(UnityTestCase):
4040 """Must be able to unlock the PIN entry lock screen."""
4141 self.launch_unity()
4242 greeter = self.main_window.get_greeter()
43− greeter.unlock()
4443
45− lockscreen = self._wait_for_lockscreen()
46− self._enter_pincode("1234")
47−
48− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
44+ if greeter.narrowMode:
45+ greeter.swipe()
46+ lockscreen = self._wait_for_lockscreen()
47+ self._enter_pincode("1234")
48+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
49+ else:
50+ self._enter_prompt_passphrase("1234")
51+ self.assertThat(greeter.shown, Eventually(Equals(False)))
4952
5053 @with_lightdm_mock("single-passphrase")
5154 def test_can_unlock_passphrase_screen(self):
5255 """Must be able to unlock the passphrase entry screen."""
5356 self.launch_unity()
5457 greeter = self.main_window.get_greeter()
55− greeter.unlock()
56−
57− lockscreen = self._wait_for_lockscreen()
58− self._enter_passphrase("password")
5958
60− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
59+ if greeter.narrowMode:
60+ greeter.swipe()
61+ lockscreen = self._wait_for_lockscreen()
62+ self._enter_pin_passphrase("password")
63+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
64+ else:
65+ self._enter_prompt_passphrase("password")
66+ self.assertThat(greeter.shown, Eventually(Equals(False)))
6167
6268 @with_lightdm_mock("single-pin")
6369 def test_pin_screen_wrong_code(self):
6470 """Entering the wrong pin code must not dismiss the lock screen."""
6571 self.launch_unity()
6672 greeter = self.main_window.get_greeter()
67− greeter.unlock()
68−
69− lockscreen = self._wait_for_lockscreen()
70− self._enter_pincode("4321")
7173
72− pinentryField = self.main_window.get_pinentryField()
73− self.assertThat(pinentryField.text, Eventually(Equals("")))
74− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
74+ if greeter.narrowMode:
75+ greeter.swipe()
76+ lockscreen = self._wait_for_lockscreen()
77+ self._enter_pincode("4321")
78+ pinentryField = self.main_window.get_pinentryField()
79+ self.assertThat(pinentryField.text, Eventually(Equals("")))
80+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
81+ else:
82+ self._enter_prompt_passphrase("4231")
83+ prompt = self.main_window.get_greeter().get_prompt()
84+ self.assertThat(prompt.text, Eventually(Equals("")))
85+ self.assertThat(greeter.shown, Eventually(Equals(True)))
7586
7687 @with_lightdm_mock("single-passphrase")
7788 def test_passphrase_screen_wrong_password(self):
7889 """Entering the wrong password must not dismiss the lock screen."""
7990 self.launch_unity()
8091 greeter = self.main_window.get_greeter()
81− greeter.unlock()
8292
83− lockscreen = self._wait_for_lockscreen()
84− self._enter_passphrase("foobar")
85−
86− pinentryField = self.main_window.get_pinentryField()
87− self.assertThat(pinentryField.text, Eventually(Equals("")))
88− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
93+ if greeter.narrowMode:
94+ greeter.swipe()
95+ lockscreen = self._wait_for_lockscreen()
96+ self._enter_pin_passphrase("foobar")
97+ pinentryField = self.main_window.get_pinentryField()
98+ self.assertThat(pinentryField.text, Eventually(Equals("")))
99+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
100+ else:
101+ self._enter_prompt_passphrase("foobar")
102+ prompt = self.main_window.get_greeter().get_prompt()
103+ self.assertThat(prompt.text, Eventually(Equals("")))
104+ self.assertThat(greeter.shown, Eventually(Equals(True)))
89105
90106 def _wait_for_lockscreen(self):
91107 """Wait for the lock screen to load, and return it."""
@@ -114,9 +130,9 @@ class TestLockscreen(UnityTestCase):
114130 )
115131 self.touch.tap_object(self.main_window.get_pinPadButton(int(num)))
116132
117− def _enter_passphrase(self, passphrase):
133+ def _enter_pin_passphrase(self, passphrase):
118134 """Enter the password specified in 'passphrase' into the password entry
119− field.
135+ field of the pin lock screen.
120136
121137 :param passphrase: The string you want to enter.
122138 :raises: TypeError if passphrase is not a string.
@@ -129,3 +145,19 @@ class TestLockscreen(UnityTestCase):
129145 self.touch.tap_object(pinentryField)
130146 self.keyboard.type(passphrase)
131147 self.keyboard.type("\n")
148+
149+ def _enter_prompt_passphrase(self, passphrase):
150+ """Enter the password specified in 'passphrase' into the password entry
151+ field of the main user list's prompt.
152+
153+ :param passphrase: The string you want to enter.
154+ :raises: TypeError if passphrase is not a string.
155+
156+ """
157+ if not isinstance(passphrase, basestring):
158+ raise TypeError("'passphrase' parameter must be a string.")
159+
160+ prompt = self.main_window.get_greeter().get_prompt()
161+ self.touch.tap_object(prompt)
162+ self.keyboard.type(passphrase)
163+ self.keyboard.type("\n")
tests/data/unity/backgrounds/blue.pngnew file

Binary file not shown.

tests/data/unity/backgrounds/red.pngnew file

Binary file not shown.

tests/mocks/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1+add_subdirectory(GSettings)
12add_subdirectory(libusermetrics)
23add_subdirectory(LightDM)
34add_subdirectory(QMenuModel)
tests/mocks/GSettings/CMakeLists.txtnew file+31
@@ -0,0 +1,31 @@
1+set(CMAKE_AUTOMOC ON)
2+
3+include(FindPkgConfig)
4+find_package(Qt5Core REQUIRED)
5+find_package(Qt5Quick REQUIRED)
6+
7+include_directories(
8+ ${CMAKE_CURRENT_BINARY_DIR}
9+ ${Qt5Core_INCLUDE_DIRS}
10+ ${Qt5Quick_INCLUDE_DIRS}
11+)
12+
13+add_definitions(-DQT_NO_KEYWORDS)
14+
15+set(GSettingsQML_SOURCES
16+ fake_gsettings.cpp
17+ plugin.cpp
18+)
19+
20+add_library(FakeGSettingsQml MODULE ${GSettingsQML_SOURCES})
21+target_link_libraries(FakeGSettingsQml
22+ ${Qt5Core_LIBRARIES}
23+ ${Qt5Quick_LIBRARIES}
24+)
25+
26+qt5_use_modules(FakeGSettingsQml Qml)
27+
28+# copy qmldir file into build directory for shadow builds
29+file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
30+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
31+ )
tests/mocks/GSettings/fake_gsettings.cppnew file+102
@@ -0,0 +1,102 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "fake_gsettings.h"
18+
19+#include <QList>
20+
21+GSettingsControllerQml* GSettingsControllerQml::s_controllerInstance = 0;
22+
23+GSettingsControllerQml::GSettingsControllerQml() {
24+}
25+
26+GSettingsControllerQml::~GSettingsControllerQml() {
27+ s_controllerInstance = 0;
28+}
29+
30+GSettingsControllerQml* GSettingsControllerQml::instance() {
31+ if(!s_controllerInstance) {
32+ s_controllerInstance = new GSettingsControllerQml();
33+ }
34+ return s_controllerInstance;
35+}
36+
37+void GSettingsControllerQml::registerSettingsObject(GSettingsQml *obj) {
38+ m_registeredGSettings.append(obj);
39+}
40+
41+void GSettingsControllerQml::unRegisterSettingsObject(GSettingsQml *obj) {
42+ m_registeredGSettings.removeOne(obj);
43+}
44+
45+void GSettingsControllerQml::setPictureUri(const QString &str) {
46+ Q_FOREACH (GSettingsQml *obj, m_registeredGSettings) {
47+ obj->setPictureUri(str);
48+ }
49+}
50+
51+GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
52+}
53+
54+QByteArray GSettingsSchemaQml::id() const {
55+ return m_id;
56+}
57+
58+void GSettingsSchemaQml::setId(const QByteArray &id) {
59+ if (m_id.isEmpty()) {
60+ qWarning("GSettings.schema.id may only be set on construction");
61+ return;
62+ }
63+
64+ m_id = id;
65+}
66+
67+QByteArray GSettingsSchemaQml::path() const {
68+ return m_path;
69+}
70+
71+void GSettingsSchemaQml::setPath(const QByteArray &path) {
72+ if (m_path.isEmpty()) {
73+ qWarning("GSettings.schema.path may only be set on construction");
74+ return;
75+ }
76+
77+ m_path = path;
78+}
79+
80+GSettingsQml::GSettingsQml(QObject *parent): QObject(parent) {
81+ m_schema = new GSettingsSchemaQml(this);
82+ GSettingsControllerQml::instance()->registerSettingsObject(this);
83+}
84+
85+GSettingsQml::~GSettingsQml() {
86+ GSettingsControllerQml::instance()->unRegisterSettingsObject(this);
87+}
88+
89+GSettingsSchemaQml * GSettingsQml::schema() const {
90+ return m_schema;
91+}
92+
93+QString GSettingsQml::pictureUri() const {
94+ return m_pictureUri;
95+}
96+
97+void GSettingsQml::setPictureUri(const QString &str) {
98+ if (str != m_pictureUri) {
99+ m_pictureUri = str;
100+ Q_EMIT pictureUriChanged(m_pictureUri);
101+ }
102+}
tests/mocks/GSettings/fake_gsettings.hnew file+90
@@ -0,0 +1,90 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef FAKE_GSETTINGS_H
18+#define FAKE_GSETTINGS_H
19+
20+#include <QList>
21+#include <QtQml>
22+
23+class GSettingsSchemaQml: public QObject
24+{
25+ Q_OBJECT
26+
27+ Q_PROPERTY(QByteArray id READ id WRITE setId)
28+
29+public:
30+ GSettingsSchemaQml(QObject *parent = NULL);
31+
32+ QByteArray id() const;
33+ void setId(const QByteArray &id);
34+
35+ QByteArray path() const;
36+ void setPath(const QByteArray &path);
37+
38+private:
39+ QByteArray m_id;
40+ QByteArray m_path;
41+};
42+
43+class GSettingsQml: public QObject
44+{
45+ Q_OBJECT
46+
47+ Q_PROPERTY(GSettingsSchemaQml* schema READ schema NOTIFY schemaChanged)
48+ Q_PROPERTY(QString pictureUri READ pictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
49+
50+public:
51+ GSettingsQml(QObject *parent = NULL);
52+ ~GSettingsQml();
53+
54+ GSettingsSchemaQml * schema() const;
55+ QString pictureUri() const;
56+
57+ void setPictureUri(const QString &str);
58+
59+Q_SIGNALS:
60+ void schemaChanged();
61+ void pictureUriChanged(const QString&);
62+
63+private:
64+ GSettingsSchemaQml* m_schema;
65+
66+ QString m_pictureUri;
67+
68+ friend class GSettingsSchemaQml;
69+};
70+
71+class GSettingsControllerQml: public QObject
72+{
73+ Q_OBJECT
74+
75+public:
76+ static GSettingsControllerQml* instance();
77+ ~GSettingsControllerQml();
78+
79+ void registerSettingsObject(GSettingsQml *obj);
80+ void unRegisterSettingsObject(GSettingsQml *obj);
81+ Q_INVOKABLE void setPictureUri(const QString &str);
82+
83+private:
84+ GSettingsControllerQml();
85+
86+ static GSettingsControllerQml* s_controllerInstance;
87+ QList<GSettingsQml *> m_registeredGSettings;
88+};
89+
90+#endif // FAKE_GSETTINGS_H
tests/mocks/GSettings/plugin.cppnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "plugin.h"
18+#include "fake_gsettings.h"
19+
20+#include <QtQml>
21+
22+static QObject* controllerProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
23+{
24+ return GSettingsControllerQml::instance();
25+}
26+
27+void FakeGSettingsQmlPlugin::registerTypes(const char *uri)
28+{
29+ qmlRegisterSingletonType<GSettingsControllerQml>(uri, 1, 0, "GSettingsController", controllerProvider);
30+ qmlRegisterType<GSettingsQml>(uri, 1, 0, "GSettings");
31+ qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
32+ "GSettingsSchema can only be used inside of a GSettings component");
33+}
tests/mocks/GSettings/plugin.hnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef PLUGIN_H
18+#define PLUGIN_H
19+
20+#include <QtQml/QQmlExtensionPlugin>
21+
22+class FakeGSettingsQmlPlugin : public QQmlExtensionPlugin
23+{
24+ Q_OBJECT
25+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26+
27+public:
28+ void registerTypes(const char *uri);
29+};
30+
31+#endif // PLUGIN_H
tests/mocks/GSettings/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module GSettings
2+plugin FakeGSettingsQml
tests/mocks/LightDM/single/GreeterPrivate.cpp+2−4
@@ -34,10 +34,8 @@ void GreeterPrivate::handleAuthenticate()
3434{
3535 Q_Q(Greeter);
3636
37− if (authenticationUser == "one") {
38− authenticated = true;
39− Q_EMIT q->authenticationComplete();
40− }
37+ authenticated = true;
38+ Q_EMIT q->authenticationComplete();
4139}
4240
4341void GreeterPrivate::handleRespond(QString const &response)
tests/qmltests/CMakeLists.txt+1−1
@@ -26,7 +26,7 @@ set(qmltest_DEFAULT_TARGETS qmluitests)
2626set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
2727set(qmltest_DEFAULT_PROPERTIES "")
2828
29−add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
29+add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
3030 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
3131add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
3232add_qml_test(Components DraggingArea)
tests/qmltests/Dash/tst_FilterGrids.qml+1−1
@@ -118,7 +118,7 @@ Rectangle {
118118 gridLoader.source = "../../../Dash/" + data.component;
119119
120120 // Wait until the FilterGrid is loaded by the loader
121− tryCompare(gridLoader, "status", Loader.Ready, "Loader couldn't load " + data.component);
121+ tryCompare(gridLoader, "status", Loader.Ready);
122122
123123 // Wait until the GridView inside the model has finished rendering
124124 var gridView = findChild(gridLoader, "responsiveGridViewGrid");
tests/qmltests/tst_Shell.qml+14
@@ -19,6 +19,7 @@
1919
2020import QtQuick 2.0
2121import QtTest 1.0
22+import GSettings 1.0
2223import Ubuntu.Application 0.1
2324import Unity.Test 0.1 as UT
2425
@@ -277,5 +278,18 @@ Item {
277278 }
278279 } while (!isStill);
279280 }
281+
282+ function test_wallpaper_data() {
283+ return [
284+ {tag: "red", url: "tests/data/unity/backgrounds/red.png"},
285+ {tag: "blue", url: "tests/data/unity/backgrounds/blue.png"}
286+ ]
287+ }
288+
289+ function test_wallpaper(data) {
290+ var backgroundImage = findChild(shell, "backgroundImage")
291+ GSettingsController.setPictureUri(data.url)
292+ tryCompareFunction(function() { return backgroundImage.source.toString().indexOf(data.url) !== -1; }, true)
293+ }
280294 }
281295}