Merge lp:~uriboni/camera-app/zoom-level-tests into lp:camera-app
- zoom-level-tests
- Merge into trunk
Proposed by
Ugo Riboni
Status: | Superseded |
---|---|
Proposed branch: | lp:~uriboni/camera-app/zoom-level-tests |
Merge into: | lp:camera-app |
Diff against target: |
737 lines (+298/-110) 12 files modified
CameraApp/advancedcamerasettings.cpp (+15/-11) CameraApp/advancedcamerasettings.h (+1/-0) SlideshowView.qml (+1/-1) VideoReview.qml (+63/-0) ViewFinderExportConfirmation.qml (+66/-49) ViewFinderOverlay.qml (+68/-9) ViewFinderOverlayLoader.qml (+4/-0) ViewFinderView.qml (+63/-32) ZoomControl.qml (+1/-1) camera-app.qml (+12/-5) camera-contenthub.json (+2/-1) tests/autopilot/camera_app/tests/test_zoom.py (+2/-1) |
To merge this branch: | bzr merge lp:~uriboni/camera-app/zoom-level-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+282201@code.launchpad.net |
This proposal has been superseded by a proposal from 2016-01-11.
Commit message
Description of the change
Fix zoom related AP tests from previous commit
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Needs Fixing
(continuous-integration)
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CameraApp/advancedcamerasettings.cpp' |
2 | --- CameraApp/advancedcamerasettings.cpp 2015-12-02 08:27:19 +0000 |
3 | +++ CameraApp/advancedcamerasettings.cpp 2016-01-11 17:08:00 +0000 |
4 | @@ -44,7 +44,8 @@ |
5 | m_cameraFlashControl(0), |
6 | m_cameraExposureControl(0), |
7 | m_imageEncoderControl(0), |
8 | - m_videoEncoderControl(0) |
9 | + m_videoEncoderControl(0), |
10 | + m_hdrEnabled(false) |
11 | { |
12 | } |
13 | |
14 | @@ -236,6 +237,9 @@ |
15 | |
16 | m_cameraFlashControl = flashControlFromCamera(m_camera); |
17 | m_cameraExposureControl = exposureControlFromCamera(m_camera); |
18 | + QVariant exposureMode = m_hdrEnabled ? QVariant::fromValue(ExposureHdr) |
19 | + : QVariant::fromValue(QCameraExposure::ExposureAuto); |
20 | + m_cameraExposureControl->setValue(QCameraExposureControl::ExposureMode, exposureMode); |
21 | |
22 | if (m_cameraExposureControl) { |
23 | QObject::connect(m_cameraExposureControl, |
24 | @@ -451,20 +455,20 @@ |
25 | |
26 | bool AdvancedCameraSettings::hdrEnabled() const |
27 | { |
28 | - if (m_cameraExposureControl) { |
29 | - QVariant exposureMode = m_cameraExposureControl->actualValue(QCameraExposureControl::ExposureMode); |
30 | - return exposureMode.value<QCameraExposure::ExposureMode>() == ExposureHdr; |
31 | - } else { |
32 | - return false; |
33 | - } |
34 | + return m_hdrEnabled; |
35 | } |
36 | |
37 | void AdvancedCameraSettings::setHdrEnabled(bool enabled) |
38 | { |
39 | - if (m_cameraExposureControl) { |
40 | - QVariant exposureMode = enabled ? QVariant::fromValue(ExposureHdr) |
41 | - : QVariant::fromValue(QCameraExposure::ExposureAuto); |
42 | - m_cameraExposureControl->setValue(QCameraExposureControl::ExposureMode, exposureMode); |
43 | + if (enabled != m_hdrEnabled) { |
44 | + m_hdrEnabled = enabled; |
45 | + if (m_cameraExposureControl) { |
46 | + QVariant exposureMode = enabled ? QVariant::fromValue(ExposureHdr) |
47 | + : QVariant::fromValue(QCameraExposure::ExposureAuto); |
48 | + m_cameraExposureControl->setValue(QCameraExposureControl::ExposureMode, exposureMode); |
49 | + } else { |
50 | + Q_EMIT hdrEnabledChanged(); |
51 | + } |
52 | } |
53 | } |
54 | |
55 | |
56 | === modified file 'CameraApp/advancedcamerasettings.h' |
57 | --- CameraApp/advancedcamerasettings.h 2015-11-17 15:25:03 +0000 |
58 | +++ CameraApp/advancedcamerasettings.h 2016-01-11 17:08:00 +0000 |
59 | @@ -108,6 +108,7 @@ |
60 | QCameraExposureControl* m_cameraExposureControl; |
61 | QImageEncoderControl* m_imageEncoderControl; |
62 | QVideoEncoderSettingsControl* m_videoEncoderControl; |
63 | + bool m_hdrEnabled; |
64 | }; |
65 | |
66 | #endif // ADVANCEDCAMERASETTINGS_H |
67 | |
68 | === modified file 'SlideshowView.qml' |
69 | --- SlideshowView.qml 2015-11-26 13:45:38 +0000 |
70 | +++ SlideshowView.qml 2016-01-11 17:08:00 +0000 |
71 | @@ -170,7 +170,7 @@ |
72 | ActivityIndicator { |
73 | anchors.centerIn: parent |
74 | visible: running |
75 | - running: image.status != Image.Ready |
76 | + running: image.status == Image.Loading |
77 | } |
78 | |
79 | PinchArea { |
80 | |
81 | === added file 'VideoReview.qml' |
82 | --- VideoReview.qml 1970-01-01 00:00:00 +0000 |
83 | +++ VideoReview.qml 2016-01-11 17:08:00 +0000 |
84 | @@ -0,0 +1,63 @@ |
85 | +/* |
86 | + * Copyright 2015 Canonical Ltd. |
87 | + * |
88 | + * This program is free software; you can redistribute it and/or modify |
89 | + * it under the terms of the GNU General Public License as published by |
90 | + * the Free Software Foundation; version 3. |
91 | + * |
92 | + * This program is distributed in the hope that it will be useful, |
93 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
94 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
95 | + * GNU General Public License for more details. |
96 | + * |
97 | + * You should have received a copy of the GNU General Public License |
98 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
99 | + */ |
100 | + |
101 | +import QtQuick 2.4 |
102 | +import Ubuntu.Components 1.3 |
103 | + |
104 | +Item { |
105 | + property string videoPath |
106 | + property int bottomMargin |
107 | + |
108 | + Image { |
109 | + id: thumbnail |
110 | + anchors.fill: parent |
111 | + |
112 | + fillMode: Image.PreserveAspectFit |
113 | + sourceSize.width: width |
114 | + sourceSize.height: height |
115 | + |
116 | + source: videoPath ? "image://thumbnailer/%1".arg(videoPath) : "" |
117 | + opacity: status == Image.Ready ? 1.0 : 0.0 |
118 | + Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration } } |
119 | + } |
120 | + |
121 | + Item { |
122 | + anchors.fill: parent |
123 | + anchors.bottomMargin: parent.bottomMargin |
124 | + |
125 | + ActivityIndicator { |
126 | + anchors.centerIn: parent |
127 | + visible: running |
128 | + running: thumbnail.status == Image.Loading |
129 | + } |
130 | + |
131 | + Icon { |
132 | + width: units.gu(5) |
133 | + height: units.gu(5) |
134 | + anchors.centerIn: parent |
135 | + name: "media-playback-start" |
136 | + color: "white" |
137 | + opacity: 0.8 |
138 | + } |
139 | + |
140 | + MouseArea { |
141 | + anchors.centerIn: parent |
142 | + width: units.gu(10) |
143 | + height: units.gu(10) |
144 | + onClicked: Qt.openUrlExternally("video://%1".arg(videoPath)); |
145 | + } |
146 | + } |
147 | +} |
148 | |
149 | === modified file 'ViewFinderExportConfirmation.qml' |
150 | --- ViewFinderExportConfirmation.qml 2015-10-22 12:21:14 +0000 |
151 | +++ ViewFinderExportConfirmation.qml 2016-01-11 17:08:00 +0000 |
152 | @@ -20,6 +20,7 @@ |
153 | Item { |
154 | id: viewFinderExportConfirmation |
155 | |
156 | + property bool isVideo |
157 | property string mediaPath |
158 | property Snapshot snapshot |
159 | |
160 | @@ -27,7 +28,7 @@ |
161 | viewFinder.visible = false; |
162 | viewFinderOverlay.visible = false; |
163 | mediaPath = path; |
164 | - snapshot.visible = true; |
165 | + if (!isVideo) snapshot.visible = true; |
166 | visible = true; |
167 | } |
168 | |
169 | @@ -46,54 +47,70 @@ |
170 | asynchronous: true |
171 | sourceComponent: Component { |
172 | Item { |
173 | - CircleButton { |
174 | - id: retryButton |
175 | - objectName: "retryButton" |
176 | - |
177 | - anchors { |
178 | - right: validateButton.left |
179 | - rightMargin: units.gu(7.5) |
180 | - bottom: parent.bottom |
181 | - bottomMargin: units.gu(6) |
182 | - } |
183 | - |
184 | - iconName: "reload" |
185 | - onClicked: viewFinderExportConfirmation.hide() |
186 | - } |
187 | - |
188 | - CircleButton { |
189 | - id: validateButton |
190 | - objectName: "validateButton" |
191 | - |
192 | - width: units.gu(8) |
193 | - anchors { |
194 | - bottom: parent.bottom |
195 | - bottomMargin: units.gu(5) |
196 | - horizontalCenter: parent.horizontalCenter |
197 | - } |
198 | - |
199 | - iconName: "ok" |
200 | - onClicked: { |
201 | - viewFinderExportConfirmation.hide(); |
202 | - main.exportContent([mediaPath]); |
203 | - } |
204 | - } |
205 | - |
206 | - CircleButton { |
207 | - id: cancelButton |
208 | - objectName: "cancelButton" |
209 | - |
210 | - anchors { |
211 | - left: validateButton.right |
212 | - leftMargin: units.gu(7.5) |
213 | - bottom: parent.bottom |
214 | - bottomMargin: units.gu(6) |
215 | - } |
216 | - |
217 | - iconName: "close" |
218 | - onClicked: { |
219 | - viewFinderExportConfirmation.hide(); |
220 | - main.cancelExport(); |
221 | + VideoReview { |
222 | + id: videoReview |
223 | + anchors.fill: parent |
224 | + bottomMargin: buttons.height |
225 | + videoPath: mediaPath |
226 | + visible: isVideo |
227 | + } |
228 | + |
229 | + Item { |
230 | + id: buttons |
231 | + anchors.bottom: parent.bottom |
232 | + anchors.left: parent.left |
233 | + anchors.right: parent.right |
234 | + height: childrenRect.height |
235 | + |
236 | + CircleButton { |
237 | + id: retryButton |
238 | + objectName: "retryButton" |
239 | + |
240 | + anchors { |
241 | + right: validateButton.left |
242 | + rightMargin: units.gu(7.5) |
243 | + bottom: parent.bottom |
244 | + bottomMargin: units.gu(6) |
245 | + } |
246 | + |
247 | + iconName: "reload" |
248 | + onClicked: viewFinderExportConfirmation.hide() |
249 | + } |
250 | + |
251 | + CircleButton { |
252 | + id: validateButton |
253 | + objectName: "validateButton" |
254 | + |
255 | + width: units.gu(8) |
256 | + anchors { |
257 | + bottom: parent.bottom |
258 | + bottomMargin: units.gu(5) |
259 | + horizontalCenter: parent.horizontalCenter |
260 | + } |
261 | + |
262 | + iconName: "ok" |
263 | + onClicked: { |
264 | + viewFinderExportConfirmation.hide(); |
265 | + main.exportContent([mediaPath]); |
266 | + } |
267 | + } |
268 | + |
269 | + CircleButton { |
270 | + id: cancelButton |
271 | + objectName: "cancelButton" |
272 | + |
273 | + anchors { |
274 | + left: validateButton.right |
275 | + leftMargin: units.gu(7.5) |
276 | + bottom: parent.bottom |
277 | + bottomMargin: units.gu(6) |
278 | + } |
279 | + |
280 | + iconName: "close" |
281 | + onClicked: { |
282 | + viewFinderExportConfirmation.hide(); |
283 | + main.cancelExport(); |
284 | + } |
285 | } |
286 | } |
287 | } |
288 | |
289 | === modified file 'ViewFinderOverlay.qml' |
290 | --- ViewFinderOverlay.qml 2015-12-02 08:28:41 +0000 |
291 | +++ ViewFinderOverlay.qml 2016-01-11 17:08:00 +0000 |
292 | @@ -208,7 +208,12 @@ |
293 | "value": sizeToString(camera.advanced.fittingResolution)}; |
294 | |
295 | photoResolutionOptionsModel.insert(0, optionMaximum); |
296 | - if (camera.advanced.fittingResolution != camera.advanced.maximumResolution) { |
297 | + |
298 | + // Only show optionFitting if it's greater than 50% of the maximum available resolution |
299 | + var fittingSize = camera.advanced.fittingResolution.width * camera.advanced.fittingResolution.height; |
300 | + var maximumSize = camera.advanced.maximumResolution.width * camera.advanced.maximumResolution.height; |
301 | + if (camera.advanced.fittingResolution != camera.advanced.maximumResolution && |
302 | + fittingSize / maximumSize >= 0.5) { |
303 | photoResolutionOptionsModel.insert(1, optionFitting); |
304 | } |
305 | |
306 | @@ -220,13 +225,11 @@ |
307 | } |
308 | } |
309 | |
310 | - Component.onCompleted: { |
311 | - camera.cameraState = Camera.LoadedState; |
312 | + function updateResolutionOptions() { |
313 | updateVideoResolutionOptions(); |
314 | updatePhotoResolutionOptions(); |
315 | // FIXME: see workaround setting camera.viewfinder.resolution above |
316 | camera.viewfinder.resolution = camera.advanced.resolution; |
317 | - camera.cameraState = Camera.ActiveState; |
318 | } |
319 | |
320 | Connections { |
321 | @@ -244,10 +247,7 @@ |
322 | // because the latter is not updated when the backend changes the resolution |
323 | settings["photoResolution" + camera.advanced.activeCameraIndex] = sizeToString(camera.advanced.imageCaptureResolution); |
324 | settings.videoResolution = sizeToString(camera.advanced.videoRecorderResolution); |
325 | - updatePhotoResolutionOptions(); |
326 | - updateVideoResolutionOptions(); |
327 | - // FIXME: see workaround setting camera.viewfinder.resolution above |
328 | - camera.viewfinder.resolution = camera.advanced.resolution; |
329 | + updateResolutionOptions(); |
330 | |
331 | // If no resolution has ever been chosen, select the one that fits the screen |
332 | if (!hasPhotoResolutionSetting) { |
333 | @@ -285,6 +285,7 @@ |
334 | height: optionsOverlayLoader.height |
335 | onOpenedChanged: optionsOverlayLoader.item.closeValueSelector() |
336 | enabled: camera.videoRecorder.recorderState == CameraRecorder.StoppedState |
337 | + && !camera.photoCaptureInProgress |
338 | opacity: enabled ? 1.0 : 0.3 |
339 | |
340 | Item { |
341 | @@ -667,7 +668,9 @@ |
342 | } |
343 | |
344 | if (camera.captureMode == Camera.CaptureVideo) { |
345 | - if (application.removableStoragePresent && settings.preferRemovableStorage) { |
346 | + if (main.contentExportMode) { |
347 | + camera.videoRecorder.outputLocation = application.temporaryLocation; |
348 | + } else if (application.removableStoragePresent && settings.preferRemovableStorage) { |
349 | camera.videoRecorder.outputLocation = application.removableStorageVideosLocation; |
350 | } else { |
351 | camera.videoRecorder.outputLocation = application.videosLocation; |
352 | @@ -694,6 +697,8 @@ |
353 | camera.imageCapture.setMetadata("GPSAltitude", position.coordinate.altitude); |
354 | } |
355 | } |
356 | + |
357 | + camera.photoCaptureInProgress = true; |
358 | if (main.contentExportMode) { |
359 | camera.imageCapture.captureToLocation(application.temporaryLocation); |
360 | } else if (application.removableStoragePresent && settings.preferRemovableStorage) { |
361 | @@ -782,6 +787,7 @@ |
362 | iconName: (camera.captureMode == Camera.CaptureStillImage) ? "camcorder" : "camera-symbolic" |
363 | onClicked: controls.changeRecordMode() |
364 | enabled: camera.videoRecorder.recorderState == CameraRecorder.StoppedState && !main.contentExportMode |
365 | + && !camera.photoCaptureInProgress |
366 | } |
367 | |
368 | ShootButton { |
369 | @@ -831,6 +837,7 @@ |
370 | } |
371 | |
372 | enabled: !camera.switchInProgress && camera.videoRecorder.recorderState == CameraRecorder.StoppedState |
373 | + && !camera.photoCaptureInProgress |
374 | iconName: "camera-flip" |
375 | onClicked: controls.switchCamera() |
376 | } |
377 | @@ -853,6 +860,7 @@ |
378 | property real maximumScale: 3.0 |
379 | property bool active: false |
380 | |
381 | + enabled: !camera.photoCaptureInProgress |
382 | onPinchStarted: { |
383 | active = true; |
384 | initialZoom = zoomControl.value; |
385 | @@ -871,6 +879,7 @@ |
386 | MouseArea { |
387 | id: manualFocusMouseArea |
388 | anchors.fill: parent |
389 | + enabled: !camera.photoCaptureInProgress |
390 | onClicked: { |
391 | camera.manualFocus(mouse.x, mouse.y); |
392 | mouse.accepted = false; |
393 | @@ -964,4 +973,54 @@ |
394 | } |
395 | } |
396 | } |
397 | + |
398 | + Connections { |
399 | + id: permissionErrorMonitor |
400 | + property var currentPermissionsDialog: null |
401 | + target: camera |
402 | + onError: { |
403 | + if (errorCode == Camera.ServiceMissingError) { |
404 | + if (currentPermissionsDialog == null) { |
405 | + currentPermissionsDialog = PopupUtils.open(noPermissionsDialogComponent); |
406 | + } |
407 | + camera.failedToConnect = true; |
408 | + } |
409 | + } |
410 | + onCameraStateChanged: { |
411 | + if (camera.cameraState != Camera.UnloadedState) { |
412 | + if (currentPermissionsDialog != null) { |
413 | + PopupUtils.close(currentPermissionsDialog); |
414 | + currentPermissionsDialog = null; |
415 | + } |
416 | + camera.failedToConnect = false; |
417 | + } else { |
418 | + camera.photoCaptureInProgress = false; |
419 | + } |
420 | + } |
421 | + } |
422 | + |
423 | + Component { |
424 | + id: noPermissionsDialogComponent |
425 | + Dialog { |
426 | + id: noPermissionsDialog |
427 | + objectName: "noPermissionsDialog" |
428 | + title: i18n.tr("Cannot access camera") |
429 | + text: i18n.tr("Camera app doesn't have permission to access the camera hardware or another error occurred.\n\nIf granting permission does not resolve this problem, reboot your phone.") |
430 | + Button { |
431 | + text: i18n.tr("Cancel") |
432 | + onClicked: { |
433 | + PopupUtils.close(noPermissionsDialog); |
434 | + permissionErrorMonitor.currentPermissionsDialog = null; |
435 | + } |
436 | + } |
437 | + Button { |
438 | + text: i18n.tr("Edit Permissions") |
439 | + onClicked: { |
440 | + Qt.openUrlExternally("settings:///system/security-privacy?service=camera"); |
441 | + PopupUtils.close(noPermissionsDialog); |
442 | + permissionErrorMonitor.currentPermissionsDialog = null; |
443 | + } |
444 | + } |
445 | + } |
446 | + } |
447 | } |
448 | |
449 | === modified file 'ViewFinderOverlayLoader.qml' |
450 | --- ViewFinderOverlayLoader.qml 2015-10-22 12:21:14 +0000 |
451 | +++ ViewFinderOverlayLoader.qml 2016-01-11 17:08:00 +0000 |
452 | @@ -29,6 +29,10 @@ |
453 | loader.item.showFocusRing(x, y); |
454 | } |
455 | |
456 | + function updateResolutionOptions() { |
457 | + loader.item.updateResolutionOptions(); |
458 | + } |
459 | + |
460 | asynchronous: true |
461 | Component.onCompleted: { |
462 | loader.setSource("ViewFinderOverlay.qml", { "camera": loader.camera }); |
463 | |
464 | === modified file 'ViewFinderView.qml' |
465 | --- ViewFinderView.qml 2015-11-17 13:23:26 +0000 |
466 | +++ ViewFinderView.qml 2016-01-11 17:08:00 +0000 |
467 | @@ -20,6 +20,7 @@ |
468 | import QtMultimedia 5.0 |
469 | import CameraApp 0.1 |
470 | import QtGraphicalEffects 1.0 |
471 | +import Ubuntu.Content 0.1 |
472 | |
473 | Item { |
474 | id: viewFinderView |
475 | @@ -33,11 +34,40 @@ |
476 | signal photoTaken(string filePath) |
477 | signal videoShot(string filePath) |
478 | |
479 | - Camera { |
480 | + onInViewChanged: decideCameraState() |
481 | + Connections { |
482 | + target: viewFinderOverlay |
483 | + onStatusChanged: decideCameraState() |
484 | + } |
485 | + Connections { |
486 | + target: Qt.application |
487 | + onActiveChanged: if (Qt.application.active && camera.failedToConnect) decideCameraState() |
488 | + } |
489 | + |
490 | + function decideCameraState() { |
491 | + if (viewFinderOverlay.status == Loader.Ready) { |
492 | + if (viewFinderView.inView) { |
493 | + camera.cameraState = Camera.LoadedState; |
494 | + viewFinderOverlay.updateResolutionOptions(); |
495 | + camera.cameraState = Camera.ActiveState; |
496 | + } else { |
497 | + camera.cameraState = Camera.LoadedState; |
498 | + viewFinderOverlay.updateResolutionOptions(); |
499 | + } |
500 | + } else { |
501 | + if (camera.videoRecorder.recorderState == CameraRecorder.RecordingState) { |
502 | + camera.videoRecorder.stop(); |
503 | + } |
504 | + camera.cameraState = Camera.UnloadedState; |
505 | + } |
506 | + } |
507 | + |
508 | + property Camera camera: Camera { |
509 | id: camera |
510 | captureMode: Camera.CaptureStillImage |
511 | cameraState: Camera.UnloadedState |
512 | StateSaver.properties: "captureMode" |
513 | + property bool failedToConnect: false |
514 | |
515 | function manualFocus(x, y) { |
516 | viewFinderOverlay.showFocusRing(x, y); |
517 | @@ -75,9 +105,20 @@ |
518 | property alias currentZoom: camera.digitalZoom |
519 | property alias maximumZoom: camera.maximumDigitalZoom |
520 | property bool switchInProgress: false |
521 | - |
522 | + property bool photoCaptureInProgress: false |
523 | + |
524 | imageCapture { |
525 | + onReadyChanged: { |
526 | + if (camera.imageCapture.ready && main.transfer) { |
527 | + if (main.transfer.contentType === ContentType.Videos) { |
528 | + viewFinderView.captureMode = Camera.CaptureVideo; |
529 | + } else { |
530 | + viewFinderView.captureMode = Camera.CaptureStillImage; |
531 | + } |
532 | + } |
533 | + } |
534 | onCaptureFailed: { |
535 | + camera.photoCaptureInProgress = false; |
536 | console.log("Capture failed for request " + requestId + ": " + message); |
537 | } |
538 | onImageCaptured: { |
539 | @@ -95,37 +136,24 @@ |
540 | viewFinderExportConfirmation.confirmExport(path); |
541 | } |
542 | viewFinderView.photoTaken(path); |
543 | + camera.photoCaptureInProgress = false; |
544 | metricPhotos.increment(); |
545 | console.log("Picture saved as " + path); |
546 | } |
547 | } |
548 | - |
549 | + |
550 | videoRecorder { |
551 | onRecorderStateChanged: { |
552 | if (videoRecorder.recorderState === CameraRecorder.StoppedState) { |
553 | - if (photoRollHint.necessary) { |
554 | - photoRollHint.enable(); |
555 | - } |
556 | metricVideos.increment() |
557 | viewFinderOverlay.visible = true; |
558 | viewFinderView.videoShot(videoRecorder.actualLocation); |
559 | - } |
560 | - } |
561 | - } |
562 | - } |
563 | - |
564 | - Connections { |
565 | - target: Qt.application |
566 | - onActiveChanged: { |
567 | - if (Qt.application.active) { |
568 | - if (camera.cameraState == Camera.LoadedState) { |
569 | - camera.cameraState = Camera.ActiveState; |
570 | - } |
571 | - } else if (!application.desktopMode) { |
572 | - if (camera.videoRecorder.recorderState == CameraRecorder.RecordingState) { |
573 | - camera.videoRecorder.stop(); |
574 | - } |
575 | - camera.cameraState = Camera.LoadedState; |
576 | + if (main.contentExportMode) { |
577 | + viewFinderExportConfirmation.confirmExport(videoRecorder.actualLocation); |
578 | + } else if (photoRollHint.necessary) { |
579 | + photoRollHint.enable(); |
580 | + } |
581 | + } |
582 | } |
583 | } |
584 | } |
585 | @@ -146,7 +174,9 @@ |
586 | // 'viewFinder.visible = false' prevents the camera switching |
587 | viewFinder.width = 1; |
588 | viewFinder.height = 1; |
589 | + camera.cameraState = Camera.LoadedState; |
590 | camera.advanced.activeCameraIndex = (camera.advanced.activeCameraIndex === 0) ? 1 : 0; |
591 | + decideCameraState(); |
592 | viewFinderSwitcherRotation.angle = 180; |
593 | } |
594 | } |
595 | @@ -157,7 +187,7 @@ |
596 | angle: 180 |
597 | } |
598 | } |
599 | - |
600 | + |
601 | transform: [ |
602 | Scale { |
603 | id: viewFinderSwitcherScale |
604 | @@ -174,11 +204,11 @@ |
605 | angle: 0 |
606 | } |
607 | ] |
608 | - |
609 | - |
610 | + |
611 | + |
612 | SequentialAnimation { |
613 | id: viewFinderSwitcherAnimation |
614 | - |
615 | + |
616 | SequentialAnimation { |
617 | ParallelAnimation { |
618 | UbuntuNumberAnimation {target: viewFinderSwitcherScale; property: "xScale"; from: 1.0; to: 0.8; duration: UbuntuAnimation.BriskDuration ; easing: UbuntuAnimation.StandardEasing} |
619 | @@ -207,16 +237,16 @@ |
620 | } |
621 | } |
622 | } |
623 | - |
624 | + |
625 | VideoOutput { |
626 | id: viewFinder |
627 | - |
628 | + |
629 | x: 0 |
630 | y: -viewFinderGeometry.y |
631 | width: parent.width |
632 | height: parent.height |
633 | source: camera |
634 | - |
635 | + |
636 | /* This rotation need to be applied since the camera hardware in the |
637 | Galaxy Nexus phone is mounted at an angle inside the device, so the video |
638 | feed is rotated too. |
639 | @@ -234,7 +264,7 @@ |
640 | // may change. |
641 | orientation = Screen.primaryOrientation === Qt.PortraitOrientation ? -90 : 0; |
642 | } |
643 | - |
644 | + |
645 | /* Convenience item tracking the real position and size of the real video feed. |
646 | Having this helps since these values depend on a lot of rules: |
647 | - the feed is automatically scaled to fit the viewfinder |
648 | @@ -242,7 +272,7 @@ |
649 | - the resolution and aspect ratio of the feed changes depending on the active camera |
650 | The item is also separated in a component so it can be unit tested. |
651 | */ |
652 | - |
653 | + |
654 | transform: Rotation { |
655 | origin.x: viewFinder.width / 2 |
656 | origin.y: viewFinder.height / 2 |
657 | @@ -423,5 +453,6 @@ |
658 | id: viewFinderExportConfirmation |
659 | anchors.fill: parent |
660 | snapshot: snapshot |
661 | + isVideo: main.transfer.contentType == ContentType.Videos |
662 | } |
663 | } |
664 | |
665 | === modified file 'ZoomControl.qml' |
666 | --- ZoomControl.qml 2015-10-22 12:21:14 +0000 |
667 | +++ ZoomControl.qml 2016-01-11 17:08:00 +0000 |
668 | @@ -64,7 +64,7 @@ |
669 | } |
670 | |
671 | live: true |
672 | - minimumValue: 1.0 // No zoom => 1.0 zoom factor |
673 | + minimumValue: 0.0 // No zoom => 0.0 zoom factor |
674 | value: minimumValue |
675 | } |
676 | |
677 | |
678 | === modified file 'camera-app.qml' |
679 | --- camera-app.qml 2015-11-20 15:36:00 +0000 |
680 | +++ camera-app.qml 2016-01-11 17:08:00 +0000 |
681 | @@ -135,7 +135,7 @@ |
682 | } |
683 | } |
684 | ] |
685 | - interactive: !viewFinderView.touchAcquired && !galleryView.touchAcquired |
686 | + interactive: !viewFinderView.touchAcquired && !galleryView.touchAcquired && !viewFinderView.camera.photoCaptureInProgress |
687 | |
688 | Component.onCompleted: { |
689 | // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition |
690 | @@ -311,10 +311,17 @@ |
691 | target: ContentHub |
692 | onExportRequested: { |
693 | viewSwitcher.switchToViewFinder(); |
694 | - if (transferContentType === ContentType.Videos) { |
695 | - viewFinderView.captureMode = Camera.CaptureVideo; |
696 | - } else { |
697 | - viewFinderView.captureMode = Camera.CaptureStillImage; |
698 | + |
699 | + // The exportRequested event can arrive before or after the |
700 | + // app is active, but setting the recording type before the |
701 | + // capture becomes ready does not have any effect. |
702 | + // See camera.imageCapture.onReadyChanged for the other case. |
703 | + if (viewFinderView.camera.imageCapture.ready) { |
704 | + if (transfer.contentType === ContentType.Videos) { |
705 | + viewFinderView.captureMode = Camera.CaptureVideo; |
706 | + } else { |
707 | + viewFinderView.captureMode = Camera.CaptureStillImage; |
708 | + } |
709 | } |
710 | main.transfer = transfer; |
711 | } |
712 | |
713 | === modified file 'camera-contenthub.json' |
714 | --- camera-contenthub.json 2014-07-31 18:41:17 +0000 |
715 | +++ camera-contenthub.json 2016-01-11 17:08:00 +0000 |
716 | @@ -1,5 +1,6 @@ |
717 | { |
718 | "source": [ |
719 | - "pictures" |
720 | + "pictures", |
721 | + "videos" |
722 | ] |
723 | } |
724 | |
725 | === modified file 'tests/autopilot/camera_app/tests/test_zoom.py' |
726 | --- tests/autopilot/camera_app/tests/test_zoom.py 2015-11-30 20:18:09 +0000 |
727 | +++ tests/autopilot/camera_app/tests/test_zoom.py 2016-01-11 17:08:00 +0000 |
728 | @@ -67,7 +67,8 @@ |
729 | ty = y + (h // 2) |
730 | |
731 | self.pointing_device.drag(tx, ty, (tx - zoom_control.width), ty) |
732 | - self.assertThat(zoom_control.value, Eventually(Equals(1.0))) |
733 | + self.assertThat(zoom_control.value, |
734 | + Eventually(Equals(zoom_control.minimumValue))) |
735 | |
736 | """Tests zoom is reset to minimum on camera switch""" |
737 | def test_zoom_reset_on_camera_change(self): |
FAILED: Continuous integration, rev:632 /code.launchpad .net/~uriboni/ camera- app/zoom- level-tests/ +merge/ 282201/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ camera- app-ci/ 481/ jenkins. qa.ubuntu. com/job/ camera- app-vivid- amd64-ci/ 176 jenkins. qa.ubuntu. com/job/ camera- app-vivid- armhf-ci/ 177 jenkins. qa.ubuntu. com/job/ camera- app-vivid- armhf-ci/ 177/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ camera- app-vivid- i386-ci/ 176 jenkins. qa.ubuntu. com/job/ generic- click-autopilot -vivid- touch/364 jenkins. qa.ubuntu. com/job/ generic- click-autopilot -runner- touch/1035 jenkins. qa.ubuntu. com/job/ generic- click-builder- vivid-armhf/ 898 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 26553
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/camera- app-ci/ 481/rebuild
http://