on xenial help sign in
Revert Session Screenshotter Fixes: #1473476

Approved by: Michael Zanetti

commit100fae8657e8d69dfe8e1cbff84f82dc3047078a authorAlbert Astals Cid <albert.astals@canonical.com> dateMon 13 Jul 2015, 14:17 (11 years ago) parent993899a92b5507
17 files changed+22−524
debian/unity8-private.install−1 plugins/CMakeLists.txt−1 plugins/SessionGrabber/CMakeLists.txt−8 plugins/SessionGrabber/SessionGrabber.qmltypes−23 plugins/SessionGrabber/plugin.cpp−27 plugins/SessionGrabber/plugin.h−32 plugins/SessionGrabber/qmldir−3 plugins/SessionGrabber/sessiongrabber.cpp−135 plugins/SessionGrabber/sessiongrabber.h−85 qml/Stages/ApplicationWindow.qml+22−46 qml/Stages/Splash.qml−2 qml/Stages/SpreadDelegate.qml−1 tests/plugins/CMakeLists.txt−1 tests/plugins/SessionGrabber/CMakeLists.txt−14 tests/plugins/SessionGrabber/sessiongrabbertest.cpp−79 tests/plugins/SessionGrabber/sessiongrabbertest.qml−22 tests/qmltests/Stages/tst_ApplicationWindow.qml−44
debian/unity8-private.install−1
@@ -8,7 +8,6 @@ usr/lib/*/unity8/qml/Lights
88usr/lib/*/unity8/qml/Powerd
99usr/lib/*/unity8/qml/ScreenGrabber
1010usr/lib/*/unity8/qml/SessionBroadcast
11−usr/lib/*/unity8/qml/SessionGrabber
1211usr/lib/*/unity8/qml/Ubuntu
1312usr/lib/*/unity8/qml/Unity
1413usr/lib/*/unity8/qml/Utils
plugins/CMakeLists.txt−1
@@ -18,7 +18,6 @@ add_subdirectory(Lights)
1818add_subdirectory(Dash)
1919add_subdirectory(Powerd)
2020add_subdirectory(SessionBroadcast)
21−add_subdirectory(SessionGrabber)
2221add_subdirectory(ScreenGrabber)
2322add_subdirectory(Ubuntu)
2423add_subdirectory(Unity)
plugins/SessionGrabber/CMakeLists.txtdeleted−8
@@ -1,8 +0,0 @@
1−include_directories(
2− ${CMAKE_CURRENT_BINARY_DIR}
3−)
4−
5−add_library(SessionGrabber-qml MODULE sessiongrabber.cpp plugin.cpp)
6−qt5_use_modules(SessionGrabber-qml Qml Gui Quick Concurrent)
7−
8−add_unity8_plugin(SessionGrabber 0.1 SessionGrabber TARGETS SessionGrabber-qml)
plugins/SessionGrabber/SessionGrabber.qmltypesdeleted−23
@@ -1,23 +0,0 @@
1−import QtQuick.tooling 1.1
2−
3−// This file describes the plugin-supplied types contained in the library.
4−// It is used for QML tooling purposes only.
5−//
6−// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable SessionGrabber 0.1 plugins'
8−
9−Module {
10− Component {
11− name: "SessionGrabber"
12− prototype: "QObject"
13− exports: ["SessionGrabber/SessionGrabber 0.1"]
14− exportMetaObjectRevisions: [0]
15− Property { name: "appId"; type: "string" }
16− Property { name: "path"; type: "string"; isReadonly: true }
17− Property { name: "target"; type: "QQuickItem"; isPointer: true }
18− Signal { name: "appIdChanged" }
19− Signal { name: "screenshotTaken" }
20− Method { name: "take" }
21− Method { name: "removeScreenshot" }
22− }
23−}
plugins/SessionGrabber/plugin.cppdeleted−27
@@ -1,27 +0,0 @@
1−/*
2− * Copyright (C) 2015 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−
18−#include "plugin.h"
19−#include "sessiongrabber.h"
20−
21−#include <QtQml/qqml.h>
22−
23−void SessionGrabberPlugin::registerTypes(const char *uri)
24−{
25− Q_ASSERT(uri == QLatin1String("SessionGrabber"));
26− qmlRegisterType<SessionGrabber>(uri, 0, 1, "SessionGrabber");
27−}
plugins/SessionGrabber/plugin.hdeleted−32
@@ -1,32 +0,0 @@
1−/*
2− * Copyright (C) 2015 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−
18−#ifndef SESSIONGRABBER_PLUGIN_H
19−#define SESSIONGRABBER_PLUGIN_H
20−
21−#include <QtQml/QQmlExtensionPlugin>
22−
23−class SessionGrabberPlugin : public QQmlExtensionPlugin
24−{
25− Q_OBJECT
26− Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27−
28−public:
29− void registerTypes(const char *uri);
30−};
31−
32−#endif
plugins/SessionGrabber/qmldirdeleted−3
@@ -1,3 +0,0 @@
1−module SessionGrabber
2−plugin SessionGrabber-qml
3−typeinfo SessionGrabber.qmltypes
plugins/SessionGrabber/sessiongrabber.cppdeleted−135
@@ -1,135 +0,0 @@
1−/*
2− * Copyright (C) 2015 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−
18−#include "sessiongrabber.h"
19−
20−#include <QDebug>
21−#include <QQuickItem>
22−#include <QQuickItemGrabResult>
23−#include <QtConcurrent>
24−
25−static QString cacheFolder()
26−{
27− return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/app_shots/";
28−}
29−
30−static QString cachePath(const QString &appId)
31−{
32− return cacheFolder() + appId + ".png";
33−}
34−
35−SessionGrabber::SessionGrabber(QObject *parent)
36− : QObject(parent)
37− , m_target(nullptr)
38− , m_watcher(nullptr)
39−{
40−}
41−
42−QString SessionGrabber::appId() const
43−{
44− return m_appId;
45−}
46−
47−void SessionGrabber::setAppId(const QString &appId)
48−{
49− if (appId != m_appId) {
50− m_appId = appId;
51− const QString path = cachePath(appId);
52− if (QFile::exists(path)) {
53− setPath(path);
54− }
55− }
56−}
57−
58−QQuickItem *SessionGrabber::target() const
59−{
60− return m_target;
61−}
62−
63−void SessionGrabber::setTarget(QQuickItem *target)
64−{
65− if (target != m_target) {
66− m_target = target;
67− Q_EMIT targetChanged();
68− }
69−}
70−
71−QString SessionGrabber::path() const
72−{
73− return m_path;
74−}
75−
76−void SessionGrabber::setPath(const QString &path)
77−{
78− if (path != m_path) {
79− m_path = path;
80− Q_EMIT pathChanged();
81− }
82−}
83−
84−static QString saveScreenshot(const QString &appId, const QSharedPointer<QQuickItemGrabResult> grabResult)
85−{
86− const QImage image = grabResult->image();
87− const QString cPath = cacheFolder();
88− QDir d;
89− d.mkpath(cPath);
90− const QString path = cachePath(appId);
91− if (image.save(path)) {
92− return path;
93− } else {
94− return QString();
95− }
96−}
97−
98−void SessionGrabber::grab()
99−{
100− if (!m_grabResult.isNull()) {
101− qWarning() << "Asked to grab a screenshot when there's one already being grabbed, ignoring";
102− return;
103− }
104−
105− if (m_target && !m_appId.isEmpty()) {
106− // grabToImage runs in a separate thread
107− m_grabResult = m_target->grabToImage();
108− connect(m_grabResult.data(), &QQuickItemGrabResult::ready, this, &SessionGrabber::grabReady);
109− } else {
110− qWarning() << "Can't grab screnshot: appId:" << m_appId << " target:" << m_target;
111− }
112−}
113−
114−void SessionGrabber::removeScreenshot()
115−{
116− const QString path = cachePath(m_appId);
117− QFile::remove(path);
118−}
119−
120−void SessionGrabber::grabReady()
121−{
122− QFuture<QString> f = QtConcurrent::run(saveScreenshot, m_appId, m_grabResult);
123− m_watcher = new QFutureWatcher<QString>(this);
124− m_watcher->setFuture(f);
125− connect(m_watcher, &QFutureWatcher<QString>::finished, this, &SessionGrabber::saveFinished);
126−}
127−
128−void SessionGrabber::saveFinished()
129−{
130− setPath(m_watcher->future().result());
131− delete m_watcher;
132− m_watcher = nullptr;
133− m_grabResult.clear();
134− Q_EMIT screenshotGrabbed();
135−}
plugins/SessionGrabber/sessiongrabber.hdeleted−85
@@ -1,85 +0,0 @@
1−/*
2− * Copyright (C) 2015 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−
18−#ifndef SESSIONGRABBER_H
19−#define SESSIONGRABBER_H
20−
21−#include <QObject>
22−#include <QSharedPointer>
23−#include <QFutureWatcher>
24−
25−class QQuickItem;
26−class QQuickItemGrabResult;
27−
28−/**
29− * SessionGrabber saves to disk screenshots of the given item.
30− * Images are saved into $HOME/.cache/app_shots/appId.png
31− * It also handles giving back the screenshot path if it already exists (e.g. because a reboot)
32− */
33−class SessionGrabber : public QObject
34−{
35− Q_OBJECT
36−
37− /// appId is the key of the screenshot name.
38− Q_PROPERTY(QString appId READ appId WRITE setAppId NOTIFY appIdChanged)
39−
40− /// path where the screenshot is saved, can be empty if no screenshot has been grabbed yet.
41− Q_PROPERTY(QString path READ path NOTIFY pathChanged)
42−
43− /// target item for the screenshot grabbing.
44− Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged)
45−
46−public:
47− explicit SessionGrabber(QObject *parent = 0);
48−
49− QString appId() const;
50− void setAppId(const QString &appId);
51−
52− QQuickItem *target() const;
53− void setTarget(QQuickItem *target);
54−
55− QString path() const;
56−
57− /// Starts grabbing a screenshot. Emits screenshotGrabbed when ready.
58− Q_INVOKABLE void grab();
59−
60− /// Removes the existing screenshot
61− Q_INVOKABLE void removeScreenshot();
62−
63−Q_SIGNALS:
64− void appIdChanged();
65− void targetChanged();
66− void pathChanged();
67−
68− /// Signals screenshot grabbing has finished.
69− void screenshotGrabbed();
70−
71−private Q_SLOTS:
72− void grabReady();
73− void saveFinished();
74−
75−private:
76− void setPath(const QString &path);
77−
78− QString m_appId;
79− QString m_path;
80− QQuickItem *m_target;
81− QFutureWatcher<QString> *m_watcher;
82− QSharedPointer<QQuickItemGrabResult> m_grabResult;
83−};
84−
85−#endif
qml/Stages/ApplicationWindow.qml+22−46
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 1.1
1919import Unity.Application 0.1
20−import SessionGrabber 0.1
2120
2221FocusScope {
2322 id: root
@@ -31,16 +30,11 @@ FocusScope {
3130 property QtObject application
3231 property int surfaceOrientationAngle
3332
34− function removeScreenshot() {
35− sessionGrabber.removeScreenshot();
36− }
37−
3833 QtObject {
3934 id: d
4035
4136 // helpers so that we don't have to check for the existence of an application everywhere
4237 // (in order to avoid breaking qml binding due to a javascript exception)
43− readonly property string appId: root.application ? root.application.appId : ""
4438 readonly property string name: root.application ? root.application.name : ""
4539 readonly property url icon: root.application ? root.application.icon : ""
4640 readonly property int applicationState: root.application ? root.application.state : -1
@@ -56,11 +50,11 @@ FocusScope {
5650 property bool hadSurface: sessionContainer.surfaceContainer.hadSurface
5751
5852 property bool needToTakeScreenshot:
59− sessionContainer.surface && d.surfaceInitialized
60− && (d.applicationState === ApplicationInfoInterface.Stopped || d.applicationState === ApplicationInfoInterface.Suspended)
53+ sessionContainer.surface && d.surfaceInitialized && screenshotImage.status === Image.Null
54+ && d.applicationState === ApplicationInfoInterface.Stopped
6155 onNeedToTakeScreenshotChanged: {
6256 if (needToTakeScreenshot) {
63− sessionGrabber.grab();
57+ screenshotImage.take();
6458 }
6559 }
6660
@@ -92,9 +86,27 @@ FocusScope {
9286 onTriggered: { if (stateGroup.state === "surface") { d.surfaceOldEnoughToBeResized = true; } }
9387 }
9488
89+ Image {
90+ id: screenshotImage
91+ objectName: "screenshotImage"
92+ source: d.defaultScreenshot
93+ anchors.fill: parent
94+ antialiasing: !root.interactive
95+
96+ function take() {
97+ // Format: "image://application/$APP_ID/$CURRENT_TIME_MS"
98+ // eg: "image://application/calculator-app/123456"
99+ var timeMs = new Date().getTime();
100+ source = "image://application/" + root.application.appId + "/" + timeMs;
101+ }
102+
103+ // Save memory by using a half-resolution (thus quarter size) screenshot
104+ sourceSize.width: root.width / 2
105+ sourceSize.height: root.height / 2
106+ }
107+
95108 Loader {
96109 id: splashLoader
97− objectName: "splashLoader"
98110 visible: active
99111 active: false
100112 anchors.fill: parent
@@ -108,46 +120,10 @@ FocusScope {
108120 backgroundColor: d.splashColor
109121 headerColor: d.splashColorHeader
110122 footerColor: d.splashColorFooter
111− activeSpinner: d.applicationState === ApplicationInfoInterface.Starting ||
112− d.applicationState === ApplicationInfoInterface.Running
113123 }
114124 }
115125 }
116126
117− Image {
118− id: screenshotImage
119− objectName: "screenshotImage"
120− source: sessionGrabber.path || d.defaultScreenshot
121− anchors.fill: parent
122− antialiasing: !root.interactive
123− cache: false
124− asynchronous: true
125−
126− // Save memory by using a half-resolution (thus quarter size) screenshot
127− sourceSize.width: root.width / 2
128− sourceSize.height: root.height / 2
129−
130− ActivityIndicator {
131− id: activityIndicator
132− anchors.centerIn: parent
133− visible: running
134− running: stateGroup.state == "screenshot" &&
135− (d.applicationState === ApplicationInfoInterface.Starting || d.applicationState === ApplicationInfoInterface.Running)
136− }
137− }
138−
139− SessionGrabber {
140− id: sessionGrabber
141− appId: d.appId
142− target: root
143−
144− onScreenshotGrabbed: {
145− // Need to reset to "" and back since it may be the same path with new content
146− screenshotImage.source = "";
147− screenshotImage.source = sessionGrabber.path;
148− }
149− }
150−
151127 SessionContainer {
152128 id: sessionContainer
153129 // A fake application might not even have a session property.
qml/Stages/Splash.qml−2
@@ -31,7 +31,6 @@ Item {
3131 property url icon
3232 property alias title: header.title
3333 property alias showHeader: header.visible
34− property alias activeSpinner: activityIndicator.running
3534
3635 Ambiance.Palette {
3736 id: ambiancePalette
@@ -145,7 +144,6 @@ Item {
145144 }
146145
147146 ActivityIndicator {
148− id: activityIndicator
149147 anchors.centerIn: header.visible ? parent : undefined
150148 anchors.verticalCenterOffset: header.visible ? header.height / 2 : 0
151149
qml/Stages/SpreadDelegate.qml−1
@@ -397,7 +397,6 @@ FocusScope {
397397 if (!running) {
398398 dragArea.moving = false;
399399 if (requestClose) {
400− appWindow.removeScreenshot();
401400 root.closed();
402401 } else {
403402 dragArea.distance = 0;
tests/plugins/CMakeLists.txt−1
@@ -2,7 +2,6 @@ add_subdirectory(AccountsService)
22add_subdirectory(Greeter)
33add_subdirectory(LightDM)
44add_subdirectory(Dash)
5−add_subdirectory(SessionGrabber)
65add_subdirectory(Ubuntu)
76add_subdirectory(Unity)
87add_subdirectory(Utils)
tests/plugins/SessionGrabber/CMakeLists.txtdeleted−14
@@ -1,14 +0,0 @@
1−add_executable(SessionGrabberTestExec
2− sessiongrabbertest.cpp
3− ${CMAKE_SOURCE_DIR}/plugins/SessionGrabber/sessiongrabber.cpp
4− )
5−qt5_use_modules(SessionGrabberTestExec Core Quick Test Concurrent)
6−
7−add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
8−
9−include_directories(
10− ${CMAKE_CURRENT_BINARY_DIR}
11− ${CMAKE_SOURCE_DIR}/plugins/SessionGrabber
12− )
13−
14−add_unity8_uitest(SessionGrabber SessionGrabberTestExec)
tests/plugins/SessionGrabber/sessiongrabbertest.cppdeleted−79
@@ -1,79 +0,0 @@
1−/*
2− * Copyright (C) 2015 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 <QtTestGui>
18−#include <QQuickItem>
19−#include <QQuickView>
20−#include <QSignalSpy>
21−
22−#include "sessiongrabber.h"
23−
24−class SessionGrabberTest : public QObject
25−{
26− Q_OBJECT
27−
28−private Q_SLOTS:
29−
30− void init()
31− {
32− view = new QQuickView();
33− view->setSource(QUrl::fromLocalFile(CURRENT_SOURCE_DIR "/sessiongrabbertest.qml"));
34− view->show();
35− QTest::qWaitForWindowExposed(view);
36− }
37−
38− void testSessionGrabber()
39− {
40− SessionGrabber s;
41− s.setAppId("test-app-id");
42− s.setTarget(view->rootObject());
43− QSignalSpy spy(&s, &SessionGrabber::screenshotGrabbed);
44−
45− QVERIFY(!QFile::exists(s.path()));
46−
47− view->rootObject()->setProperty("color", "red");
48− s.grab();
49− spy.wait();
50−
51− QVERIFY(QFile::exists(s.path()));
52− QImage image(s.path());
53− QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0));
54−
55− view->rootObject()->setProperty("color", "blue");
56− s.grab();
57− spy.wait();
58−
59− QVERIFY(QFile::exists(s.path()));
60− image = QImage(s.path());
61− QCOMPARE(image.pixel(0, 0), qRgb(0, 0, 255));
62−
63− s.removeScreenshot();
64−
65− QVERIFY(!QFile::exists(s.path()));
66− }
67−
68− void cleanup()
69− {
70− delete view;
71− }
72−
73−private:
74− QQuickView *view;
75−};
76−
77−QTEST_MAIN(SessionGrabberTest)
78−
79−#include "sessiongrabbertest.moc"
tests/plugins/SessionGrabber/sessiongrabbertest.qmldeleted−22
@@ -1,22 +0,0 @@
1−/*
2− * Copyright (C) 2015 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−import QtQuick 2.4
18−
19−Rectangle {
20− width: 100
21− height: 100
22−}
tests/qmltests/Stages/tst_ApplicationWindow.qml−44
@@ -35,9 +35,6 @@ Rectangle {
3535 root.fakeApplication.manualSurfaceCreation = true;
3636 root.fakeApplication.setState(ApplicationInfoInterface.Starting);
3737 }
38− Component.onDestruction: {
39− applicationWindowLoader.item.removeScreenshot();
40− }
4138 property QtObject fakeApplication: null
4239 readonly property var fakeSession: fakeApplication ? fakeApplication.session : null
4340
@@ -334,40 +331,6 @@ Rectangle {
334331 tryCompare(screenshotImage, "status", Image.Null);
335332 }
336333
337− function test_suspendrestartApp() {
338− var screenshotImage = findChild(applicationWindowLoader.item, "screenshotImage");
339−
340− initSession();
341− setApplicationState(appRunning);
342− tryCompare(stateGroup, "state", "surface");
343− waitUntilTransitionsEnd();
344−
345− setApplicationState(appSuspended);
346−
347− cleanupSession();
348−
349− tryCompare(stateGroup, "state", "screenshot");
350− waitUntilTransitionsEnd();
351− tryCompare(fakeApplication, "session", null);
352−
353− // and restart it
354− setApplicationState(appStarting);
355−
356− waitUntilTransitionsEnd();
357− verify(stateGroup.state === "screenshot");
358− verify(fakeSession === null);
359−
360− setApplicationState(appRunning);
361−
362− waitUntilTransitionsEnd();
363− verify(stateGroup.state === "screenshot");
364−
365− initSession();
366−
367− tryCompare(stateGroup, "state", "surface");
368− tryCompare(screenshotImage, "status", Image.Null);
369− }
370−
371334 function test_appCrashed() {
372335 initSession();
373336 setApplicationState(appRunning);
@@ -445,12 +408,5 @@ Rectangle {
445408 applicationWindowLoader.item.interactive = true;
446409 compare(fakeSession.surface.activeFocus, true);
447410 }
448−
449− function test_no_spinner_if_stopped() {
450− setApplicationState(appStopped);
451− tryCompare(stateGroup, "state", "splashScreen");
452− var splashLoader = findChild(applicationWindowLoader.item, "splashLoader");
453− verify(!splashLoader.item.activeSpinner);
454− }
455411 }
456412}