Merge lp:~dandrader/unity8/app-state-handling into lp:unity8

Proposed by Daniel d'Andrada
Status: Merged
Approved by: Albert Astals Cid
Approved revision: 1829
Merged at revision: 1901
Proposed branch: lp:~dandrader/unity8/app-state-handling
Merge into: lp:unity8
Prerequisite: lp:~dandrader/unity8/autoInstallTouchRegistry
Diff against target: 1115 lines (+468/-121)
22 files modified
CMakeLists.txt (+1/-1)
debian/control (+1/-1)
plugins/Greeter/Unity/Launcher/CMakeLists.txt (+0/-1)
plugins/Unity/Launcher/CMakeLists.txt (+0/-1)
qml/Components/Unity8Settings.qml (+50/-0)
qml/OrientedShell.qml (+3/-3)
qml/Shell.qml (+10/-12)
qml/Stages/DesktopStage.qml (+13/-0)
qml/Stages/PhoneStage.qml (+10/-0)
qml/Stages/TabletStage.qml (+14/-0)
tests/mocks/Unity/Application/ApplicationInfo.cpp (+40/-6)
tests/mocks/Unity/Application/ApplicationInfo.h (+7/-0)
tests/mocks/Unity/Application/ApplicationManager.cpp (+2/-49)
tests/mocks/Unity/Application/ApplicationManager.h (+0/-7)
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt (+0/-1)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+3/-4)
tests/qmltests/Stages/ApplicationCheckBox.qml (+21/-0)
tests/qmltests/Stages/tst_DesktopStage.qml (+2/-2)
tests/qmltests/Stages/tst_PhoneStage.qml (+75/-3)
tests/qmltests/Stages/tst_TabletStage.qml (+161/-1)
tests/qmltests/tst_OrientedShell.qml (+3/-3)
tests/qmltests/tst_Shell.qml (+52/-26)
To merge this branch: bzr merge lp:~dandrader/unity8/app-state-handling
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Abstain
PS Jenkins bot (community) continuous-integration Needs Fixing
Gerry Boland (community) Approve
Review via email: mp+258653@code.launchpad.net

Commit message

Stages now control the "requestedState" property of applications

We now decide whether a application is suspended or not via the new Application.requestedState property.

Previously that was controlled by qtmir and tied to Application.focus. We don't want that anymore since it does not apply to a windowed usage mode scenario, for instance.

Description of the change

This branch contains lp:~dandrader/unity8/fixOrientedShellTests and lp:~dandrader/unity8/fixShellTests since I cannot set multiple prerequisites

* Are there any related MPs required for this MP to build/function as expected? Please list.
https://code.launchpad.net/~dandrader/unity-api/app-state-handling/+merge/258643
https://code.launchpad.net/~dandrader/qtmir/detach-state-from-focus/+merge/258648

This also has https://code.launchpad.net/~nick-dedekind/unity8/desktop-app-focus/+merge/256287 as prerequisite (in addition to lp:~dandrader/unity8/autoInstallTouchRegistry) but launchpad doesn't allow multiple prerequisites. So launchpad's diff will show more than the changes from this branch.

* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

* Did you make sure that your branch does not contain spurious tags?
Yes

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable

* If you changed the UI, has there been a design review?
Not applicable

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in plugins/Ubuntu/Gestures/TouchGate.cpp
Text conflict in plugins/Ubuntu/Gestures/TouchGate.h
2 conflicts encountered.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Text conflict in plugins/Ubuntu/Gestures/TouchGate.cpp
> Text conflict in plugins/Ubuntu/Gestures/TouchGate.h
> 2 conflicts encountered.

Fixed.

Revision history for this message
Gerry Boland (gerboland) wrote :

Please update commit message to refer to "requestedState" instead of the old "active" application property.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Please update commit message to refer to "requestedState" instead of the old
> "active" application property.

Done.

Revision history for this message
Gerry Boland (gerboland) wrote :

Bug:
via launcher, rapidly launch camera, webbrowser and contacts. When contacts finally appears, open spread: camera app is showing live preview, it should be suspended. Browser is also running. If you return to dash, the wakelock is not released (as other apps considered "running"

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :

Bug: open camera app. Then open gallery. Tap the camera icon in the Gallery header. It should cause focus to switch to the camera app, but actually nothing happens

Revision history for this message
Gerry Boland (gerboland) wrote :

Bug (probably same as above, but reporting for completeness), if Settings app running, another app open and focused, open indicators and select "Battery Settings" menu option - nothing happens. Indicators should close and Settings app brought to front.

Revision history for this message
Gerry Boland (gerboland) wrote :

Bug: open system settings. Switch to dash. Via ssh, kill the system-settings process. Then switch to the system settings app in unity8. It should cause the process to be respawned, but it appears to do nothing.

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :

Bug: launch camera, then immediately hit the power key to turn off the display. Camera app is not suspended. Wakelock is held.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 13/05/15 12:45, Gerry Boland wrote:
> Review: Needs Fixing
>
> Bug:
> via launcher, rapidly launch camera, webbrowser and contacts. When contacts finally appears, open spread: camera app is showing live preview, it should be suspended. Browser is also running. If you return to dash, the wakelock is not released (as other apps considered "running"
unity8 logic is sound and working fine in that case. Problem lies in
qtmir. Just realized how messy the relationship between application
state, session state and surface creation is. Man, this is going to take
some refactoring...

Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in tests/plugins/Unity/Launcher/launchermodeltest.cpp
Text conflict in tests/qmltests/tst_Shell.qml
2 conflicts encountered.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 21/05/2015 09:04, Albert Astals Cid wrote:
> Text conflict in tests/plugins/Unity/Launcher/launchermodeltest.cpp
> Text conflict in tests/qmltests/tst_Shell.qml
> 2 conflicts encountered.
>

Fixed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 13/05/15 12:45, Gerry Boland wrote:
> Review: Needs Fixing
>
> Bug:
> via launcher, rapidly launch camera, webbrowser and contacts. When contacts finally appears, open spread: camera app is showing live preview, it should be suspended. Browser is also running. If you return to dash, the wakelock is not released (as other apps considered "running"
Fixed.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 13/05/15 12:49, Gerry Boland wrote:
> Bug: open camera app. Then open gallery. Tap the camera icon in the Gallery header. It should cause focus to switch to the camera app, but actually nothing happens
Fixed in qtmir.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 13/05/15 13:11, Gerry Boland wrote:
> Bug (probably same as above, but reporting for completeness), if Settings app running, another app open and focused, open indicators and select "Battery Settings" menu option - nothing happens. Indicators should close and Settings app brought to front.
It is. Fixed in qtmir.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 13/05/15 13:16, Gerry Boland wrote:
> Review: Needs Fixing
>
> Bug: open system settings. Switch to dash. Via ssh, kill the system-settings process. Then switch to the system settings app in unity8. It should cause the process to be respawned, but it appears to do nothing.
Fixed.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 13/05/15 13:21, Gerry Boland wrote:
> Bug: launch camera, then immediately hit the power key to turn off the display. Camera app is not suspended. Wakelock is held.
Fixed.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 27/05/15 18:15, Daniel d'Andrada wrote:
> On 13/05/15 12:45, Gerry Boland wrote:
>> Review: Needs Fixing
>>
>> Bug:
>> via launcher, rapidly launch camera, webbrowser and contacts. When contacts finally appears, open spread: camera app is showing live preview, it should be suspended. Browser is also running. If you return to dash, the wakelock is not released (as other apps considered "running"
> Fixed.
>
Fixed in qtmir, to be more clear.

Revision history for this message
Gerry Boland (gerboland) wrote :

Pass 2 testing. Things much improved! Am still testing, but found this small issue:

Start dialer-app, let it load. Switch to Dash. Wait until dialer-app suspended. Kill it from command line. Then open spread and select Dialer app. There is a nasty flicker between the old snapshot disappearing & the resumed app's first frame.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 29/05/15 19:29, Gerry Boland wrote:
> Review: Needs Fixing
>
> Pass 2 testing. Things much improved! Am still testing, but found this small issue:
>
> Start dialer-app, let it load. Switch to Dash. Wait until dialer-app suspended. Kill it from command line. Then open spread and select Dialer app. There is a nasty flicker between the old snapshot disappearing & the resumed app's first frame.
>
>
Fixed in qtmir.

The flicker is the whole SpreadDelegate disappearing for a split second.
After spending 1.5 workdays on it I still don't know exactly how or why
it was happening. But at least I found that a simple and harmless change
in qtmir makes it go away (deferring respawning of the app to the next
event loop by using a queued connection instead of a direct one).

It was also pretty curious that a short right-edge swipe didn't exhibit
this issue.

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Added a clarification/comment on the current GSettingsQt situation

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Added a clarification/comment on the current GSettingsQt situation

Updated the FIXME comment. Thanks.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in tests/qmltests/tst_Shell.qml
1 conflicts encountered.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 23/06/15 04:34, Albert Astals Cid wrote:
> Text conflict in tests/qmltests/tst_Shell.qml
> 1 conflicts encountered.

Fixed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Looking good on desktop

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :

Ok, tested on phone, tablet & desktop. Unable to find any regression, nice one.

review: Approve (functional)
Revision history for this message
Gerry Boland (gerboland) wrote :

I can't fault the code. Functional testing works well. AP tests pass here. Approve!

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Y
 * Did CI run pass? If not, please explain why.
Depends on qtmir/unity-api change
 * Did you make sure that the branch does not contain spurious tags?
Y

review: Approve
Revision history for this message
Albert Astals Cid (aacid) wrote :

Setting as needs fixing because of
  Text conflict in qml/OrientedShell.qml
  Text conflict in tests/qmltests/tst_OrientedShell.qml
  2 conflicts encountered.

Should top-approve again once re-merged

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 06/07/15 04:20, Albert Astals Cid wrote:
> Review: Needs Fixing
>
> Setting as needs fixing because of
> Text conflict in qml/OrientedShell.qml
> Text conflict in tests/qmltests/tst_OrientedShell.qml
> 2 conflicts encountered.
>
> Should top-approve again once re-merged

Fixed.

Revision history for this message
Gerry Boland (gerboland) wrote :

Need to depend on unity-api 7.98

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Need to depend on unity-api 7.98

Done.

Revision history for this message
Gerry Boland (gerboland) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Please merge trunk, some conflicts have appeared

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :

My fault, merges ok

review: Approve
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in plugins/Greeter/Unity/Launcher/CMakeLists.txt
Text conflict in plugins/Unity/Launcher/CMakeLists.txt
Text conflict in qml/Shell.qml
Text conflict in qml/Stages/DesktopStage.qml
Text conflict in tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt
Text conflict in tests/qmltests/tst_Shell.qml

Was top approved before

review: Needs Fixing
1827. By Daniel d'Andrada

Merge trunk

[ CI Train Bot ]
* Resync trunk.
* allow opening the manage dash area by clicking with a mouse on the
  arrow label (LP: #1431564)
* TouchRegistry: remove null candidates from list of candidates (LP:
  #1473492)
[ Lukáš Tinkl ]
* Fix power dialogs on desktop
* Provide DBUS compatibility with various session services
  (suspend/hibernate, lock/unlock, screensaver, etc)
* React on PrtScr keyboard shortcut for taking screenshots on desktop
  (LP: #1474149)
* launcher parity: close apps from quicklist (LP: #1457201)
[ Michael Zanetti ]
* Implement first edition for a desktop Alt+Tab spread
* drop the gcc-4.9 dependency (LP: #1452348)
[ Mirco Müller ]
* Added corresponding tests and visual tweaks to a launcher-item's
  progress-overlay.
* Added corresponding tests and visual tweaks to a launcher-item's
  progress-overlay.
* Implemented alert/wiggle feature for launcher-icons.
* Implemented alert/wiggle feature for launcher-icons.
[ handsome_feng ]
* makes left swip reset the search string. (LP: #1413791)
[ handsome_feng<email address hidden> ]
* Don't expand indicators when tap to return to call. (LP: #1453217)
* makes left swip reset the search string. (LP: #1413791)

1828. By Daniel d'Andrada

Remove stuff

1829. By Daniel d'Andrada

Update debian/control

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 03/08/15 10:20, Albert Astals Cid wrote:
> Review: Needs Fixing
>
> Text conflict in plugins/Greeter/Unity/Launcher/CMakeLists.txt
> Text conflict in plugins/Unity/Launcher/CMakeLists.txt
> Text conflict in qml/Shell.qml
> Text conflict in qml/Stages/DesktopStage.qml
> Text conflict in tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt
> Text conflict in tests/qmltests/tst_Shell.qml
>
> Was top approved before

Fixed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) :
review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2015-06-17 12:14:27 +0000
+++ CMakeLists.txt 2015-08-03 14:21:12 +0000
@@ -56,7 +56,7 @@
56find_package(Qt5Concurrent 5.2 REQUIRED)56find_package(Qt5Concurrent 5.2 REQUIRED)
57find_package(Qt5Sql 5.2 REQUIRED)57find_package(Qt5Sql 5.2 REQUIRED)
5858
59pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)59pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=7)
6060
61# Standard install paths61# Standard install paths
62include(GNUInstallDirs)62include(GNUInstallDirs)
6363
=== modified file 'debian/control'
--- debian/control 2015-07-29 12:38:53 +0000
+++ debian/control 2015-08-03 14:21:12 +0000
@@ -28,7 +28,7 @@
28 libqt5xmlpatterns5-dev,28 libqt5xmlpatterns5-dev,
29 libsystemsettings-dev,29 libsystemsettings-dev,
30 libudev-dev,30 libudev-dev,
31 libunity-api-dev (>= 7.98),31 libunity-api-dev (>= 7.99),
32 libusermetricsoutput1-dev,32 libusermetricsoutput1-dev,
33 libxcb1-dev,33 libxcb1-dev,
34 pkg-config,34 pkg-config,
3535
=== modified file 'plugins/Greeter/Unity/Launcher/CMakeLists.txt'
--- plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-07-23 10:31:56 +0000
+++ plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-08-03 14:21:12 +0000
@@ -1,5 +1,4 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
43
5add_definitions(-DSM_BUSNAME=systemBus)4add_definitions(-DSM_BUSNAME=systemBus)
65
=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
--- plugins/Unity/Launcher/CMakeLists.txt 2015-07-23 10:31:56 +0000
+++ plugins/Unity/Launcher/CMakeLists.txt 2015-08-03 14:21:12 +0000
@@ -1,5 +1,4 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
43
5add_definitions(-DSM_BUSNAME=systemBus)4add_definitions(-DSM_BUSNAME=systemBus)
65
=== added file 'qml/Components/Unity8Settings.qml'
--- qml/Components/Unity8Settings.qml 1970-01-01 00:00:00 +0000
+++ qml/Components/Unity8Settings.qml 2015-08-03 14:21:12 +0000
@@ -0,0 +1,50 @@
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
17import QtQuick 2.0
18import GSettings 1.0
19
20QtObject {
21 id: root
22
23 property string usageMode: "Staged"
24
25 // FIXME: Works around a bug where if we change a Loader's source in response to a GSettings
26 // property change in the same event loop, the Loader's previously loaded component does not
27 // get destroyed and its bindings continue to operate!
28 //
29 // Shouldn't be needed after
30 // https://code.launchpad.net/~lukas-kde/gsettings-qt/queued-processing/+merge/259883 gets
31 // merged.
32 property var timer: Timer {
33 interval: 1
34 onTriggered: { root.usageMode = root.wrapped.usageMode; }
35 }
36 property var wrappedConnections: Connections {
37 target: root.wrapped
38 ignoreUnknownSignals: true // don't spam us
39 onUsageModeChanged: { root.timer.start(); }
40 }
41 property var wrapped: GSettings {
42 schema.id: "com.canonical.Unity8"
43 Component.onCompleted: {
44 // init the value. it's a dynamic prop, so we have to check first
45 if (root.usageMode) {
46 root.usageMode = root.wrapped.usageMode;
47 }
48 }
49 }
50}
051
=== modified file 'qml/OrientedShell.qml'
--- qml/OrientedShell.qml 2015-07-01 17:52:34 +0000
+++ qml/OrientedShell.qml 2015-08-03 14:21:12 +0000
@@ -43,7 +43,7 @@
4343
4444
45 // to be overwritten by tests45 // to be overwritten by tests
46 property var usageModeSettings: GSettings { schema.id: "com.canonical.Unity8" }46 property var unity8Settings: Unity8Settings {}
47 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }47 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
4848
49 property int physicalOrientation: Screen.orientation49 property int physicalOrientation: Screen.orientation
@@ -160,9 +160,9 @@
160 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),160 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
161 // what's the output device (eg: big TV, desktop monitor, phone display), etc.161 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
162 usageScenario: {162 usageScenario: {
163 if (root.usageModeSettings.usageMode === "Windowed") {163 if (root.unity8Settings.usageMode === "Windowed") {
164 return "desktop";164 return "desktop";
165 } else if (root.usageModeSettings.usageMode === "Staged") {165 } else if (root.unity8Settings.usageMode === "Staged") {
166 if (deviceConfiguration.category === "phone") {166 if (deviceConfiguration.category === "phone") {
167 return "phone";167 return "phone";
168 } else {168 } else {
169169
=== modified file 'qml/Shell.qml'
--- qml/Shell.qml 2015-07-29 12:38:53 +0000
+++ qml/Shell.qml 2015-08-03 14:21:12 +0000
@@ -191,12 +191,6 @@
191 z: dialogs.z + 10191 z: dialogs.z + 10
192 }192 }
193193
194 Binding {
195 target: ApplicationManager
196 property: "forceDashActive"
197 value: launcher.shown || launcher.dashSwipe
198 }
199
200 WindowKeysFilter {194 WindowKeysFilter {
201 Keys.onPressed: physicalKeysMapper.onKeyPressed(event);195 Keys.onPressed: physicalKeysMapper.onKeyPressed(event);
202 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);196 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
@@ -354,6 +348,16 @@
354 }348 }
355 Binding {349 Binding {
356 target: applicationsDisplayLoader.item350 target: applicationsDisplayLoader.item
351 property: "keepDashRunning"
352 value: launcher.shown || launcher.dashSwipe
353 }
354 Binding {
355 target: applicationsDisplayLoader.item
356 property: "suspended"
357 value: greeter.shown
358 }
359 Binding {
360 target: applicationsDisplayLoader.item
357 property: "altTabPressed"361 property: "altTabPressed"
358 value: physicalKeysMapper.altTabPressed362 value: physicalKeysMapper.altTabPressed
359 }363 }
@@ -459,12 +463,6 @@
459 }463 }
460464
461 onEmergencyCall: startLockedApp("dialer-app")465 onEmergencyCall: startLockedApp("dialer-app")
462
463 Binding {
464 target: ApplicationManager
465 property: "suspended"
466 value: greeter.shown
467 }
468 }466 }
469 }467 }
470468
471469
=== modified file 'qml/Stages/DesktopStage.qml'
--- qml/Stages/DesktopStage.qml 2015-07-16 15:26:26 +0000
+++ qml/Stages/DesktopStage.qml 2015-08-03 14:21:12 +0000
@@ -39,6 +39,8 @@
39 property int shellPrimaryOrientation39 property int shellPrimaryOrientation
40 property int nativeOrientation40 property int nativeOrientation
41 property bool beingResized: false41 property bool beingResized: false
42 property bool keepDashRunning: true
43 property bool suspended: false
4244
43 // functions to be called from outside45 // functions to be called from outside
44 function updateFocusedAppOrientation() { /* TODO */ }46 function updateFocusedAppOrientation() { /* TODO */ }
@@ -215,6 +217,17 @@
215 }217 }
216 }218 }
217219
220 Binding {
221 target: ApplicationManager.get(index)
222 property: "requestedState"
223 // TODO: figure out some lifecycle policy, like suspending minimized apps
224 // if running on a tablet or something.
225 // TODO: If the device has a dozen suspended apps because it was running
226 // in staged mode, when it switches to Windowed mode it will suddenly
227 // resume all those apps at once. We might want to avoid that.
228 value: ApplicationInfoInterface.RequestedRunning // Always running for now
229 }
230
218 function maximize() {231 function maximize() {
219 minimized = false;232 minimized = false;
220 maximized = true;233 maximized = true;
221234
=== modified file 'qml/Stages/PhoneStage.qml'
--- qml/Stages/PhoneStage.qml 2015-07-14 08:09:58 +0000
+++ qml/Stages/PhoneStage.qml 2015-08-03 14:21:12 +0000
@@ -36,6 +36,8 @@
36 property bool altTabEnabled: true36 property bool altTabEnabled: true
37 property real startScale: 1.137 property real startScale: 1.1
38 property real endScale: 0.738 property real endScale: 0.7
39 property bool keepDashRunning: true
40 property bool suspended: false
39 property int shellOrientationAngle: 041 property int shellOrientationAngle: 0
40 property int shellOrientation42 property int shellOrientation
41 property int shellPrimaryOrientation43 property int shellPrimaryOrientation
@@ -428,6 +430,14 @@
428 dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated430 dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
429 focusFirstApp: root.focusFirstApp431 focusFirstApp: root.focusFirstApp
430432
433 Binding {
434 target: appDelegate.application
435 property: "requestedState"
436 value: (isDash && root.keepDashRunning) || (!root.suspended && appDelegate.focus)
437 ? ApplicationInfoInterface.RequestedRunning
438 : ApplicationInfoInterface.RequestedSuspended
439 }
440
431 readonly property bool isDash: model.appId == "unity8-dash"441 readonly property bool isDash: model.appId == "unity8-dash"
432442
433 z: isDash && !spreadView.active ? -1 : behavioredIndex443 z: isDash && !spreadView.active ? -1 : behavioredIndex
434444
=== modified file 'qml/Stages/TabletStage.qml'
--- qml/Stages/TabletStage.qml 2015-07-06 09:31:43 +0000
+++ qml/Stages/TabletStage.qml 2015-08-03 14:21:12 +0000
@@ -36,6 +36,8 @@
36 property bool spreadEnabled: true // If false, animations and right edge will be disabled36 property bool spreadEnabled: true // If false, animations and right edge will be disabled
3737
38 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.38 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
39 property bool keepDashRunning: true
40 property bool suspended: false
39 property int shellOrientationAngle: 041 property int shellOrientationAngle: 0
40 property int shellOrientation42 property int shellOrientation
41 property int shellPrimaryOrientation43 property int shellPrimaryOrientation
@@ -117,6 +119,7 @@
117119
118 QtObject {120 QtObject {
119 id: priv121 id: priv
122 objectName: "stagesPriv"
120123
121 property string focusedAppId: ApplicationManager.focusedApplicationId124 property string focusedAppId: ApplicationManager.focusedApplicationId
122 readonly property var focusedAppDelegate: {125 readonly property var focusedAppDelegate: {
@@ -626,6 +629,17 @@
626629
627 readonly property bool isDash: model.appId == "unity8-dash"630 readonly property bool isDash: model.appId == "unity8-dash"
628631
632 Binding {
633 target: spreadTile.application
634 property: "requestedState"
635 value: (spreadTile.isDash && root.keepDashRunning)
636 ||
637 (!root.suspended && (model.appId == priv.mainStageAppId
638 || model.appId == priv.sideStageAppId))
639 ? ApplicationInfoInterface.RequestedRunning
640 : ApplicationInfoInterface.RequestedSuspended
641 }
642
629 // FIXME: A regular binding doesn't update any more after closing an app.643 // FIXME: A regular binding doesn't update any more after closing an app.
630 // Using a Binding for now.644 // Using a Binding for now.
631 Binding {645 Binding {
632646
=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp'
--- tests/mocks/Unity/Application/ApplicationInfo.cpp 2015-03-06 04:44:11 +0000
+++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2015-08-03 14:21:12 +0000
@@ -30,7 +30,7 @@
30 : ApplicationInfoInterface(appId, parent)30 : ApplicationInfoInterface(appId, parent)
31 , m_appId(appId)31 , m_appId(appId)
32 , m_stage(MainStage)32 , m_stage(MainStage)
33 , m_state(Starting)33 , m_state(Stopped)
34 , m_focused(false)34 , m_focused(false)
35 , m_fullscreen(false)35 , m_fullscreen(false)
36 , m_session(0)36 , m_session(0)
@@ -39,6 +39,7 @@
39 Qt::InvertedPortraitOrientation |39 Qt::InvertedPortraitOrientation |
40 Qt::InvertedLandscapeOrientation)40 Qt::InvertedLandscapeOrientation)
41 , m_rotatesWindowContents(false)41 , m_rotatesWindowContents(false)
42 , m_requestedState(RequestedRunning)
42 , m_manualSurfaceCreation(false)43 , m_manualSurfaceCreation(false)
43{44{
44}45}
@@ -46,7 +47,7 @@
46ApplicationInfo::ApplicationInfo(QObject *parent)47ApplicationInfo::ApplicationInfo(QObject *parent)
47 : ApplicationInfoInterface(QString(), parent)48 : ApplicationInfoInterface(QString(), parent)
48 , m_stage(MainStage)49 , m_stage(MainStage)
49 , m_state(Starting)50 , m_state(Stopped)
50 , m_focused(false)51 , m_focused(false)
51 , m_fullscreen(false)52 , m_fullscreen(false)
52 , m_session(0)53 , m_session(0)
@@ -55,6 +56,7 @@
55 Qt::InvertedPortraitOrientation |56 Qt::InvertedPortraitOrientation |
56 Qt::InvertedLandscapeOrientation)57 Qt::InvertedLandscapeOrientation)
57 , m_rotatesWindowContents(false)58 , m_rotatesWindowContents(false)
59 , m_requestedState(RequestedRunning)
58 , m_manualSurfaceCreation(false)60 , m_manualSurfaceCreation(false)
59{61{
60}62}
@@ -74,7 +76,6 @@
7476
75void ApplicationInfo::setSession(Session* session)77void ApplicationInfo::setSession(Session* session)
76{78{
77 qDebug() << "Application::setSession - appId=" << appId() << "session=" << session;
78 if (m_session == session)79 if (m_session == session)
79 return;80 return;
8081
@@ -91,6 +92,8 @@
91 m_session->setApplication(this);92 m_session->setApplication(this);
92 m_session->setParent(this);93 m_session->setParent(this);
93 SessionManager::singleton()->registerSession(m_session);94 SessionManager::singleton()->registerSession(m_session);
95 connect(m_session, &Session::surfaceChanged,
96 this, &ApplicationInfo::onSessionSurfaceChanged);
9497
95 if (!m_manualSurfaceCreation) {98 if (!m_manualSurfaceCreation) {
96 QTimer::singleShot(500, m_session, SLOT(createSurface()));99 QTimer::singleShot(500, m_session, SLOT(createSurface()));
@@ -161,11 +164,12 @@
161 m_state = value;164 m_state = value;
162 Q_EMIT stateChanged(value);165 Q_EMIT stateChanged(value);
163166
164 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {167 if (!m_manualSurfaceCreation && !m_session && m_state == ApplicationInfo::Starting) {
165 QTimer::singleShot(500, this, SLOT(createSession()));168 QTimer::singleShot(500, this, SLOT(createSession()));
166 } else if (m_state == ApplicationInfo::Stopped) {169 } else if (m_state == ApplicationInfo::Stopped) {
167 delete m_session;170 Session *session = m_session;
168 m_session = nullptr;171 setSession(nullptr);
172 delete session;
169 }173 }
170 }174 }
171}175}
@@ -213,3 +217,33 @@
213{217{
214 m_rotatesWindowContents = value;218 m_rotatesWindowContents = value;
215}219}
220
221ApplicationInfo::RequestedState ApplicationInfo::requestedState() const
222{
223 return m_requestedState;
224}
225
226void ApplicationInfo::setRequestedState(RequestedState value)
227{
228 if (m_requestedState != value) {
229 m_requestedState = value;
230 Q_EMIT requestedStateChanged(m_requestedState);
231
232 if (m_requestedState == RequestedRunning && m_state == Suspended) {
233 setState(Running);
234 } else if (m_requestedState == RequestedSuspended && m_state == Running) {
235 setState(Suspended);
236 }
237 }
238}
239
240void ApplicationInfo::onSessionSurfaceChanged(MirSurfaceItem* surface)
241{
242 if (surface != nullptr && m_state == Starting) {
243 if (m_requestedState == RequestedRunning) {
244 setState(Running);
245 } else {
246 setState(Suspended);
247 }
248 }
249}
216250
=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
--- tests/mocks/Unity/Application/ApplicationInfo.h 2015-03-06 04:44:11 +0000
+++ tests/mocks/Unity/Application/ApplicationInfo.h 2015-08-03 14:21:12 +0000
@@ -46,6 +46,9 @@
46 ApplicationInfo(const QString &appId, QObject *parent = nullptr);46 ApplicationInfo(const QString &appId, QObject *parent = nullptr);
47 ~ApplicationInfo();47 ~ApplicationInfo();
4848
49 RequestedState requestedState() const override;
50 void setRequestedState(RequestedState) override;
51
49 void setIconId(const QString &iconId);52 void setIconId(const QString &iconId);
50 void setScreenshotId(const QString &screenshotId);53 void setScreenshotId(const QString &screenshotId);
5154
@@ -101,6 +104,9 @@
101public Q_SLOTS:104public Q_SLOTS:
102 Q_INVOKABLE void createSession();105 Q_INVOKABLE void createSession();
103106
107private Q_SLOTS:
108 void onSessionSurfaceChanged(MirSurfaceItem*);
109
104private:110private:
105 void setIcon(const QUrl &value);111 void setIcon(const QUrl &value);
106112
@@ -116,6 +122,7 @@
116 Session* m_session;122 Session* m_session;
117 Qt::ScreenOrientations m_supportedOrientations;123 Qt::ScreenOrientations m_supportedOrientations;
118 bool m_rotatesWindowContents;124 bool m_rotatesWindowContents;
125 RequestedState m_requestedState;
119126
120 bool m_manualSurfaceCreation;127 bool m_manualSurfaceCreation;
121};128};
122129
=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
--- tests/mocks/Unity/Application/ApplicationManager.cpp 2015-06-24 11:41:09 +0000
+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2015-08-03 14:21:12 +0000
@@ -49,8 +49,6 @@
4949
50ApplicationManager::ApplicationManager(QObject *parent)50ApplicationManager::ApplicationManager(QObject *parent)
51 : ApplicationManagerInterface(parent)51 : ApplicationManagerInterface(parent)
52 , m_suspended(false)
53 , m_forceDashActive(false)
54{52{
55 m_roleNames.insert(RoleSession, "session");53 m_roleNames.insert(RoleSession, "session");
56 m_roleNames.insert(RoleFullscreen, "fullscreen");54 m_roleNames.insert(RoleFullscreen, "fullscreen");
@@ -217,7 +215,7 @@
217 && application->stage() == ApplicationInfo::SideStage) {215 && application->stage() == ApplicationInfo::SideStage) {
218 application->setStage(ApplicationInfo::MainStage);216 application->setStage(ApplicationInfo::MainStage);
219 }217 }
220 application->setState(ApplicationInfo::Running);218 application->setState(ApplicationInfo::Starting);
221219
222 return application;220 return application;
223}221}
@@ -262,50 +260,6 @@
262 return QString();260 return QString();
263}261}
264262
265bool ApplicationManager::suspended() const
266{
267 return m_suspended;
268}
269
270void ApplicationManager::setSuspended(bool suspended)
271{
272 ApplicationInfo *focusedApp = findApplication(focusedApplicationId());
273 if (focusedApp) {
274 if (suspended) {
275 focusedApp->setState(ApplicationInfo::Suspended);
276 } else {
277 focusedApp->setState(ApplicationInfo::Running);
278 }
279 }
280 m_suspended = suspended;
281 Q_EMIT suspendedChanged();
282}
283
284bool ApplicationManager::forceDashActive() const
285{
286 return m_forceDashActive;
287}
288
289void ApplicationManager::setForceDashActive(bool forceDashActive)
290{
291 if (m_forceDashActive == forceDashActive) {
292 return;
293 }
294
295 ApplicationInfo *dash = findApplication("unity8-dash");
296 if (dash) {
297 if (forceDashActive) {
298 dash->setState(ApplicationInfo::Running);
299 } else {
300 if (!dash->focused()) {
301 dash->setState(ApplicationInfo::Suspended);
302 }
303 }
304 }
305 m_forceDashActive = forceDashActive;
306 Q_EMIT forceDashActiveChanged();
307}
308
309bool ApplicationManager::focusApplication(const QString &appId)263bool ApplicationManager::focusApplication(const QString &appId)
310{264{
311 ApplicationInfo *application = findApplication(appId);265 ApplicationInfo *application = findApplication(appId);
@@ -316,13 +270,11 @@
316 for (ApplicationInfo *app : m_runningApplications) {270 for (ApplicationInfo *app : m_runningApplications) {
317 if (app->focused()) {271 if (app->focused()) {
318 app->setFocused(false);272 app->setFocused(false);
319 app->setState(ApplicationInfo::Suspended);
320 }273 }
321 }274 }
322275
323 // focus this app276 // focus this app
324 application->setFocused(true);277 application->setFocused(true);
325 application->setState(ApplicationInfo::Running);
326278
327 // move app to top of stack279 // move app to top of stack
328 move(m_runningApplications.indexOf(application), 0);280 move(m_runningApplications.indexOf(application), 0);
@@ -394,6 +346,7 @@
394 application->setScreenshotId("gallery");346 application->setScreenshotId("gallery");
395 application->setIconId("gallery");347 application->setIconId("gallery");
396 application->setFullscreen(true);348 application->setFullscreen(true);
349 application->setStage(ApplicationInfo::MainStage);
397 m_availableApplications.append(application);350 m_availableApplications.append(application);
398351
399 application = new ApplicationInfo(this);352 application = new ApplicationInfo(this);
400353
=== modified file 'tests/mocks/Unity/Application/ApplicationManager.h'
--- tests/mocks/Unity/Application/ApplicationManager.h 2015-04-01 11:25:54 +0000
+++ tests/mocks/Unity/Application/ApplicationManager.h 2015-08-03 14:21:12 +0000
@@ -69,11 +69,6 @@
69 Q_INVOKABLE bool stopApplication(const QString &appId) override;69 Q_INVOKABLE bool stopApplication(const QString &appId) override;
7070
71 QString focusedApplicationId() const override;71 QString focusedApplicationId() const override;
72 bool suspended() const override;
73 void setSuspended(bool suspended) override;
74
75 bool forceDashActive() const override;
76 void setForceDashActive(bool forceDashActive) override;
7772
78 // Only for testing73 // Only for testing
79 QStringList availableApplications();74 QStringList availableApplications();
@@ -96,8 +91,6 @@
96 void remove(ApplicationInfo* application);91 void remove(ApplicationInfo* application);
97 void buildListOfAvailableApplications();92 void buildListOfAvailableApplications();
98 void onWindowCreated();93 void onWindowCreated();
99 bool m_suspended;
100 bool m_forceDashActive;
101 QList<ApplicationInfo*> m_runningApplications;94 QList<ApplicationInfo*> m_runningApplications;
102 QList<ApplicationInfo*> m_availableApplications;95 QList<ApplicationInfo*> m_availableApplications;
103 QTimer m_windowCreatedTimer;96 QTimer m_windowCreatedTimer;
10497
=== modified file 'tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt'
--- tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-07-23 10:31:56 +0000
+++ tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-08-03 14:21:12 +0000
@@ -1,5 +1,4 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
32
4include_directories(3include_directories(
5 ${CMAKE_CURRENT_SOURCE_DIR}4 ${CMAKE_CURRENT_SOURCE_DIR}
65
=== modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp'
--- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-07-23 14:13:57 +0000
+++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-08-03 14:21:12 +0000
@@ -39,6 +39,9 @@
39 Q_OBJECT39 Q_OBJECT
40public:40public:
41 MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }41 MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
42
43 RequestedState requestedState() const override { return RequestedRunning; }
44 void setRequestedState(RequestedState) override {}
42 QString appId() const override { return m_appId; }45 QString appId() const override { return m_appId; }
43 QString name() const override { return "mock"; }46 QString name() const override { return "mock"; }
44 QString comment() const override { return "this is a mock"; }47 QString comment() const override { return "this is a mock"; }
@@ -117,10 +120,6 @@
117 endRemoveRows();120 endRemoveRows();
118 }121 }
119 bool requestFocusApplication(const QString &appId) override { Q_UNUSED(appId); return true; }122 bool requestFocusApplication(const QString &appId) override { Q_UNUSED(appId); return true; }
120 bool suspended() const override { return false; }
121 void setSuspended(bool) override {}
122 bool forceDashActive() const override { return false; }
123 void setForceDashActive(bool) override {}
124123
125private:124private:
126 QList<MockApp*> m_list;125 QList<MockApp*> m_list;
127126
=== modified file 'tests/qmltests/Stages/ApplicationCheckBox.qml'
--- tests/qmltests/Stages/ApplicationCheckBox.qml 2015-06-12 16:07:43 +0000
+++ tests/qmltests/Stages/ApplicationCheckBox.qml 2015-08-03 14:21:12 +0000
@@ -86,8 +86,29 @@
86 }86 }
87 }87 }
88 Label {88 Label {
89 id: appIdLabel
89 text: root.appId90 text: root.appId
90 color: "white"91 color: "white"
91 anchors.verticalCenter: parent.verticalCenter92 anchors.verticalCenter: parent.verticalCenter
92 }93 }
94 Rectangle {
95 color: {
96 if (d.application) {
97 if (d.application.state === ApplicationInfoInterface.Starting) {
98 return "yellow";
99 } else if (d.application.state === ApplicationInfoInterface.Running) {
100 return "green";
101 } else if (d.application.state === ApplicationInfoInterface.Suspended) {
102 return "blue";
103 } else {
104 return "darkred";
105 }
106 } else {
107 return "darkred";
108 }
109 }
110 width: height
111 height: appIdLabel.height * 0.7
112 anchors.verticalCenter: parent.verticalCenter
113 }
93}114}
94115
=== modified file 'tests/qmltests/Stages/tst_DesktopStage.qml'
--- tests/qmltests/Stages/tst_DesktopStage.qml 2015-05-01 13:21:30 +0000
+++ tests/qmltests/Stages/tst_DesktopStage.qml 2015-08-03 14:21:12 +0000
@@ -24,9 +24,8 @@
2424
25import "../../../qml/Stages"25import "../../../qml/Stages"
2626
27Rectangle {27Item {
28 id: root28 id: root
29 color: "darkblue"
30 width: desktopStageLoader.width + controls.width29 width: desktopStageLoader.width + controls.width
31 height: desktopStageLoader.height30 height: desktopStageLoader.height
3231
@@ -57,6 +56,7 @@
57 property bool itemDestroyed: false56 property bool itemDestroyed: false
58 sourceComponent: Component {57 sourceComponent: Component {
59 DesktopStage {58 DesktopStage {
59 color: "darkblue"
60 anchors.fill: parent60 anchors.fill: parent
61 Component.onDestruction: {61 Component.onDestruction: {
62 desktopStageLoader.itemDestroyed = true;62 desktopStageLoader.itemDestroyed = true;
6363
=== modified file 'tests/qmltests/Stages/tst_PhoneStage.qml'
--- tests/qmltests/Stages/tst_PhoneStage.qml 2015-06-23 14:20:23 +0000
+++ tests/qmltests/Stages/tst_PhoneStage.qml 2015-08-03 14:21:12 +0000
@@ -301,16 +301,16 @@
301 addApps(2);301 addApps(2);
302302
303 var secondApp = ApplicationManager.get(0);303 var secondApp = ApplicationManager.get(0);
304 tryCompare(secondApp, "state", ApplicationInfoInterface.Running);304 tryCompare(secondApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
305 tryCompare(secondApp, "focused", true);305 tryCompare(secondApp, "focused", true);
306306
307 var firstApp = ApplicationManager.get(1);307 var firstApp = ApplicationManager.get(1);
308 tryCompare(firstApp, "state", ApplicationInfoInterface.Suspended);308 tryCompare(firstApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
309 tryCompare(firstApp, "focused", false);309 tryCompare(firstApp, "focused", false);
310310
311 ApplicationManager.stopApplication(secondApp.appId);311 ApplicationManager.stopApplication(secondApp.appId);
312312
313 tryCompare(firstApp, "state", ApplicationInfoInterface.Running);313 tryCompare(firstApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
314 tryCompare(firstApp, "focused", true);314 tryCompare(firstApp, "focused", true);
315 }315 }
316316
@@ -388,5 +388,77 @@
388388
389 tryCompare(focusedDelegate, "x", 0);389 tryCompare(focusedDelegate, "x", 0);
390 }390 }
391
392 function test_focusedAppIsTheOnlyRunningApp() {
393 addApps(2);
394
395 var delegateA = findChild(phoneStage, "appDelegate0");
396 verify(delegateA);
397 var delegateB = findChild(phoneStage, "appDelegate1");
398 verify(delegateB);
399
400 // A is focused and running, B is unfocused and suspended
401 compare(delegateA.focus, true);
402 compare(delegateA.application.requestedState, ApplicationInfoInterface.RequestedRunning);
403 compare(delegateB.focus, false);
404 compare(delegateB.application.requestedState, ApplicationInfoInterface.RequestedSuspended);
405
406 // Switch foreground/focused appp from A to B
407 goToSpread();
408 phoneStage.select(delegateB.application.appId);
409
410 // Now it's the other way round
411 // A is unfocused and suspended, B is focused and running
412 tryCompare(delegateA, "focus", false);
413 tryCompare(delegateA.application, "requestedState", ApplicationInfoInterface.RequestedSuspended);
414 tryCompare(delegateB, "focus", true);
415 tryCompare(delegateB.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
416 }
417
418 function test_dashRemainsRunningIfStageIsToldSo() {
419 addApps(1);
420
421 var delegateDash = findChild(phoneStage, "appDelegate1");
422 verify(delegateDash);
423 compare(delegateDash.application.appId, "unity8-dash");
424
425 var delegateOther = findChild(phoneStage, "appDelegate0");
426 verify(delegateOther);
427
428 goToSpread();
429 phoneStage.select("unity8-dash");
430
431 tryCompare(delegateDash, "focus", true);
432 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
433 compare(delegateOther.focus, false);
434 compare(delegateOther.application.requestedState, ApplicationInfoInterface.RequestedSuspended);
435
436 goToSpread();
437 phoneStage.select(delegateOther.application.appId);
438
439 // The other app gets focused and running but dash is kept running despite being unfocused
440 tryCompare(delegateDash, "focus", false);
441 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
442 compare(delegateOther.focus, true);
443 compare(delegateOther.application.requestedState, ApplicationInfoInterface.RequestedRunning);
444 }
445
446 function test_foregroundAppIsSuspendedWhenStageIsSuspended() {
447 addApps(1);
448
449 var delegate = findChild(phoneStage, "appDelegate0");
450 verify(delegate);
451
452 compare(delegate.focus, true);
453 compare(delegate.application.requestedState, ApplicationInfoInterface.RequestedRunning);
454
455 phoneStage.suspended = true;
456
457 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedSuspended);
458
459 phoneStage.suspended = false;
460
461 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
462 }
391 }463 }
392}464}
393465
=== modified file 'tests/qmltests/Stages/tst_TabletStage.qml'
--- tests/qmltests/Stages/tst_TabletStage.qml 2015-06-12 16:07:43 +0000
+++ tests/qmltests/Stages/tst_TabletStage.qml 2015-08-03 14:21:12 +0000
@@ -77,9 +77,17 @@
77 appId: "webbrowser-app"77 appId: "webbrowser-app"
78 }78 }
79 ApplicationCheckBox {79 ApplicationCheckBox {
80 id: galleryCheckBox
81 appId: "gallery-app"
82 }
83 ApplicationCheckBox {
80 id: dialerCheckBox84 id: dialerCheckBox
81 appId: "dialer-app"85 appId: "dialer-app"
82 }86 }
87 ApplicationCheckBox {
88 id: facebookCheckBox
89 appId: "facebook-webapp"
90 }
83 }91 }
84 }92 }
8593
@@ -93,6 +101,19 @@
93 function init() {101 function init() {
94 tabletStageLoader.active = true;102 tabletStageLoader.active = true;
95 tryCompare(tabletStageLoader, "status", Loader.Ready);103 tryCompare(tabletStageLoader, "status", Loader.Ready);
104
105 // this is very strange, but sometimes the test starts without
106 // TabletStage components having finished loading themselves
107 var appWindow = null;
108 while (!appWindow) {
109 appWindow = findChild(tabletStage, "appWindow_unity8-dash");
110 if (!appWindow) {
111 console.log("didn't find appWindow_unity8-dash in " + tabletStage + ". Trying again...");
112 wait(50);
113 }
114 }
115
116 waitUntilAppSurfaceShowsUp("unity8-dash");
96 }117 }
97118
98 function cleanup() {119 function cleanup() {
@@ -109,7 +130,9 @@
109130
110 // kill all (fake) running apps131 // kill all (fake) running apps
111 webbrowserCheckBox.checked = false;132 webbrowserCheckBox.checked = false;
133 galleryCheckBox.checked = false;
112 dialerCheckBox.checked = false;134 dialerCheckBox.checked = false;
135 facebookCheckBox.checked = false;
113 }136 }
114137
115 function waitUntilAppSurfaceShowsUp(appId) {138 function waitUntilAppSurfaceShowsUp(appId) {
@@ -120,6 +143,34 @@
120 tryCompare(appWindowStates, "state", "surface");143 tryCompare(appWindowStates, "state", "surface");
121 }144 }
122145
146 function switchToApp(targetAppId) {
147 touchFlick(tabletStage,
148 tabletStage.width - (tabletStage.dragAreaWidth / 2), tabletStage.height / 2,
149 tabletStage.x + 1, tabletStage.height / 2);
150
151 var spreadView = findChild(tabletStage, "spreadView");
152 verify(spreadView);
153 tryCompare(spreadView, "phase", 2);
154 tryCompare(spreadView, "flicking", false);
155 tryCompare(spreadView, "moving", false);
156
157 waitUntilAppDelegateStopsMoving(targetAppId);
158
159 var targetAppWindow = findChild(tabletStage, "appWindow_" + targetAppId);
160 tap(targetAppWindow, 10, 10);
161 }
162
163 function waitUntilAppDelegateStopsMoving(targetAppId)
164 {
165 var targetAppDelegate = findChild(tabletStage, "tabletSpreadDelegate_" + targetAppId);
166 verify(targetAppDelegate);
167 var lastValue = undefined;
168 do {
169 lastValue = targetAppDelegate.animatedProgress;
170 wait(30);
171 } while (lastValue != targetAppDelegate.animatedProgress);
172 }
173
123 function test_tappingSwitchesFocusBetweenStages() {174 function test_tappingSwitchesFocusBetweenStages() {
124 webbrowserCheckBox.checked = true;175 webbrowserCheckBox.checked = true;
125 waitUntilAppSurfaceShowsUp(webbrowserCheckBox.appId);176 waitUntilAppSurfaceShowsUp(webbrowserCheckBox.appId);
@@ -155,7 +206,6 @@
155 tryCompare(webbrowserApp.session.surface, "activeFocus", false);206 tryCompare(webbrowserApp.session.surface, "activeFocus", false);
156 }207 }
157208
158
159 function test_closeAppInSideStage() {209 function test_closeAppInSideStage() {
160 dialerCheckBox.checked = true;210 dialerCheckBox.checked = true;
161 waitUntilAppSurfaceShowsUp(dialerCheckBox.appId);211 waitUntilAppSurfaceShowsUp(dialerCheckBox.appId);
@@ -200,6 +250,116 @@
200 appWindow.width / 2, appWindow.height / 2,250 appWindow.width / 2, appWindow.height / 2,
201 appWindow.width / 2, -appWindow.height / 2);251 appWindow.width / 2, -appWindow.height / 2);
202 }252 }
253
254 function test_suspendsAndResumesAppsInMainStage() {
255 webbrowserCheckBox.checked = true;
256 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
257 compare(webbrowserApp.stage, ApplicationInfoInterface.MainStage);
258
259 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Running);
260
261 galleryCheckBox.checked = true;
262 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
263 compare(galleryApp.stage, ApplicationInfoInterface.MainStage);
264
265 tryCompare(galleryApp, "state", ApplicationInfoInterface.Running);
266 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Suspended);
267
268 switchToApp(webbrowserApp.appId);
269
270 tryCompare(galleryApp, "state", ApplicationInfoInterface.Suspended);
271 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Running);
272
273 switchToApp(galleryApp.appId);
274
275 tryCompare(galleryApp, "state", ApplicationInfoInterface.Running);
276 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Suspended);
277 }
278
279
280 function test_foregroundMainAndSideStageAppsAreKeptRunning() {
281
282 var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
283 verify(stagesPriv);
284
285 // launch two main stage apps
286 // gallery will be on foreground and webbrowser on background
287
288 webbrowserCheckBox.checked = true;
289 waitUntilAppSurfaceShowsUp(webbrowserCheckBox.appId)
290 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
291 compare(webbrowserApp.stage, ApplicationInfoInterface.MainStage);
292
293 galleryCheckBox.checked = true;
294 waitUntilAppSurfaceShowsUp(galleryCheckBox.appId)
295 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
296 compare(galleryApp.stage, ApplicationInfoInterface.MainStage);
297
298 compare(stagesPriv.mainStageAppId, galleryCheckBox.appId);
299
300 // then launch two side stage apps
301 // facebook will be on foreground and dialer on background
302
303 dialerCheckBox.checked = true;
304 waitUntilAppSurfaceShowsUp(dialerCheckBox.appId)
305 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
306 compare(dialerApp.stage, ApplicationInfoInterface.SideStage);
307
308 facebookCheckBox.checked = true;
309 waitUntilAppSurfaceShowsUp(facebookCheckBox.appId)
310 var facebookApp = ApplicationManager.findApplication(facebookCheckBox.appId);
311 compare(facebookApp.stage, ApplicationInfoInterface.SideStage);
312
313 compare(stagesPriv.sideStageAppId, facebookCheckBox.appId);
314
315 // Now check that the foreground apps are running and that the background ones
316 // are suspended
317
318 tryCompare(galleryApp, "state", ApplicationInfoInterface.Running);
319 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Suspended);
320 tryCompare(facebookApp, "state", ApplicationInfoInterface.Running);
321 tryCompare(dialerApp, "state", ApplicationInfoInterface.Suspended);
322
323 switchToApp(dialerCheckBox.appId);
324
325 tryCompare(galleryApp, "state", ApplicationInfoInterface.Running);
326 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Suspended);
327 tryCompare(facebookApp, "state", ApplicationInfoInterface.Suspended);
328 tryCompare(dialerApp, "state", ApplicationInfoInterface.Running);
329
330 switchToApp(webbrowserCheckBox.appId);
331
332 tryCompare(galleryApp, "state", ApplicationInfoInterface.Suspended);
333 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Running);
334 tryCompare(facebookApp, "state", ApplicationInfoInterface.Suspended);
335 tryCompare(dialerApp, "state", ApplicationInfoInterface.Running);
336 }
337
338 function test_foregroundAppsAreSuspendedWhenStageIsSuspended() {
339 webbrowserCheckBox.checked = true;
340 waitUntilAppSurfaceShowsUp(webbrowserCheckBox.appId)
341 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
342 compare(webbrowserApp.stage, ApplicationInfoInterface.MainStage);
343
344 dialerCheckBox.checked = true;
345 waitUntilAppSurfaceShowsUp(dialerCheckBox.appId)
346 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
347 compare(dialerApp.stage, ApplicationInfoInterface.SideStage);
348
349
350 compare(webbrowserApp.requestedState, ApplicationInfoInterface.RequestedRunning);
351 compare(dialerApp.requestedState, ApplicationInfoInterface.RequestedRunning);
352
353 tabletStage.suspended = true;
354
355 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
356 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
357
358 tabletStage.suspended = false;
359
360 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
361 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
362 }
203 }363 }
204364
205}365}
206366
=== modified file 'tests/qmltests/tst_OrientedShell.qml'
--- tests/qmltests/tst_OrientedShell.qml 2015-07-10 14:44:55 +0000
+++ tests/qmltests/tst_OrientedShell.qml 2015-08-03 14:21:12 +0000
@@ -46,7 +46,7 @@
46 }46 }
4747
48 QtObject {48 QtObject {
49 id: mockUsageModeSettings49 id: mockUnity8Settings
50 property string usageMode: usageModeSelector.model[usageModeSelector.selectedIndex]50 property string usageMode: usageModeSelector.model[usageModeSelector.selectedIndex]
51 }51 }
5252
@@ -125,7 +125,7 @@
125 sourceComponent: Component {125 sourceComponent: Component {
126 OrientedShell {126 OrientedShell {
127 anchors.fill: parent127 anchors.fill: parent
128 usageModeSettings: mockUsageModeSettings128 unity8Settings: mockUnity8Settings
129 oskSettings: mockOskSettings129 oskSettings: mockOskSettings
130 physicalOrientation: root.physicalOrientation0130 physicalOrientation: root.physicalOrientation0
131 orientationLocked: orientationLockedCheckBox.checked131 orientationLocked: orientationLockedCheckBox.checked
@@ -926,7 +926,7 @@
926926
927 function test_attachRemoveInputDevices() {927 function test_attachRemoveInputDevices() {
928 usageModeSelector.selectedIndex = 2;928 usageModeSelector.selectedIndex = 2;
929 tryCompare(mockUsageModeSettings, "usageMode", "Automatic")929 tryCompare(mockUnity8Settings, "usageMode", "Automatic")
930930
931 loadShell("mako")931 loadShell("mako")
932 var shell = findChild(orientedShell, "shell");932 var shell = findChild(orientedShell, "shell");
933933
=== modified file 'tests/qmltests/tst_Shell.qml'
--- tests/qmltests/tst_Shell.qml 2015-07-29 12:38:53 +0000
+++ tests/qmltests/tst_Shell.qml 2015-08-03 14:21:12 +0000
@@ -67,11 +67,6 @@
67 width: units.gu(40)67 width: units.gu(40)
68 height: units.gu(71)68 height: units.gu(71)
69 }69 }
70 StateChangeScript {
71 script: {
72 GSettingsController.setUsageMode("Staged")
73 }
74 }
75 },70 },
76 State {71 State {
77 name: "tablet"72 name: "tablet"
@@ -80,11 +75,6 @@
80 width: units.gu(100)75 width: units.gu(100)
81 height: units.gu(71)76 height: units.gu(71)
82 }77 }
83 StateChangeScript {
84 script: {
85 GSettingsController.setUsageMode("Staged")
86 }
87 }
88 },78 },
89 State {79 State {
90 name: "desktop"80 name: "desktop"
@@ -97,11 +87,6 @@
97 target: mouseEmulation87 target: mouseEmulation
98 checked: false88 checked: false
99 }89 }
100 StateChangeScript {
101 script: {
102 GSettingsController.setUsageMode("Windowed")
103 }
104 }
105 }90 }
106 ]91 ]
10792
@@ -317,7 +302,6 @@
317 mouseEmulation.checked = true;302 mouseEmulation.checked = true;
318 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state303 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
319 tearDown();304 tearDown();
320 GSettingsController.setUsageMode("Staged");
321 }305 }
322306
323 function loadShell(formFactor) {307 function loadShell(formFactor) {
@@ -602,9 +586,9 @@
602 verify(mainAppId != "");586 verify(mainAppId != "");
603 var mainApp = ApplicationManager.findApplication(mainAppId);587 var mainApp = ApplicationManager.findApplication(mainAppId);
604 verify(mainApp);588 verify(mainApp);
605 tryCompare(mainApp, "state", ApplicationInfoInterface.Running);589 tryCompare(mainApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
606590
607 // Suspend while call is active...591 // Display off while call is active...
608 callManager.foregroundCall = phoneCall;592 callManager.foregroundCall = phoneCall;
609 Powerd.status = Powerd.Off;593 Powerd.status = Powerd.Off;
610 tryCompare(greeter, "shown", false);594 tryCompare(greeter, "shown", false);
@@ -615,8 +599,7 @@
615 Powerd.status = Powerd.Off;599 Powerd.status = Powerd.Off;
616 tryCompare(greeter, "fullyShown", true);600 tryCompare(greeter, "fullyShown", true);
617601
618 tryCompare(ApplicationManager, "suspended", true);602 compare(mainApp.requestedState, ApplicationInfoInterface.RequestedSuspended);
619 compare(mainApp.state, ApplicationInfoInterface.Suspended);
620603
621 // And wake up604 // And wake up
622 Powerd.status = Powerd.On;605 Powerd.status = Powerd.On;
@@ -632,8 +615,7 @@
632 removeTimeConstraintsFromDirectionalDragAreas(greeter);615 removeTimeConstraintsFromDirectionalDragAreas(greeter);
633 swipeAwayGreeter();616 swipeAwayGreeter();
634617
635 tryCompare(ApplicationManager, "suspended", false);618 compare(mainApp.requestedState, ApplicationInfoInterface.RequestedRunning);
636 compare(mainApp.state, ApplicationInfoInterface.Running);
637 tryCompare(ApplicationManager, "focusedApplicationId", mainAppId);619 tryCompare(ApplicationManager, "focusedApplicationId", mainAppId);
638 }620 }
639621
@@ -804,15 +786,15 @@
804786
805 function test_launchedAppHasActiveFocus_data() {787 function test_launchedAppHasActiveFocus_data() {
806 return [788 return [
807 {tag: "phone", formFactor: "phone", usageMode: "Staged"},789 {tag: "phone", formFactor: "phone", usageScenario: "phone"},
808 {tag: "tablet", formFactor: "tablet", usageMode: "Staged"},790 {tag: "tablet", formFactor: "tablet", usageScenario: "tablet"},
809 {tag: "desktop", formFactor: "tablet", usageMode: "Windowed"}791 {tag: "desktop", formFactor: "tablet", usageScenario: "desktop"}
810 ]792 ]
811 }793 }
812794
813 function test_launchedAppHasActiveFocus(data) {795 function test_launchedAppHasActiveFocus(data) {
814 GSettingsController.setUsageMode(data.usageMode);
815 loadShell(data.formFactor);796 loadShell(data.formFactor);
797 shell.usageScenario = data.usageScenario;
816 swipeAwayGreeter();798 swipeAwayGreeter();
817799
818 var webApp = ApplicationManager.startApplication("webbrowser-app");800 var webApp = ApplicationManager.startApplication("webbrowser-app");
@@ -1347,6 +1329,50 @@
1347 compare(launcher.inverted, data.launcherInverted);1329 compare(launcher.inverted, data.launcherInverted);
1348 }1330 }
13491331
1332 function test_unfocusedAppsGetSuspendedAfterEnteringStagedMode() {
1333 loadShell("tablet");
1334 shell.usageScenario = "desktop";
1335
1336 var webBrowserApp = ApplicationManager.startApplication("webbrowser-app");
1337 waitUntilAppWindowIsFullyLoaded(webBrowserApp);
1338
1339 var galleryApp = ApplicationManager.startApplication("gallery-app");
1340 waitUntilAppWindowIsFullyLoaded(galleryApp);
1341
1342 ApplicationManager.requestFocusApplication("unity8-dash");
1343 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
1344
1345 compare(webBrowserApp.requestedState, ApplicationInfoInterface.RequestedRunning);
1346 compare(galleryApp.requestedState, ApplicationInfoInterface.RequestedRunning);
1347
1348 shell.usageScenario = "tablet";
1349
1350 tryCompare(webBrowserApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
1351 tryCompare(galleryApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
1352 }
1353
1354 function test_unfocusedAppsAreResumedWhenEnteringWindowedMode() {
1355 loadShell("tablet");
1356 shell.usageScenario = "tablet";
1357
1358 var webBrowserApp = ApplicationManager.startApplication("webbrowser-app");
1359 waitUntilAppWindowIsFullyLoaded(webBrowserApp);
1360
1361 var galleryApp = ApplicationManager.startApplication("gallery-app");
1362 waitUntilAppWindowIsFullyLoaded(galleryApp);
1363
1364 ApplicationManager.requestFocusApplication("unity8-dash");
1365 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
1366
1367 compare(webBrowserApp.requestedState, ApplicationInfoInterface.RequestedSuspended);
1368 compare(galleryApp.requestedState, ApplicationInfoInterface.RequestedSuspended);
1369
1370 shell.usageScenario = "desktop";
1371
1372 tryCompare(webBrowserApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
1373 tryCompare(galleryApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
1374 }
1375
1350 function test_altTabSwitchesFocus() {1376 function test_altTabSwitchesFocus() {
1351 loadShell("desktop");1377 loadShell("desktop");
1352 shell.usageScenario = "desktop"1378 shell.usageScenario = "desktop"

Subscribers

People subscribed via source and target branches