Merge lp:~mzanetti/unity8/appmanager-rework into lp:unity8

Proposed by Michael Zanetti
Status: Rejected
Rejected by: Michael Zanetti
Proposed branch: lp:~mzanetti/unity8/appmanager-rework
Merge into: lp:unity8
Diff against target: 1949 lines (+987/-314)
22 files modified
plugins/Utils/CMakeLists.txt (+2/-1)
plugins/Utils/easingcurve.cpp (+49/-0)
plugins/Utils/easingcurve.h (+42/-0)
plugins/Utils/plugin.cpp (+2/-0)
qml/Components/ResponsiveFlowView.qml (+3/-10)
qml/Dash/Apps/RunningApplicationTile.qml (+13/-24)
qml/Dash/Apps/RunningApplicationsGrid.qml (+5/-20)
qml/Dash/DashApps.qml (+4/-10)
qml/Dash/GenericScopeView.qml (+1/-2)
qml/Shell.qml (+85/-243)
qml/Stages/PhoneStage.qml (+574/-0)
run_on_device (+1/-0)
tests/mocks/Unity/Application/ApplicationInfo.h (+3/-0)
tests/mocks/Unity/Application/ApplicationManager.cpp (+56/-1)
tests/mocks/Unity/Application/ApplicationManager.h (+2/-0)
tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp (+69/-0)
tests/mocks/Unity/Application/ApplicationScreenshotProvider.h (+34/-0)
tests/mocks/Unity/Application/CMakeLists.txt (+1/-0)
tests/mocks/Unity/Application/plugin.cpp (+18/-3)
tests/mocks/Unity/Application/plugin.h (+1/-0)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+3/-0)
tests/qmltests/tst_Shell.qml (+19/-0)
To merge this branch: bzr merge lp:~mzanetti/unity8/appmanager-rework
Reviewer Review Type Date Requested Status
Michael Zanetti (community) Disapprove
Review via email: mp+199815@code.launchpad.net

Commit message

rework ApplicationManager handling

Description of the change

This completely reworks how the Shell talks to the ApplicationManager as a preparation for the upcoming Right Edge work.

It drops ApplicationManagerWrapper as that one was mostly a leftover from very early prototypes and was the reason for many workarounds building up around it.

Also it cuts ties between the RunningApplicationGrid and the Stages. Both only talk directly to the ApplicationManager now.

Last but not least it drops the stages code as it is now and starts fresh with a PhoneStage for the upcoming Right Edge work. In the future a TabledStage and DesktopStage should be easily addable.

To post a comment you must log in.
575. By Michael Zanetti

initial try on the right edge animation

576. By Michael Zanetti

make it interactive

577. By Michael Zanetti

added a bit of scaling. not matching spec yet

578. By Michael Zanetti

make it actually switch apps

579. By Michael Zanetti

improve mouse interaction with CoverFlip

580. By Michael Zanetti

update screenshots before starting right edge animation

581. By Michael Zanetti

merge trunk

582. By Michael Zanetti

reworked animation

583. By Michael Zanetti

improved the whole animation a lot

584. By Michael Zanetti

fix glitch with focusing the right app when moving backwards, after having already passed progressmarker1

585. By Michael Zanetti

make it look nicer if there are only 3 running apps

586. By Michael Zanetti

make flicking AND clicking work

587. By Michael Zanetti

cleanup

588. By Michael Zanetti

fix selected animation

589. By Michael Zanetti

drop unused file

590. By Michael Zanetti

merge trunk

591. By Michael Zanetti

add a point of no return

592. By Michael Zanetti

some work on bringing the fake application plugin up to date with the new api

593. By Michael Zanetti

added missing files

594. By Michael Zanetti

more progress on the fake application manager

595. By Michael Zanetti

fix hiding the stage when the app is killed

596. By Michael Zanetti

added a dropshadow

597. By Michael Zanetti

slow down scrolling a bit and fix the flickables contentWidth to roughly reflect the app's positions

598. By Michael Zanetti

shrink app tiles a little to make 3 of them fit into one row again

Revision history for this message
Michael Zanetti (mzanetti) wrote :

superseeded by the right-edge-2 branch

review: Disapprove

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Utils/CMakeLists.txt'
2--- plugins/Utils/CMakeLists.txt 2013-12-10 14:22:43 +0000
3+++ plugins/Utils/CMakeLists.txt 2014-01-22 10:43:18 +0000
4@@ -18,6 +18,7 @@
5 qsortfilterproxymodelqml.cpp
6 timeformatter.cpp
7 unitymenumodelpaths.cpp
8+ easingcurve.cpp
9 plugin.cpp
10 )
11
12@@ -33,7 +34,7 @@
13 # files directly in targets.
14 set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
15
16-qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns)
17+qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns Gui)
18
19 # export the qmldir qmltypes and plugin files
20 export_qmlfiles(Utils Utils)
21
22=== added file 'plugins/Utils/easingcurve.cpp'
23--- plugins/Utils/easingcurve.cpp 1970-01-01 00:00:00 +0000
24+++ plugins/Utils/easingcurve.cpp 2014-01-22 10:43:18 +0000
25@@ -0,0 +1,49 @@
26+#include "easingcurve.h"
27+
28+
29+EasingCurve::EasingCurve(QObject *parent):
30+ QObject(parent)
31+{
32+
33+}
34+
35+QEasingCurve::Type EasingCurve::type() const
36+{
37+ return m_easingCurve.type();
38+}
39+
40+void EasingCurve::setType(const QEasingCurve::Type &type)
41+{
42+ m_easingCurve.setType(type);
43+ Q_EMIT typeChanged();
44+}
45+
46+qreal EasingCurve::period() const
47+{
48+ return m_easingCurve.period();
49+}
50+
51+void EasingCurve::setPeriod(qreal period)
52+{
53+ m_easingCurve.setPeriod(period);
54+ Q_EMIT periodChanged();
55+}
56+
57+qreal EasingCurve::progress() const
58+{
59+ return m_progress;
60+}
61+
62+void EasingCurve::setProgress(qreal progress)
63+{
64+ if (m_progress != progress) {
65+ m_progress = progress;
66+ m_value = m_easingCurve.valueForProgress(m_progress);
67+ Q_EMIT progressChanged();
68+ }
69+}
70+
71+qreal EasingCurve::value() const
72+{
73+ return m_value;
74+}
75
76=== added file 'plugins/Utils/easingcurve.h'
77--- plugins/Utils/easingcurve.h 1970-01-01 00:00:00 +0000
78+++ plugins/Utils/easingcurve.h 2014-01-22 10:43:18 +0000
79@@ -0,0 +1,42 @@
80+#ifndef EASINGCURVE_H
81+#define EASINGCURVE_H
82+
83+#include <QObject>
84+#include <QEasingCurve>
85+
86+class EasingCurve: public QObject
87+{
88+ Q_OBJECT
89+ Q_ENUMS(QEasingCurve::Type)
90+ Q_PROPERTY(QEasingCurve::Type type READ type WRITE setType NOTIFY typeChanged)
91+ Q_PROPERTY(qreal period READ period WRITE setPeriod NOTIFY periodChanged)
92+ Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
93+ Q_PROPERTY(qreal value READ value NOTIFY progressChanged)
94+
95+public:
96+ EasingCurve(QObject *parent = 0);
97+
98+ QEasingCurve::Type type() const;
99+ void setType(const QEasingCurve::Type &type);
100+
101+ qreal period() const;
102+ void setPeriod(qreal period);
103+
104+ qreal progress() const;
105+ void setProgress(qreal progress);
106+
107+ qreal value() const;
108+
109+Q_SIGNALS:
110+ void typeChanged();
111+ void periodChanged();
112+ void progressChanged();
113+
114+private:
115+ QEasingCurve m_easingCurve;
116+ qreal m_progress;
117+ qreal m_value;
118+};
119+
120+#endif
121+
122
123=== modified file 'plugins/Utils/plugin.cpp'
124--- plugins/Utils/plugin.cpp 2013-12-10 14:22:43 +0000
125+++ plugins/Utils/plugin.cpp 2014-01-22 10:43:18 +0000
126@@ -32,6 +32,7 @@
127 #include "qsortfilterproxymodelqml.h"
128 #include "timeformatter.h"
129 #include "unitymenumodelpaths.h"
130+#include "easingcurve.h"
131
132 static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";
133 static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";
134@@ -46,6 +47,7 @@
135 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
136 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
137 qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
138+ qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
139 }
140
141 void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
142
143=== modified file 'qml/Components/ResponsiveFlowView.qml'
144--- qml/Components/ResponsiveFlowView.qml 2013-06-05 22:03:08 +0000
145+++ qml/Components/ResponsiveFlowView.qml 2014-01-22 10:43:18 +0000
146@@ -27,9 +27,8 @@
147 property alias verticalSpacing: flow.verticalSpacing
148 property alias horizontalSpacing: flow.horizontalSpacing
149 property int referenceDelegateWidth
150- property alias firstModel: repeater1.model
151- property alias secondModel: repeater2.model
152- property alias delegate: repeater1.delegate
153+ property alias model: repeater.model
154+ property alias delegate: repeater.delegate
155 readonly property int cellWidth: referenceDelegateWidth + horizontalSpacing
156 readonly property int cellHeight: referenceDelegateWidth + verticalSpacing
157 property alias move: flow.move
158@@ -69,13 +68,7 @@
159 property int margin: allocatableVerticalSpace - columns * horizontalSpacing
160
161 Repeater {
162- id: repeater1
163- model: (root.model) ? root.model[0] : null
164- }
165- Repeater {
166- id: repeater2
167- model: (root.model) ? root.model[1] : null
168- delegate: repeater1.delegate
169+ id: repeater
170 }
171 }
172 }
173
174=== modified file 'qml/Dash/Apps/RunningApplicationTile.qml'
175--- qml/Dash/Apps/RunningApplicationTile.qml 2013-10-28 14:12:24 +0000
176+++ qml/Dash/Apps/RunningApplicationTile.qml 2014-01-22 10:43:18 +0000
177@@ -23,7 +23,6 @@
178 AbstractButton {
179 id: root
180 property var application
181- property bool __sideStageEnabled: shell.applicationManager.sideStageEnabled
182
183 signal requestedApplicationActivation(var application)
184 signal requestedApplicationTermination(var application)
185@@ -51,32 +50,22 @@
186 }
187 }
188
189- function updateScreenshotFromCache() {
190- applicationImage.updateFromCache();
191- }
192-
193- // FIXME: should use UbuntuShape from SDK
194- UbuntuShapeForItem {
195+ UbuntuShape {
196 id: shapedApplicationImage
197- anchors {
198- top: parent.top
199- horizontalCenter: parent.horizontalCenter
200+ anchors { top: parent.top; horizontalCenter: parent.horizontalCenter }
201+
202+ height: units.gu(17)
203+ width: applicationImage.width
204+ radius: "medium"
205+
206+ image: Image {
207+ id: applicationImage
208+ source: application.screenshot
209+ // height : width = ss.height : ss.width
210+ height: shapedApplicationImage.height
211+ width: height * sourceSize.width / sourceSize.height
212 }
213
214- // FIXME: width and height should be defined according to the
215- // application window's aspect ratio.
216- width: (application.stage === ApplicationInfo.MainStage && __sideStageEnabled) ?
217- units.gu(22) : units.gu(11)
218- height: (__sideStageEnabled) ? units.gu(22) : units.gu(19)
219- radius: "medium"
220- image: applicationImage
221- }
222-
223- ApplicationImage {
224- id: applicationImage
225- source: ApplicationManager.findApplication((application) ? application.appId : "")
226- width: shapedApplicationImage.width
227- height: shapedApplicationImage.height
228 }
229
230 UbuntuShape {
231
232=== modified file 'qml/Dash/Apps/RunningApplicationsGrid.qml'
233--- qml/Dash/Apps/RunningApplicationsGrid.qml 2013-11-29 08:57:13 +0000
234+++ qml/Dash/Apps/RunningApplicationsGrid.qml 2014-01-22 10:43:18 +0000
235@@ -18,6 +18,7 @@
236 import "../../Components"
237
238 import Ubuntu.Gestures 0.1
239+import Unity.Application 0.1
240
241 ResponsiveFlowView {
242 id: root
243@@ -25,13 +26,7 @@
244
245 signal updateScreenshots
246 property alias enableHeightBehavior: heightBehaviour.enabled
247- property bool enableHeightBehaviorOnNextCreation: firstModel.count + secondModel.count == 0
248-
249- Connections {
250- target: shell
251- onDashShownChanged: if (shell.dashShown && shell.stageScreenshotsReady) updateScreenshots();
252- onStageScreenshotsReadyChanged: if (shell.dashShown && shell.stageScreenshotsReady) updateScreenshots();
253- }
254+ property bool enableHeightBehaviorOnNextCreation: model.count === 0
255
256 Behavior on height {
257 id: heightBehaviour
258@@ -40,13 +35,7 @@
259 }
260
261 Connections {
262- target: root.firstModel
263- onCountChanged: {
264- heightBehaviour.enabled = true;
265- }
266- }
267- Connections {
268- target: root.secondModel
269+ target: root.model
270 onCountChanged: {
271 heightBehaviour.enabled = true;
272 }
273@@ -85,17 +74,13 @@
274 root.terminationModeEnabled = true
275 }
276 onRequestedApplicationTermination: {
277- shell.applicationManager.stopApplication(model.appId)
278+ ApplicationManager.stopApplication(model.appId)
279 }
280 onRequestedApplicationActivation: {
281- shell.activateApplication(model.appId)
282+ ApplicationManager.focusApplication(model.appId)
283 }
284
285 terminationModeEnabled: root.terminationModeEnabled
286-
287- Component.onCompleted: {
288- root.updateScreenshots.connect(updateScreenshotFromCache);
289- }
290 }
291 }
292
293
294=== modified file 'qml/Dash/DashApps.qml'
295--- qml/Dash/DashApps.qml 2013-12-02 13:23:28 +0000
296+++ qml/Dash/DashApps.qml 2014-01-22 10:43:18 +0000
297@@ -17,6 +17,7 @@
298 import QtQuick 2.0
299 import Ubuntu.Components 0.1
300 import Utils 0.1
301+import Unity.Application 0.1
302 import "../Components"
303 import "../Components/ListItems"
304 import "Apps"
305@@ -25,10 +26,6 @@
306 id: scopeView
307 objectName: "DashApps"
308
309- // FIXME: a way to aggregate these models would be ideal
310- property var mainStageApplicationsModel: shell.applicationManager.mainStageApplications
311- property var sideStageApplicationModel: shell.applicationManager.sideStageApplications
312-
313 ListModel {
314 id: dummyVisibilityModifier
315
316@@ -38,19 +35,16 @@
317 SortFilterProxyModel {
318 id: runningApplicationsModel
319
320- property var firstModel: mainStageApplicationsModel
321- property var secondModel: sideStageApplicationModel
322 property bool canEnableTerminationMode: scopeView.isCurrent
323
324- model: dummyVisibilityModifier
325+ model: ApplicationManager
326 filterRole: 0
327- filterRegExp: invertMatch ? ((mainStageApplicationsModel.count === 0 &&
328- sideStageApplicationModel.count === 0) ? RegExp("running-apps") : RegExp("")) : RegExp("disabled")
329+ filterRegExp: invertMatch ? (ApplicationManager.count === 0 ? RegExp("running-apps") : RegExp("")) : RegExp("disabled")
330 invertMatch: scopeView.scope.searchQuery.length == 0
331 }
332
333 onScopeChanged: {
334 scopeView.scope.categories.overrideResults("recent", runningApplicationsModel);
335- enableHeightBehaviorOnNextCreation = (mainStageApplicationsModel.count + sideStageApplicationModel.count == 0)
336+ enableHeightBehaviorOnNextCreation = ApplicationManager.count === 0
337 }
338 }
339
340=== modified file 'qml/Dash/GenericScopeView.qml'
341--- qml/Dash/GenericScopeView.qml 2014-01-07 17:06:01 +0000
342+++ qml/Dash/GenericScopeView.qml 2014-01-22 10:43:18 +0000
343@@ -159,8 +159,7 @@
344 }
345 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
346 // TODO: the running apps grid doesn't support standard scope results model yet
347- item.firstModel = Qt.binding(function() { return results.firstModel })
348- item.secondModel = Qt.binding(function() { return results.secondModel })
349+ item.model = Qt.binding(function() { return results.model })
350 item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })
351 } else {
352 item.model = Qt.binding(function() { return results })
353
354=== modified file 'qml/Shell.qml'
355--- qml/Shell.qml 2014-01-02 08:21:56 +0000
356+++ qml/Shell.qml 2014-01-22 10:43:18 +0000
357@@ -49,20 +49,22 @@
358 readonly property real panelHeight: panel.panelHeight
359
360 property bool dashShown: dash.shown
361- property bool stageScreenshotsReady: {
362- if (sideStage.shown) {
363- if (mainStage.applications.count > 0) {
364- return mainStage.usingScreenshots && sideStage.usingScreenshots;
365- } else {
366- return sideStage.usingScreenshots;
367- }
368+
369+ function activateApplication(appId) {
370+ if (ApplicationManager.findApplication(appId)) {
371+ print("Shell.qml: activating app", appId);
372+ ApplicationManager.activateApplication(appId);
373 } else {
374- return mainStage.usingScreenshots;
375+ print("starting app", appId);
376+
377+ // FIXME:
378+// var execFlags = sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
379+ var execFlags = ApplicationManager.ForceMainStage;
380+
381+ ApplicationManager.startApplication(appId, execFlags);
382 }
383 }
384
385- property var applicationManager: ApplicationManagerWrapper {}
386-
387 Binding {
388 target: LauncherModel
389 property: "applicationManager"
390@@ -71,49 +73,6 @@
391
392 Component.onCompleted: {
393 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
394-
395- applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
396-
397- // FIXME: if application focused before shell starts, shell draws on top of it only.
398- // We should detect already running applications on shell start and bring them to the front.
399- applicationManager.unfocusCurrentApplication();
400- }
401-
402- readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
403- || !!applicationManager.sideStageFocusedApplication
404- // Used for autopilot testing.
405- readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
406-
407- readonly property bool fullscreenMode: {
408- if (greeter.shown || lockscreen.shown) {
409- return false;
410- } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
411- return mainStage.switchingFromFullscreenToFullscreen;
412- } else if (applicationManager.mainStageFocusedApplication) {
413- return applicationManager.mainStageFocusedApplication.fullscreen;
414- } else {
415- return false;
416- }
417- }
418-
419- function activateApplication(appId, argument) {
420- if (applicationManager) {
421- // For newly started applications, as it takes them time to draw their first frame
422- // we add a delay before we hide the animation screenshots to compensate.
423- var addDelay = !applicationManager.getApplicationFromDesktopFile(appId);
424-
425- var application;
426- application = applicationManager.activateApplication(appId, argument);
427- if (application == null) {
428- return;
429- }
430- if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
431- mainStage.activateApplication(appId, addDelay);
432- } else {
433- sideStage.activateApplication(appId, addDelay);
434- }
435- stages.show();
436- }
437 }
438
439 GSettings {
440@@ -161,19 +120,19 @@
441 // Whether the underlay is fully covered by opaque UI elements.
442 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
443
444- readonly property bool applicationRunning: ((mainStage.applications && mainStage.applications.count > 0)
445- || (sideStage.applications && sideStage.applications.count > 0))
446+ readonly property bool applicationRunning: ApplicationManager.focusedApplicationId.length > 0
447+ onApplicationRunningChanged: print("***************+ application running", applicationRunning)
448
449 // Whether the user should see the topmost application surface (if there's one at all).
450- readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.fullyHidden
451- && !mainStage.usingScreenshots // but want sideStage animating over app surface
452-
453-
454-
455- // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
456+ readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.painting
457+
458+ // NB! Application surfaces are stacked behind the shell one. So they can only be seen by the user
459 // through the translucent parts of the shell surface.
460 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
461
462+ onVisibleChanged: print("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", visible, fullyCovered, applicationSurfaceShouldBeSeen,
463+ applicationRunning, stages.fullyHidden, stages.painting)
464+
465 CrossFadeImage {
466 id: backgroundImage
467 objectName: "backgroundImage"
468@@ -197,12 +156,6 @@
469 hides: [stages, launcher, panel.indicators]
470 shown: disappearingAnimationProgress !== 1.0
471 enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
472- // FIXME: unfocus all applications when going back to the dash
473- onEnabledChanged: {
474- if (enabled) {
475- shell.applicationManager.unfocusCurrentApplication()
476- }
477- }
478
479 anchors {
480 fill: parent
481@@ -233,8 +186,7 @@
482 x: launcher.progress
483 Behavior on x {SmoothedAnimation{velocity: 600}}
484
485- property real showProgress:
486- MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
487+ property real showProgress: MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
488
489 Showable {
490 id: stages
491@@ -244,6 +196,9 @@
492
493 property bool fullyShown: shown && x == 0 && parent.x == 0
494 property bool fullyHidden: !shown && x == width
495+
496+ property bool painting: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.painting : false
497+
498 available: !greeter.shown
499 hides: [panel.indicators]
500 shown: false
501@@ -254,128 +209,57 @@
502 width: parent.width
503 height: parent.height
504
505- // close the stages when no focused application remains
506- Connections {
507- target: shell.applicationManager
508- onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
509- onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
510- ignoreUnknownSignals: true
511- }
512-
513- function closeIfNoApplications() {
514- if (!shell.applicationManager.mainStageFocusedApplication
515- && !shell.applicationManager.sideStageFocusedApplication
516- && shell.applicationManager.mainStageApplications.count == 0
517- && shell.applicationManager.sideStageApplications.count == 0) {
518- stages.hide();
519- }
520- }
521-
522- // show the stages when an application gets the focus
523- Connections {
524- target: shell.applicationManager
525- onMainStageFocusedApplicationChanged: {
526- if (shell.applicationManager.mainStageFocusedApplication) {
527- mainStage.show();
528- stages.show();
529- }
530- }
531- onSideStageFocusedApplicationChanged: {
532- if (shell.applicationManager.sideStageFocusedApplication) {
533- sideStage.show();
534- stages.show();
535- }
536- }
537- ignoreUnknownSignals: true
538- }
539-
540- Stage {
541- id: mainStage
542-
543+ property string lastFocusedAppId
544+ onShownChanged: {
545+ print("stages shown", shown)
546+ if (shown) {
547+ if (!ApplicationManager.focusedApplicationId && lastFocusedAppId) {
548+ ApplicationManager.focusApplication(lastFocusedAppId);
549+ }
550+ } else {
551+ lastFocusedAppId = ApplicationManager.focusedApplicationId;
552+ ApplicationManager.unfocusCurrentApplication();
553+ }
554+ }
555+
556+ Connections {
557+ target: ApplicationManager
558+ onFocusedApplicationIdChanged: {
559+ if (ApplicationManager.focusedApplicationId.length > 0) {
560+ print("should show stages")
561+ stages.show();
562+ } else {
563+ stages.hide();
564+ }
565+ }
566+
567+ onApplicationAdded: {
568+ stages.show();
569+ }
570+ }
571+
572+ Loader {
573+ id: applicationsDisplayLoader
574 anchors.fill: parent
575- fullyShown: stages.fullyShown
576- fullyHidden: stages.fullyHidden
577- shouldUseScreenshots: !fullyShown
578- rightEdgeEnabled: !sideStage.enabled
579-
580- applicationManager: shell.applicationManager
581- rightEdgeDraggingAreaWidth: shell.edgeSize
582- normalApplicationY: shell.panelHeight
583-
584- shown: true
585- function show() {
586- stages.show();
587- }
588- function hide() {
589- }
590-
591- // FIXME: workaround the fact that focusing a main stage application
592- // raises its surface on top of all other surfaces including the ones
593- // that belong to side stage applications.
594- onFocusedApplicationChanged: {
595- if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
596- shell.applicationManager.focusApplication(sideStage.focusedApplication);
597- }
598- }
599- }
600-
601- SideStage {
602- id: sideStage
603-
604- applicationManager: shell.applicationManager
605- rightEdgeDraggingAreaWidth: shell.edgeSize
606- normalApplicationY: shell.panelHeight
607-
608- onShownChanged: {
609- if (!shown && mainStage.applications.count == 0) {
610- stages.hide();
611- }
612- }
613- // FIXME: when hiding the side stage, refocus the main stage
614- // application so that it goes in front of the side stage
615- // application and hides it
616- onFullyShownChanged: {
617- if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
618- shell.applicationManager.focusApplication(mainStage.focusedApplication);
619- }
620- }
621-
622- enabled: shell.width >= units.gu(60)
623- visible: enabled
624- fullyShown: stages.fullyShown && shown
625- && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
626- shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
627-
628- available: !greeter.shown && !lockscreen.shown && enabled
629- hides: [launcher, panel.indicators]
630- shown: false
631- showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
632- hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
633-
634- width: units.gu(40)
635- height: stages.height
636- handleExpanded: sideStageRevealer.pressed
637- }
638-
639- Revealer {
640- id: sideStageRevealer
641-
642- enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
643- && sideStage.available
644- direction: Qt.RightToLeft
645- openedValue: parent.width - sideStage.width
646- hintDisplacement: units.gu(3)
647- /* The size of the sidestage handle needs to be bigger than the
648- typical size used for edge detection otherwise it is really
649- hard to grab.
650- */
651- handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
652- closedValue: parent.width + sideStage.handleSizeCollapsed
653- target: sideStage
654- x: parent.width - width
655- width: sideStage.width + handleSize * 0.7
656- height: sideStage.height
657- orientation: Qt.Horizontal
658+
659+// source: "Stages/StageWithSideStage.qml"
660+ source: "Stages/PhoneStage.qml"
661+
662+ Binding {
663+ target: applicationsDisplayLoader.item
664+ property: "moving"
665+ value: !stages.fullyShown
666+ }
667+ Binding {
668+ target: applicationsDisplayLoader.item
669+ property: "shown"
670+ value: stages.shown
671+ }
672+ Binding {
673+ target: applicationsDisplayLoader.item
674+ property: "dragAreaWidth"
675+ value: shell.edgeSize
676+ }
677 }
678
679 DragHandle {
680@@ -388,7 +272,7 @@
681 width: shell.edgeSize
682 direction: Direction.Leftwards
683 enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled
684- property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
685+ property bool haveApps: ApplicationManager.count > 0
686
687 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
688 // Make autocompletion impossible when !haveApps
689@@ -473,23 +357,6 @@
690 property var previousMainApp: null
691 property var previousSideApp: null
692
693- function removeApplicationFocus() {
694- greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
695- greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
696- applicationManager.unfocusCurrentApplication();
697- }
698-
699- function restoreApplicationFocus() {
700- if (greeter.previousMainApp) {
701- applicationManager.focusApplication(greeter.previousMainApp);
702- greeter.previousMainApp = null;
703- }
704- if (greeter.previousSideApp) {
705- applicationManager.focusApplication(greeter.previousSideApp);
706- greeter.previousSideApp = null;
707- }
708- }
709-
710 onShownChanged: {
711 if (shown) {
712 lockscreen.reset();
713@@ -500,9 +367,6 @@
714 greeter.selected(0);
715 }
716 greeter.forceActiveFocus();
717- removeApplicationFocus();
718- } else {
719- restoreApplicationFocus();
720 }
721 }
722
723@@ -519,34 +383,11 @@
724 launcher.tease();
725 }
726 }
727-
728- Connections {
729- target: applicationManager
730- ignoreUnknownSignals: true
731- // If any app is focused when greeter is open, it's due to a user action
732- // like a snap decision (say, an incoming call).
733- // TODO: these should be protected to only unlock for certain applications / certain usecases
734- // potentially only in connection with a notification.
735- onMainStageFocusedApplicationChanged: {
736- if (greeter.shown && applicationManager.mainStageFocusedApplication) {
737- greeter.previousMainApp = null // make way for new focused app
738- greeter.previousSideApp = null
739- greeter.hide()
740- }
741- }
742- onSideStageFocusedApplicationChanged: {
743- if (greeter.shown && applicationManager.sideStageFocusedApplication) {
744- greeter.previousMainApp = null // make way for new focused app
745- greeter.previousSideApp = null
746- greeter.hide()
747- }
748- }
749- }
750 }
751
752 InputFilterArea {
753 anchors.fill: parent
754- blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
755+ blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
756 || panel.indicators.shown || hud.shown
757 }
758
759@@ -595,7 +436,9 @@
760 available: edgeDemo.panelEnabled
761 contentEnabled: edgeDemo.panelContentEnabled
762 }
763- fullscreenMode: shell.fullscreenMode
764+ property string focusedAppId: ApplicationManager.focusedApplicationId
765+ property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
766+ fullscreenMode: focusedApplication && focusedApplication.fullscreen && !greeter.shown && !lockscreen.shown
767 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown
768
769 InputFilterArea {
770@@ -621,9 +464,8 @@
771 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
772
773 Connections {
774- target: shell.applicationManager
775- onMainStageFocusedApplicationChanged: hud.hide()
776- onSideStageFocusedApplicationChanged: hud.hide()
777+ target: ApplicationManager
778+ onFocusedApplicationIdChanged: hud.hide()
779 }
780 }
781
782@@ -648,7 +490,7 @@
783 theHud: hud
784 anchors.fill: parent
785 enabled: hud.available
786- applicationIsOnForeground: applicationFocused
787+ applicationIsOnForeground: ApplicationManager.focusedApplicationId
788 }
789
790 InputFilterArea {
791@@ -774,14 +616,14 @@
792 anchors.bottom: parent.bottom
793 anchors.left: parent.left
794 anchors.right: parent.right
795- height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0
796+ height: ApplicationManager.keyboardVisible ? ApplicationManager.keyboardHeight : 0
797
798- enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
799+ enabled: ApplicationManager.keyboardVisible
800 }
801
802 Label {
803 anchors.centerIn: parent
804- visible: applicationManager.fake
805+ visible: ApplicationManager.fake ? ApplicationManager.fake : false
806 text: "EARLY ALPHA\nNOT READY FOR USE"
807 color: "lightgrey"
808 opacity: 0.2
809
810=== added directory 'qml/Stages'
811=== added file 'qml/Stages/PhoneStage.qml'
812--- qml/Stages/PhoneStage.qml 1970-01-01 00:00:00 +0000
813+++ qml/Stages/PhoneStage.qml 2014-01-22 10:43:18 +0000
814@@ -0,0 +1,574 @@
815+import QtQuick 2.0
816+import Ubuntu.Components 0.1
817+import Ubuntu.Gestures 0.1
818+import Unity.Application 0.1
819+import Utils 0.1
820+import "../Components"
821+
822+/*
823+
824+*/
825+
826+Item {
827+ id: root
828+
829+ // Controls to be set from outside
830+ property bool shown: false
831+ property bool moving: false
832+ property int dragAreaWidth
833+
834+ // State information propagated to the outside
835+ readonly property bool painting: mainScreenshotImage.visible || fadeInScreenshotImage.visible || appSplash.visible
836+ onPaintingChanged: print("**********************+ painting changed", painting)
837+
838+ onMovingChanged: {
839+ if (moving) {
840+ priv.requestNewScreenshot();
841+ } else {
842+ mainScreenshotImage.visible = false;
843+ }
844+ }
845+
846+ Connections {
847+ target: ApplicationManager
848+
849+ onFocusRequested: {
850+ priv.switchToApp(appId);
851+ }
852+
853+ onFocusedApplicationIdChanged: {
854+ if (ApplicationManager.focusedApplicationId.length > 0) {
855+ if (priv.secondApplicationStarting || priv.applicationStarting) {
856+ appSplashTimer.start();
857+ } else {
858+ mainScreenshotImage.src = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).screenshot
859+ }
860+ }
861+ }
862+
863+ onApplicationAdded: {
864+ if (!priv.focusedApplication) {
865+ mainScreenshotImage.src = "";
866+ mainScreenshotImage.visible = false;
867+ priv.applicationStarting = true;
868+ } else {
869+ mainScreenshotImage.src = "foobar";
870+ priv.newFocusedAppId = appId;
871+ priv.secondApplicationStarting = true;
872+ priv.requestNewScreenshot();
873+ }
874+ }
875+ }
876+
877+ QtObject {
878+ id: priv
879+
880+ property string focusedAppId: ApplicationManager.focusedApplicationId
881+ property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
882+ property url focusedScreenshot: focusedApplication ? focusedApplication.screenshot : ""
883+
884+ property bool waitingForScreenshot: false
885+
886+ property bool applicationStarting: false
887+ property bool secondApplicationStarting: false
888+
889+ property string newFocusedAppId
890+
891+ onFocusedScreenshotChanged: {
892+ if (root.moving && priv.waitingForScreenshot) {
893+ mainScreenshotImage.anchors.leftMargin = 0;
894+ mainScreenshotImage.src = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).screenshot;
895+ mainScreenshotImage.visible = true;
896+ } else if (priv.secondApplicationStarting && priv.waitingForScreenshot) {
897+ applicationSwitchingAnimation.start();
898+ }
899+ waitingForScreenshot = false;
900+ }
901+
902+ function requestNewScreenshot() {
903+ waitingForScreenshot = true;
904+ ApplicationManager.updateScreenshot(ApplicationManager.focusedApplicationId);
905+ }
906+
907+ function switchToApp(appId) {
908+ priv.newFocusedAppId = appId;
909+ applicationSwitchingAnimation.start();
910+ grantFocusTimer.start();
911+ }
912+
913+ }
914+
915+ // FIXME: the signal connection seems to get lost with the fake application manager.
916+ // Check with Qt 5.2, see if we can remove this Connections object
917+ Connections {
918+ target: priv.focusedApplication
919+ onScreenshotChanged: priv.focusedScreenshot = priv.focusedApplication.screenshot
920+ }
921+
922+ Timer {
923+ id: grantFocusTimer
924+ // Delay the actual switch to be covered by the animation for sure.
925+ // 1) If we switch before starting the animation, the Mir event loop paints before the Qt event loop => flickering
926+ // 2) If we do the switch after the animation, the panel wouldn't fade in early enough.
927+ interval: UbuntuAnimation.SlowDuration / 4
928+ repeat: false
929+ onTriggered: {
930+ ApplicationManager.focusApplication(priv.newFocusedAppId);
931+ }
932+ }
933+
934+ Timer {
935+ id: appSplashTimer
936+ // This is to show the splash screen a bit longer.
937+ // Mir signals us that the newly started app has gotten focus before it paints something on the screen
938+ // This would result in the old app surface becoming visible for a bit.
939+ // FIXME: change appManager to only change the focusedApplicationId when the surface is ready to be shown.
940+ interval: 1500
941+ repeat: false
942+ onTriggered: {
943+ priv.applicationStarting = false;
944+ priv.secondApplicationStarting = false;
945+ }
946+ }
947+
948+ SequentialAnimation {
949+ id: applicationSwitchingAnimation
950+ // setup
951+ PropertyAction { target: mainScreenshotImage; property: "anchors.leftMargin"; value: 0 }
952+ // PropertyAction seems to fail when secondApplicationStarting and we didn't have another screenshot before
953+ ScriptAction { script: mainScreenshotImage.src = priv.focusedScreenshot }
954+ PropertyAction { target: mainScreenshotImage; property: "visible"; value: true }
955+ PropertyAction { target: fadeInScreenshotImage; property: "source"; value: ApplicationManager.findApplication(priv.newFocusedAppId).screenshot }
956+ PropertyAction { target: fadeInScreenshotImage; property: "visible"; value: true }
957+ PropertyAction { target: fadeInScreenshotImage; property: "opacity"; value: 0 }
958+ PropertyAction { target: fadeInScreenshotImage; property: "scale"; value: .8 }
959+
960+
961+ // The actual animation
962+ ParallelAnimation {
963+ UbuntuNumberAnimation { target: mainScreenshotImage; property: "anchors.leftMargin"; to: root.width; duration: UbuntuAnimation.SlowDuration }
964+ UbuntuNumberAnimation { target: fadeInScreenshotImage; property: "opacity"; to: 1; duration: UbuntuAnimation.SlowDuration }
965+ UbuntuNumberAnimation { target: fadeInScreenshotImage; property: "scale"; to: 1; duration: UbuntuAnimation.SlowDuration }
966+ }
967+
968+ // restore stuff
969+ PropertyAction { target: fadeInScreenshotImage; property: "visible"; value: false }
970+ PropertyAction { target: mainScreenshotImage; property: "visible"; value: false }
971+ }
972+
973+ // FIXME: Drop this and make the imageprovider show a splashscreen instead
974+ Rectangle {
975+ id: appSplash2
976+ anchors.fill: parent
977+ color: "white"
978+ visible: priv.secondApplicationStarting
979+ }
980+ Image {
981+ id: fadeInScreenshotImage
982+ anchors { left: parent.left; bottom: parent.bottom }
983+ width: parent.width
984+ scale: .7
985+ visible: false
986+ }
987+
988+ Rectangle {
989+ id: appSplash
990+ anchors.fill: parent
991+ color: "white"
992+ visible: priv.applicationStarting
993+ }
994+ Image {
995+ id: mainScreenshotImage
996+ anchors { left: parent.left; bottom: parent.bottom }
997+ width: parent.width
998+
999+ property string src
1000+ source: src
1001+ visible: false
1002+ }
1003+
1004+ EdgeDragArea {
1005+ id: coverFlipDragArea
1006+ direction: Direction.Leftwards
1007+
1008+ //enabled: root.available
1009+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1010+ width: root.dragAreaWidth
1011+
1012+ onTouchXChanged: {
1013+ if (!dragging && !priv.waitingForScreenshot) {
1014+ priv.requestNewScreenshot();
1015+ }
1016+ if (dragging && !priv.waitingForScreenshot) {
1017+ coverFlickable.contentX = -touchX
1018+ }
1019+ }
1020+
1021+ onDraggingChanged: {
1022+ if (!dragging) {
1023+ coverFlip.snap();
1024+ }
1025+ }
1026+ }
1027+
1028+ Rectangle {
1029+ id: coverFlipBackground
1030+ anchors.fill: parent
1031+ color: "black"
1032+ visible: coverFlip.visible
1033+ }
1034+
1035+ InputFilterArea {
1036+ anchors.fill: root
1037+ blockInput: coverFlip.visible
1038+ }
1039+
1040+ Flickable {
1041+ id: coverFlickable
1042+ anchors.fill: root
1043+ contentHeight: height
1044+ contentWidth: width * 2 + ((ApplicationManager.count - 2) * root.width * coverFlip.tileDistance * 1.5)
1045+ flickableDirection: Qt.Horizontal
1046+ enabled: coverFlip.visible
1047+
1048+ property bool passedFirstStage: false
1049+
1050+ onContentXChanged: {
1051+ if (coverFlickable.passedFirstStage && contentX < width * coverFlip.progressMarker1) {
1052+ contentX = width * coverFlip.progressMarker1;
1053+ return;
1054+ }
1055+ var progress = contentX / width
1056+ if (progress > coverFlip.progressMarker1) {
1057+ coverFlickable.passedFirstStage = true;
1058+ }
1059+ coverFlip.progress = progress;
1060+ }
1061+
1062+ Row {
1063+ id: coverFlip
1064+ height: parent.height
1065+ // The MouseAreas on the AppImages need to be children of the flickable in order to make focus stealing
1066+ // for flicking vs. clicking work correctly.
1067+ // However, for the animation calculations to become easier we don't want the row to move so we don't
1068+ // always have to take contentX into account. So lets just compensate the flickable's movement here.
1069+ x: coverFlickable.contentX
1070+ visible: progress > 0
1071+
1072+ property real progress: 0
1073+ property real startAngle: 45
1074+ property int endAngle: 10
1075+
1076+ property real maxScale: 1.4
1077+ property real minScale: .6
1078+
1079+ // Markers: relative screen position from left to right
1080+ // marks the line where first application is finished moving in from the right
1081+ property real progressMarker1: 0.5
1082+
1083+ property real tileDistance: 0.1
1084+
1085+ property bool animatingBack: false
1086+
1087+ property real tileWidth: root.width
1088+
1089+ property real oldProgress: 0
1090+ onProgressChanged: {
1091+ if (coverFlipDragArea.dragging) {
1092+ if (oldProgress < coverFlip.progressMarker1 && progress >= coverFlip.progressMarker1) {
1093+ ApplicationManager.move(0, 1)
1094+ } else if (oldProgress >= coverFlip.progressMarker1 && progress < coverFlip.progressMarker1) {
1095+ ApplicationManager.move(0, 1)
1096+ }
1097+ }
1098+ oldProgress = progress;
1099+ }
1100+
1101+ function snap() {
1102+ if (coverFlip.progress < 0.25) {
1103+ snapAnimation.targetContentX = 0
1104+ snapAnimation.targetAppId = ApplicationManager.get(0).appId;
1105+ } else if (coverFlip.progress < coverFlip.progressMarker1) {
1106+ snapAnimation.targetContentX = root.width * coverFlip.progressMarker1
1107+ snapAnimation.targetAppId = ApplicationManager.get(1).appId;
1108+ } else if (coverFlip.progress < 0.6) {
1109+ snapAnimation.targetContentX = root.width * coverFlip.progressMarker1
1110+ snapAnimation.targetAppId = ApplicationManager.get(0).appId;
1111+ } else {
1112+ if (ApplicationManager.count == 3) {
1113+ snapAnimation.targetContentX = root.width * 1.1;
1114+ } else {
1115+ snapAnimation.targetContentX = root.width * 1.25;
1116+ }
1117+ snapAnimation.targetAppId = "";
1118+ }
1119+ snapAnimation.start();
1120+ }
1121+
1122+ function selectItem(index) {
1123+ tileRepeater.itemAt(index).select();
1124+ }
1125+
1126+ SequentialAnimation {
1127+ id: snapAnimation
1128+ property int targetContentX: 0
1129+ property string targetAppId
1130+
1131+ UbuntuNumberAnimation {
1132+ target: coverFlickable
1133+ properties: "contentX"
1134+ to: snapAnimation.targetContentX
1135+ duration: UbuntuAnimation.SnapDuration
1136+ }
1137+ ScriptAction {
1138+ script: {
1139+ if (snapAnimation.targetAppId) {
1140+ coverFlickable.passedFirstStage = false;
1141+ ApplicationManager.focusApplication(snapAnimation.targetAppId);
1142+ }
1143+ if (snapAnimation.targetContentX == root.width * coverFlip.progressMarker1) {
1144+ coverFlickable.contentX = 0;
1145+ }
1146+ }
1147+ }
1148+ }
1149+
1150+ Repeater {
1151+ id: tileRepeater
1152+ model: ApplicationManager
1153+
1154+ Item {
1155+ id: appItem
1156+ height: parent.height
1157+ width: coverFlip.tileWidth
1158+
1159+ // This is the main progress, of the gesture, the same for every tile
1160+ property real progress: coverFlip.progress
1161+ // The progress, translated for the second stage of the animation, after the first app switch has happened
1162+ // Additionally it speeds it up a bit, depending on the distance of the tile
1163+ property real translatedProgress: appItem.progress - coverFlip.progressMarker1 - (coverFlip.tileDistance * (index-1))
1164+
1165+ // Is this tile selected by a click?
1166+ property bool isSelected: false
1167+ // We need to remember some values when app is selected to be able to animate it to the foreground
1168+ property real selectedXTranslation: 0
1169+ property real selectedTranslatedProgress: 0
1170+ property real selectedProgress: 0
1171+ property real selectedAngle: 0
1172+ property real selectedXScale: 0
1173+
1174+ function select() {
1175+ appItem.selectedXTranslation = appItem.xTranslation;
1176+ appItem.selectedAngle = appItem.angle;
1177+ appItem.selectedXScale = appItem.xScale;
1178+ appItem.selectedTranslatedProgress = appItem.translatedProgress - coverFlip.progressMarker1;
1179+ appItem.selectedProgress = appItem.progress - coverFlip.progressMarker1;
1180+ appItem.isSelected = true;
1181+ switchToAppAnimation.targetContentX = coverFlip.progressMarker1 * root.width
1182+ switchToAppAnimation.start();
1183+ }
1184+
1185+ property int xTranslation: {
1186+ var xTranslate = 0;
1187+ var minXTranslate = -index * root.width + index * units.dp(3);
1188+ switch (index) {
1189+ case 0:
1190+ if (appItem.progress < coverFlip.progressMarker1) {
1191+ var progress = appItem.progress
1192+ var progressDiff = coverFlip.progressMarker1
1193+ var translateDiff = -root.width * 0.25
1194+ // progress : progressDiff = translate : translateDiff
1195+ xTranslate = progress * translateDiff / progressDiff
1196+ }
1197+ break;
1198+ case 1:
1199+ if (appItem.progress < coverFlip.progressMarker1) {
1200+ var progress = appItem.progress;
1201+ var progressDiff = coverFlip.progressMarker1;
1202+ var translateDiff = -root.width;
1203+ // progress : progressDiff = translate : translateDiff
1204+ xTranslate = progress * translateDiff / progressDiff;
1205+ break;
1206+ }
1207+ // Intentionally no break here...
1208+ default:
1209+ if (appItem.progress > coverFlip.progressMarker1) {
1210+ xTranslate = xTranslateEasing.value * xTranslateEasing.period;
1211+ if (appItem.isSelected) {
1212+ var translateDiff = root.width * index + appItem.selectedXTranslation
1213+ var progressDiff = appItem.selectedProgress
1214+ var progress = progressDiff - (appItem.progress - coverFlip.progressMarker1);
1215+ // progress : progressDiff = translate : translateDiff
1216+ var newTranslate = progress * translateDiff / progressDiff;
1217+
1218+ xTranslate = appItem.selectedXTranslation - newTranslate;
1219+ }
1220+ break;
1221+ }
1222+ }
1223+ return xTranslate;
1224+ }
1225+
1226+ property real angle: {
1227+ var newAngle = 0;
1228+ switch (index) {
1229+ case 0:
1230+ if (appItem.progress < coverFlip.progressMarker1) {
1231+ var progress = appItem.progress;
1232+ var angleDiff = coverFlip.endAngle;
1233+ var progressDiff = coverFlip.progressMarker1;
1234+ // progress : progressDiff = angle : angleDiff
1235+ newAngle = progress * angleDiff / progressDiff;
1236+ } else {
1237+ var progress = appItem.progress - coverFlip.progressMarker1;
1238+ var angleDiff = coverFlip.endAngle;
1239+ var progressDiff = 1 - coverFlip.progressMarker1;
1240+ // progress : progressDiff = angle : angleDiff
1241+ newAngle = progress * angleDiff / progressDiff;
1242+ newAngle = Math.min(coverFlip.endAngle, newAngle);
1243+ }
1244+ break;
1245+ case 1:
1246+ if (appItem.progress < coverFlip.progressMarker1) {
1247+ var progress = coverFlip.progress;
1248+ var angleDiff = coverFlip.startAngle;
1249+ var progressDiff = coverFlip.progressMarker1;
1250+ // progress : progressDiff = angle : angleDiff
1251+ var angle = progress * angleDiff / progressDiff;
1252+ newAngle = coverFlip.startAngle - angle;
1253+ break;
1254+ }
1255+ // Intentionally no break here...
1256+ default:
1257+ newAngle = coverFlip.startAngle - (angleEasing.value * angleEasing.period);
1258+ // make sure we stop at the left screen edge
1259+ newAngle = Math.max(newAngle, coverFlip.endAngle);
1260+
1261+ if (appItem.isSelected) {
1262+// var selectedAngleTranslate = selectedAngleEasing.value * selectedAngleEasing.period
1263+ var angleDiff = appItem.selectedAngle
1264+ var progressDiff = appItem.selectedProgress
1265+ var progress = progressDiff - (appItem.progress - coverFlip.progressMarker1);
1266+ // progress : progressDiff = angle : angleDiff
1267+ var selectedAngleTranslate = progress * angleDiff / progressDiff;
1268+
1269+ newAngle = appItem.selectedAngle - selectedAngleTranslate;
1270+ }
1271+ }
1272+ return newAngle;
1273+ }
1274+
1275+ property real xScale: {
1276+ var scale = 1;
1277+
1278+ switch (index) {
1279+ case 0:
1280+ if (appItem.progress > coverFlip.progressMarker1) {
1281+ var scaleDiff = coverFlip.maxScale - 1;
1282+ var progressDiff = 1.5 - coverFlip.progressMarker1;
1283+ // progress : progressDiff = scale : scaleDiff
1284+ scale = 1 - (appItem.progress - coverFlip.progressMarker1) * scaleDiff / progressDiff;
1285+ }
1286+ break;
1287+ case 1:
1288+ if (appItem.progress < coverFlip.progressMarker1) {
1289+ var scaleDiff = coverFlip.maxScale - 1
1290+ var progressDiff = coverFlip.progressMarker1
1291+ // progress : progressDiff = scale : scaleDiff
1292+ scale = coverFlip.maxScale - (appItem.progress * scaleDiff / progressDiff);
1293+ break;
1294+ }
1295+ // Intentionally no break
1296+ default:
1297+ scale = coverFlip.maxScale - scaleEasing.value * scaleEasing.period;
1298+ if (appItem.isSelected) {
1299+ var scaleDiff = -(1 - appItem.selectedXScale)
1300+ var progressDiff = appItem.selectedProgress
1301+ var progress = progressDiff - (appItem.progress - coverFlip.progressMarker1);
1302+ // progress : progressDiff = angle : angleDiff
1303+ var selectedScaleTranslate = progress * scaleDiff / progressDiff;
1304+
1305+ scale = appItem.selectedXScale - selectedScaleTranslate;
1306+ }
1307+ }
1308+ return Math.min(coverFlip.maxScale, Math.max(coverFlip.minScale, scale));
1309+ }
1310+
1311+ EasingCurve {
1312+ id: xTranslateEasing
1313+ type: EasingCurve.OutQuad
1314+ period: index * -width
1315+ progress: appItem.translatedProgress
1316+ }
1317+ EasingCurve {
1318+ id: angleEasing
1319+ type: EasingCurve.InQuad
1320+ period: coverFlip.startAngle - coverFlip.endAngle
1321+ progress: appItem.translatedProgress
1322+ }
1323+ EasingCurve {
1324+ id: scaleEasing
1325+ type: EasingCurve.Linear
1326+ period: coverFlip.maxScale - coverFlip.minScale
1327+ progress: appItem.translatedProgress
1328+ }
1329+
1330+ transform: [
1331+ Rotation {
1332+ origin { x: 0; y: coverFlip.height / 2 }
1333+ axis { x: 0; y: 1; z: 0 }
1334+ angle: appItem.angle
1335+ },
1336+ Translate {
1337+ x: appItem.xTranslation
1338+ },
1339+ Scale {
1340+ origin { x: appItem.xTranslation; y: root.height / 2 - (root.height - appImage.height)}
1341+ xScale: appItem.xScale
1342+ yScale: xScale
1343+ }
1344+ ]
1345+
1346+ Image {
1347+ id: dropShadow
1348+ anchors.fill: appImage
1349+ anchors.margins: -units.gu(2)
1350+ source: "graphics/dropshadow.png"
1351+ }
1352+ Image {
1353+ id: appImage
1354+ anchors { left: parent.left; bottom: parent.bottom }
1355+ width: root.width
1356+ source: ApplicationManager.get(index).screenshot
1357+ scale: 1
1358+ }
1359+ MouseArea {
1360+ anchors.fill: parent
1361+ onClicked: {
1362+ appItem.select()
1363+ }
1364+ }
1365+
1366+ SequentialAnimation {
1367+ id: switchToAppAnimation
1368+ property int targetContentX
1369+ UbuntuNumberAnimation {
1370+ target: coverFlickable;
1371+ property: "contentX";
1372+ to: switchToAppAnimation.targetContentX;
1373+ duration: UbuntuAnimation.SnapDuration
1374+ }
1375+ ScriptAction {
1376+ script: {
1377+ ApplicationManager.focusApplication(ApplicationManager.get(index).appId);
1378+ appItem.isSelected = false;
1379+ coverFlip.progress = 0;
1380+ coverFlickable.passedFirstStage = false;
1381+ }
1382+ }
1383+ }
1384+ }
1385+ }
1386+ }
1387+ }
1388+}
1389
1390=== added directory 'qml/Stages/graphics'
1391=== added file 'qml/Stages/graphics/dropshadow.png'
1392Binary files qml/Stages/graphics/dropshadow.png 1970-01-01 00:00:00 +0000 and qml/Stages/graphics/dropshadow.png 2014-01-22 10:43:18 +0000 differ
1393=== modified file 'run_on_device'
1394--- run_on_device 2013-11-27 11:47:14 +0000
1395+++ run_on_device 2014-01-22 10:43:18 +0000
1396@@ -103,6 +103,7 @@
1397 ARGS="$ARGS -k"
1398 fi
1399
1400+ exec_with_ssh "killall -9 dialer-app; killall -9 gallery-app; killall -9 messaging-app; killall -9 address-book-app"
1401 exec_with_ssh "stop unity8"
1402 exec_with_ssh "start maliit-server"
1403 exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
1404
1405=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
1406--- tests/mocks/Unity/Application/ApplicationInfo.h 2013-10-11 11:37:04 +0000
1407+++ tests/mocks/Unity/Application/ApplicationInfo.h 2014-01-22 10:43:18 +0000
1408@@ -19,6 +19,7 @@
1409
1410 #include <QObject>
1411 #include <QQmlComponent>
1412+#include <QDebug>
1413
1414 class QQuickItem;
1415
1416@@ -56,6 +57,7 @@
1417 { \
1418 if (m_##name != value) { \
1419 m_##name = value; \
1420+ qDebug() << "emitting changed" << this << Q_FUNC_INFO; \
1421 Q_EMIT name##Changed(); \
1422 } \
1423 } \
1424@@ -74,6 +76,7 @@
1425 IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool)
1426 IMPLEMENT_PROPERTY(imageQml, ImageQml, QString)
1427 IMPLEMENT_PROPERTY(windowQml, WindowQml, QString)
1428+ IMPLEMENT_PROPERTY(screenshot, Screenshot, QUrl)
1429
1430 #undef IMPLEMENT_PROPERTY
1431
1432
1433=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
1434--- tests/mocks/Unity/Application/ApplicationManager.cpp 2013-12-17 16:04:47 +0000
1435+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2014-01-22 10:43:18 +0000
1436@@ -24,6 +24,9 @@
1437 #include <QQuickItem>
1438 #include <QQuickView>
1439 #include <QQmlComponent>
1440+#include <QTimer>
1441+#include <QDateTime>
1442+#include <QDebug>
1443
1444 ApplicationManager::ApplicationManager(QObject *parent)
1445 : ApplicationManagerInterface(parent)
1446@@ -63,6 +66,8 @@
1447 return app->state();
1448 case RoleFocused:
1449 return app->focused();
1450+ case RoleScreenshot:
1451+ return app->screenshot();
1452 default:
1453 return QVariant();
1454 }
1455@@ -75,7 +80,9 @@
1456 }
1457
1458 ApplicationInfo *ApplicationManager::findApplication(const QString &appId) const {
1459+ qDebug() << "findapp called";
1460 for (ApplicationInfo *app : m_runningApplications) {
1461+ qDebug() << "searching app"<< app->appId();
1462 if (app->appId() == appId) {
1463 return app;
1464 }
1465@@ -84,8 +91,10 @@
1466 }
1467
1468 void ApplicationManager::add(ApplicationInfo *application) {
1469- if (!application)
1470+ qDebug() << "add() " << application->appId();
1471+ if (!application) {
1472 return;
1473+ }
1474
1475 beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size());
1476 m_runningApplications.append(application);
1477@@ -171,6 +180,8 @@
1478 }
1479 add(application);
1480
1481+ QMetaObject::invokeMethod(this, "focusApplication", Qt::QueuedConnection, Q_ARG(QString, appId));
1482+
1483 return application;
1484 }
1485
1486@@ -182,9 +193,33 @@
1487
1488 remove(application);
1489 Q_EMIT focusedApplicationIdChanged();
1490+ qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
1491 return true;
1492 }
1493
1494+void ApplicationManager::updateScreenshot(const QString &appId)
1495+{
1496+ int idx = -1;
1497+ ApplicationInfo *application = nullptr;
1498+ for (int i = 0; i < m_availableApplications.count(); ++i) {
1499+ application = m_availableApplications.at(i);
1500+ if (application->appId() == appId) {
1501+ idx = i;
1502+ break;
1503+ }
1504+ }
1505+
1506+ if (idx == -1) {
1507+ return;
1508+ }
1509+
1510+ qDebug() << "setting new screenshot" << application->screenshot() << application;
1511+ application->setScreenshot(QString("image://application/%1/%2").arg(appId).arg(QDateTime::currentMSecsSinceEpoch()));
1512+ qDebug() << "set new screenshot" << application->screenshot();
1513+ QModelIndex appIndex = index(idx);
1514+ Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleScreenshot);
1515+}
1516+
1517 QString ApplicationManager::focusedApplicationId() const {
1518 for (ApplicationInfo *app : m_runningApplications) {
1519 if (app->focused()) {
1520@@ -238,10 +273,16 @@
1521
1522 // move app to top of stack
1523 move(m_runningApplications.indexOf(application), 0);
1524+ qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
1525 Q_EMIT focusedApplicationIdChanged();
1526 return true;
1527 }
1528
1529+void ApplicationManager::activateApplication(const QString &appId)
1530+{
1531+ QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId));
1532+}
1533+
1534 void ApplicationManager::unfocusCurrentApplication()
1535 {
1536 for (ApplicationInfo *app : m_runningApplications) {
1537@@ -250,6 +291,7 @@
1538 app->setFocused(false);
1539 }
1540 }
1541+ qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
1542 Q_EMIT focusedApplicationIdChanged();
1543 }
1544
1545@@ -299,6 +341,7 @@
1546 application->setName("Phone");
1547 application->setIcon(QUrl("phone"));
1548 application->setStage(ApplicationInfo::SideStage);
1549+ application->setScreenshot(QString("image://application/%1/123456789").arg(application->appId()));
1550 generateQmlStrings(application);
1551 m_availableApplications.append(application);
1552
1553@@ -307,6 +350,7 @@
1554 application->setName("Camera");
1555 application->setIcon(QUrl("camera"));
1556 application->setFullscreen(true);
1557+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1558 generateQmlStrings(application);
1559 m_availableApplications.append(application);
1560
1561@@ -314,6 +358,7 @@
1562 application->setAppId("gallery-app");
1563 application->setName("Gallery");
1564 application->setIcon(QUrl("gallery"));
1565+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1566 generateQmlStrings(application);
1567 m_availableApplications.append(application);
1568
1569@@ -322,6 +367,7 @@
1570 application->setName("Facebook");
1571 application->setIcon(QUrl("facebook"));
1572 application->setStage(ApplicationInfo::SideStage);
1573+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1574 generateQmlStrings(application);
1575 m_availableApplications.append(application);
1576
1577@@ -329,6 +375,7 @@
1578 application->setAppId("webbrowser-app");
1579 application->setName("Browser");
1580 application->setIcon(QUrl("browser"));
1581+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1582 generateQmlStrings(application);
1583 m_availableApplications.append(application);
1584
1585@@ -337,6 +384,7 @@
1586 application->setName("Twitter");
1587 application->setIcon(QUrl("twitter"));
1588 application->setStage(ApplicationInfo::SideStage);
1589+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1590 generateQmlStrings(application);
1591 m_availableApplications.append(application);
1592
1593@@ -344,6 +392,7 @@
1594 application->setAppId("gmail-webapp");
1595 application->setName("GMail");
1596 application->setIcon(QUrl("gmail"));
1597+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1598 m_availableApplications.append(application);
1599
1600 application = new ApplicationInfo(this);
1601@@ -351,6 +400,7 @@
1602 application->setName("Weather");
1603 application->setIcon(QUrl("weather"));
1604 application->setStage(ApplicationInfo::SideStage);
1605+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1606 generateQmlStrings(application);
1607 m_availableApplications.append(application);
1608
1609@@ -359,6 +409,7 @@
1610 application->setName("Notepad");
1611 application->setIcon(QUrl("notepad"));
1612 application->setStage(ApplicationInfo::SideStage);
1613+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1614 m_availableApplications.append(application);
1615
1616 application = new ApplicationInfo(this);
1617@@ -366,6 +417,7 @@
1618 application->setName("Calendar");
1619 application->setIcon(QUrl("calendar"));
1620 application->setStage(ApplicationInfo::SideStage);
1621+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1622 m_availableApplications.append(application);
1623
1624 application = new ApplicationInfo(this);
1625@@ -373,18 +425,21 @@
1626 application->setName("Media Player");
1627 application->setIcon(QUrl("mediaplayer-app"));
1628 application->setFullscreen(true);
1629+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1630 m_availableApplications.append(application);
1631
1632 application = new ApplicationInfo(this);
1633 application->setAppId("evernote");
1634 application->setName("Evernote");
1635 application->setIcon(QUrl("evernote"));
1636+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1637 m_availableApplications.append(application);
1638
1639 application = new ApplicationInfo(this);
1640 application->setAppId("map");
1641 application->setName("Map");
1642 application->setIcon(QUrl("map"));
1643+ application->setScreenshot(QUrl("image://application/phone/123456789"));
1644 generateQmlStrings(application);
1645 m_availableApplications.append(application);
1646
1647
1648=== modified file 'tests/mocks/Unity/Application/ApplicationManager.h'
1649--- tests/mocks/Unity/Application/ApplicationManager.h 2013-10-11 11:37:04 +0000
1650+++ tests/mocks/Unity/Application/ApplicationManager.h 2014-01-22 10:43:18 +0000
1651@@ -88,10 +88,12 @@
1652
1653 // Application control methods
1654 Q_INVOKABLE bool focusApplication(const QString &appId) override;
1655+ Q_INVOKABLE void activateApplication(const QString &appId) override;
1656 Q_INVOKABLE void unfocusCurrentApplication() override;
1657 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
1658 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());
1659 Q_INVOKABLE bool stopApplication(const QString &appId) override;
1660+ Q_INVOKABLE void updateScreenshot(const QString &appId) override;
1661
1662 QString focusedApplicationId() const override;
1663
1664
1665=== added file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp'
1666--- tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 1970-01-01 00:00:00 +0000
1667+++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-01-22 10:43:18 +0000
1668@@ -0,0 +1,69 @@
1669+/*
1670+ * Copyright (C) 2013 Canonical, Ltd.
1671+ *
1672+ * This program is free software: you can redistribute it and/or modify it under
1673+ * the terms of the GNU Lesser General Public License version 3, as published by
1674+ * the Free Software Foundation.
1675+ *
1676+ * This program is distributed in the hope that it will be useful, but WITHOUT
1677+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1678+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1679+ * Lesser General Public License for more details.
1680+ *
1681+ * You should have received a copy of the GNU Lesser General Public License
1682+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1683+ */
1684+
1685+#include "ApplicationScreenshotProvider.h"
1686+#include "ApplicationManager.h"
1687+#include "ApplicationInfo.h"
1688+
1689+#include "paths.h"
1690+
1691+#include <QDebug>
1692+#include <QGuiApplication>
1693+#include <QWindow>
1694+#include <QQuickWindow>
1695+
1696+ApplicationScreenshotProvider::ApplicationScreenshotProvider(ApplicationManager *appManager)
1697+ : QQuickImageProvider(QQuickImageProvider::Image)
1698+ , m_appManager(appManager)
1699+{
1700+}
1701+
1702+QImage ApplicationScreenshotProvider::requestImage(const QString &imageId, QSize * size,
1703+ const QSize &requestedSize)
1704+{
1705+ // We ignore requestedSize here intentionally to avoid keeping scaled copies around
1706+ Q_UNUSED(requestedSize)
1707+
1708+ QString appId = imageId.split('/').first();
1709+
1710+ ApplicationInfo* app = static_cast<ApplicationInfo*>(m_appManager->findApplication(appId));
1711+ if (app == NULL) {
1712+ qDebug() << "ApplicationScreenshotProvider - app not found:" << appId;
1713+ return QImage();
1714+ }
1715+
1716+ QString filePath = QString("%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()).arg(app->icon().toString());
1717+
1718+ QImage image;
1719+ if (!image.load(filePath)) {
1720+ qDebug() << "failed loading app image" << filePath;
1721+ }
1722+
1723+ QGuiApplication *unity = qobject_cast<QGuiApplication*>(qApp);
1724+
1725+ Q_FOREACH (QWindow *win, unity->allWindows()) {
1726+ QQuickWindow *quickWin = qobject_cast<QQuickWindow*>(win);
1727+ if (quickWin) {
1728+ image = image.scaledToWidth(quickWin->width());
1729+ }
1730+ }
1731+
1732+ size->setWidth(image.width());
1733+ size->setHeight(image.height());
1734+ qDebug() << "got image of size" << size->width() << size->height() << requestedSize;
1735+
1736+ return image;
1737+}
1738
1739=== added file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.h'
1740--- tests/mocks/Unity/Application/ApplicationScreenshotProvider.h 1970-01-01 00:00:00 +0000
1741+++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.h 2014-01-22 10:43:18 +0000
1742@@ -0,0 +1,34 @@
1743+/*
1744+ * Copyright (C) 2013 Canonical, Ltd.
1745+ *
1746+ * This program is free software: you can redistribute it and/or modify it under
1747+ * the terms of the GNU Lesser General Public License version 3, as published by
1748+ * the Free Software Foundation.
1749+ *
1750+ * This program is distributed in the hope that it will be useful, but WITHOUT
1751+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1752+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1753+ * Lesser General Public License for more details.
1754+ *
1755+ * You should have received a copy of the GNU Lesser General Public License
1756+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1757+ */
1758+
1759+#ifndef APPLICATIONSCREENSHOTPROVIDER_H
1760+#define APPLICATIONSCREENSHOTPROVIDER_H
1761+
1762+#include <QQuickImageProvider>
1763+
1764+class ApplicationManager;
1765+class ApplicationScreenshotProvider : public QQuickImageProvider
1766+{
1767+public:
1768+ explicit ApplicationScreenshotProvider(ApplicationManager *appManager);
1769+
1770+ QImage requestImage(const QString &appId, QSize *size, const QSize &requestedSize) override;
1771+
1772+private:
1773+ ApplicationManager* m_appManager;
1774+};
1775+
1776+#endif // APPLICATIONSCREENSHOTPROVIDER_H
1777
1778=== modified file 'tests/mocks/Unity/Application/CMakeLists.txt'
1779--- tests/mocks/Unity/Application/CMakeLists.txt 2013-12-13 01:02:53 +0000
1780+++ tests/mocks/Unity/Application/CMakeLists.txt 2014-01-22 10:43:18 +0000
1781@@ -5,6 +5,7 @@
1782 ApplicationInfo.cpp
1783 ApplicationImage.cpp
1784 ApplicationManager.cpp
1785+ ApplicationScreenshotProvider.cpp
1786 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
1787 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
1788 )
1789
1790=== modified file 'tests/mocks/Unity/Application/plugin.cpp'
1791--- tests/mocks/Unity/Application/plugin.cpp 2013-09-11 15:33:02 +0000
1792+++ tests/mocks/Unity/Application/plugin.cpp 2014-01-22 10:43:18 +0000
1793@@ -18,13 +18,20 @@
1794 #include "ApplicationInfo.h"
1795 #include "ApplicationImage.h"
1796 #include "ApplicationManager.h"
1797+#include "ApplicationScreenshotProvider.h"
1798
1799 #include <qqml.h>
1800+#include <QQmlEngine>
1801+
1802+ApplicationManager *s_appManager = 0;
1803
1804 static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
1805- Q_UNUSED(engine);
1806- Q_UNUSED(scriptEngine);
1807- return new ApplicationManager();
1808+ Q_UNUSED(engine);
1809+ Q_UNUSED(scriptEngine);
1810+ if (!s_appManager) {
1811+ s_appManager = new ApplicationManager();
1812+ }
1813+ return s_appManager;
1814 }
1815
1816 void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
1817@@ -37,3 +44,11 @@
1818
1819 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
1820 }
1821+
1822+void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
1823+{
1824+ QQmlExtensionPlugin::initializeEngine(engine, uri);
1825+
1826+ ApplicationManager* appManager = static_cast<ApplicationManager*>(applicationManagerSingleton(engine, NULL));
1827+ engine->addImageProvider(QLatin1String("application"), new ApplicationScreenshotProvider(appManager));
1828+}
1829
1830=== modified file 'tests/mocks/Unity/Application/plugin.h'
1831--- tests/mocks/Unity/Application/plugin.h 2013-09-04 13:42:27 +0000
1832+++ tests/mocks/Unity/Application/plugin.h 2014-01-22 10:43:18 +0000
1833@@ -25,6 +25,7 @@
1834 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
1835 public:
1836 void registerTypes(const char *uri);
1837+ void initializeEngine(QQmlEngine *engine, const char *uri);
1838 };
1839
1840 #endif
1841
1842=== modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp'
1843--- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2013-09-16 17:59:13 +0000
1844+++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-01-22 10:43:18 +0000
1845@@ -39,6 +39,7 @@
1846 ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; }
1847 ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; }
1848 bool focused() const { return m_focused; }
1849+ QUrl screenshot() const { return QUrl(); }
1850
1851 // Methods used for mocking (not in the interface)
1852 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
1853@@ -92,6 +93,8 @@
1854 m_list.takeAt(index)->deleteLater();
1855 endRemoveRows();
1856 }
1857+ void updateScreenshot(const QString &appId) { Q_UNUSED(appId); }
1858+ void activateApplication(const QString &appId) { Q_UNUSED(appId); }
1859
1860 private:
1861 QList<MockApp*> m_list;
1862
1863=== modified file 'tests/qmltests/tst_Shell.qml'
1864--- tests/qmltests/tst_Shell.qml 2014-01-16 12:37:57 +0000
1865+++ tests/qmltests/tst_Shell.qml 2014-01-22 10:43:18 +0000
1866@@ -117,6 +117,7 @@
1867 while (apps.count > 0) {
1868 ApplicationManager.stopApplication(apps.get(0).appId);
1869 }
1870+ compare(ApplicationManager.count, 0)
1871 }
1872
1873 /*
1874@@ -182,28 +183,34 @@
1875 function test_suspend() {
1876 var greeter = findChild(shell, "greeter");
1877
1878+ print("step1")
1879 // Launch an app from the launcher
1880 dragLauncherIntoView();
1881 tapOnAppIconInLauncher();
1882 waitUntilApplicationWindowIsFullyVisible();
1883
1884+ print("step2")
1885 var mainApp = ApplicationManager.focusedApplicationId;
1886 verify(mainApp != "");
1887
1888+ print("step3")
1889 // Try to suspend while proximity is engaged...
1890 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
1891 tryCompare(greeter, "showProgress", 0);
1892
1893+ print("step4")
1894 // Now really suspend
1895 Powerd.displayPowerStateChange(Powerd.Off, 0);
1896 tryCompare(greeter, "showProgress", 1);
1897 tryCompare(ApplicationManager, "focusedApplicationId", "");
1898
1899+ print("step5")
1900 // And wake up
1901 Powerd.displayPowerStateChange(Powerd.On, 0);
1902 tryCompare(ApplicationManager, "focusedApplicationId", "");
1903 tryCompare(greeter, "showProgress", 1);
1904
1905+ print("step6")
1906 // Swipe away greeter to focus app
1907 swipeAwayGreeter();
1908 tryCompare(ApplicationManager, "focusedApplicationId", mainApp);
1909@@ -503,6 +510,8 @@
1910
1911 function test_DashShown(data) {
1912
1913+ print("step1")
1914+ // greeter: false,
1915 if (data.greeter) {
1916 // Swipe the greeter in
1917 var greeter = findChild(shell, "greeter");
1918@@ -510,21 +519,31 @@
1919 tryCompare(greeter, "showProgress", 1);
1920 }
1921
1922+ print("step2")
1923+ //app: false,
1924 if (data.app) {
1925 dragLauncherIntoView();
1926 tapOnAppIconInLauncher();
1927 }
1928
1929+ print("step3")
1930+ // launcher: true,
1931 if (data.launcher) {
1932 dragLauncherIntoView();
1933 }
1934
1935+ print("step4")
1936+ // indicators: false,
1937 if (data.indicators) {
1938 showIndicators();
1939 }
1940
1941+ print("step5")
1942+ //expectedShown: true},
1943 var dash = findChild(shell, "dash");
1944+ print("step6", dash, dash.shown, data.expectedShown)
1945 tryCompare(dash, "shown", data.expectedShown);
1946+ print("step7")
1947 }
1948
1949 function test_searchIndicatorHidesOnAppFocus() {

Subscribers

People subscribed via source and target branches