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
1=== modified file 'BottomEdgeIndicators.qml'
2--- BottomEdgeIndicators.qml 2015-10-22 12:21:14 +0000
3+++ BottomEdgeIndicators.qml 2015-11-25 17:47:09 +0000
4@@ -84,7 +84,7 @@
5 id: indicatorIcon
6 anchors.fill: parent
7 color: "white"
8- name: modelData && modelData.isToggle ? modelData.icon : modelData.get(model.selectedIndex).icon
9+ name: modelData && modelData.isToggle ? modelData.icon : (modelData.get(model.selectedIndex) ? modelData.get(model.selectedIndex).icon : "")
10 source: name ? "image://theme/%1".arg(name) : (modelData.iconSource || "")
11 visible: source != ""
12 }
13
14=== modified file 'CameraApp/advancedcamerasettings.cpp'
15--- CameraApp/advancedcamerasettings.cpp 2015-10-27 09:17:27 +0000
16+++ CameraApp/advancedcamerasettings.cpp 2015-11-25 17:47:09 +0000
17@@ -26,6 +26,10 @@
18 #include <QtMultimedia/QVideoDeviceSelectorControl>
19 #include <QtMultimedia/QCameraFlashControl>
20 #include <QtMultimedia/QCameraExposureControl>
21+#include <QGuiApplication>
22+#include <QScreen>
23+
24+#include <cmath>
25
26 // Definition of this enum value is duplicated in qtubuntu-camera
27 static const QCameraExposure::ExposureMode ExposureHdr = static_cast<QCameraExposure::ExposureMode>(QCameraExposure::ExposureModeVendor + 1);
28@@ -222,6 +226,12 @@
29 QObject::connect(m_cameraControl,
30 SIGNAL(captureModeChanged(QCamera::CaptureModes)),
31 this, SIGNAL(resolutionChanged()));
32+ QObject::connect(m_cameraControl,
33+ SIGNAL(captureModeChanged(QCamera::CaptureModes)),
34+ this, SIGNAL(maximumResolutionChanged()));
35+ QObject::connect(m_cameraControl,
36+ SIGNAL(captureModeChanged(QCamera::CaptureModes)),
37+ this, SIGNAL(fittingResolutionChanged()));
38 }
39
40 m_cameraFlashControl = flashControlFromCamera(m_camera);
41@@ -237,6 +247,8 @@
42 m_videoEncoderControl = videoEncoderControlFromCamera(m_camera);
43
44 Q_EMIT resolutionChanged();
45+ Q_EMIT maximumResolutionChanged();
46+ Q_EMIT fittingResolutionChanged();
47 Q_EMIT hasFlashChanged();
48 Q_EMIT hasHdrChanged();
49 Q_EMIT hdrEnabledChanged();
50@@ -260,6 +272,8 @@
51 }
52 Q_EMIT activeCameraIndexChanged();
53 Q_EMIT resolutionChanged();
54+ Q_EMIT maximumResolutionChanged();
55+ Q_EMIT fittingResolutionChanged();
56 Q_EMIT hasFlashChanged();
57 Q_EMIT videoSupportedResolutionsChanged();
58 }
59@@ -277,6 +291,117 @@
60 return QSize();
61 }
62
63+QSize AdvancedCameraSettings::imageCaptureResolution() const
64+{
65+ if (m_imageEncoderControl != 0) {
66+ return m_imageEncoderControl->imageSettings().resolution();
67+ }
68+
69+ return QSize();
70+}
71+
72+QSize AdvancedCameraSettings::videoRecorderResolution() const
73+{
74+ if (m_videoEncoderControl != 0) {
75+ return m_videoEncoderControl->videoSettings().resolution();
76+ }
77+
78+ return QSize();
79+}
80+
81+QSize AdvancedCameraSettings::maximumResolution() const
82+{
83+ if (m_imageEncoderControl) {
84+ QList<QSize> sizes = m_imageEncoderControl->supportedResolutions(
85+ m_imageEncoderControl->imageSettings());
86+
87+ QSize maximumSize;
88+ long maximumPixels = 0;
89+
90+ QList<QSize>::const_iterator it = sizes.begin();
91+ while (it != sizes.end()) {
92+ const long pixels = ((long)((*it).width())) * ((long)((*it).height()));
93+ if (pixels > maximumPixels) {
94+ maximumSize = *it;
95+ maximumPixels = pixels;
96+ }
97+ ++it;
98+ }
99+
100+ return maximumSize;
101+ }
102+
103+ return QSize();
104+}
105+
106+float AdvancedCameraSettings::getScreenAspectRatio() const
107+{
108+ float screenAspectRatio;
109+ QScreen *screen = QGuiApplication::primaryScreen();
110+ Q_ASSERT(!screen);
111+ const int kScreenWidth = screen->geometry().width();
112+ const int kScreenHeight = screen->geometry().height();
113+ Q_ASSERT(kScreenWidth > 0 && kScreenHeight > 0);
114+
115+ screenAspectRatio = (kScreenWidth > kScreenHeight) ?
116+ ((float)kScreenWidth / (float)kScreenHeight) : ((float)kScreenHeight / (float)kScreenWidth);
117+
118+ return screenAspectRatio;
119+}
120+
121+QSize AdvancedCameraSettings::fittingResolution() const
122+{
123+ QList<float> prioritizedAspectRatios;
124+ prioritizedAspectRatios.append(getScreenAspectRatio());
125+ const float backAspectRatios[4] = { 16.0f/9.0f, 3.0f/2.0f, 4.0f/3.0f, 5.0f/4.0f };
126+ for (int i=0; i<4; ++i) {
127+ if (!prioritizedAspectRatios.contains(backAspectRatios[i])) {
128+ prioritizedAspectRatios.append(backAspectRatios[i]);
129+ }
130+ }
131+
132+ if (m_imageEncoderControl) {
133+ QList<QSize> sizes = m_imageEncoderControl->supportedResolutions(
134+ m_imageEncoderControl->imageSettings());
135+
136+ QSize optimalSize;
137+ long optimalPixels = 0;
138+
139+ if (!sizes.empty()) {
140+ float aspectRatio;
141+
142+ // Loop over all reported camera resolutions until we find the highest
143+ // one that matches the current prioritized aspect ratio. If it doesn't
144+ // find one on the current aspect ration, it selects the next ratio and
145+ // tries again.
146+ QList<float>::const_iterator ratioIt = prioritizedAspectRatios.begin();
147+ while (ratioIt != prioritizedAspectRatios.end()) {
148+ // Don't update the aspect ratio when using this function for finding
149+ // the optimal thumbnail size as it will affect the preview window size
150+ aspectRatio = (*ratioIt);
151+
152+ QList<QSize>::const_iterator it = sizes.begin();
153+ while (it != sizes.end()) {
154+ const float ratio = (float)(*it).width() / (float)(*it).height();
155+ const long pixels = ((long)((*it).width())) * ((long)((*it).height()));
156+ const float EPSILON = 0.02;
157+ if (fabs(ratio - aspectRatio) < EPSILON && pixels > optimalPixels) {
158+ optimalSize = *it;
159+ optimalPixels = pixels;
160+ }
161+ ++it;
162+ }
163+ if (optimalPixels > 0) break;
164+ ++ratioIt;
165+ }
166+ }
167+
168+ return optimalSize;
169+ }
170+
171+ return QSize();
172+}
173+
174 QStringList AdvancedCameraSettings::videoSupportedResolutions() const
175 {
176 if (m_videoEncoderControl) {
177
178=== modified file 'CameraApp/advancedcamerasettings.h'
179--- CameraApp/advancedcamerasettings.h 2014-12-08 19:12:52 +0000
180+++ CameraApp/advancedcamerasettings.h 2015-11-25 17:47:09 +0000
181@@ -40,6 +40,10 @@
182 Q_PROPERTY (int activeCameraIndex READ activeCameraIndex WRITE setActiveCameraIndex
183 NOTIFY activeCameraIndexChanged)
184 Q_PROPERTY (QSize resolution READ resolution NOTIFY resolutionChanged)
185+ Q_PROPERTY (QSize imageCaptureResolution READ imageCaptureResolution)
186+ Q_PROPERTY (QSize videoRecorderResolution READ videoRecorderResolution)
187+ Q_PROPERTY (QSize maximumResolution READ maximumResolution NOTIFY maximumResolutionChanged)
188+ Q_PROPERTY (QSize fittingResolution READ fittingResolution NOTIFY fittingResolutionChanged)
189 Q_PROPERTY (QStringList videoSupportedResolutions READ videoSupportedResolutions NOTIFY videoSupportedResolutionsChanged)
190 Q_PROPERTY (bool hasFlash READ hasFlash NOTIFY hasFlashChanged)
191 Q_PROPERTY (bool hdrEnabled READ hdrEnabled WRITE setHdrEnabled NOTIFY hdrEnabledChanged)
192@@ -53,6 +57,11 @@
193 void setCamera(QObject* camera);
194 void setActiveCameraIndex(int index);
195 QSize resolution() const;
196+ QSize imageCaptureResolution() const;
197+ QSize videoRecorderResolution() const;
198+ QSize maximumResolution() const;
199+ QSize fittingResolution() const;
200+ float getScreenAspectRatio() const;
201 QStringList videoSupportedResolutions() const;
202 bool hasFlash() const;
203 bool hasHdr() const;
204@@ -66,6 +75,8 @@
205 void cameraChanged();
206 void activeCameraIndexChanged();
207 void resolutionChanged();
208+ void maximumResolutionChanged();
209+ void fittingResolutionChanged();
210 void hasFlashChanged();
211 void hasHdrChanged();
212 void hdrEnabledChanged();
213
214=== modified file 'OptionButton.qml'
215--- OptionButton.qml 2015-10-22 12:21:14 +0000
216+++ OptionButton.qml 2015-11-25 17:47:09 +0000
217@@ -23,7 +23,7 @@
218 property var model
219 property string settingsProperty: model.settingsProperty
220
221- iconName: model.isToggle || !model.get(model.selectedIndex).icon ? model.icon : model.get(model.selectedIndex).icon
222+ iconName: !model.get(model.selectedIndex).icon ? model.icon : model.get(model.selectedIndex).icon
223 iconSource: (model && model.iconSource) ? model.iconSource : ""
224 on: model.isToggle ? model.get(model.selectedIndex).value : true
225 enabled: model.available
226
227=== modified file 'ViewFinderOverlay.qml'
228--- ViewFinderOverlay.qml 2015-10-22 12:21:14 +0000
229+++ ViewFinderOverlay.qml 2015-11-25 17:47:09 +0000
230@@ -50,6 +50,13 @@
231 property bool gridEnabled: false
232 property bool preferRemovableStorage: false
233 property string videoResolution: "1920x1080"
234+ property bool playShutterSound: true
235+ // FIXME: stores the resolution selected for 2 cameras. Instead it should:
236+ // - support any number of cameras
237+ // - not rely on the camera index but on Camera.deviceId
238+ // Ref.: http://doc.qt.io/qt-5/qml-qtmultimedia-camera.html#deviceId-prop
239+ property string photoResolution0
240+ property string photoResolution1
241
242 onFlashModeChanged: if (flashMode != Camera.FlashOff) hdrEnabled = false;
243 onHdrEnabledChanged: if (hdrEnabled) flashMode = Camera.FlashOff
244@@ -87,12 +94,83 @@
245 value: settings.videoResolution
246 }
247
248+ Binding {
249+ target: camera.imageCapture
250+ property: "resolution"
251+ value: settings["photoResolution" + camera.advanced.activeCameraIndex]
252+ }
253+
254+ Connections {
255+ target: camera.imageCapture
256+ onResolutionChanged: {
257+ // FIXME: this is a necessary workaround because:
258+ // - Neither camera.viewfinder.resolution nor camera.advanced.resolution
259+ // emit a changed signal when the underlying AalViewfinderSettingsControl's
260+ // resolution changes
261+ // - we know that qtubuntu-camera changes the resolution of the
262+ // viewfinder automatically when the capture resolution is set
263+ // - we need camera.viewfinder.resolution to hold the right
264+ // value
265+ camera.viewfinder.resolution = camera.advanced.resolution;
266+ }
267+ }
268+
269+ Connections {
270+ target: camera.videoRecorder
271+ onResolutionChanged: {
272+ // FIXME: see workaround setting camera.viewfinder.resolution above
273+ camera.viewfinder.resolution = camera.advanced.resolution;
274+ }
275+ }
276+
277+ Connections {
278+ target: camera
279+ onCaptureModeChanged: {
280+ // FIXME: see workaround setting camera.viewfinder.resolution above
281+ camera.viewfinder.resolution = camera.advanced.resolution;
282+ }
283+ }
284+
285 function resolutionToLabel(resolution) {
286 // takes in a resolution string (e.g. "1920x1080") and returns a nicer
287 // form of it for display in the UI: "1080p"
288 return resolution.split("x").pop() + "p";
289 }
290
291+ function sizeToString(size) {
292+ return size.width + "x" + size.height;
293+ }
294+
295+ function stringToSize(resolution) {
296+ var r = resolution.split("x");
297+ return Qt.size(r[0], r[1]);
298+ }
299+
300+ function sizeToAspectRatio(size) {
301+ var ratio = Math.max(size.width, size.height) / Math.min(size.width, size.height);
302+ var maxDenominator = 12;
303+ var epsilon;
304+ var numerator;
305+ var denominator;
306+ var bestDenominator;
307+ var bestEpsilon = 10000;
308+ for (denominator = 2; denominator <= maxDenominator; denominator++) {
309+ numerator = ratio * denominator;
310+ epsilon = Math.abs(Math.round(numerator) - numerator);
311+ if (epsilon < bestEpsilon) {
312+ bestEpsilon = epsilon;
313+ bestDenominator = denominator;
314+ }
315+ }
316+ numerator = Math.round(ratio * bestDenominator);
317+ return "%1:%2".arg(numerator).arg(bestDenominator);
318+ }
319+
320+ function sizeToMegapixels(size) {
321+ var megapixels = (size.width * size.height) / 1000000;
322+ return parseFloat(megapixels.toFixed(1))
323+ }
324+
325 function updateVideoResolutionOptions() {
326 // Clear and refill videoResolutionOptionsModel with available resolutions
327 // Try to only display well known resolutions: 1080p, 720p and 480p
328@@ -110,25 +188,71 @@
329 }
330
331 // If resolution setting chosen is not supported select the highest available resolution
332- if (supported.indexOf(settings.videoResolution) == -1) {
333+ if (supported.length > 0 && supported.indexOf(settings.videoResolution) == -1) {
334 settings.videoResolution = supported[supported.length - 1];
335 }
336 }
337
338+ function updatePhotoResolutionOptions() {
339+ // Clear and refill photoResolutionOptionsModel with available resolutions
340+ photoResolutionOptionsModel.clear();
341+
342+ var optionMaximum = {"icon": "",
343+ "label": "%1 (%2MP)".arg(sizeToAspectRatio(camera.advanced.maximumResolution))
344+ .arg(sizeToMegapixels(camera.advanced.maximumResolution)),
345+ "value": sizeToString(camera.advanced.maximumResolution)};
346+
347+ var optionFitting = {"icon": "",
348+ "label": "%1 (%2MP)".arg(sizeToAspectRatio(camera.advanced.fittingResolution))
349+ .arg(sizeToMegapixels(camera.advanced.fittingResolution)),
350+ "value": sizeToString(camera.advanced.fittingResolution)};
351+
352+ photoResolutionOptionsModel.insert(0, optionMaximum);
353+ if (camera.advanced.fittingResolution != camera.advanced.maximumResolution) {
354+ photoResolutionOptionsModel.insert(1, optionFitting);
355+ }
356+
357+ var photoResolution = settings["photoResolution" + camera.advanced.activeCameraIndex];
358+ // If resolution setting chosen is not supported select the fitting resolution
359+ if (photoResolution != optionFitting.value &&
360+ photoResolution != optionMaximum.value) {
361+ settings["photoResolution" + camera.advanced.activeCameraIndex] = optionFitting.value;
362+ }
363+ }
364+
365 Component.onCompleted: {
366+ camera.cameraState = Camera.LoadedState;
367 updateVideoResolutionOptions();
368+ updatePhotoResolutionOptions();
369+ // FIXME: see workaround setting camera.viewfinder.resolution above
370+ camera.viewfinder.resolution = camera.advanced.resolution;
371+ camera.cameraState = Camera.ActiveState;
372 }
373
374 Connections {
375 target: camera.advanced
376 onVideoSupportedResolutionsChanged: updateVideoResolutionOptions();
377+ onFittingResolutionChanged: updatePhotoResolutionOptions();
378+ onMaximumResolutionChanged: updatePhotoResolutionOptions();
379 }
380
381 Connections {
382 target: camera.advanced
383 onActiveCameraIndexChanged: {
384+ var hasPhotoResolutionSetting = (settings["photoResolution" + camera.advanced.activeCameraIndex] != "")
385+ // FIXME: use camera.advanced.imageCaptureResolution instead of camera.imageCapture.resolution
386+ // because the latter is not updated when the backend changes the resolution
387+ settings["photoResolution" + camera.advanced.activeCameraIndex] = sizeToString(camera.advanced.imageCaptureResolution);
388+ settings.videoResolution = sizeToString(camera.advanced.videoRecorderResolution);
389+ updatePhotoResolutionOptions();
390 updateVideoResolutionOptions();
391- camera.videoRecorder.resolution = settings.videoResolution;
392+ // FIXME: see workaround setting camera.viewfinder.resolution above
393+ camera.viewfinder.resolution = camera.advanced.resolution;
394+
395+ // If no resolution has ever been chosen, select the one that fits the screen
396+ if (!hasPhotoResolutionSetting) {
397+ settings["photoResolution" + camera.advanced.activeCameraIndex] = sizeToString(camera.advanced.fittingResolution);
398+ }
399 }
400 }
401
402@@ -280,7 +404,7 @@
403 property bool isToggle: true
404 property int selectedIndex: bottomEdge.indexForValue(hdrOptionsModel, settings.hdrEnabled)
405 property bool available: camera.advanced.hasHdr
406- property bool visible: true
407+ property bool visible: camera.captureMode === Camera.CaptureStillImage
408 property bool showInIndicators: true
409
410 ListElement {
411@@ -404,6 +528,41 @@
412 property bool available: true
413 property bool visible: camera.captureMode == Camera.CaptureVideo
414 property bool showInIndicators: false
415+ },
416+ ListModel {
417+ id: shutterSoundOptionsModel
418+
419+ property string settingsProperty: "playShutterSound"
420+ property string icon: ""
421+ property string label: ""
422+ property bool isToggle: true
423+ property int selectedIndex: bottomEdge.indexForValue(shutterSoundOptionsModel, settings.playShutterSound)
424+ property bool available: true
425+ property bool visible: camera.captureMode === Camera.CaptureStillImage
426+ property bool showInIndicators: false
427+
428+ ListElement {
429+ icon: "audio-volume-high"
430+ label: QT_TR_NOOP("On")
431+ value: true
432+ }
433+ ListElement {
434+ icon: "audio-volume-muted"
435+ label: QT_TR_NOOP("Off")
436+ value: false
437+ }
438+ },
439+ ListModel {
440+ id: photoResolutionOptionsModel
441+
442+ property string settingsProperty: "photoResolution" + camera.advanced.activeCameraIndex
443+ property string icon: ""
444+ property string label: sizeToAspectRatio(stringToSize(settings[settingsProperty]))
445+ property bool isToggle: false
446+ property int selectedIndex: bottomEdge.indexForValue(photoResolutionOptionsModel, settings[settingsProperty])
447+ property bool available: true
448+ property bool visible: camera.captureMode == Camera.CaptureStillImage
449+ property bool showInIndicators: false
450 }
451 ]
452
453@@ -571,18 +730,25 @@
454 function completeSwitch() {
455 viewFinderSwitcherAnimation.restart();
456 camera.switchInProgress = false;
457+ zoomControl.value = camera.currentZoom;
458 }
459
460 function changeRecordMode() {
461 if (camera.captureMode == Camera.CaptureVideo) camera.videoRecorder.stop()
462 camera.captureMode = (camera.captureMode == Camera.CaptureVideo) ? Camera.CaptureStillImage : Camera.CaptureVideo
463+ zoomControl.value = camera.currentZoom
464+ }
465+
466+ Connections {
467+ target: Qt.application
468+ onActiveChanged: if (active) zoomControl.value = camera.currentZoom
469 }
470
471 Timer {
472 id: shootingTimer
473 repeat: true
474 triggeredOnStart: true
475-
476+
477 property int remainingSecs: 0
478
479 onTriggered: {
480
481=== modified file 'ViewFinderView.qml'
482--- ViewFinderView.qml 2015-11-16 15:54:25 +0000
483+++ ViewFinderView.qml 2015-11-25 17:47:09 +0000
484@@ -36,6 +36,7 @@
485 Camera {
486 id: camera
487 captureMode: Camera.CaptureStillImage
488+ cameraState: Camera.UnloadedState
489 StateSaver.properties: "captureMode"
490
491 function manualFocus(x, y) {
492@@ -67,10 +68,6 @@
493 StateSaver.properties: "activeCameraIndex"
494 }
495
496- Component.onCompleted: {
497- camera.start();
498- }
499-
500 /* Use only digital zoom for now as it's what phone cameras mostly use.
501 TODO: if optical zoom is available, maximumZoom should be the combined
502 range of optical and digital zoom and currentZoom should adjust the two
503@@ -121,12 +118,14 @@
504 target: Qt.application
505 onActiveChanged: {
506 if (Qt.application.active) {
507- camera.start()
508+ if (camera.cameraState == Camera.LoadedState) {
509+ camera.cameraState = Camera.ActiveState;
510+ }
511 } else if (!application.desktopMode) {
512 if (camera.videoRecorder.recorderState == CameraRecorder.RecordingState) {
513 camera.videoRecorder.stop();
514 }
515- camera.stop()
516+ camera.cameraState = Camera.LoadedState;
517 }
518 }
519 }
520@@ -250,16 +249,16 @@
521 axis.x: 0; axis.y: 1; axis.z: 0
522 angle: application.desktopMode ? 180 : 0
523 }
524-
525- ViewFinderGeometry {
526- id: viewFinderGeometry
527- anchors.centerIn: parent
528-
529- cameraResolution: camera.advanced.resolution
530- viewFinderHeight: viewFinder.height
531- viewFinderWidth: viewFinder.width
532- viewFinderOrientation: viewFinder.orientation
533- }
534+ }
535+
536+ ViewFinderGeometry {
537+ id: viewFinderGeometry
538+ anchors.centerIn: parent
539+
540+ cameraResolution: camera.viewfinder.resolution
541+ viewFinderHeight: viewFinder.height
542+ viewFinderWidth: viewFinder.width
543+ viewFinderOrientation: viewFinder.orientation
544 }
545
546 Item {
547
548=== modified file 'tests/autopilot/camera_app/emulators/main_window.py'
549--- tests/autopilot/camera_app/emulators/main_window.py 2015-11-20 15:01:02 +0000
550+++ tests/autopilot/camera_app/emulators/main_window.py 2015-11-25 17:47:09 +0000
551@@ -7,7 +7,7 @@
552
553 from camera_app.emulators.panel import Panel
554 from autopilot.matchers import Eventually
555-from testtools.matchers import Equals
556+from testtools.matchers import Equals, NotEquals
557
558
559 class MainWindow(object):
560@@ -163,3 +163,22 @@
561 tx, ty, (tx + view_switcher.width // 2), ty, rate=1)
562 viewfinder = self.get_viewfinder()
563 testCase.assertThat(viewfinder.inView, Eventually(Equals(True)))
564+
565+ def switch_cameras(self):
566+ # Swap cameras and wait for camera to settle
567+ shoot_button = self.get_exposure_button()
568+ swap_camera_button = self.get_swap_camera_button()
569+ self.app.pointing_device.move_to_object(swap_camera_button)
570+ self.app.pointing_device.click()
571+ shoot_button.enabled.wait_for(True)
572+
573+ def switch_recording_mode(self):
574+ record_control = self.get_record_control()
575+
576+ # Wait for the camera overlay to be loaded
577+ record_control.enabled.wait_for(True)
578+ record_control.width.wait_for(NotEquals(0))
579+ record_control.height.wait_for(NotEquals(0))
580+
581+ self.app.pointing_device.move_to_object(record_control)
582+ self.app.pointing_device.click()
583
584=== modified file 'tests/autopilot/camera_app/tests/test_capture.py'
585--- tests/autopilot/camera_app/tests/test_capture.py 2015-10-05 13:14:12 +0000
586+++ tests/autopilot/camera_app/tests/test_capture.py 2015-11-25 17:47:09 +0000
587@@ -90,13 +90,11 @@
588
589 """
590 # Get all the elements
591- record_control = self.main_window.get_record_control()
592 stop_watch = self.main_window.get_stop_watch()
593 exposure_button = self.main_window.get_exposure_button()
594
595 # Click the record button to toggle photo/video mode
596- self.pointing_device.move_to_object(record_control)
597- self.pointing_device.click()
598+ self.main_window.switch_recording_mode()
599
600 # Before recording the stop watch should read zero recording time
601 # and not be visible anyway.
602@@ -137,8 +135,7 @@
603 # Now stop the video and go back to picture mode and check if
604 # everything resets itself to previous states
605 self.pointing_device.click()
606- self.pointing_device.move_to_object(record_control)
607- self.pointing_device.click()
608+ self.main_window.switch_recording_mode()
609
610 self.assertThat(stop_watch.opacity, Eventually(Equals(0.0)))
611
612@@ -268,7 +265,7 @@
613 """Test recording videos at a set resolution and switching cameras"""
614 def test_video_resolution_setting_switching_cameras(self):
615 # switch to video recording and empty video folder
616- self.switch_to_video_recording()
617+ self.main_window.switch_recording_mode()
618 self.delete_all_videos()
619
620 # select the first resolution for the current camera
621@@ -277,14 +274,14 @@
622 self.set_video_resolution(initial_resolution)
623
624 # switch cameras and select the last resolution for the current camera
625- self.switch_cameras()
626+ self.main_window.switch_cameras()
627 resolutions = self.get_available_video_resolutions()
628 expected_resolution = resolutions[-1]
629 self.assertThat(expected_resolution, NotEquals(initial_resolution))
630 self.set_video_resolution(expected_resolution)
631
632 # switch back to the initial camera and record a video
633- self.switch_cameras()
634+ self.main_window.switch_cameras()
635 self.record_video(2)
636 video_file = self.get_first_video()
637 height = self.read_video_height(video_file)
638@@ -292,17 +289,9 @@
639 expected_resolution)
640 self.assertThat(height, Equals(expected_height))
641
642- def switch_cameras(self):
643- # Swap cameras and wait for camera to settle
644- shoot_button = self.main_window.get_exposure_button()
645- swap_camera_button = self.main_window.get_swap_camera_button()
646- self.pointing_device.move_to_object(swap_camera_button)
647- self.pointing_device.click()
648- self.assertThat(shoot_button.enabled, Eventually(Equals(True)))
649-
650 """Test recording videos at various resolutions"""
651 def test_video_resolution_setting(self):
652- self.switch_to_video_recording()
653+ self.main_window.switch_recording_mode()
654 resolutions = self.get_available_video_resolutions()
655
656 for resolution_label in resolutions:
657@@ -316,16 +305,6 @@
658 self.assertThat(height, Equals(expected_height))
659 self.dismiss_first_photo_hint()
660
661- def switch_to_video_recording(self):
662- record_control = self.main_window.get_record_control()
663- # Wait for the camera overlay to be loaded
664- self.assertThat(record_control.enabled, Eventually(Equals(True)))
665- self.assertThat(record_control.width, Eventually(NotEquals(0)))
666- self.assertThat(record_control.height, Eventually(NotEquals(0)))
667-
668- self.pointing_device.move_to_object(record_control)
669- self.pointing_device.click()
670-
671 def get_available_video_resolutions(self):
672 # open bottom edge
673 bottom_edge = self.main_window.get_bottom_edge()
674
675=== modified file 'tests/autopilot/camera_app/tests/test_zoom.py'
676--- tests/autopilot/camera_app/tests/test_zoom.py 2015-04-29 15:56:44 +0000
677+++ tests/autopilot/camera_app/tests/test_zoom.py 2015-11-25 17:47:09 +0000
678@@ -68,3 +68,50 @@
679
680 self.pointing_device.drag(tx, ty, (tx - zoom_control.width), ty)
681 self.assertThat(zoom_control.value, Eventually(Equals(1.0)))
682+
683+ """Tests zoom is reset to minimum on camera switch"""
684+ def test_zoom_reset_on_camera_change(self):
685+ zoom_control = self.main_window.get_zoom_control()
686+ zoom_slider = self.main_window.get_zoom_slider()
687+
688+ self.activate_zoom()
689+ x, y, w, h = zoom_slider.globalRect
690+ tx = x + (w // 2)
691+ ty = y + (h // 2)
692+ self.pointing_device.drag(tx, ty, (tx + zoom_control.width), ty)
693+ self.assertThat(
694+ zoom_control.value, Eventually(Equals(zoom_control.maximumValue)))
695+
696+ self.main_window.switch_cameras()
697+ self.assertThat(
698+ zoom_control.value, Eventually(Equals(zoom_control.minimumValue)))
699+
700+ self.activate_zoom()
701+ self.pointing_device.drag(tx, ty, (tx + zoom_control.width), ty)
702+ self.assertThat(
703+ zoom_control.value, Eventually(Equals(zoom_control.maximumValue)))
704+
705+ self.main_window.switch_cameras()
706+ self.assertThat(
707+ zoom_control.value, Eventually(Equals(zoom_control.minimumValue)))
708+
709+ """Tests zoom is reset to minimum on recording mode switch"""
710+ def test_zoom_reset_on_recording_mode_change(self):
711+ zoom_control = self.main_window.get_zoom_control()
712+ zoom_slider = self.main_window.get_zoom_slider()
713+
714+ self.activate_zoom()
715+ x, y, w, h = zoom_slider.globalRect
716+ tx = x + (w // 2)
717+ ty = y + (h // 2)
718+ self.pointing_device.drag(tx, ty, (tx + zoom_control.width), ty)
719+ self.assertThat(
720+ zoom_control.value, Eventually(Equals(zoom_control.maximumValue)))
721+
722+ self.main_window.switch_recording_mode()
723+ self.assertThat(
724+ zoom_control.value, Eventually(Equals(zoom_control.minimumValue)))
725+
726+ # Ideally we should test the same thing when switching back to photo
727+ # mode, however due to http://pad.lv/1191088 zooming when recording
728+ # video is disabled, so adding that test is pointless until fixed.

Subscribers

People subscribed via source and target branches