Merge lp:~fboucault/camera-app/resolution_options into lp:camera-app

Proposed by Florian Boucault
Status: Superseded
Proposed branch: lp:~fboucault/camera-app/resolution_options
Merge into: lp:camera-app
Diff against target: 728 lines (+396/-50)
9 files modified
BottomEdgeIndicators.qml (+1/-1)
CameraApp/advancedcamerasettings.cpp (+125/-0)
CameraApp/advancedcamerasettings.h (+11/-0)
OptionButton.qml (+1/-1)
ViewFinderOverlay.qml (+170/-4)
ViewFinderView.qml (+15/-16)
tests/autopilot/camera_app/emulators/main_window.py (+20/-1)
tests/autopilot/camera_app/tests/test_capture.py (+6/-27)
tests/autopilot/camera_app/tests/test_zoom.py (+47/-0)
To merge this branch: bzr merge lp:~fboucault/camera-app/resolution_options
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Bill Filler (community) Needs Fixing
Review via email: mp+274402@code.launchpad.net

This proposal has been superseded by a proposal from 2015-11-25.

Commit message

New option for the user to choose between the maximum resolution the sensor allows or the resolution that fits the screen.

To post a comment you must log in.
Revision history for this message
Florian Boucault (fboucault) wrote :
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Bill Filler (bfiller) wrote :

Framework version needs to be 15.04.3 as the required qtubuntu-camera change is not in the current 15.04.2 version that is in ota8

review: Needs Fixing
598. By Florian Boucault

Bumping framework version required by the app.

599. By Florian Boucault

Reverted framework bumps

600. By Florian Boucault

Dynamically show/hide the resolution options depending on the presence of framework ubuntu-sdk-15.04.3 (OTA9)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
601. By Florian Boucault

Add /usr/share/click/frameworks/ to apparmor read path so that available frameworks can be determined.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
602. By Florian Boucault

Merged with trunk

Revision history for this message
Florian Boucault (fboucault) wrote :
603. By Florian Boucault

Merged staging

604. By Florian Boucault

Reverted making the resolution options contingent on the presence of framework

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
=== modified file 'BottomEdgeIndicators.qml'
--- BottomEdgeIndicators.qml 2015-10-22 12:21:14 +0000
+++ BottomEdgeIndicators.qml 2015-11-25 17:47:09 +0000
@@ -84,7 +84,7 @@
84 id: indicatorIcon84 id: indicatorIcon
85 anchors.fill: parent85 anchors.fill: parent
86 color: "white"86 color: "white"
87 name: modelData && modelData.isToggle ? modelData.icon : modelData.get(model.selectedIndex).icon87 name: modelData && modelData.isToggle ? modelData.icon : (modelData.get(model.selectedIndex) ? modelData.get(model.selectedIndex).icon : "")
88 source: name ? "image://theme/%1".arg(name) : (modelData.iconSource || "")88 source: name ? "image://theme/%1".arg(name) : (modelData.iconSource || "")
89 visible: source != ""89 visible: source != ""
90 }90 }
9191
=== modified file 'CameraApp/advancedcamerasettings.cpp'
--- CameraApp/advancedcamerasettings.cpp 2015-10-27 09:17:27 +0000
+++ CameraApp/advancedcamerasettings.cpp 2015-11-25 17:47:09 +0000
@@ -26,6 +26,10 @@
26#include <QtMultimedia/QVideoDeviceSelectorControl>26#include <QtMultimedia/QVideoDeviceSelectorControl>
27#include <QtMultimedia/QCameraFlashControl>27#include <QtMultimedia/QCameraFlashControl>
28#include <QtMultimedia/QCameraExposureControl>28#include <QtMultimedia/QCameraExposureControl>
29#include <QGuiApplication>
30#include <QScreen>
31
32#include <cmath>
2933
30// Definition of this enum value is duplicated in qtubuntu-camera34// Definition of this enum value is duplicated in qtubuntu-camera
31static const QCameraExposure::ExposureMode ExposureHdr = static_cast<QCameraExposure::ExposureMode>(QCameraExposure::ExposureModeVendor + 1);35static const QCameraExposure::ExposureMode ExposureHdr = static_cast<QCameraExposure::ExposureMode>(QCameraExposure::ExposureModeVendor + 1);
@@ -222,6 +226,12 @@
222 QObject::connect(m_cameraControl,226 QObject::connect(m_cameraControl,
223 SIGNAL(captureModeChanged(QCamera::CaptureModes)),227 SIGNAL(captureModeChanged(QCamera::CaptureModes)),
224 this, SIGNAL(resolutionChanged()));228 this, SIGNAL(resolutionChanged()));
229 QObject::connect(m_cameraControl,
230 SIGNAL(captureModeChanged(QCamera::CaptureModes)),
231 this, SIGNAL(maximumResolutionChanged()));
232 QObject::connect(m_cameraControl,
233 SIGNAL(captureModeChanged(QCamera::CaptureModes)),
234 this, SIGNAL(fittingResolutionChanged()));
225 }235 }
226236
227 m_cameraFlashControl = flashControlFromCamera(m_camera);237 m_cameraFlashControl = flashControlFromCamera(m_camera);
@@ -237,6 +247,8 @@
237 m_videoEncoderControl = videoEncoderControlFromCamera(m_camera);247 m_videoEncoderControl = videoEncoderControlFromCamera(m_camera);
238248
239 Q_EMIT resolutionChanged();249 Q_EMIT resolutionChanged();
250 Q_EMIT maximumResolutionChanged();
251 Q_EMIT fittingResolutionChanged();
240 Q_EMIT hasFlashChanged();252 Q_EMIT hasFlashChanged();
241 Q_EMIT hasHdrChanged();253 Q_EMIT hasHdrChanged();
242 Q_EMIT hdrEnabledChanged();254 Q_EMIT hdrEnabledChanged();
@@ -260,6 +272,8 @@
260 }272 }
261 Q_EMIT activeCameraIndexChanged();273 Q_EMIT activeCameraIndexChanged();
262 Q_EMIT resolutionChanged();274 Q_EMIT resolutionChanged();
275 Q_EMIT maximumResolutionChanged();
276 Q_EMIT fittingResolutionChanged();
263 Q_EMIT hasFlashChanged();277 Q_EMIT hasFlashChanged();
264 Q_EMIT videoSupportedResolutionsChanged();278 Q_EMIT videoSupportedResolutionsChanged();
265 }279 }
@@ -277,6 +291,117 @@
277 return QSize();291 return QSize();
278}292}
279293
294QSize AdvancedCameraSettings::imageCaptureResolution() const
295{
296 if (m_imageEncoderControl != 0) {
297 return m_imageEncoderControl->imageSettings().resolution();
298 }
299
300 return QSize();
301}
302
303QSize AdvancedCameraSettings::videoRecorderResolution() const
304{
305 if (m_videoEncoderControl != 0) {
306 return m_videoEncoderControl->videoSettings().resolution();
307 }
308
309 return QSize();
310}
311
312QSize AdvancedCameraSettings::maximumResolution() const
313{
314 if (m_imageEncoderControl) {
315 QList<QSize> sizes = m_imageEncoderControl->supportedResolutions(
316 m_imageEncoderControl->imageSettings());
317
318 QSize maximumSize;
319 long maximumPixels = 0;
320
321 QList<QSize>::const_iterator it = sizes.begin();
322 while (it != sizes.end()) {
323 const long pixels = ((long)((*it).width())) * ((long)((*it).height()));
324 if (pixels > maximumPixels) {
325 maximumSize = *it;
326 maximumPixels = pixels;
327 }
328 ++it;
329 }
330
331 return maximumSize;
332 }
333
334 return QSize();
335}
336
337float AdvancedCameraSettings::getScreenAspectRatio() const
338{
339 float screenAspectRatio;
340 QScreen *screen = QGuiApplication::primaryScreen();
341 Q_ASSERT(!screen);
342 const int kScreenWidth = screen->geometry().width();
343 const int kScreenHeight = screen->geometry().height();
344 Q_ASSERT(kScreenWidth > 0 && kScreenHeight > 0);
345
346 screenAspectRatio = (kScreenWidth > kScreenHeight) ?
347 ((float)kScreenWidth / (float)kScreenHeight) : ((float)kScreenHeight / (float)kScreenWidth);
348
349 return screenAspectRatio;
350}
351
352QSize AdvancedCameraSettings::fittingResolution() const
353{
354 QList<float> prioritizedAspectRatios;
355 prioritizedAspectRatios.append(getScreenAspectRatio());
356 const float backAspectRatios[4] = { 16.0f/9.0f, 3.0f/2.0f, 4.0f/3.0f, 5.0f/4.0f };
357 for (int i=0; i<4; ++i) {
358 if (!prioritizedAspectRatios.contains(backAspectRatios[i])) {
359 prioritizedAspectRatios.append(backAspectRatios[i]);
360 }
361 }
362
363 if (m_imageEncoderControl) {
364 QList<QSize> sizes = m_imageEncoderControl->supportedResolutions(
365 m_imageEncoderControl->imageSettings());
366
367 QSize optimalSize;
368 long optimalPixels = 0;
369
370 if (!sizes.empty()) {
371 float aspectRatio;
372
373 // Loop over all reported camera resolutions until we find the highest
374 // one that matches the current prioritized aspect ratio. If it doesn't
375 // find one on the current aspect ration, it selects the next ratio and
376 // tries again.
377 QList<float>::const_iterator ratioIt = prioritizedAspectRatios.begin();
378 while (ratioIt != prioritizedAspectRatios.end()) {
379 // Don't update the aspect ratio when using this function for finding
380 // the optimal thumbnail size as it will affect the preview window size
381 aspectRatio = (*ratioIt);
382
383 QList<QSize>::const_iterator it = sizes.begin();
384 while (it != sizes.end()) {
385 const float ratio = (float)(*it).width() / (float)(*it).height();
386 const long pixels = ((long)((*it).width())) * ((long)((*it).height()));
387 const float EPSILON = 0.02;
388 if (fabs(ratio - aspectRatio) < EPSILON && pixels > optimalPixels) {
389 optimalSize = *it;
390 optimalPixels = pixels;
391 }
392 ++it;
393 }
394 if (optimalPixels > 0) break;
395 ++ratioIt;
396 }
397 }
398
399 return optimalSize;
400 }
401
402 return QSize();
403}
404
280QStringList AdvancedCameraSettings::videoSupportedResolutions() const405QStringList AdvancedCameraSettings::videoSupportedResolutions() const
281{406{
282 if (m_videoEncoderControl) {407 if (m_videoEncoderControl) {
283408
=== modified file 'CameraApp/advancedcamerasettings.h'
--- CameraApp/advancedcamerasettings.h 2014-12-08 19:12:52 +0000
+++ CameraApp/advancedcamerasettings.h 2015-11-25 17:47:09 +0000
@@ -40,6 +40,10 @@
40 Q_PROPERTY (int activeCameraIndex READ activeCameraIndex WRITE setActiveCameraIndex40 Q_PROPERTY (int activeCameraIndex READ activeCameraIndex WRITE setActiveCameraIndex
41 NOTIFY activeCameraIndexChanged)41 NOTIFY activeCameraIndexChanged)
42 Q_PROPERTY (QSize resolution READ resolution NOTIFY resolutionChanged)42 Q_PROPERTY (QSize resolution READ resolution NOTIFY resolutionChanged)
43 Q_PROPERTY (QSize imageCaptureResolution READ imageCaptureResolution)
44 Q_PROPERTY (QSize videoRecorderResolution READ videoRecorderResolution)
45 Q_PROPERTY (QSize maximumResolution READ maximumResolution NOTIFY maximumResolutionChanged)
46 Q_PROPERTY (QSize fittingResolution READ fittingResolution NOTIFY fittingResolutionChanged)
43 Q_PROPERTY (QStringList videoSupportedResolutions READ videoSupportedResolutions NOTIFY videoSupportedResolutionsChanged)47 Q_PROPERTY (QStringList videoSupportedResolutions READ videoSupportedResolutions NOTIFY videoSupportedResolutionsChanged)
44 Q_PROPERTY (bool hasFlash READ hasFlash NOTIFY hasFlashChanged)48 Q_PROPERTY (bool hasFlash READ hasFlash NOTIFY hasFlashChanged)
45 Q_PROPERTY (bool hdrEnabled READ hdrEnabled WRITE setHdrEnabled NOTIFY hdrEnabledChanged)49 Q_PROPERTY (bool hdrEnabled READ hdrEnabled WRITE setHdrEnabled NOTIFY hdrEnabledChanged)
@@ -53,6 +57,11 @@
53 void setCamera(QObject* camera);57 void setCamera(QObject* camera);
54 void setActiveCameraIndex(int index);58 void setActiveCameraIndex(int index);
55 QSize resolution() const;59 QSize resolution() const;
60 QSize imageCaptureResolution() const;
61 QSize videoRecorderResolution() const;
62 QSize maximumResolution() const;
63 QSize fittingResolution() const;
64 float getScreenAspectRatio() const;
56 QStringList videoSupportedResolutions() const;65 QStringList videoSupportedResolutions() const;
57 bool hasFlash() const;66 bool hasFlash() const;
58 bool hasHdr() const;67 bool hasHdr() const;
@@ -66,6 +75,8 @@
66 void cameraChanged();75 void cameraChanged();
67 void activeCameraIndexChanged();76 void activeCameraIndexChanged();
68 void resolutionChanged();77 void resolutionChanged();
78 void maximumResolutionChanged();
79 void fittingResolutionChanged();
69 void hasFlashChanged();80 void hasFlashChanged();
70 void hasHdrChanged();81 void hasHdrChanged();
71 void hdrEnabledChanged();82 void hdrEnabledChanged();
7283
=== modified file 'OptionButton.qml'
--- OptionButton.qml 2015-10-22 12:21:14 +0000
+++ OptionButton.qml 2015-11-25 17:47:09 +0000
@@ -23,7 +23,7 @@
23 property var model23 property var model
24 property string settingsProperty: model.settingsProperty24 property string settingsProperty: model.settingsProperty
2525
26 iconName: model.isToggle || !model.get(model.selectedIndex).icon ? model.icon : model.get(model.selectedIndex).icon26 iconName: !model.get(model.selectedIndex).icon ? model.icon : model.get(model.selectedIndex).icon
27 iconSource: (model && model.iconSource) ? model.iconSource : ""27 iconSource: (model && model.iconSource) ? model.iconSource : ""
28 on: model.isToggle ? model.get(model.selectedIndex).value : true28 on: model.isToggle ? model.get(model.selectedIndex).value : true
29 enabled: model.available29 enabled: model.available
3030
=== modified file 'ViewFinderOverlay.qml'
--- ViewFinderOverlay.qml 2015-10-22 12:21:14 +0000
+++ ViewFinderOverlay.qml 2015-11-25 17:47:09 +0000
@@ -50,6 +50,13 @@
50 property bool gridEnabled: false50 property bool gridEnabled: false
51 property bool preferRemovableStorage: false51 property bool preferRemovableStorage: false
52 property string videoResolution: "1920x1080"52 property string videoResolution: "1920x1080"
53 property bool playShutterSound: true
54 // FIXME: stores the resolution selected for 2 cameras. Instead it should:
55 // - support any number of cameras
56 // - not rely on the camera index but on Camera.deviceId
57 // Ref.: http://doc.qt.io/qt-5/qml-qtmultimedia-camera.html#deviceId-prop
58 property string photoResolution0
59 property string photoResolution1
5360
54 onFlashModeChanged: if (flashMode != Camera.FlashOff) hdrEnabled = false;61 onFlashModeChanged: if (flashMode != Camera.FlashOff) hdrEnabled = false;
55 onHdrEnabledChanged: if (hdrEnabled) flashMode = Camera.FlashOff62 onHdrEnabledChanged: if (hdrEnabled) flashMode = Camera.FlashOff
@@ -87,12 +94,83 @@
87 value: settings.videoResolution94 value: settings.videoResolution
88 }95 }
8996
97 Binding {
98 target: camera.imageCapture
99 property: "resolution"
100 value: settings["photoResolution" + camera.advanced.activeCameraIndex]
101 }
102
103 Connections {
104 target: camera.imageCapture
105 onResolutionChanged: {
106 // FIXME: this is a necessary workaround because:
107 // - Neither camera.viewfinder.resolution nor camera.advanced.resolution
108 // emit a changed signal when the underlying AalViewfinderSettingsControl's
109 // resolution changes
110 // - we know that qtubuntu-camera changes the resolution of the
111 // viewfinder automatically when the capture resolution is set
112 // - we need camera.viewfinder.resolution to hold the right
113 // value
114 camera.viewfinder.resolution = camera.advanced.resolution;
115 }
116 }
117
118 Connections {
119 target: camera.videoRecorder
120 onResolutionChanged: {
121 // FIXME: see workaround setting camera.viewfinder.resolution above
122 camera.viewfinder.resolution = camera.advanced.resolution;
123 }
124 }
125
126 Connections {
127 target: camera
128 onCaptureModeChanged: {
129 // FIXME: see workaround setting camera.viewfinder.resolution above
130 camera.viewfinder.resolution = camera.advanced.resolution;
131 }
132 }
133
90 function resolutionToLabel(resolution) {134 function resolutionToLabel(resolution) {
91 // takes in a resolution string (e.g. "1920x1080") and returns a nicer135 // takes in a resolution string (e.g. "1920x1080") and returns a nicer
92 // form of it for display in the UI: "1080p"136 // form of it for display in the UI: "1080p"
93 return resolution.split("x").pop() + "p";137 return resolution.split("x").pop() + "p";
94 }138 }
95139
140 function sizeToString(size) {
141 return size.width + "x" + size.height;
142 }
143
144 function stringToSize(resolution) {
145 var r = resolution.split("x");
146 return Qt.size(r[0], r[1]);
147 }
148
149 function sizeToAspectRatio(size) {
150 var ratio = Math.max(size.width, size.height) / Math.min(size.width, size.height);
151 var maxDenominator = 12;
152 var epsilon;
153 var numerator;
154 var denominator;
155 var bestDenominator;
156 var bestEpsilon = 10000;
157 for (denominator = 2; denominator <= maxDenominator; denominator++) {
158 numerator = ratio * denominator;
159 epsilon = Math.abs(Math.round(numerator) - numerator);
160 if (epsilon < bestEpsilon) {
161 bestEpsilon = epsilon;
162 bestDenominator = denominator;
163 }
164 }
165 numerator = Math.round(ratio * bestDenominator);
166 return "%1:%2".arg(numerator).arg(bestDenominator);
167 }
168
169 function sizeToMegapixels(size) {
170 var megapixels = (size.width * size.height) / 1000000;
171 return parseFloat(megapixels.toFixed(1))
172 }
173
96 function updateVideoResolutionOptions() {174 function updateVideoResolutionOptions() {
97 // Clear and refill videoResolutionOptionsModel with available resolutions175 // Clear and refill videoResolutionOptionsModel with available resolutions
98 // Try to only display well known resolutions: 1080p, 720p and 480p176 // Try to only display well known resolutions: 1080p, 720p and 480p
@@ -110,25 +188,71 @@
110 }188 }
111189
112 // If resolution setting chosen is not supported select the highest available resolution190 // If resolution setting chosen is not supported select the highest available resolution
113 if (supported.indexOf(settings.videoResolution) == -1) {191 if (supported.length > 0 && supported.indexOf(settings.videoResolution) == -1) {
114 settings.videoResolution = supported[supported.length - 1];192 settings.videoResolution = supported[supported.length - 1];
115 }193 }
116 }194 }
117195
196 function updatePhotoResolutionOptions() {
197 // Clear and refill photoResolutionOptionsModel with available resolutions
198 photoResolutionOptionsModel.clear();
199
200 var optionMaximum = {"icon": "",
201 "label": "%1 (%2MP)".arg(sizeToAspectRatio(camera.advanced.maximumResolution))
202 .arg(sizeToMegapixels(camera.advanced.maximumResolution)),
203 "value": sizeToString(camera.advanced.maximumResolution)};
204
205 var optionFitting = {"icon": "",
206 "label": "%1 (%2MP)".arg(sizeToAspectRatio(camera.advanced.fittingResolution))
207 .arg(sizeToMegapixels(camera.advanced.fittingResolution)),
208 "value": sizeToString(camera.advanced.fittingResolution)};
209
210 photoResolutionOptionsModel.insert(0, optionMaximum);
211 if (camera.advanced.fittingResolution != camera.advanced.maximumResolution) {
212 photoResolutionOptionsModel.insert(1, optionFitting);
213 }
214
215 var photoResolution = settings["photoResolution" + camera.advanced.activeCameraIndex];
216 // If resolution setting chosen is not supported select the fitting resolution
217 if (photoResolution != optionFitting.value &&
218 photoResolution != optionMaximum.value) {
219 settings["photoResolution" + camera.advanced.activeCameraIndex] = optionFitting.value;
220 }
221 }
222
118 Component.onCompleted: {223 Component.onCompleted: {
224 camera.cameraState = Camera.LoadedState;
119 updateVideoResolutionOptions();225 updateVideoResolutionOptions();
226 updatePhotoResolutionOptions();
227 // FIXME: see workaround setting camera.viewfinder.resolution above
228 camera.viewfinder.resolution = camera.advanced.resolution;
229 camera.cameraState = Camera.ActiveState;
120 }230 }
121231
122 Connections {232 Connections {
123 target: camera.advanced233 target: camera.advanced
124 onVideoSupportedResolutionsChanged: updateVideoResolutionOptions();234 onVideoSupportedResolutionsChanged: updateVideoResolutionOptions();
235 onFittingResolutionChanged: updatePhotoResolutionOptions();
236 onMaximumResolutionChanged: updatePhotoResolutionOptions();
125 }237 }
126238
127 Connections {239 Connections {
128 target: camera.advanced240 target: camera.advanced
129 onActiveCameraIndexChanged: {241 onActiveCameraIndexChanged: {
242 var hasPhotoResolutionSetting = (settings["photoResolution" + camera.advanced.activeCameraIndex] != "")
243 // FIXME: use camera.advanced.imageCaptureResolution instead of camera.imageCapture.resolution
244 // because the latter is not updated when the backend changes the resolution
245 settings["photoResolution" + camera.advanced.activeCameraIndex] = sizeToString(camera.advanced.imageCaptureResolution);
246 settings.videoResolution = sizeToString(camera.advanced.videoRecorderResolution);
247 updatePhotoResolutionOptions();
130 updateVideoResolutionOptions();248 updateVideoResolutionOptions();
131 camera.videoRecorder.resolution = settings.videoResolution;249 // FIXME: see workaround setting camera.viewfinder.resolution above
250 camera.viewfinder.resolution = camera.advanced.resolution;
251
252 // If no resolution has ever been chosen, select the one that fits the screen
253 if (!hasPhotoResolutionSetting) {
254 settings["photoResolution" + camera.advanced.activeCameraIndex] = sizeToString(camera.advanced.fittingResolution);
255 }
132 }256 }
133 }257 }
134258
@@ -280,7 +404,7 @@
280 property bool isToggle: true404 property bool isToggle: true
281 property int selectedIndex: bottomEdge.indexForValue(hdrOptionsModel, settings.hdrEnabled)405 property int selectedIndex: bottomEdge.indexForValue(hdrOptionsModel, settings.hdrEnabled)
282 property bool available: camera.advanced.hasHdr406 property bool available: camera.advanced.hasHdr
283 property bool visible: true407 property bool visible: camera.captureMode === Camera.CaptureStillImage
284 property bool showInIndicators: true408 property bool showInIndicators: true
285409
286 ListElement {410 ListElement {
@@ -404,6 +528,41 @@
404 property bool available: true528 property bool available: true
405 property bool visible: camera.captureMode == Camera.CaptureVideo529 property bool visible: camera.captureMode == Camera.CaptureVideo
406 property bool showInIndicators: false530 property bool showInIndicators: false
531 },
532 ListModel {
533 id: shutterSoundOptionsModel
534
535 property string settingsProperty: "playShutterSound"
536 property string icon: ""
537 property string label: ""
538 property bool isToggle: true
539 property int selectedIndex: bottomEdge.indexForValue(shutterSoundOptionsModel, settings.playShutterSound)
540 property bool available: true
541 property bool visible: camera.captureMode === Camera.CaptureStillImage
542 property bool showInIndicators: false
543
544 ListElement {
545 icon: "audio-volume-high"
546 label: QT_TR_NOOP("On")
547 value: true
548 }
549 ListElement {
550 icon: "audio-volume-muted"
551 label: QT_TR_NOOP("Off")
552 value: false
553 }
554 },
555 ListModel {
556 id: photoResolutionOptionsModel
557
558 property string settingsProperty: "photoResolution" + camera.advanced.activeCameraIndex
559 property string icon: ""
560 property string label: sizeToAspectRatio(stringToSize(settings[settingsProperty]))
561 property bool isToggle: false
562 property int selectedIndex: bottomEdge.indexForValue(photoResolutionOptionsModel, settings[settingsProperty])
563 property bool available: true
564 property bool visible: camera.captureMode == Camera.CaptureStillImage
565 property bool showInIndicators: false
407 }566 }
408 ]567 ]
409568
@@ -571,18 +730,25 @@
571 function completeSwitch() {730 function completeSwitch() {
572 viewFinderSwitcherAnimation.restart();731 viewFinderSwitcherAnimation.restart();
573 camera.switchInProgress = false;732 camera.switchInProgress = false;
733 zoomControl.value = camera.currentZoom;
574 }734 }
575735
576 function changeRecordMode() {736 function changeRecordMode() {
577 if (camera.captureMode == Camera.CaptureVideo) camera.videoRecorder.stop()737 if (camera.captureMode == Camera.CaptureVideo) camera.videoRecorder.stop()
578 camera.captureMode = (camera.captureMode == Camera.CaptureVideo) ? Camera.CaptureStillImage : Camera.CaptureVideo738 camera.captureMode = (camera.captureMode == Camera.CaptureVideo) ? Camera.CaptureStillImage : Camera.CaptureVideo
739 zoomControl.value = camera.currentZoom
740 }
741
742 Connections {
743 target: Qt.application
744 onActiveChanged: if (active) zoomControl.value = camera.currentZoom
579 }745 }
580746
581 Timer {747 Timer {
582 id: shootingTimer748 id: shootingTimer
583 repeat: true749 repeat: true
584 triggeredOnStart: true750 triggeredOnStart: true
585 751
586 property int remainingSecs: 0752 property int remainingSecs: 0
587753
588 onTriggered: {754 onTriggered: {
589755
=== modified file 'ViewFinderView.qml'
--- ViewFinderView.qml 2015-11-16 15:54:25 +0000
+++ ViewFinderView.qml 2015-11-25 17:47:09 +0000
@@ -36,6 +36,7 @@
36 Camera {36 Camera {
37 id: camera37 id: camera
38 captureMode: Camera.CaptureStillImage38 captureMode: Camera.CaptureStillImage
39 cameraState: Camera.UnloadedState
39 StateSaver.properties: "captureMode"40 StateSaver.properties: "captureMode"
4041
41 function manualFocus(x, y) {42 function manualFocus(x, y) {
@@ -67,10 +68,6 @@
67 StateSaver.properties: "activeCameraIndex"68 StateSaver.properties: "activeCameraIndex"
68 }69 }
6970
70 Component.onCompleted: {
71 camera.start();
72 }
73
74 /* Use only digital zoom for now as it's what phone cameras mostly use.71 /* Use only digital zoom for now as it's what phone cameras mostly use.
75 TODO: if optical zoom is available, maximumZoom should be the combined72 TODO: if optical zoom is available, maximumZoom should be the combined
76 range of optical and digital zoom and currentZoom should adjust the two73 range of optical and digital zoom and currentZoom should adjust the two
@@ -121,12 +118,14 @@
121 target: Qt.application118 target: Qt.application
122 onActiveChanged: {119 onActiveChanged: {
123 if (Qt.application.active) {120 if (Qt.application.active) {
124 camera.start()121 if (camera.cameraState == Camera.LoadedState) {
122 camera.cameraState = Camera.ActiveState;
123 }
125 } else if (!application.desktopMode) {124 } else if (!application.desktopMode) {
126 if (camera.videoRecorder.recorderState == CameraRecorder.RecordingState) {125 if (camera.videoRecorder.recorderState == CameraRecorder.RecordingState) {
127 camera.videoRecorder.stop();126 camera.videoRecorder.stop();
128 }127 }
129 camera.stop()128 camera.cameraState = Camera.LoadedState;
130 }129 }
131 }130 }
132 }131 }
@@ -250,16 +249,16 @@
250 axis.x: 0; axis.y: 1; axis.z: 0249 axis.x: 0; axis.y: 1; axis.z: 0
251 angle: application.desktopMode ? 180 : 0250 angle: application.desktopMode ? 180 : 0
252 }251 }
253252 }
254 ViewFinderGeometry {253
255 id: viewFinderGeometry254 ViewFinderGeometry {
256 anchors.centerIn: parent255 id: viewFinderGeometry
257256 anchors.centerIn: parent
258 cameraResolution: camera.advanced.resolution257
259 viewFinderHeight: viewFinder.height258 cameraResolution: camera.viewfinder.resolution
260 viewFinderWidth: viewFinder.width259 viewFinderHeight: viewFinder.height
261 viewFinderOrientation: viewFinder.orientation260 viewFinderWidth: viewFinder.width
262 }261 viewFinderOrientation: viewFinder.orientation
263 }262 }
264263
265 Item {264 Item {
266265
=== modified file 'tests/autopilot/camera_app/emulators/main_window.py'
--- tests/autopilot/camera_app/emulators/main_window.py 2015-11-20 15:01:02 +0000
+++ tests/autopilot/camera_app/emulators/main_window.py 2015-11-25 17:47:09 +0000
@@ -7,7 +7,7 @@
77
8from camera_app.emulators.panel import Panel8from camera_app.emulators.panel import Panel
9from autopilot.matchers import Eventually9from autopilot.matchers import Eventually
10from testtools.matchers import Equals10from testtools.matchers import Equals, NotEquals
1111
1212
13class MainWindow(object):13class MainWindow(object):
@@ -163,3 +163,22 @@
163 tx, ty, (tx + view_switcher.width // 2), ty, rate=1)163 tx, ty, (tx + view_switcher.width // 2), ty, rate=1)
164 viewfinder = self.get_viewfinder()164 viewfinder = self.get_viewfinder()
165 testCase.assertThat(viewfinder.inView, Eventually(Equals(True)))165 testCase.assertThat(viewfinder.inView, Eventually(Equals(True)))
166
167 def switch_cameras(self):
168 # Swap cameras and wait for camera to settle
169 shoot_button = self.get_exposure_button()
170 swap_camera_button = self.get_swap_camera_button()
171 self.app.pointing_device.move_to_object(swap_camera_button)
172 self.app.pointing_device.click()
173 shoot_button.enabled.wait_for(True)
174
175 def switch_recording_mode(self):
176 record_control = self.get_record_control()
177
178 # Wait for the camera overlay to be loaded
179 record_control.enabled.wait_for(True)
180 record_control.width.wait_for(NotEquals(0))
181 record_control.height.wait_for(NotEquals(0))
182
183 self.app.pointing_device.move_to_object(record_control)
184 self.app.pointing_device.click()
166185
=== modified file 'tests/autopilot/camera_app/tests/test_capture.py'
--- tests/autopilot/camera_app/tests/test_capture.py 2015-10-05 13:14:12 +0000
+++ tests/autopilot/camera_app/tests/test_capture.py 2015-11-25 17:47:09 +0000
@@ -90,13 +90,11 @@
9090
91 """91 """
92 # Get all the elements92 # Get all the elements
93 record_control = self.main_window.get_record_control()
94 stop_watch = self.main_window.get_stop_watch()93 stop_watch = self.main_window.get_stop_watch()
95 exposure_button = self.main_window.get_exposure_button()94 exposure_button = self.main_window.get_exposure_button()
9695
97 # Click the record button to toggle photo/video mode96 # Click the record button to toggle photo/video mode
98 self.pointing_device.move_to_object(record_control)97 self.main_window.switch_recording_mode()
99 self.pointing_device.click()
10098
101 # Before recording the stop watch should read zero recording time99 # Before recording the stop watch should read zero recording time
102 # and not be visible anyway.100 # and not be visible anyway.
@@ -137,8 +135,7 @@
137 # Now stop the video and go back to picture mode and check if135 # Now stop the video and go back to picture mode and check if
138 # everything resets itself to previous states136 # everything resets itself to previous states
139 self.pointing_device.click()137 self.pointing_device.click()
140 self.pointing_device.move_to_object(record_control)138 self.main_window.switch_recording_mode()
141 self.pointing_device.click()
142139
143 self.assertThat(stop_watch.opacity, Eventually(Equals(0.0)))140 self.assertThat(stop_watch.opacity, Eventually(Equals(0.0)))
144141
@@ -268,7 +265,7 @@
268 """Test recording videos at a set resolution and switching cameras"""265 """Test recording videos at a set resolution and switching cameras"""
269 def test_video_resolution_setting_switching_cameras(self):266 def test_video_resolution_setting_switching_cameras(self):
270 # switch to video recording and empty video folder267 # switch to video recording and empty video folder
271 self.switch_to_video_recording()268 self.main_window.switch_recording_mode()
272 self.delete_all_videos()269 self.delete_all_videos()
273270
274 # select the first resolution for the current camera271 # select the first resolution for the current camera
@@ -277,14 +274,14 @@
277 self.set_video_resolution(initial_resolution)274 self.set_video_resolution(initial_resolution)
278275
279 # switch cameras and select the last resolution for the current camera276 # switch cameras and select the last resolution for the current camera
280 self.switch_cameras()277 self.main_window.switch_cameras()
281 resolutions = self.get_available_video_resolutions()278 resolutions = self.get_available_video_resolutions()
282 expected_resolution = resolutions[-1]279 expected_resolution = resolutions[-1]
283 self.assertThat(expected_resolution, NotEquals(initial_resolution))280 self.assertThat(expected_resolution, NotEquals(initial_resolution))
284 self.set_video_resolution(expected_resolution)281 self.set_video_resolution(expected_resolution)
285282
286 # switch back to the initial camera and record a video283 # switch back to the initial camera and record a video
287 self.switch_cameras()284 self.main_window.switch_cameras()
288 self.record_video(2)285 self.record_video(2)
289 video_file = self.get_first_video()286 video_file = self.get_first_video()
290 height = self.read_video_height(video_file)287 height = self.read_video_height(video_file)
@@ -292,17 +289,9 @@
292 expected_resolution)289 expected_resolution)
293 self.assertThat(height, Equals(expected_height))290 self.assertThat(height, Equals(expected_height))
294291
295 def switch_cameras(self):
296 # Swap cameras and wait for camera to settle
297 shoot_button = self.main_window.get_exposure_button()
298 swap_camera_button = self.main_window.get_swap_camera_button()
299 self.pointing_device.move_to_object(swap_camera_button)
300 self.pointing_device.click()
301 self.assertThat(shoot_button.enabled, Eventually(Equals(True)))
302
303 """Test recording videos at various resolutions"""292 """Test recording videos at various resolutions"""
304 def test_video_resolution_setting(self):293 def test_video_resolution_setting(self):
305 self.switch_to_video_recording()294 self.main_window.switch_recording_mode()
306 resolutions = self.get_available_video_resolutions()295 resolutions = self.get_available_video_resolutions()
307296
308 for resolution_label in resolutions:297 for resolution_label in resolutions:
@@ -316,16 +305,6 @@
316 self.assertThat(height, Equals(expected_height))305 self.assertThat(height, Equals(expected_height))
317 self.dismiss_first_photo_hint()306 self.dismiss_first_photo_hint()
318307
319 def switch_to_video_recording(self):
320 record_control = self.main_window.get_record_control()
321 # Wait for the camera overlay to be loaded
322 self.assertThat(record_control.enabled, Eventually(Equals(True)))
323 self.assertThat(record_control.width, Eventually(NotEquals(0)))
324 self.assertThat(record_control.height, Eventually(NotEquals(0)))
325
326 self.pointing_device.move_to_object(record_control)
327 self.pointing_device.click()
328
329 def get_available_video_resolutions(self):308 def get_available_video_resolutions(self):
330 # open bottom edge309 # open bottom edge
331 bottom_edge = self.main_window.get_bottom_edge()310 bottom_edge = self.main_window.get_bottom_edge()
332311
=== modified file 'tests/autopilot/camera_app/tests/test_zoom.py'
--- tests/autopilot/camera_app/tests/test_zoom.py 2015-04-29 15:56:44 +0000
+++ tests/autopilot/camera_app/tests/test_zoom.py 2015-11-25 17:47:09 +0000
@@ -68,3 +68,50 @@
6868
69 self.pointing_device.drag(tx, ty, (tx - zoom_control.width), ty)69 self.pointing_device.drag(tx, ty, (tx - zoom_control.width), ty)
70 self.assertThat(zoom_control.value, Eventually(Equals(1.0)))70 self.assertThat(zoom_control.value, Eventually(Equals(1.0)))
71
72 """Tests zoom is reset to minimum on camera switch"""
73 def test_zoom_reset_on_camera_change(self):
74 zoom_control = self.main_window.get_zoom_control()
75 zoom_slider = self.main_window.get_zoom_slider()
76
77 self.activate_zoom()
78 x, y, w, h = zoom_slider.globalRect
79 tx = x + (w // 2)
80 ty = y + (h // 2)
81 self.pointing_device.drag(tx, ty, (tx + zoom_control.width), ty)
82 self.assertThat(
83 zoom_control.value, Eventually(Equals(zoom_control.maximumValue)))
84
85 self.main_window.switch_cameras()
86 self.assertThat(
87 zoom_control.value, Eventually(Equals(zoom_control.minimumValue)))
88
89 self.activate_zoom()
90 self.pointing_device.drag(tx, ty, (tx + zoom_control.width), ty)
91 self.assertThat(
92 zoom_control.value, Eventually(Equals(zoom_control.maximumValue)))
93
94 self.main_window.switch_cameras()
95 self.assertThat(
96 zoom_control.value, Eventually(Equals(zoom_control.minimumValue)))
97
98 """Tests zoom is reset to minimum on recording mode switch"""
99 def test_zoom_reset_on_recording_mode_change(self):
100 zoom_control = self.main_window.get_zoom_control()
101 zoom_slider = self.main_window.get_zoom_slider()
102
103 self.activate_zoom()
104 x, y, w, h = zoom_slider.globalRect
105 tx = x + (w // 2)
106 ty = y + (h // 2)
107 self.pointing_device.drag(tx, ty, (tx + zoom_control.width), ty)
108 self.assertThat(
109 zoom_control.value, Eventually(Equals(zoom_control.maximumValue)))
110
111 self.main_window.switch_recording_mode()
112 self.assertThat(
113 zoom_control.value, Eventually(Equals(zoom_control.minimumValue)))
114
115 # Ideally we should test the same thing when switching back to photo
116 # mode, however due to http://pad.lv/1191088 zooming when recording
117 # video is disabled, so adding that test is pointless until fixed.

Subscribers

People subscribed via source and target branches