~josharenson/unity8/fix_trust_store_focus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*
 * Copyright 2013 Canonical Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import QtQuick 2.0
import QtTest 1.0
import ".."
import "../../../qml/Components"
import Unity.Application 0.1
import Ubuntu.Components 0.1
import Unity.Test 0.1 as UT
import "tst_Stage"

Rectangle {
    width: units.gu(70)
    height: stageRect.height

    // Even though we replace the ApplicationScreenshot instances in Stage
    // with our own fake ones, ApplicationScreenshot.qml still gives out a warning
    // if shell.importUbuntuApplicationAvailable is missing.
    // For we have this here for the sake of keeping a clean log output.
    Item {
        id: shell
        property bool importUbuntuApplicationAvailable: false
    }

    // A fake ApplicationManager implementation to be passed to Stage
    QtObject {
        id: fakeAppManager
        property ListModel mainStageApplications: ListModel {}
        property ListModel sideStageApplications: ListModel {}
        property var mainStageFocusedApplication

        property Component fakeAppWindowComponent: Component {
            Rectangle {
                width: stage.width
                height: stage.height
                property alias text : txt.text
                Text {id:txt}
            }
        }

        function activateApplication(desktopFile, argument) {
            var appWindow = fakeAppWindowComponent.createObject(fakeWindowContainer)
            var application = {
                'icon': "foo",
                'handle': desktopFile,
                'name': "Foo",
                'fullscreen': false,
                'desktopFile': desktopFile,
                'stage': ApplicationInfo.MainStage,
                'argument': 0,
                'color': desktopFile,
                'window': appWindow
            };
            appWindow.color = application.color
            appWindow.text = desktopFile + " actual";

            mainStageApplications.append(application)
            updateZOrderOfWindows(mainStageApplications)

            return application
        }

        function focusApplication(application) {
            mainStageFocusedApplication = application
        }

        function getApplicationFromDesktopFile(desktopFile, stageType) {
            var sideStage = (stage == ApplicationInfo.SideStage);
            var applications = sideStage ? sideStageApplications
                                         : mainStageApplications;

            for (var i = 0; i < applications.count; i++ ) {
                var application = applications.get(i);
                if (application.desktopFile === desktopFile) {
                    return application;
                }
            }
            return null;
        }

        function moveRunningApplicationStackPosition(from, to, stage) {
            var sideStage = (stage == ApplicationInfo.SideStage);
            var applications = sideStage ? sideStageApplications
                                         : mainStageApplications;

            if (from !== to && applications.count > 0 && from >= 0 && to >= 0) {
                applications.move(from, to, 1);
            }

            updateZOrderOfWindows(applications)
        }

        function updateZOrderOfWindows(applications) {
            var nextZ = 100
            for (var i = 0; i < applications.count; i++ ) {
                var application = applications.get(i);
                application.window.z = nextZ--;
            }
        }

        function deacticateApplication(desktopFile) {
            for (var i = 0; i < mainStageApplications.count; i++ ) {
                var application = mainStageApplications.get(i)
                if (application.desktopFile === desktopFile) {
                    focusApplication(null)
                    application.window.destroy();
                    mainStageApplications.remove(i)
                    updateZOrderOfWindows(mainStageApplications)
                    return;
                }
            }
        }
    }

    Rectangle {
        id: stageRect
        x:0
        y:0
        width: childrenRect.width
        height: childrenRect.height

        color: "grey"

        // This is where the fake windows are held.
        // They stay behind the stage, so that the stage's screenshots are shown
        // on top of them
        // On a real usage scenario, the current application's surface is composited behind
        // the shell's surface (where Stage lives). fakeWindowContainer simulates this stacking
        Item {
            id: fakeWindowContainer
            anchors.fill: parent
        }


        // A black rectangle behind the stage so that the window switch animations
        // look good, just like in Stage's real usage.
        Rectangle {
            anchors.fill: parent
            color: "black"
            visible: stage.usingScreenshots
        }

        Stage {
            id: stage
            y: 0
            shouldUseScreenshots: false
            applicationManager: fakeAppManager
            rightEdgeDraggingAreaWidth: units.gu(2)
            fullyShown: true
            fullyHidden: false
            newApplicationScreenshot: FakeApplicationScreenshot {
                    id: newAppScreenshot
                    parent: stage
                    width: stage.width
                    height: stage.height - stage.y}
            oldApplicationScreenshot: FakeApplicationScreenshot {
                    id: oldAppScreenshot
                    parent: stage
                    width: stage.width
                    height: stage.height - stage.y}
        }
    }

    Rectangle {
        id: controlsRect
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        anchors.left: stageRect.right
        anchors.right: parent.right
        color: "lightgrey"

        Column {
            id: controls
            spacing: units.gu(1)
            AppControl {id: redControl; desktopFile:"red"}
            AppControl {id: greenControl; desktopFile:"green"}
            AppControl {id: blueControl; desktopFile:"blue"}
        }
    }

    UT.UnityTestCase {
        name: "Stage"
        when: windowShown

        function isCurrentAppFadingOut() {
            // it should get a bit translucent and smaller
            return oldAppScreenshot.opacity < 0.99
                && oldAppScreenshot.opacity >= 0.1
                && oldAppScreenshot.scale < 0.99
                && oldAppScreenshot.scale >= 0.1
                && oldAppScreenshot.visible
        }

        function init() {
            redControl.checked = false;
            greenControl.checked = false;
            blueControl.checked = false;
            // give some room for animations to start
            wait(50)
            // wait until animations end, if any
            tryCompare(stage, "usingScreenshots", false)
        }

        /* If you flick from the right edge of the stage leftwards it should cause an
           application switch.  */
        function test_dragFromRightEdgeToSwitchApplication() {
            redControl.checked = true

            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
            tryCompare(stage, "usingScreenshots", false) // and then for it to end
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "red")
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "red")

            greenControl.checked = true

            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
            tryCompare(stage, "usingScreenshots", false) // and then for it to end
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "green")
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "green")

            var touchX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
            var touchY = stage.height / 2
            touchFlick(stage, touchX, touchY, stage.width * 0.25, touchY)

            // wait until animations end, if any
            tryCompare(stage, "usingScreenshots", false)

            // "red" should be the new topmost, focused, application
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "red")
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "red")
        }

        /* When an application is launched, it needs a background before it's drawn on screen
           so that the user does not see the previous running app while the new one is launching.
           When switching between applications, backgrounds are unnecessary, 'cause the
           applications are in front of them. */
        function test_background() {
            redControl.checked = true
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start

            compare(newAppScreenshot.withBackground, true, "starting app screenshot does not have background enabled")

            tryCompare(stage, "usingScreenshots", false) // wait for the animation to finish

            greenControl.checked = true
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
            tryCompare(stage, "usingScreenshots", false) // and finish

            var draggingAreaCenterX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
            var draggingAreaCenterY = stage.height / 2
            var finalTouchX = draggingAreaCenterX - units.gu(5)
            touchFlick(stage, draggingAreaCenterX, draggingAreaCenterY,
                       finalTouchX, draggingAreaCenterY,
                       true /* beginTouch */, false /* endTouch */)

            // wait for the animation to start
            tryCompare(stage, "usingScreenshots", true)

            compare(newAppScreenshot.withBackground, false, "switched app does have background enabled")

            touchRelease(stage, finalTouchX, draggingAreaCenterY)
        }
    }
}