Merge lp:camera-app/staging into lp:camera-app
- staging
- Merge into trunk
Proposed by
Florian Boucault
Status: | Merged | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Florian Boucault | ||||||||||||||||||||||||||||||||
Approved revision: | 686 | ||||||||||||||||||||||||||||||||
Merged at revision: | 643 | ||||||||||||||||||||||||||||||||
Proposed branch: | lp:camera-app/staging | ||||||||||||||||||||||||||||||||
Merge into: | lp:camera-app | ||||||||||||||||||||||||||||||||
Diff against target: |
1655 lines (+587/-221) 25 files modified
GalleryView.qml (+4/-4) GalleryViewHeader.qml (+3/-0) MimeTypeMapper.js (+1/-1) OptionButton.qml (+2/-2) PhotogridView.qml (+42/-6) SlideshowView.qml (+16/-6) UnableShareDialog.qml (+34/-0) ViewFinderOverlay.qml (+16/-9) ViewFinderOverlayLoader.qml (+3/-1) ViewFinderView.qml (+14/-15) camera-app.qml (+41/-18) debian/control (+3/-0) tests/autopilot/camera_app/emulators/main_window.py (+77/-9) tests/autopilot/camera_app/emulators/panel.py (+8/-2) tests/autopilot/camera_app/tests/__init__.py (+14/-8) tests/autopilot/camera_app/tests/test_capture.py (+67/-20) tests/autopilot/camera_app/tests/test_diskspace.py (+4/-7) tests/autopilot/camera_app/tests/test_flash.py (+12/-13) tests/autopilot/camera_app/tests/test_focus.py (+17/-18) tests/autopilot/camera_app/tests/test_gallery_view.py (+118/-41) tests/autopilot/camera_app/tests/test_options.py (+0/-8) tests/autopilot/camera_app/tests/test_photo_editor.py (+2/-22) tests/autopilot/camera_app/tests/test_zoom.py (+0/-10) tests/unittests/CMakeLists.txt (+1/-1) tests/unittests/tst_PhotogridView.qml (+88/-0) |
||||||||||||||||||||||||||||||||
To merge this branch: | bzr merge lp:camera-app/staging | ||||||||||||||||||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | Pending | ||
Review via email: mp+288646@code.launchpad.net |
Commit message
New release:
- Only accept manual focus on points inside the viewfinder.
- viewFinderView.
- Disable controls and prevent navigation while a delayed/timed shoot is ongoing.
- Display a stock icon as the video thumbnail when thumbnailer fails (which it will do now if it can't process a video)
- Allow sharing multiple files, except if they are mixed content
- Only use full screen in staged mode.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'GalleryView.qml' |
2 | --- GalleryView.qml 2016-02-23 11:46:52 +0000 |
3 | +++ GalleryView.qml 2016-03-23 15:42:41 +0000 |
4 | @@ -16,7 +16,7 @@ |
5 | |
6 | import QtQuick 2.4 |
7 | import Ubuntu.Components 1.3 |
8 | -import Ubuntu.Content 0.1 |
9 | +import Ubuntu.Content 1.3 |
10 | import Ubuntu.Thumbnailer 0.1 |
11 | import CameraApp 0.1 |
12 | import "MimeTypeMapper.js" as MimeTypeMapper |
13 | @@ -35,7 +35,7 @@ |
14 | StorageLocations.removableStorageVideosLocation] |
15 | typeFilters: !main.contentExportMode ? [ "image", "video" ] |
16 | : [MimeTypeMapper.contentTypeToMimeType(main.transferContentType)] |
17 | - singleSelectionOnly: main.transfer.selectionType === ContentTransfer.Single |
18 | + singleSelectionOnly: main.contentExportMode && main.transfer.selectionType === ContentTransfer.Single |
19 | } |
20 | |
21 | property bool gridMode: main.contentExportMode |
22 | @@ -58,7 +58,6 @@ |
23 | |
24 | function exitUserSelectionMode() { |
25 | model.clearSelection(); |
26 | - model.singleSelectionOnly = true; |
27 | userSelectionMode = false; |
28 | } |
29 | |
30 | @@ -76,6 +75,7 @@ |
31 | model: galleryView.model |
32 | visible: opacity != 0.0 |
33 | inView: galleryView.inView && galleryView.currentView == slideshowView |
34 | + focus: inView |
35 | inSelectionMode: main.contentExportMode || galleryView.userSelectionMode |
36 | onToggleSelection: model.toggleSelected(currentIndex) |
37 | onToggleHeader: header.toggle(); |
38 | @@ -89,6 +89,7 @@ |
39 | model: galleryView.model |
40 | visible: opacity != 0.0 |
41 | inView: galleryView.inView && galleryView.currentView == photogridView |
42 | + focus: inView |
43 | inSelectionMode: main.contentExportMode || galleryView.userSelectionMode |
44 | onPhotoClicked: { |
45 | slideshowView.showPhotoAtIndex(index); |
46 | @@ -97,7 +98,6 @@ |
47 | onPhotoPressAndHold: { |
48 | if (!galleryView.userSelectionMode) { |
49 | galleryView.userSelectionMode = true; |
50 | - model.singleSelectionOnly = false; |
51 | model.toggleSelected(index); |
52 | } |
53 | } |
54 | |
55 | === modified file 'GalleryViewHeader.qml' |
56 | --- GalleryViewHeader.qml 2016-02-25 13:01:05 +0000 |
57 | +++ GalleryViewHeader.qml 2016-03-23 15:42:41 +0000 |
58 | @@ -153,6 +153,7 @@ |
59 | |
60 | Item { |
61 | id: actionsDrawer |
62 | + objectName: "actionsDrawer" |
63 | |
64 | anchors { |
65 | top: parent.bottom |
66 | @@ -170,6 +171,8 @@ |
67 | } |
68 | |
69 | property bool opened: false |
70 | + property bool fullyOpened: actionsColumn.y == 0 |
71 | + property bool fullyClosed: actionsColumn.y == -actionsColumn.height |
72 | property list<Action> actions |
73 | |
74 | onOpenedChanged: { |
75 | |
76 | === modified file 'MimeTypeMapper.js' |
77 | --- MimeTypeMapper.js 2014-07-31 18:41:17 +0000 |
78 | +++ MimeTypeMapper.js 2016-03-23 15:42:41 +0000 |
79 | @@ -17,7 +17,7 @@ |
80 | */ |
81 | |
82 | .pragma library |
83 | -.import Ubuntu.Content 0.1 as UbuntuContent |
84 | +.import Ubuntu.Content 1.3 as UbuntuContent |
85 | |
86 | function startsWith(string, prefix) { |
87 | return string.indexOf(prefix) === 0; |
88 | |
89 | === modified file 'OptionButton.qml' |
90 | --- OptionButton.qml 2015-11-24 15:44:58 +0000 |
91 | +++ OptionButton.qml 2016-03-23 15:42:41 +0000 |
92 | @@ -26,8 +26,8 @@ |
93 | iconName: !model.get(model.selectedIndex).icon ? model.icon : model.get(model.selectedIndex).icon |
94 | iconSource: (model && model.iconSource) ? model.iconSource : "" |
95 | on: model.isToggle ? model.get(model.selectedIndex).value : true |
96 | - enabled: model.available |
97 | + enabled: model.visible && model.available |
98 | label: model.label |
99 | - visible: model.visible |
100 | + visible: model.visible && model.available |
101 | automaticOrientation: false |
102 | } |
103 | |
104 | === modified file 'PhotogridView.qml' |
105 | --- PhotogridView.qml 2016-02-23 11:46:52 +0000 |
106 | +++ PhotogridView.qml 2016-03-23 15:42:41 +0000 |
107 | @@ -18,11 +18,11 @@ |
108 | import Ubuntu.Components 1.3 |
109 | import Ubuntu.Components.Popups 1.3 |
110 | import Ubuntu.Thumbnailer 0.1 |
111 | -import Ubuntu.Content 0.1 |
112 | +import Ubuntu.Content 1.3 |
113 | import CameraApp 0.1 |
114 | import "MimeTypeMapper.js" as MimeTypeMapper |
115 | |
116 | -Item { |
117 | +FocusScope { |
118 | id: photogridView |
119 | |
120 | property var model |
121 | @@ -40,11 +40,14 @@ |
122 | Action { |
123 | text: i18n.tr("Share") |
124 | iconName: "share" |
125 | - enabled: model.selectedFiles.length <= 1 |
126 | + enabled: model.selectedFiles.length > 0 |
127 | onTriggered: { |
128 | - if (model.selectedFiles.length > 0) { |
129 | - var dialog = PopupUtils.open(sharePopoverComponent) |
130 | - dialog.parent = photogridView |
131 | + // Display a warning message if we are attempting to share mixed |
132 | + // content, as the framework does not properly support this |
133 | + if (selectionContainsMixedMedia()) { |
134 | + PopupUtils.open(unableShareDialogComponent).parent = photogridView; |
135 | + } else { |
136 | + PopupUtils.open(sharePopoverComponent).parent = photogridView; |
137 | } |
138 | } |
139 | }, |
140 | @@ -60,6 +63,19 @@ |
141 | } |
142 | ] |
143 | |
144 | + function selectionContainsMixedMedia() { |
145 | + var selection = model.selectedFiles; |
146 | + var lastType = model.get(selection[0], "fileType"); |
147 | + for (var i = 1; i < selection.length; i++) { |
148 | + var type = model.get(selection[i], "fileType"); |
149 | + if (type !== lastType) { |
150 | + return true; |
151 | + } |
152 | + lastType = type; |
153 | + } |
154 | + return false; |
155 | + } |
156 | + |
157 | function showPhotoAtIndex(index) { |
158 | gridView.positionViewAtIndex(index, GridView.Center); |
159 | } |
160 | @@ -139,6 +155,16 @@ |
161 | visible: isVideo |
162 | } |
163 | |
164 | + Icon { |
165 | + objectName: "thumbnailLoadingErrorIcon" |
166 | + anchors.centerIn: parent |
167 | + width: units.gu(6) |
168 | + height: width |
169 | + name: cellDelegate.isVideo ? "stock_video" : "stock_image" |
170 | + color: "white" |
171 | + opacity: thumbnail.status == Image.Error ? 1.0 : 0.0 |
172 | + } |
173 | + |
174 | MouseArea { |
175 | anchors.fill: parent |
176 | onClicked: photogridView.photoClicked(index) |
177 | @@ -160,6 +186,7 @@ |
178 | visible: inSelectionMode |
179 | |
180 | Icon { |
181 | + objectName: "mediaItemCheckBox" |
182 | anchors.centerIn: parent |
183 | width: parent.width * 0.8 |
184 | height: parent.height * 0.8 |
185 | @@ -225,4 +252,13 @@ |
186 | onVisibleChanged: photogridView.toggleHeader() |
187 | } |
188 | } |
189 | + |
190 | + Component { |
191 | + id: unableShareDialogComponent |
192 | + UnableShareDialog { |
193 | + objectName: "unableShareDialog" |
194 | + onVisibleChanged: photogridView.toggleHeader() |
195 | + } |
196 | + } |
197 | + |
198 | } |
199 | |
200 | === modified file 'SlideshowView.qml' |
201 | --- SlideshowView.qml 2016-02-23 11:46:52 +0000 |
202 | +++ SlideshowView.qml 2016-03-23 15:42:41 +0000 |
203 | @@ -18,12 +18,12 @@ |
204 | import Ubuntu.Components 1.3 |
205 | import Ubuntu.Components.ListItems 1.3 as ListItems |
206 | import Ubuntu.Components.Popups 1.3 |
207 | -import Ubuntu.Content 0.1 |
208 | +import Ubuntu.Content 1.3 |
209 | import Ubuntu.Thumbnailer 0.1 |
210 | import CameraApp 0.1 |
211 | import "MimeTypeMapper.js" as MimeTypeMapper |
212 | |
213 | -Item { |
214 | +FocusScope { |
215 | id: slideshowView |
216 | |
217 | property var model |
218 | @@ -111,14 +111,12 @@ |
219 | |
220 | anchors.fill: parent |
221 | model: slideshowView.model |
222 | + focus: true |
223 | orientation: ListView.Horizontal |
224 | boundsBehavior: Flickable.StopAtBounds |
225 | cacheBuffer: width |
226 | highlightRangeMode: ListView.StrictlyEnforceRange |
227 | - // FIXME: this disables the animation introduced by highlightRangeMode |
228 | - // happening setting currentIndex; it is necessary at least because we |
229 | - // were hitting https://bugreports.qt-project.org/browse/QTBUG-41035 |
230 | - highlightMoveDuration: 0 |
231 | + highlightMoveDuration: UbuntuAnimation.FastDuration |
232 | snapMode: ListView.SnapOneItem |
233 | onCountChanged: { |
234 | // currentIndex is -1 by default and stays so until manually set to something else |
235 | @@ -140,6 +138,7 @@ |
236 | } |
237 | delegate: Item { |
238 | id: delegate |
239 | + objectName: "mediaItem" + index |
240 | property bool pinchInProgress: zoomPinchArea.active |
241 | property string url: fileURL |
242 | property bool isSelected: selected |
243 | @@ -183,6 +182,7 @@ |
244 | property real maximumZoom: 3.0 |
245 | property bool active: false |
246 | property var center |
247 | + enabled: !media.isVideo |
248 | |
249 | onPinchStarted: { |
250 | active = true; |
251 | @@ -258,6 +258,16 @@ |
252 | } |
253 | fillMode: Image.PreserveAspectFit |
254 | } |
255 | + |
256 | + Icon { |
257 | + objectName: "thumbnailLoadingErrorIcon" |
258 | + anchors.centerIn: parent |
259 | + width: units.gu(30) |
260 | + height: width |
261 | + name: media.isVideo ? "stock_video" : "stock_image" |
262 | + color: "white" |
263 | + opacity: image.status == Image.Error ? 1.0 : 0.0 |
264 | + } |
265 | } |
266 | |
267 | Icon { |
268 | |
269 | === added file 'UnableShareDialog.qml' |
270 | --- UnableShareDialog.qml 1970-01-01 00:00:00 +0000 |
271 | +++ UnableShareDialog.qml 2016-03-23 15:42:41 +0000 |
272 | @@ -0,0 +1,34 @@ |
273 | +/* |
274 | + * Copyright (C) 2016 Canonical Ltd |
275 | + * |
276 | + * This program is free software: you can redistribute it and/or modify |
277 | + * it under the terms of the GNU General Public License version 3 as |
278 | + * published by the Free Software Foundation. |
279 | + * |
280 | + * This program is distributed in the hope that it will be useful, |
281 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
282 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
283 | + * GNU General Public License for more details. |
284 | + * |
285 | + * You should have received a copy of the GNU General Public License |
286 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
287 | + */ |
288 | + |
289 | +import QtQuick 2.4 |
290 | +import Ubuntu.Components 1.3 |
291 | +import Ubuntu.Components.Popups 1.3 |
292 | + |
293 | +Dialog { |
294 | + id: dialog |
295 | + objectName: "unableShareDialog" |
296 | + |
297 | + title: i18n.tr("Unable to share") |
298 | + text: i18n.tr("Unable to share photos and videos at the same time") |
299 | + |
300 | + Button { |
301 | + objectName: "unableShareDialogOk" |
302 | + text: i18n.tr("Ok") |
303 | + color: UbuntuColors.orange |
304 | + onClicked: PopupUtils.close(dialog); |
305 | + } |
306 | +} |
307 | |
308 | === modified file 'ViewFinderOverlay.qml' |
309 | --- ViewFinderOverlay.qml 2016-02-23 11:46:52 +0000 |
310 | +++ ViewFinderOverlay.qml 2016-03-23 15:42:41 +0000 |
311 | @@ -33,6 +33,7 @@ |
312 | property var controls: controls |
313 | property var settings: settings |
314 | property bool readyForCapture |
315 | + property int sensorOrientation |
316 | |
317 | function showFocusRing(x, y) { |
318 | focusRing.center = Qt.point(x, y); |
319 | @@ -289,6 +290,7 @@ |
320 | id: bottomEdgeClose |
321 | anchors.fill: parent |
322 | onClicked: optionsOverlayClose() |
323 | + enabled: !camera.timedCaptureInProgress |
324 | } |
325 | |
326 | OrientationHelper { |
327 | @@ -305,8 +307,9 @@ |
328 | height: optionsOverlayLoader.height |
329 | onOpenedChanged: optionsOverlayLoader.item.closeValueSelector() |
330 | enabled: camera.videoRecorder.recorderState == CameraRecorder.StoppedState |
331 | - && !camera.photoCaptureInProgress |
332 | + && !camera.photoCaptureInProgress && !camera.timedCaptureInProgress |
333 | opacity: enabled ? 1.0 : 0.3 |
334 | + property bool ready: optionsOverlayLoader.status == Loader.Ready |
335 | |
336 | /* At startup, opened is false and 'bottomEdge.height' is 0 until |
337 | optionsOverlayLoader has finished loading. When that happens |
338 | @@ -652,13 +655,15 @@ |
339 | enabled: visible |
340 | |
341 | function timedShoot(secs) { |
342 | + camera.timedCaptureInProgress = true; |
343 | timedShootFeedback.start(); |
344 | shootingTimer.remainingSecs = secs; |
345 | shootingTimer.start(); |
346 | } |
347 | |
348 | function cancelTimedShoot() { |
349 | - if (shootingTimer.running) { |
350 | + if (camera.timedCaptureInProgress) { |
351 | + camera.timedCaptureInProgress = false; |
352 | shootingTimer.stop(); |
353 | timedShootFeedback.stop(); |
354 | } |
355 | @@ -692,9 +697,8 @@ |
356 | break; |
357 | } |
358 | |
359 | - if (Screen.primaryOrientation == Qt.PortraitOrientation) { |
360 | - orientation += 90; |
361 | - } |
362 | + // account for the orientation of the sensor |
363 | + orientation -= viewFinderOverlay.sensorOrientation; |
364 | |
365 | if (camera.captureMode == Camera.CaptureVideo) { |
366 | if (main.contentExportMode) { |
367 | @@ -774,6 +778,7 @@ |
368 | onTriggered: { |
369 | if (remainingSecs == 0) { |
370 | running = false; |
371 | + camera.timedCaptureInProgress = false; |
372 | controls.shoot(); |
373 | timedShootFeedback.stop(); |
374 | } else { |
375 | @@ -819,7 +824,7 @@ |
376 | iconName: (camera.captureMode == Camera.CaptureStillImage) ? "camcorder" : "camera-symbolic" |
377 | onClicked: controls.changeRecordMode() |
378 | enabled: camera.videoRecorder.recorderState == CameraRecorder.StoppedState && !main.contentExportMode |
379 | - && !camera.photoCaptureInProgress |
380 | + && !camera.photoCaptureInProgress && !camera.timedCaptureInProgress |
381 | } |
382 | |
383 | ShootButton { |
384 | @@ -833,6 +838,7 @@ |
385 | } |
386 | |
387 | enabled: viewFinderOverlay.readyForCapture && !storageMonitor.diskSpaceCriticallyLow |
388 | + && !camera.timedCaptureInProgress |
389 | state: (camera.captureMode == Camera.CaptureVideo) ? |
390 | ((camera.videoRecorder.recorderState == CameraRecorder.StoppedState) ? "record_off" : "record_on") : |
391 | "camera" |
392 | @@ -869,7 +875,7 @@ |
393 | } |
394 | |
395 | enabled: !camera.switchInProgress && camera.videoRecorder.recorderState == CameraRecorder.StoppedState |
396 | - && !camera.photoCaptureInProgress |
397 | + && !camera.photoCaptureInProgress && !camera.timedCaptureInProgress |
398 | iconName: "camera-flip" |
399 | onClicked: controls.switchCamera() |
400 | } |
401 | @@ -892,7 +898,7 @@ |
402 | property real maximumScale: 3.0 |
403 | property bool active: false |
404 | |
405 | - enabled: !camera.photoCaptureInProgress |
406 | + enabled: !camera.photoCaptureInProgress && !camera.timedCaptureInProgress |
407 | onPinchStarted: { |
408 | active = true; |
409 | initialZoom = zoomControl.value; |
410 | @@ -910,6 +916,7 @@ |
411 | |
412 | MouseArea { |
413 | id: manualFocusMouseArea |
414 | + objectName: "manualFocusMouseArea" |
415 | anchors { |
416 | fill: parent |
417 | // Pinch gestures need more clearance at the edges of the screen, but |
418 | @@ -918,7 +925,7 @@ |
419 | rightMargin: -bottomEdgeIndicators.height |
420 | } |
421 | enabled: camera.focus.isFocusPointModeSupported(Camera.FocusPointCustom) && |
422 | - !camera.photoCaptureInProgress |
423 | + !camera.photoCaptureInProgress && !camera.timedCaptureInProgress |
424 | onClicked: { |
425 | camera.manualFocus(mouse.x, mouse.y); |
426 | mouse.accepted = false; |
427 | |
428 | === modified file 'ViewFinderOverlayLoader.qml' |
429 | --- ViewFinderOverlayLoader.qml 2016-02-23 11:46:52 +0000 |
430 | +++ ViewFinderOverlayLoader.qml 2016-03-23 15:42:41 +0000 |
431 | @@ -25,6 +25,7 @@ |
432 | property var controls: loader.item ? loader.item.controls : null |
433 | property var settings: loader.item.settings |
434 | property bool readyForCapture |
435 | + property int sensorOrientation |
436 | |
437 | function showFocusRing(x, y) { |
438 | loader.item.showFocusRing(x, y); |
439 | @@ -37,7 +38,8 @@ |
440 | asynchronous: true |
441 | Component.onCompleted: { |
442 | loader.setSource("ViewFinderOverlay.qml", { "camera": loader.camera, |
443 | - "readyForCapture": Qt.binding(function() { return loader.readyForCapture}) |
444 | + "readyForCapture": Qt.binding(function() { return loader.readyForCapture}), |
445 | + "sensorOrientation": Qt.binding(function () {return loader.sensorOrientation}) |
446 | }); |
447 | } |
448 | } |
449 | |
450 | === modified file 'ViewFinderView.qml' |
451 | --- ViewFinderView.qml 2016-02-23 11:46:52 +0000 |
452 | +++ ViewFinderView.qml 2016-03-23 15:42:41 +0000 |
453 | @@ -21,9 +21,9 @@ |
454 | import QtMultimedia 5.0 |
455 | import CameraApp 0.1 |
456 | import QtGraphicalEffects 1.0 |
457 | -import Ubuntu.Content 0.1 |
458 | +import Ubuntu.Content 1.3 |
459 | |
460 | -Item { |
461 | +FocusScope { |
462 | id: viewFinderView |
463 | |
464 | property bool overlayVisible: true |
465 | @@ -60,11 +60,15 @@ |
466 | property bool failedToConnect: false |
467 | |
468 | function manualFocus(x, y) { |
469 | - viewFinderOverlay.showFocusRing(x, y); |
470 | - autoFocusTimer.restart(); |
471 | - focus.focusMode = Camera.FocusAuto; |
472 | - focus.customFocusPoint = viewFinder.mapPointToSourceNormalized(Qt.point(x, y)); |
473 | - focus.focusPointMode = Camera.FocusPointCustom; |
474 | + var normalizedPoint = viewFinder.mapPointToSourceNormalized(Qt.point(x, y - viewFinder.y)); |
475 | + if (normalizedPoint.x >= 0.0 && normalizedPoint.x <= 1.0 && |
476 | + normalizedPoint.y >= 0.0 && normalizedPoint.y <= 1.0) { |
477 | + viewFinderOverlay.showFocusRing(x, y); |
478 | + autoFocusTimer.restart(); |
479 | + focus.focusMode = Camera.FocusAuto; |
480 | + focus.customFocusPoint = normalizedPoint; |
481 | + focus.focusPointMode = Camera.FocusPointCustom; |
482 | + } |
483 | } |
484 | |
485 | function autoFocus() { |
486 | @@ -96,6 +100,7 @@ |
487 | property alias maximumZoom: camera.maximumDigitalZoom |
488 | property bool switchInProgress: false |
489 | property bool photoCaptureInProgress: false |
490 | + property bool timedCaptureInProgress: false |
491 | |
492 | onPhotoCaptureInProgressChanged: { |
493 | if (main.contentExportMode && camera.photoCaptureInProgress) { |
494 | @@ -110,14 +115,6 @@ |
495 | if (photoRollHint.necessary && !main.transfer) photoRollHint.enable(); |
496 | camera.photoCaptureInProgress = false; |
497 | } |
498 | - |
499 | - if (main.transfer) { |
500 | - if (main.transfer.contentType === ContentType.Videos) { |
501 | - viewFinderView.captureMode = Camera.CaptureVideo; |
502 | - } else { |
503 | - viewFinderView.captureMode = Camera.CaptureStillImage; |
504 | - } |
505 | - } |
506 | } |
507 | } |
508 | |
509 | @@ -265,6 +262,7 @@ |
510 | // Set orientation only at startup because later on Screen.primaryOrientation |
511 | // may change. |
512 | orientation = Screen.primaryOrientation === Qt.PortraitOrientation ? -90 : 0; |
513 | + viewFinderOverlay.sensorOrientation = orientation; |
514 | } |
515 | |
516 | transform: Rotation { |
517 | @@ -421,6 +419,7 @@ |
518 | |
519 | PhotoRollHint { |
520 | id: photoRollHint |
521 | + objectName: "photoRollHint" |
522 | anchors.fill: parent |
523 | visible: enabled |
524 | |
525 | |
526 | === modified file 'camera-app.qml' |
527 | --- camera-app.qml 2016-02-23 11:46:52 +0000 |
528 | +++ camera-app.qml 2016-03-23 15:42:41 +0000 |
529 | @@ -20,7 +20,7 @@ |
530 | import Ubuntu.Components 1.3 |
531 | import Ubuntu.Unity.Action 1.1 as UnityActions |
532 | import UserMetrics 0.1 |
533 | -import Ubuntu.Content 0.1 |
534 | +import Ubuntu.Content 1.3 |
535 | import CameraApp 0.1 |
536 | |
537 | Window { |
538 | @@ -30,6 +30,26 @@ |
539 | height: units.gu(80) |
540 | color: "black" |
541 | title: "Camera" |
542 | + // special flag only supported by Unity8/MIR so far that hides the shell's |
543 | + // top panel in Staged mode |
544 | + flags: Qt.Window | 0x00800000 |
545 | + |
546 | + property int preFullScreenVisibility |
547 | + |
548 | + function toggleFullScreen() { |
549 | + if (main.visibility != Window.FullScreen) { |
550 | + preFullScreenVisibility = main.visibility; |
551 | + main.visibility = Window.FullScreen; |
552 | + } else { |
553 | + main.visibility = preFullScreenVisibility; |
554 | + } |
555 | + } |
556 | + |
557 | + function exitFullScreen() { |
558 | + if (main.visibility == Window.FullScreen) { |
559 | + main.visibility = preFullScreenVisibility; |
560 | + } |
561 | + } |
562 | |
563 | UnityActions.ActionManager { |
564 | actions: [ |
565 | @@ -63,11 +83,7 @@ |
566 | |
567 | Component.onCompleted: { |
568 | i18n.domain = "camera-app"; |
569 | - if (!application.desktopMode) { |
570 | - main.showFullScreen(); |
571 | - } else { |
572 | - main.show(); |
573 | - } |
574 | + main.show(); |
575 | } |
576 | |
577 | |
578 | @@ -78,6 +94,15 @@ |
579 | flickableDirection: state == "PORTRAIT" ? Flickable.HorizontalFlick : Flickable.VerticalFlick |
580 | boundsBehavior: Flickable.StopAtBounds |
581 | |
582 | + Keys.onPressed: { |
583 | + if (event.key == Qt.Key_F11) { |
584 | + main.toggleFullScreen(); |
585 | + event.accepted = true; |
586 | + } |
587 | + } |
588 | + Keys.onEscapePressed: main.exitFullScreen() |
589 | + |
590 | + |
591 | property real panesMargin: units.gu(1) |
592 | property real ratio |
593 | property int orientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) |
594 | @@ -135,7 +160,9 @@ |
595 | } |
596 | } |
597 | ] |
598 | - interactive: !viewFinderView.touchAcquired && !galleryView.touchAcquired && !viewFinderView.camera.photoCaptureInProgress |
599 | + interactive: !viewFinderView.touchAcquired && !galleryView.touchAcquired |
600 | + && !viewFinderView.camera.photoCaptureInProgress |
601 | + && !viewFinderView.camera.timedCaptureInProgress |
602 | |
603 | Component.onCompleted: { |
604 | // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition |
605 | @@ -256,6 +283,7 @@ |
606 | height: viewSwitcher.height |
607 | overlayVisible: !viewSwitcher.moving && !viewSwitcher.flicking |
608 | inView: viewSwitcher.ratio < 0.5 |
609 | + focus: !galleryView.focus |
610 | opacity: inView ? 1.0 : 0.0 |
611 | onPhotoTaken: { |
612 | galleryView.prependMediaToModel(filePath); |
613 | @@ -273,6 +301,7 @@ |
614 | width: viewSwitcher.width |
615 | height: viewSwitcher.height |
616 | inView: viewSwitcher.ratio > 0.0 |
617 | + focus: inView |
618 | onExit: viewSwitcher.switchToViewFinder() |
619 | opacity: inView ? 1.0 : 0.0 |
620 | } |
621 | @@ -280,7 +309,7 @@ |
622 | |
623 | property bool contentExportMode: transfer !== null |
624 | property var transfer: null |
625 | - property var transferContentType: ContentType.Pictures |
626 | + property var transferContentType: transfer ? transfer.contentType : "image" |
627 | |
628 | function exportContent(urls) { |
629 | if (!main.transfer) return; |
630 | @@ -312,16 +341,10 @@ |
631 | onExportRequested: { |
632 | viewSwitcher.switchToViewFinder(); |
633 | |
634 | - // The exportRequested event can arrive before or after the |
635 | - // app is active, but setting the recording type before the |
636 | - // capture becomes ready does not have any effect. |
637 | - // See camera.imageCapture.onReadyChanged for the other case. |
638 | - if (viewFinderView.camera.imageCapture.ready) { |
639 | - if (transfer.contentType === ContentType.Videos) { |
640 | - viewFinderView.captureMode = Camera.CaptureVideo; |
641 | - } else { |
642 | - viewFinderView.captureMode = Camera.CaptureStillImage; |
643 | - } |
644 | + if (transfer.contentType === ContentType.Videos) { |
645 | + viewFinderView.captureMode = Camera.CaptureVideo; |
646 | + } else { |
647 | + viewFinderView.captureMode = Camera.CaptureStillImage; |
648 | } |
649 | main.transfer = transfer; |
650 | } |
651 | |
652 | === modified file 'debian/control' |
653 | --- debian/control 2015-07-31 02:23:54 +0000 |
654 | +++ debian/control 2016-03-23 15:42:41 +0000 |
655 | @@ -13,11 +13,14 @@ |
656 | qtbase5-dev, |
657 | qtdeclarative5-dev, |
658 | qml-module-qtquick2, |
659 | + qml-module-qtpositioning, |
660 | qml-module-qttest, |
661 | qtdeclarative5-ubuntu-ui-toolkit-plugin, |
662 | qtdeclarative5-unity-action-plugin (>= 1.1.0), |
663 | qtdeclarative5-usermetrics0.1, |
664 | qtdeclarative5-ubuntu-content1, |
665 | + qtdeclarative5-ubuntu-thumbnailer0.1, |
666 | + qtdeclarative5-ubuntu-ui-extras0.2, |
667 | qtmultimedia5-dev, |
668 | libusermetricsinput1-dev, |
669 | gettext, |
670 | |
671 | === modified file 'tests/autopilot/camera_app/emulators/main_window.py' |
672 | --- tests/autopilot/camera_app/emulators/main_window.py 2015-11-25 17:00:31 +0000 |
673 | +++ tests/autopilot/camera_app/emulators/main_window.py 2016-03-23 15:42:41 +0000 |
674 | @@ -36,10 +36,29 @@ |
675 | """Returns the gallery view""" |
676 | return self.app.wait_select_single("GalleryView") |
677 | |
678 | + def get_media(self, index=0): |
679 | + """Returns media at index in the currently loaded view in gallery""" |
680 | + gallery = self.get_gallery() |
681 | + view = gallery.select_single("SlideshowView") |
682 | + if not view.visible: |
683 | + view = gallery.select_single("PhotogridView") |
684 | + |
685 | + return view.wait_select_single(objectName="mediaItem" + str(index)) |
686 | + |
687 | + def get_broken_media_icon(self, index=0): |
688 | + """Returns the broken media icon""" |
689 | + media = self.get_media(index) |
690 | + return media.wait_select_single(objectName="thumbnailLoadingErrorIcon") |
691 | + |
692 | def get_no_media_hint(self): |
693 | """Returns the Item representing the hint that no media is available""" |
694 | return self.app.wait_select_single(objectName="noMediaHint") |
695 | |
696 | + def get_focus_mouse_area(self): |
697 | + """Returns the focus mouse area""" |
698 | + return self.app.wait_select_single("QQuickMouseArea", |
699 | + objectName="manualFocusMouseArea") |
700 | + |
701 | def get_focus_ring(self): |
702 | """Returns the focus ring of the camera""" |
703 | return self.app.wait_select_single("FocusRing") |
704 | @@ -49,9 +68,9 @@ |
705 | return self.app.wait_select_single("ShootButton") |
706 | |
707 | def get_photo_roll_hint(self): |
708 | - """Returns the layer that serves at hinting to the existence of the |
709 | - photo roll""" |
710 | - return self.app.wait_select_single("PhotoRollHint") |
711 | + """Returns the photo roll hint""" |
712 | + return self.app.wait_select_single("PhotoRollHint", |
713 | + objectName="photoRollHint") |
714 | |
715 | def get_record_control(self): |
716 | """Returns the button that toggles between photo and video recording""" |
717 | @@ -63,8 +82,12 @@ |
718 | in settingsProperty |
719 | """ |
720 | optionButtons = self.app.select_many("OptionButton") |
721 | - return next(button for button in optionButtons |
722 | - if button.settingsProperty == settingsProperty) |
723 | + optionButton = next(button for button in optionButtons |
724 | + if button.settingsProperty == settingsProperty) |
725 | + if optionButton.visible: |
726 | + return optionButton |
727 | + else: |
728 | + return None |
729 | |
730 | def get_flash_button(self): |
731 | """Returns the flash control button of the camera""" |
732 | @@ -90,6 +113,10 @@ |
733 | """Returns the video resolution button of the camera""" |
734 | return self.get_option_button("videoResolution") |
735 | |
736 | + def get_timer_delay_button(self): |
737 | + """Returns the timer delay option button of the camera""" |
738 | + return self.get_option_button("selfTimerDelay") |
739 | + |
740 | def get_stop_watch(self): |
741 | """Returns the stop watch when using the record button of the camera""" |
742 | return self.app.wait_select_single("StopWatch") |
743 | @@ -139,30 +166,71 @@ |
744 | except: |
745 | return None |
746 | |
747 | + def open_actions_drawer(self, gallery): |
748 | + """Opens action drawer of gallery""" |
749 | + actionsDrawerButton = gallery.wait_select_single( |
750 | + "IconButton", |
751 | + objectName="additionalActionsButton") |
752 | + self.app.pointing_device.move_to_object(actionsDrawerButton) |
753 | + self.app.pointing_device.click() |
754 | + actionsDrawer = gallery.wait_select_single("QQuickItem", |
755 | + objectName="actionsDrawer") |
756 | + actionsDrawer.fullyOpened.wait_for(True) |
757 | + |
758 | + def close_actions_drawer(self, gallery): |
759 | + """Closes action drawer of gallery""" |
760 | + actionsDrawerButton = gallery.wait_select_single( |
761 | + "IconButton", |
762 | + objectName="additionalActionsButton") |
763 | + self.app.pointing_device.move_to_object(actionsDrawerButton) |
764 | + self.app.pointing_device.click() |
765 | + actionsDrawer = gallery.wait_select_single("QQuickItem", |
766 | + objectName="actionsDrawer") |
767 | + actionsDrawer.fullyClosed.wait_for(True) |
768 | + |
769 | def swipe_to_gallery(self, testCase): |
770 | view_switcher = self.get_view_switcher() |
771 | + viewfinder = self.get_viewfinder() |
772 | + view_switcher.interactive.wait_for(True) |
773 | + view_switcher.enabled.wait_for(True) |
774 | + view_switcher.settling.wait_for(False) |
775 | + view_switcher.switching.wait_for(False) |
776 | + viewfinder.inView.wait_for(True) |
777 | x, y = view_switcher.x, view_switcher.y |
778 | w, h = view_switcher.width, view_switcher.height |
779 | |
780 | tx = x + (w // 2) |
781 | ty = y + (h // 2) |
782 | |
783 | - self.app.pointing_device.drag(tx, ty, x, ty, rate=1) |
784 | - viewfinder = self.get_viewfinder() |
785 | + # FIXME: a rate higher than 1 does not always make view_switcher move |
786 | + self.app.pointing_device.drag(tx, ty, x, ty, rate=1, |
787 | + time_between_events=0.0001) |
788 | + |
789 | testCase.assertThat(viewfinder.inView, Eventually(Equals(False))) |
790 | + view_switcher.settling.wait_for(False) |
791 | + view_switcher.switching.wait_for(False) |
792 | |
793 | def swipe_to_viewfinder(self, testCase): |
794 | view_switcher = self.get_view_switcher() |
795 | + viewfinder = self.get_viewfinder() |
796 | + view_switcher.interactive.wait_for(True) |
797 | + view_switcher.enabled.wait_for(True) |
798 | + view_switcher.settling.wait_for(False) |
799 | + view_switcher.switching.wait_for(False) |
800 | + viewfinder.inView.wait_for(False) |
801 | x, y = view_switcher.x, view_switcher.y |
802 | w, h = view_switcher.width, view_switcher.height |
803 | |
804 | tx = x + (w // 2) |
805 | ty = y + (h // 2) |
806 | |
807 | + # FIXME: a rate higher than 1 does not always make view_switcher move |
808 | self.app.pointing_device.drag( |
809 | - tx, ty, (tx + view_switcher.width // 2), ty, rate=1) |
810 | - viewfinder = self.get_viewfinder() |
811 | + tx, ty, (tx + view_switcher.width // 2), ty, rate=1, |
812 | + time_between_events=0.0001) |
813 | testCase.assertThat(viewfinder.inView, Eventually(Equals(True))) |
814 | + view_switcher.settling.wait_for(False) |
815 | + view_switcher.switching.wait_for(False) |
816 | |
817 | def switch_cameras(self): |
818 | # Swap cameras and wait for camera to settle |
819 | |
820 | === modified file 'tests/autopilot/camera_app/emulators/panel.py' |
821 | --- tests/autopilot/camera_app/emulators/panel.py 2015-12-01 09:03:34 +0000 |
822 | +++ tests/autopilot/camera_app/emulators/panel.py 2016-03-23 15:42:41 +0000 |
823 | @@ -24,6 +24,7 @@ |
824 | :return: The panel. |
825 | |
826 | """ |
827 | + self.ready.wait_for(True) |
828 | self.animating.wait_for(False) |
829 | if not self.opened: |
830 | self._drag_to_open() |
831 | @@ -38,11 +39,14 @@ |
832 | start_y = y + self.height - 1 |
833 | stop_y = y |
834 | |
835 | - self.pointing_device.drag(line_x, start_y, line_x, stop_y) |
836 | + # FIXME: a rate higher than 1 does not always make panel move |
837 | + self.pointing_device.drag(line_x, start_y, line_x, stop_y, rate=1, |
838 | + time_between_events=0.0001) |
839 | |
840 | @autopilot_logging.log_action(logger.info) |
841 | def close(self): |
842 | """Close the panel if it's opened.""" |
843 | + self.ready.wait_for(True) |
844 | self.animating.wait_for(False) |
845 | if self.opened: |
846 | self._drag_to_close() |
847 | @@ -55,4 +59,6 @@ |
848 | start_y = y |
849 | stop_y = y + self.height - 1 |
850 | |
851 | - self.pointing_device.drag(line_x, start_y, line_x, stop_y) |
852 | + # FIXME: a rate higher than 1 does not always make panel move |
853 | + self.pointing_device.drag(line_x, start_y, line_x, stop_y, rate=1, |
854 | + time_between_events=0.0001) |
855 | |
856 | === modified file 'tests/autopilot/camera_app/tests/__init__.py' |
857 | --- tests/autopilot/camera_app/tests/__init__.py 2015-05-15 07:29:16 +0000 |
858 | +++ tests/autopilot/camera_app/tests/__init__.py 2016-03-23 15:42:41 +0000 |
859 | @@ -8,7 +8,6 @@ |
860 | """Camera-app autopilot tests.""" |
861 | |
862 | import os |
863 | -import time |
864 | import shutil |
865 | from pkg_resources import resource_filename |
866 | |
867 | @@ -42,6 +41,12 @@ |
868 | sample_dir = resource_filename('camera_app', 'data') |
869 | |
870 | def setUp(self): |
871 | + # Remove configuration file |
872 | + config_file = os.path.expanduser( |
873 | + "~/.config/com.ubuntu.camera/com.ubuntu.camera.conf") |
874 | + if os.path.exists(config_file): |
875 | + os.remove(config_file) |
876 | + |
877 | self.pointing_device = Pointer(self.input_device_class.create()) |
878 | super(CameraAppTestCase, self).setUp() |
879 | if os.path.exists(self.local_location): |
880 | @@ -51,11 +56,7 @@ |
881 | else: |
882 | self.launch_click_installed() |
883 | |
884 | - # wait and sleep as workaround for bug #1373039. To |
885 | - # make sure large components get loaded asynchronously on start-up |
886 | - # -- Chris Gagnon 11-17-2014 |
887 | self.main_window.get_qml_view().visible.wait_for(True) |
888 | - time.sleep(5) |
889 | |
890 | def launch_test_local(self): |
891 | self.app = self.launch_test_application( |
892 | @@ -107,6 +108,11 @@ |
893 | shutil.copyfile(os.path.join(self.sample_dir, "sample.jpg"), |
894 | os.path.join(self.pictures_dir, "sample.jpg")) |
895 | |
896 | - def add_sample_video(self): |
897 | - shutil.copyfile(os.path.join(self.sample_dir, "sample.mp4"), |
898 | - os.path.join(self.videos_dir, "sample.mp4")) |
899 | + def add_sample_video(self, broken=False): |
900 | + if broken: |
901 | + path = os.path.join(self.videos_dir, "sample_broken.mp4") |
902 | + with open(path, "w") as video: |
903 | + video.write("I AM NOT A VIDEO") |
904 | + else: |
905 | + shutil.copyfile(os.path.join(self.sample_dir, "sample.mp4"), |
906 | + os.path.join(self.videos_dir, "sample.mp4")) |
907 | |
908 | === modified file 'tests/autopilot/camera_app/tests/test_capture.py' |
909 | --- tests/autopilot/camera_app/tests/test_capture.py 2015-12-01 09:03:34 +0000 |
910 | +++ tests/autopilot/camera_app/tests/test_capture.py 2016-03-23 15:42:41 +0000 |
911 | @@ -17,6 +17,7 @@ |
912 | import unittest |
913 | import time |
914 | import os |
915 | +import glob |
916 | |
917 | |
918 | class TestCapture(CameraAppTestCase): |
919 | @@ -25,23 +26,10 @@ |
920 | """ This is needed to wait for the application to start. |
921 | In the testfarm, the application may take some time to show up.""" |
922 | def setUp(self): |
923 | - # Remove configuration file where knowledge of the photo roll hint's |
924 | - # necessity is stored |
925 | - config_file = os.path.expanduser( |
926 | - "~/.config/com.ubuntu.camera/com.ubuntu.camera.conf") |
927 | - if os.path.exists(config_file): |
928 | - os.remove(config_file) |
929 | - |
930 | super(TestCapture, self).setUp() |
931 | - |
932 | - self.assertThat( |
933 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
934 | self.pictures_dir = os.path.expanduser("~/Pictures/com.ubuntu.camera") |
935 | self.videos_dir = os.path.expanduser("~/Videos/com.ubuntu.camera") |
936 | |
937 | - def tearDown(self): |
938 | - super(TestCapture, self).tearDown() |
939 | - |
940 | """Test taking a picture""" |
941 | def test_take_picture(self): |
942 | exposure_button = self.main_window.get_exposure_button() |
943 | @@ -83,6 +71,62 @@ |
944 | # check that the camera is able to capture another photo |
945 | self.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
946 | |
947 | + """Test taking a picture with a timer set""" |
948 | + def test_take_picture_with_timer(self): |
949 | + delay = 5 |
950 | + self.enable_timer("%s seconds" % str(delay)) |
951 | + |
952 | + # start timed shoot |
953 | + shoot_button = self.main_window.get_exposure_button() |
954 | + self.assertThat(shoot_button.enabled, Eventually(Equals(True))) |
955 | + self.pointing_device.move_to_object(shoot_button) |
956 | + self.pointing_device.click() |
957 | + |
958 | + switch_cameras_button = self.main_window.get_swap_camera_button() |
959 | + record_mode_button = self.main_window.get_record_control() |
960 | + view_switcher = self.main_window.get_view_switcher() |
961 | + |
962 | + # controls and navigation should be disabled at this point |
963 | + self.assertThat(shoot_button.enabled, |
964 | + Eventually(Equals(True))) |
965 | + self.assertThat(switch_cameras_button.enabled, |
966 | + Eventually(Equals(True))) |
967 | + self.assertThat(record_mode_button.enabled, |
968 | + Eventually(Equals(True))) |
969 | + self.assertThat(view_switcher.interactive, |
970 | + Eventually(Equals(True))) |
971 | + |
972 | + # after the delay controls and navigation should be re-enabled |
973 | + self.assertThat(shoot_button.enabled, |
974 | + Eventually(Equals(True), timeout=delay)) |
975 | + self.assertThat(switch_cameras_button.enabled, |
976 | + Eventually(Equals(True), timeout=delay)) |
977 | + self.assertThat(record_mode_button.enabled, |
978 | + Eventually(Equals(True), timeout=delay)) |
979 | + self.assertThat(view_switcher.interactive, |
980 | + Eventually(Equals(True), timeout=delay)) |
981 | + |
982 | + def enable_timer(self, label_value): |
983 | + # open bottom edge |
984 | + bottom_edge = self.main_window.get_bottom_edge() |
985 | + bottom_edge.open() |
986 | + |
987 | + # open video resolution option value selector showing the possible |
988 | + # values |
989 | + timer_delay_button = self.main_window.get_timer_delay_button() |
990 | + self.pointing_device.move_to_object(timer_delay_button) |
991 | + self.pointing_device.click() |
992 | + option_value_selector = self.main_window.get_option_value_selector() |
993 | + self.assertThat( |
994 | + option_value_selector.visible, Eventually(Equals(True))) |
995 | + |
996 | + # select a 5 seconds delay |
997 | + option = self.main_window.get_option_value_button(label_value) |
998 | + self.pointing_device.move_to_object(option) |
999 | + self.pointing_device.click() |
1000 | + |
1001 | + bottom_edge.close() |
1002 | + |
1003 | def test_record_video(self): |
1004 | """Test clicking on the record control. |
1005 | |
1006 | @@ -208,7 +252,7 @@ |
1007 | def get_first_picture(self, timeout=10): |
1008 | pictures = [] |
1009 | for i in range(0, timeout): |
1010 | - pictures = os.listdir(self.pictures_dir) |
1011 | + pictures = glob.glob(os.path.join(self.pictures_dir, "*.jpg")) |
1012 | if len(pictures) != 0: |
1013 | break |
1014 | time.sleep(1) |
1015 | @@ -236,9 +280,11 @@ |
1016 | return quality |
1017 | |
1018 | def dismiss_first_photo_hint(self): |
1019 | - # Swipe to photo roll and back to viewfinder |
1020 | - self.main_window.swipe_to_gallery(self) |
1021 | - self.main_window.swipe_to_viewfinder(self) |
1022 | + photo_roll_hint = self.main_window.get_photo_roll_hint() |
1023 | + if photo_roll_hint.enabled: |
1024 | + # Swipe to photo roll and back to viewfinder |
1025 | + self.main_window.swipe_to_gallery(self) |
1026 | + self.main_window.swipe_to_viewfinder(self) |
1027 | |
1028 | def set_compression_quality(self, quality="Normal Quality"): |
1029 | # open bottom edge |
1030 | @@ -276,9 +322,10 @@ |
1031 | # switch cameras and select the last resolution for the current camera |
1032 | self.main_window.switch_cameras() |
1033 | resolutions = self.get_available_video_resolutions() |
1034 | - expected_resolution = resolutions[-1] |
1035 | - self.assertThat(expected_resolution, NotEquals(initial_resolution)) |
1036 | - self.set_video_resolution(expected_resolution) |
1037 | + if len(resolutions) > 1: |
1038 | + expected_resolution = resolutions[-1] |
1039 | + self.assertThat(expected_resolution, NotEquals(initial_resolution)) |
1040 | + self.set_video_resolution(expected_resolution) |
1041 | |
1042 | # switch back to the initial camera and record a video |
1043 | self.main_window.switch_cameras() |
1044 | |
1045 | === modified file 'tests/autopilot/camera_app/tests/test_diskspace.py' |
1046 | --- tests/autopilot/camera_app/tests/test_diskspace.py 2015-04-29 15:56:44 +0000 |
1047 | +++ tests/autopilot/camera_app/tests/test_diskspace.py 2016-03-23 15:42:41 +0000 |
1048 | @@ -61,9 +61,6 @@ |
1049 | # threshold as they all expect a normal situation at the start |
1050 | self.assertThat(self.diskSpaceAvailable(), GreaterThan(LOW_THRESHOLD)) |
1051 | |
1052 | - self.assertThat( |
1053 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1054 | - |
1055 | def tearDown(self): |
1056 | super(TestCameraDiskSpace, self).tearDown() |
1057 | os.remove(self.diskFiller) if os.path.exists(self.diskFiller) else None |
1058 | @@ -75,8 +72,8 @@ |
1059 | exposure_button = self.main_window.get_exposure_button() |
1060 | no_space_hint = self.main_window.get_no_space_hint() |
1061 | |
1062 | - self.assertThat(exposure_button.enabled, Equals(True)) |
1063 | - self.assertThat(no_space_hint.visible, Equals(False)) |
1064 | + self.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
1065 | + self.assertThat(no_space_hint.visible, Eventually(Equals(False))) |
1066 | |
1067 | self.setFreeSpaceTo(CRITICAL_THRESHOLD - MEGABYTE) |
1068 | self.assertThat( |
1069 | @@ -89,8 +86,8 @@ |
1070 | self.assertThat( |
1071 | self.diskSpaceAvailable(), GreaterThan(CRITICAL_THRESHOLD)) |
1072 | |
1073 | - self.assertThat(exposure_button.enabled, Equals(True)) |
1074 | - self.assertThat(no_space_hint.visible, Equals(False)) |
1075 | + self.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
1076 | + self.assertThat(no_space_hint.visible, Eventually(Equals(False))) |
1077 | |
1078 | def test_low_disk(self): |
1079 | """Verify proper behavior when disk space becomes low""" |
1080 | |
1081 | === modified file 'tests/autopilot/camera_app/tests/test_flash.py' |
1082 | --- tests/autopilot/camera_app/tests/test_flash.py 2015-07-03 13:27:48 +0000 |
1083 | +++ tests/autopilot/camera_app/tests/test_flash.py 2016-03-23 15:42:41 +0000 |
1084 | @@ -16,21 +16,14 @@ |
1085 | class TestCameraFlash(CameraAppTestCase): |
1086 | """Tests the flash""" |
1087 | |
1088 | - """ This is needed to wait for the application to start. |
1089 | - In the testfarm, the application may take some time to show up.""" |
1090 | - def setUp(self): |
1091 | - super(TestCameraFlash, self).setUp() |
1092 | - self.assertThat( |
1093 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1094 | - |
1095 | - def tearDown(self): |
1096 | - super(TestCameraFlash, self).tearDown() |
1097 | - |
1098 | """Test that flash modes activate properly""" |
1099 | def test_cycle_flash(self): |
1100 | bottom_edge = self.main_window.get_bottom_edge() |
1101 | bottom_edge.open() |
1102 | flash_button = self.main_window.get_flash_button() |
1103 | + if not flash_button: |
1104 | + return |
1105 | + |
1106 | option_value_selector = self.main_window.get_option_value_selector() |
1107 | |
1108 | # open option value selector showing the possible values |
1109 | @@ -67,10 +60,13 @@ |
1110 | bottom_edge = self.main_window.get_bottom_edge() |
1111 | bottom_edge.open() |
1112 | flash_button = self.main_window.get_video_flash_button() |
1113 | + if not flash_button: |
1114 | + return |
1115 | + |
1116 | option_value_selector = self.main_window.get_option_value_selector() |
1117 | |
1118 | # ensure initial state |
1119 | - self.assertThat(flash_button.iconName, Equals("torch-off")) |
1120 | + self.assertThat(flash_button.iconName, Eventually(Equals("torch-off"))) |
1121 | |
1122 | # open option value selector showing the possible values |
1123 | self.pointing_device.move_to_object(flash_button) |
1124 | @@ -83,19 +79,22 @@ |
1125 | option = self.main_window.get_option_value_button("On") |
1126 | self.pointing_device.move_to_object(option) |
1127 | self.pointing_device.click() |
1128 | - self.assertThat(flash_button.iconName, Equals("torch-on")) |
1129 | + self.assertThat(flash_button.iconName, Eventually(Equals("torch-on"))) |
1130 | |
1131 | # set flash to "off" |
1132 | option = self.main_window.get_option_value_button("Off") |
1133 | self.pointing_device.move_to_object(option) |
1134 | self.pointing_device.click() |
1135 | - self.assertThat(flash_button.iconName, Equals("torch-off")) |
1136 | + self.assertThat(flash_button.iconName, Eventually(Equals("torch-off"))) |
1137 | |
1138 | """Test that flash and hdr modes are mutually exclusive""" |
1139 | def test_flash_hdr_mutually_exclusive(self): |
1140 | bottom_edge = self.main_window.get_bottom_edge() |
1141 | bottom_edge.open() |
1142 | flash_button = self.main_window.get_flash_button() |
1143 | + if not flash_button: |
1144 | + return |
1145 | + |
1146 | hdr_button = self.main_window.get_hdr_button() |
1147 | option_value_selector = self.main_window.get_option_value_selector() |
1148 | |
1149 | |
1150 | === modified file 'tests/autopilot/camera_app/tests/test_focus.py' |
1151 | --- tests/autopilot/camera_app/tests/test_focus.py 2016-02-26 08:52:37 +0000 |
1152 | +++ tests/autopilot/camera_app/tests/test_focus.py 2016-03-23 15:42:41 +0000 |
1153 | @@ -18,26 +18,19 @@ |
1154 | class TestFocus(CameraAppTestCase): |
1155 | """Tests the focus""" |
1156 | |
1157 | - """ This is needed to wait for the application to start. |
1158 | - In the testfarm, the application may take some time to show up.""" |
1159 | - def setUp(self): |
1160 | - super(TestFocus, self).setUp() |
1161 | - self.assertThat( |
1162 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1163 | - |
1164 | - def tearDown(self): |
1165 | - super(TestFocus, self).tearDown() |
1166 | - |
1167 | def verify_focus_ring_after_click_at(self, ring, x, y): |
1168 | # The focus ring should be invisible in the beginning |
1169 | self.assertThat(ring.opacity, Eventually(Equals(0.0))) |
1170 | |
1171 | + focus_mouse_area = self.main_window.get_focus_mouse_area() |
1172 | + self.assertThat(focus_mouse_area.enabled, Eventually(Equals(True))) |
1173 | + |
1174 | # Click in the designated spot |
1175 | self.pointing_device.move(x, y) |
1176 | self.pointing_device.click() |
1177 | |
1178 | # The focus ring sould be visible now |
1179 | - self.assertThat(ring.opacity, Eventually(GreaterThan(0.5))) |
1180 | + self.assertThat(ring.opacity, Eventually(GreaterThan(0.1))) |
1181 | |
1182 | # After some seconds the focus ring should fade out |
1183 | self.assertThat(ring.opacity, Eventually(Equals(0.0))) |
1184 | @@ -45,19 +38,22 @@ |
1185 | """Test focusing in an area where we know the picture is""" |
1186 | @unittest.skipIf(model() == 'Galaxy Nexus', 'Unusable with Mir on maguro') |
1187 | def test_focus_valid_and_disappear(self): |
1188 | + geometry = self.main_window.get_viewfinder_geometry() |
1189 | focus_ring = self.main_window.get_focus_ring() |
1190 | - feed = self.main_window.get_viewfinder_geometry() |
1191 | switch_cameras = self.main_window.get_swap_camera_button() |
1192 | exposure_button = self.main_window.get_exposure_button() |
1193 | |
1194 | # Click in the center of the viewfinder area |
1195 | - mid_x, mid_y = self.get_center(feed) |
1196 | + mid_x, mid_y = self.get_center(geometry) |
1197 | self.verify_focus_ring_after_click_at(focus_ring, mid_x, mid_y) |
1198 | |
1199 | # Then try on the side edges and top edge to verify they |
1200 | # are focusable too |
1201 | - self.verify_focus_ring_after_click_at(focus_ring, 1, mid_y) |
1202 | - self.verify_focus_ring_after_click_at(focus_ring, feed.width - 1, |
1203 | + self.verify_focus_ring_after_click_at(focus_ring, |
1204 | + geometry.globalRect.x + 1, mid_y) |
1205 | + self.verify_focus_ring_after_click_at(focus_ring, |
1206 | + geometry.globalRect.x + |
1207 | + geometry.globalRect.width - 1, |
1208 | mid_y) |
1209 | self.verify_focus_ring_after_click_at(focus_ring, mid_x, 1) |
1210 | |
1211 | @@ -69,10 +65,13 @@ |
1212 | # Click in the center of the viewfinder area |
1213 | self.verify_focus_ring_after_click_at(focus_ring, mid_x, mid_y) |
1214 | |
1215 | - # Then try on the side edges and top edge to verify they |
1216 | + # Then try on the left, right and above the center to verify they |
1217 | # are focusable too |
1218 | - self.verify_focus_ring_after_click_at(focus_ring, 1, mid_y) |
1219 | - self.verify_focus_ring_after_click_at(focus_ring, feed.width - 1, |
1220 | + self.verify_focus_ring_after_click_at(focus_ring, |
1221 | + geometry.globalRect.x + 1, mid_y) |
1222 | + self.verify_focus_ring_after_click_at(focus_ring, |
1223 | + geometry.globalRect.x + |
1224 | + geometry.globalRect.width - 1, |
1225 | mid_y) |
1226 | self.verify_focus_ring_after_click_at(focus_ring, mid_x, 1) |
1227 | |
1228 | |
1229 | === modified file 'tests/autopilot/camera_app/tests/test_gallery_view.py' |
1230 | --- tests/autopilot/camera_app/tests/test_gallery_view.py 2015-04-29 15:56:44 +0000 |
1231 | +++ tests/autopilot/camera_app/tests/test_gallery_view.py 2016-03-23 15:42:41 +0000 |
1232 | @@ -7,7 +7,7 @@ |
1233 | |
1234 | """Tests for the Camera App zoom""" |
1235 | |
1236 | -from testtools.matchers import Equals |
1237 | +from testtools.matchers import Equals, NotEquals |
1238 | from autopilot.matchers import Eventually |
1239 | |
1240 | from camera_app.tests import CameraAppTestCase |
1241 | @@ -35,16 +35,19 @@ |
1242 | self.assertThat(slideshow_view.visible, Eventually(Equals(False))) |
1243 | self.assertThat(photogrid_view.visible, Eventually(Equals(True))) |
1244 | |
1245 | - def select_first_photo(self): |
1246 | - # select the first photo |
1247 | - gallery = self.main_window.get_gallery() |
1248 | - photo = gallery.wait_select_single(objectName="mediaItem0") |
1249 | - self.pointing_device.move_to_object(photo) |
1250 | - |
1251 | - # do a long press to enter Multiselection mode |
1252 | - self.pointing_device.press() |
1253 | - sleep(1) |
1254 | - self.pointing_device.release() |
1255 | + def select_media(self, index=0): |
1256 | + media = self.main_window.get_media(index) |
1257 | + checkbox = media.wait_select_single(objectName="mediaItemCheckBox") |
1258 | + |
1259 | + self.pointing_device.move_to_object(checkbox) |
1260 | + |
1261 | + if checkbox.visible: |
1262 | + self.click() |
1263 | + else: |
1264 | + # do a long press to enter Multiselection mode |
1265 | + self.pointing_device.press() |
1266 | + sleep(1) |
1267 | + self.pointing_device.release() |
1268 | |
1269 | |
1270 | class TestCameraGalleryView(CameraAppTestCase, TestCameraGalleryViewMixin): |
1271 | @@ -53,11 +56,6 @@ |
1272 | def setUp(self): |
1273 | self.delete_all_media() |
1274 | super(TestCameraGalleryView, self).setUp() |
1275 | - self.assertThat( |
1276 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1277 | - |
1278 | - def tearDown(self): |
1279 | - super(TestCameraGalleryView, self).tearDown() |
1280 | |
1281 | """Tests swiping to the gallery and pressing the back button""" |
1282 | def test_swipe_to_gallery(self): |
1283 | @@ -112,26 +110,55 @@ |
1284 | def setUp(self): |
1285 | self.delete_all_media() |
1286 | self.add_sample_video() |
1287 | - |
1288 | super(TestCameraGalleryViewWithVideo, self).setUp() |
1289 | - self.assertThat( |
1290 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1291 | - |
1292 | - def tearDown(self): |
1293 | - super(TestCameraGalleryViewWithVideo, self).tearDown() |
1294 | |
1295 | """Tests the thumnails for video load correctly in slideshow view""" |
1296 | def test_video_thumbnails(self): |
1297 | viewfinder = self.main_window.get_viewfinder() |
1298 | gallery = self.main_window.get_gallery() |
1299 | - |
1300 | - self.main_window.swipe_to_gallery(self) |
1301 | - |
1302 | - self.assertThat(viewfinder.inView, Eventually(Equals(False))) |
1303 | - self.assertThat(gallery.inView, Eventually(Equals(True))) |
1304 | - |
1305 | - spinner = gallery.wait_select_single("ActivityIndicator") |
1306 | - self.assertThat(spinner.running, Eventually(Equals(False))) |
1307 | + self.main_window.swipe_to_gallery(self) |
1308 | + |
1309 | + self.assertThat(viewfinder.inView, Eventually(Equals(False))) |
1310 | + self.assertThat(gallery.inView, Eventually(Equals(True))) |
1311 | + |
1312 | + spinner = gallery.wait_select_single("ActivityIndicator") |
1313 | + self.assertThat(spinner.running, Eventually(Equals(False))) |
1314 | + |
1315 | + thumb_error = self.main_window.get_broken_media_icon() |
1316 | + self.assertThat(thumb_error.opacity, Eventually(Equals(0.0))) |
1317 | + |
1318 | + self.move_from_slideshow_to_photogrid() |
1319 | + thumb_error = self.main_window.get_broken_media_icon() |
1320 | + self.assertThat(thumb_error.opacity, Eventually(Equals(0.0))) |
1321 | + |
1322 | + |
1323 | +class TestCameraGalleryViewWithBrokenVideo( |
1324 | + TestCameraGalleryViewMixin, CameraAppTestCase): |
1325 | + """Tests the camera gallery view with a broken video already present""" |
1326 | + |
1327 | + def setUp(self): |
1328 | + self.delete_all_media() |
1329 | + self.add_sample_video(broken=True) |
1330 | + super(TestCameraGalleryViewWithBrokenVideo, self).setUp() |
1331 | + |
1332 | + """Tests the placeholder thumnails for broken video loads correctly""" |
1333 | + def test_video_thumbnails(self): |
1334 | + viewfinder = self.main_window.get_viewfinder() |
1335 | + gallery = self.main_window.get_gallery() |
1336 | + |
1337 | + self.main_window.swipe_to_gallery(self) |
1338 | + self.assertThat(viewfinder.inView, Eventually(Equals(False))) |
1339 | + self.assertThat(gallery.inView, Eventually(Equals(True))) |
1340 | + |
1341 | + spinner = gallery.wait_select_single("ActivityIndicator") |
1342 | + self.assertThat(spinner.running, Eventually(Equals(False))) |
1343 | + |
1344 | + thumb_error = self.main_window.get_broken_media_icon() |
1345 | + self.assertThat(thumb_error.opacity, Eventually(NotEquals(0.0))) |
1346 | + |
1347 | + self.move_from_slideshow_to_photogrid() |
1348 | + thumb_error = self.main_window.get_broken_media_icon() |
1349 | + self.assertThat(thumb_error.opacity, Eventually(NotEquals(0.0))) |
1350 | |
1351 | |
1352 | class TestCameraGalleryViewWithPhoto( |
1353 | @@ -141,25 +168,17 @@ |
1354 | def setUp(self): |
1355 | self.delete_all_media() |
1356 | self.add_sample_photo() |
1357 | - |
1358 | super(TestCameraGalleryViewWithPhoto, self).setUp() |
1359 | - self.assertThat( |
1360 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1361 | - |
1362 | - def tearDown(self): |
1363 | - super(TestCameraGalleryViewWithPhoto, self).tearDown() |
1364 | |
1365 | """Test deleting photo from multiselection""" |
1366 | def test_delete_photo_from_multiselection(self): |
1367 | self.main_window.swipe_to_gallery(self) |
1368 | self.move_from_slideshow_to_photogrid() |
1369 | - self.select_first_photo() |
1370 | + self.select_media() |
1371 | |
1372 | # open actions drawer |
1373 | gallery = self.main_window.get_gallery() |
1374 | - opt = gallery.wait_select_single(objectName="additionalActionsButton") |
1375 | - self.pointing_device.move_to_object(opt) |
1376 | - self.pointing_device.click() |
1377 | + self.main_window.open_actions_drawer(gallery) |
1378 | |
1379 | # click delete action button |
1380 | delete = gallery.wait_select_single(objectName="actionButtonDelete") |
1381 | @@ -178,7 +197,7 @@ |
1382 | def test_multiselection_mode(self): |
1383 | self.main_window.swipe_to_gallery(self) |
1384 | self.move_from_slideshow_to_photogrid() |
1385 | - self.select_first_photo() |
1386 | + self.select_media() |
1387 | |
1388 | # exit the multiselection mode |
1389 | gallery = self.main_window.get_gallery() |
1390 | @@ -191,3 +210,61 @@ |
1391 | |
1392 | self.assertThat(slideshow_view.visible, Eventually(Equals(False))) |
1393 | self.assertThat(photogrid_view.visible, Eventually(Equals(True))) |
1394 | + |
1395 | + |
1396 | +class TestCameraGalleryViewWithPhotosAndVideo( |
1397 | + TestCameraGalleryViewMixin, CameraAppTestCase): |
1398 | + """Tests the camera gallery view with two photos and a video""" |
1399 | + |
1400 | + def setUp(self): |
1401 | + self.delete_all_media() |
1402 | + self.add_sample_photo() |
1403 | + self.add_sample_video() |
1404 | + super(TestCameraGalleryViewWithPhotosAndVideo, self).setUp() |
1405 | + |
1406 | + def verify_share_state(self, expectedState, close=True): |
1407 | + gallery = self.main_window.get_gallery() |
1408 | + self.main_window.open_actions_drawer(gallery) |
1409 | + |
1410 | + # verify expected state |
1411 | + share = gallery.wait_select_single(objectName="actionButtonShare") |
1412 | + self.assertThat(share.enabled, Eventually(Equals(expectedState))) |
1413 | + |
1414 | + if (close): |
1415 | + self.main_window.close_actions_drawer(gallery) |
1416 | + else: |
1417 | + return share |
1418 | + |
1419 | + """Tests share button enable or disabled correctly in multiselection""" |
1420 | + def test_multiselection_share_enabled(self): |
1421 | + self.main_window.swipe_to_gallery(self) |
1422 | + self.move_from_slideshow_to_photogrid() |
1423 | + |
1424 | + # Verify options button disabled until we select something |
1425 | + gallery = self.main_window.get_gallery() |
1426 | + opt = gallery.wait_select_single(objectName="additionalActionsButton") |
1427 | + self.assertThat(opt.visible, Eventually(Equals(False))) |
1428 | + |
1429 | + # Verify that if we select one photo options and share are enabled |
1430 | + self.select_media(0) |
1431 | + self.assertThat(opt.visible, Eventually(Equals(True))) |
1432 | + self.verify_share_state(True) |
1433 | + |
1434 | + # Verify that it stays enabled with mixed media selected |
1435 | + self.select_media(1) |
1436 | + self.verify_share_state(True) |
1437 | + |
1438 | + """Tests sharing with mixed media generates a warning dialog""" |
1439 | + def test_no_share_mixed_media(self): |
1440 | + self.main_window.swipe_to_gallery(self) |
1441 | + self.move_from_slideshow_to_photogrid() |
1442 | + |
1443 | + self.select_media(0) |
1444 | + self.select_media(1) |
1445 | + share = self.verify_share_state(True, close=False) |
1446 | + |
1447 | + self.pointing_device.move_to_object(share) |
1448 | + self.pointing_device.click() |
1449 | + |
1450 | + gallery = self.main_window.get_gallery() |
1451 | + gallery.wait_select_single(objectName="unableShareDialog") |
1452 | |
1453 | === modified file 'tests/autopilot/camera_app/tests/test_options.py' |
1454 | --- tests/autopilot/camera_app/tests/test_options.py 2016-02-25 13:42:01 +0000 |
1455 | +++ tests/autopilot/camera_app/tests/test_options.py 2016-03-23 15:42:41 +0000 |
1456 | @@ -16,14 +16,6 @@ |
1457 | class TestCameraOptions(CameraAppTestCase): |
1458 | """Tests the options overlay""" |
1459 | |
1460 | - """ This is needed to wait for the application to start. |
1461 | - In the testfarm, the application may take some time to show up.""" |
1462 | - def setUp(self): |
1463 | - super(TestCameraOptions, self).setUp() |
1464 | - # FIXME: this should be in parent class |
1465 | - self.assertThat( |
1466 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1467 | - |
1468 | """Test that the options overlay closes properly by tapping""" |
1469 | def test_overlay_tap_to_close(self): |
1470 | bottom_edge = self.main_window.get_bottom_edge() |
1471 | |
1472 | === modified file 'tests/autopilot/camera_app/tests/test_photo_editor.py' |
1473 | --- tests/autopilot/camera_app/tests/test_photo_editor.py 2015-07-07 11:09:05 +0000 |
1474 | +++ tests/autopilot/camera_app/tests/test_photo_editor.py 2016-03-23 15:42:41 +0000 |
1475 | @@ -20,13 +20,7 @@ |
1476 | def setUp(self): |
1477 | self.delete_all_media() |
1478 | self.add_sample_photo() |
1479 | - |
1480 | super(TestCameraPhotoEditorWithPhoto, self).setUp() |
1481 | - self.assertThat( |
1482 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1483 | - |
1484 | - def tearDown(self): |
1485 | - super(TestCameraPhotoEditorWithPhoto, self).tearDown() |
1486 | |
1487 | """Tests editor opening and closing correctly for pictures""" |
1488 | def test_editor_appears(self): |
1489 | @@ -37,11 +31,7 @@ |
1490 | self.main_window.swipe_to_gallery(self) |
1491 | |
1492 | self.assertThat(gallery.inView, Eventually(Equals(True))) |
1493 | - |
1494 | - # open actions drawer |
1495 | - opt = gallery.wait_select_single(objectName="additionalActionsButton") |
1496 | - self.pointing_device.move_to_object(opt) |
1497 | - self.pointing_device.click() |
1498 | + self.main_window.open_actions_drawer(gallery) |
1499 | |
1500 | # If the editor button is not there when in the gallery view, then |
1501 | # we are not on a system that has the UI extras package installed or |
1502 | @@ -77,13 +67,7 @@ |
1503 | def setUp(self): |
1504 | self.delete_all_media() |
1505 | self.add_sample_video() |
1506 | - |
1507 | super(TestCameraPhotoEditorWithVideo, self).setUp() |
1508 | - self.assertThat( |
1509 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1510 | - |
1511 | - def tearDown(self): |
1512 | - super(TestCameraPhotoEditorWithVideo, self).tearDown() |
1513 | |
1514 | """Tests editor not being available for videos""" |
1515 | def test_editor_not_on_videos(self): |
1516 | @@ -95,11 +79,7 @@ |
1517 | self.main_window.swipe_to_gallery(self) |
1518 | |
1519 | self.assertThat(gallery.inView, Eventually(Equals(True))) |
1520 | - |
1521 | - # open actions drawer |
1522 | - opt = gallery.wait_select_single(objectName="additionalActionsButton") |
1523 | - self.pointing_device.move_to_object(opt) |
1524 | - self.pointing_device.click() |
1525 | + self.main_window.open_actions_drawer(gallery) |
1526 | |
1527 | # If the editor button is not there when in the gallery view, then |
1528 | # we are not on a system that has the UI extras package installed or |
1529 | |
1530 | === modified file 'tests/autopilot/camera_app/tests/test_zoom.py' |
1531 | --- tests/autopilot/camera_app/tests/test_zoom.py 2016-01-11 17:07:21 +0000 |
1532 | +++ tests/autopilot/camera_app/tests/test_zoom.py 2016-03-23 15:42:41 +0000 |
1533 | @@ -19,16 +19,6 @@ |
1534 | class TestCameraZoom(CameraAppTestCase): |
1535 | """Tests the main camera features""" |
1536 | |
1537 | - """ This is needed to wait for the application to start. |
1538 | - In the testfarm, the application may take some time to show up.""" |
1539 | - def setUp(self): |
1540 | - super(TestCameraZoom, self).setUp() |
1541 | - self.assertThat( |
1542 | - self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
1543 | - |
1544 | - def tearDown(self): |
1545 | - super(TestCameraZoom, self).tearDown() |
1546 | - |
1547 | def activate_zoom(self): |
1548 | viewfinder = self.main_window.get_viewfinder_geometry() |
1549 | viewfinder_center = self.get_center(viewfinder) |
1550 | |
1551 | === modified file 'tests/unittests/CMakeLists.txt' |
1552 | --- tests/unittests/CMakeLists.txt 2016-02-26 15:24:03 +0000 |
1553 | +++ tests/unittests/CMakeLists.txt 2016-03-23 15:42:41 +0000 |
1554 | @@ -7,7 +7,7 @@ |
1555 | add_executable(tst_QmlTests tst_QmlTests.cpp) |
1556 | qt5_use_modules(tst_QmlTests Core Qml Quick Test QuickTest) |
1557 | target_link_libraries(tst_QmlTests ${TPL_QT5_LIBRARIES}) |
1558 | -add_test(tst_QmlTests ${XVFB_RUN_CMD} ${CMAKE_CURRENT_BINARY_DIR}/tst_QmlTests -import ${CMAKE_SOURCE_DIR}) |
1559 | +add_test(tst_QmlTests ${XVFB_RUN_CMD} ${CMAKE_CURRENT_BINARY_DIR}/tst_QmlTests -import ${CMAKE_SOURCE_DIR} -import ${CMAKE_BINARY_DIR}) |
1560 | |
1561 | # copy qml test files to build dir |
1562 | file(GLOB qmlTestFiles RELATIVE ${CMAKE_SOURCE_DIR}/tests/unittests/ *qml) |
1563 | |
1564 | === added file 'tests/unittests/tst_PhotogridView.qml' |
1565 | --- tests/unittests/tst_PhotogridView.qml 1970-01-01 00:00:00 +0000 |
1566 | +++ tests/unittests/tst_PhotogridView.qml 2016-03-23 15:42:41 +0000 |
1567 | @@ -0,0 +1,88 @@ |
1568 | +/* |
1569 | + * Copyright 2016 Canonical Ltd. |
1570 | + * |
1571 | + * This program is free software; you can redistribute it and/or modify |
1572 | + * it under the terms of the GNU General Public License as published by |
1573 | + * the Free Software Foundation; version 3. |
1574 | + * |
1575 | + * This program is distributed in the hope that it will be useful, |
1576 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1577 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1578 | + * GNU General Public License for more details. |
1579 | + * |
1580 | + * You should have received a copy of the GNU General Public License |
1581 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1582 | + * |
1583 | + */ |
1584 | + |
1585 | +import QtQuick 2.4 |
1586 | +import QtTest 1.0 |
1587 | +import "../../" |
1588 | +import "../../.." //Needed for out of source build |
1589 | + |
1590 | +TestCase { |
1591 | + name: "PhotogridView" |
1592 | + |
1593 | + function test_mixedMediaSelection_data() { |
1594 | + return [ |
1595 | + { // one item only |
1596 | + isMixedMedia: false, |
1597 | + listItems: [ |
1598 | + { fileType: "image", selected: true, fileURL: "" } |
1599 | + ] |
1600 | + }, |
1601 | + { // mixed media but only non-mixed selected |
1602 | + isMixedMedia: false, |
1603 | + listItems: [ |
1604 | + { fileType: "video", selected: false, fileURL: "" }, |
1605 | + { fileType: "image", selected: true, fileURL: "" }, |
1606 | + { fileType: "image", selected: true, fileURL: "" } |
1607 | + ] |
1608 | + }, |
1609 | + { // mixed media |
1610 | + isMixedMedia: true, |
1611 | + listItems: [ |
1612 | + { fileType: "video", selected: true, fileURL: "" }, |
1613 | + { fileType: "image", selected: true, fileURL: "" }, |
1614 | + { fileType: "image", selected: true, fileURL: "" } |
1615 | + ] |
1616 | + }, |
1617 | + ]; |
1618 | + } |
1619 | + |
1620 | + function test_mixedMediaSelection(data) { |
1621 | + list.clear() |
1622 | + list.data = data.listItems; |
1623 | + for (var i = 0; i < data.listItems.length; i++) { |
1624 | + list.append(data.listItems[i]); |
1625 | + } |
1626 | + list.updateSelectedFiles(); |
1627 | + grid.model = list |
1628 | + compare(grid.selectionContainsMixedMedia(), data.isMixedMedia, "Mixed media not detected correctly") |
1629 | + } |
1630 | + |
1631 | + ListModel { |
1632 | + id: list |
1633 | + property var data |
1634 | + property var selectedFiles: [] |
1635 | + function updateSelectedFiles() { |
1636 | + // need to re-assign entire list due to the way list properties work in QML |
1637 | + var selected = []; |
1638 | + for (var i = 0; i < list.count; i++) { |
1639 | + if (list.data[i].selected) selected.push(i); |
1640 | + } |
1641 | + list.selectedFiles = selected; |
1642 | + } |
1643 | + function get(i, key) { |
1644 | + return list.data[i][key]; |
1645 | + } |
1646 | + } |
1647 | + |
1648 | + PhotogridView { |
1649 | + id: grid |
1650 | + width: 600 |
1651 | + height: 800 |
1652 | + inView: true |
1653 | + inSelectionMode: true |
1654 | + } |
1655 | +} |