Volume up and down keys should now work and change zoom
[harmattan/cameraplus] / src / cameraresources.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "cameraresources.h"
22 #include <dbusconnectioneventloop.h>
23 #include <QDebug>
24
25 #define APPLICATION_CLASS "camera"
26
27 CameraResources::CameraResources(QObject *parent) :
28   QObject(parent),
29   m_worker(new CameraResourcesWorker) {
30
31   m_worker->moveToThread(&m_thread);
32   DBUSConnectionEventLoop::getInstance().moveToThread(&m_thread);
33
34   QObject::connect(&m_thread, SIGNAL(started()), m_worker, SLOT(init()));
35   m_thread.start();
36
37   qRegisterMetaType<CameraResources::Mode>("CameraResources::Mode");
38   qRegisterMetaType<bool *>("bool *");
39
40   QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(acquiredChanged()));
41   QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(hijackedChanged()));
42   QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(updated()));
43   QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(scaleAcquisitionChanged()));
44   QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(scaleAcquisitionChanged()));
45   QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(scaleAcquisitionChanged()));
46 }
47
48 CameraResources::~CameraResources() {
49   acquire(CameraResources::None);
50   m_thread.exit(0);
51
52   while (m_thread.isRunning()) {
53     m_thread.wait(10);
54   }
55
56   delete m_worker;
57   m_worker = 0;
58 }
59
60 bool CameraResources::isResourceGranted(const ResourcePolicy::ResourceType& resource) const {
61   bool ok = false;
62
63   QMetaObject::invokeMethod(m_worker, "isResourceGranted", Qt::BlockingQueuedConnection,
64                             Q_ARG(bool *, &ok), Q_ARG(int, resource));
65
66   return ok;
67 }
68
69 bool CameraResources::acquire(const Mode& mode) {
70   bool ok = false;
71
72   QMetaObject::invokeMethod(m_worker, "acquire", Qt::BlockingQueuedConnection,
73                             Q_ARG(bool *, &ok), Q_ARG(CameraResources::Mode, mode));
74
75   return ok;
76 }
77
78 bool CameraResources::acquired() const {
79   bool ok = false;
80
81   QMetaObject::invokeMethod(m_worker, "acquired", Qt::BlockingQueuedConnection,
82                             Q_ARG(bool *, &ok));
83
84   return ok;
85 }
86
87 bool CameraResources::hijacked() const {
88   bool ok = false;
89
90   QMetaObject::invokeMethod(m_worker, "hijacked", Qt::BlockingQueuedConnection,
91                             Q_ARG(bool *, &ok));
92
93   return ok;
94 }
95
96 bool CameraResources::isScaleAcquired() const {
97   return isResourceGranted(ResourcePolicy::ScaleButtonType);
98 }
99
100 CameraResourcesWorker::CameraResourcesWorker(QObject *parent) :
101   QObject(parent),
102   m_set(0),
103   m_mode(CameraResources::None),
104   m_acquired(false),
105   m_acquiring(false),
106   m_hijacked(false) {
107
108 }
109
110 CameraResourcesWorker::~CameraResourcesWorker() {
111
112 }
113
114 void CameraResourcesWorker::init() {
115   m_set = new ResourcePolicy::ResourceSet(APPLICATION_CLASS, this);
116   m_set->setAlwaysReply();
117
118   QObject::connect(m_set, SIGNAL(resourcesReleased()), this, SLOT(resourcesReleased()));
119   QObject::connect(m_set, SIGNAL(lostResources()), this, SLOT(lostResources()));
120   QObject::connect(m_set, SIGNAL(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)),
121                    this, SLOT(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)));
122   QObject::connect(m_set, SIGNAL(resourcesDenied()), this, SLOT(resourcesDenied()));
123
124   if (!m_set->initAndConnect()) {
125     qCritical() << "Failed to connect to resource policy engine";
126   }
127 }
128
129 void CameraResourcesWorker::resourcesReleased() {
130   setHijacked(false);
131   setAcquired(false);
132
133   m_acquiring = false;
134 }
135
136 void CameraResourcesWorker::lostResources() {
137   setAcquired(false);
138   setHijacked(true);
139
140   m_acquiring = false;
141 }
142
143 void CameraResourcesWorker::resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional) {
144   Q_UNUSED(optional);
145
146   if (!m_acquiring) {
147     // This can happen when:
148     // 1) We lose/gain optional resources.
149     // 2) A higher priority application releases resources back.
150     emit updated();
151   }
152
153   m_acquiring = false;
154
155   setAcquired(true);
156   setHijacked(false);
157 }
158
159 void CameraResourcesWorker::resourcesDenied() {
160   setAcquired(false);
161   setHijacked(true);
162
163   m_acquiring = false;
164 }
165
166 QList<ResourcePolicy::ResourceType> CameraResourcesWorker::listSet() {
167   QList<ResourcePolicy::Resource *> resources = m_set->resources();
168
169   QList<ResourcePolicy::ResourceType> set;
170
171   foreach (ResourcePolicy::Resource *r, resources) {
172     set << r->type();
173   }
174
175   return set;
176 }
177
178 void CameraResourcesWorker::acquire(bool *ok, const CameraResources::Mode& mode) {
179   if (mode == m_mode) {
180     *ok = true;
181     return;
182   }
183
184   m_mode = mode;
185
186   *ok = false;
187
188   switch (m_mode) {
189   case CameraResources::None:
190     *ok = release();
191     break;
192
193   case CameraResources::Image:
194     *ok = updateSet(QList<ResourcePolicy::ResourceType>()
195                     << ResourcePolicy::VideoPlaybackType
196                     << ResourcePolicy::VideoRecorderType,
197                     QList<ResourcePolicy::ResourceType>()
198                     << ResourcePolicy::ScaleButtonType);
199     break;
200
201   case CameraResources::Video:
202     *ok = updateSet(QList<ResourcePolicy::ResourceType>()
203                     << ResourcePolicy::VideoPlaybackType
204                     << ResourcePolicy::VideoRecorderType,
205                     QList<ResourcePolicy::ResourceType>()
206                     << ResourcePolicy::ScaleButtonType);
207     break;
208
209   case CameraResources::Recording:
210     *ok = updateSet(QList<ResourcePolicy::ResourceType>()
211                     << ResourcePolicy::VideoPlaybackType
212                     << ResourcePolicy::VideoRecorderType,
213                     QList<ResourcePolicy::ResourceType>()
214                     << ResourcePolicy::ScaleButtonType
215                     << ResourcePolicy::AudioRecorderType
216                     << ResourcePolicy::AudioPlaybackType);
217     break;
218
219   case CameraResources::PostCapture:
220     *ok = updateSet(QList<ResourcePolicy::ResourceType>(),
221                     QList<ResourcePolicy::ResourceType>()
222                     << ResourcePolicy::ScaleButtonType);
223     break;
224
225   default:
226     qWarning() << "Unknown mode" << mode;
227
228     *ok = false;
229   }
230 }
231
232 void CameraResourcesWorker::acquired(bool *ok) {
233   *ok = m_acquired;
234 }
235
236 void CameraResourcesWorker::hijacked(bool *ok) {
237   *ok = m_hijacked;
238 }
239
240 bool CameraResourcesWorker::updateSet(const QList<ResourcePolicy::ResourceType>& required,
241                                       const QList<ResourcePolicy::ResourceType>& optional) {
242
243
244   QList<ResourcePolicy::ResourceType> set = listSet();
245
246   foreach (ResourcePolicy::ResourceType r, set) {
247     if (required.indexOf(r) != -1) {
248       m_set->resource(r)->setOptional(false);
249     }
250     else if (optional.indexOf(r) != -1) {
251       m_set->resource(r)->setOptional(true);
252     }
253     else {
254       m_set->deleteResource(r);
255     }
256   }
257
258   foreach (ResourcePolicy::ResourceType r, required) {
259     m_set->addResource(r);
260   }
261
262   foreach (ResourcePolicy::ResourceType r, optional) {
263     m_set->addResource(r);
264     ResourcePolicy::Resource *res = m_set->resource(r);
265     if (res) {
266       res->setOptional(true);
267     }
268   }
269
270   if (m_set->contains(ResourcePolicy::AudioPlaybackType)) {
271     bool isOptional = m_set->resource(ResourcePolicy::AudioPlaybackType)->isOptional();
272
273     ResourcePolicy::AudioResource *audio = new ResourcePolicy::AudioResource(APPLICATION_CLASS);
274     audio->setProcessID(QCoreApplication::applicationPid());
275     audio->setOptional(isOptional);
276     m_set->addResourceObject(audio);
277   }
278
279   m_acquiring = true;
280
281   m_set->update();
282   m_set->acquire();
283
284   while (m_acquiring) {
285     QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
286   }
287
288   return m_acquired;
289 }
290
291 bool CameraResourcesWorker::release() {
292   m_acquiring = true;
293
294   m_set->release();
295
296   while (m_acquiring) {
297     QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
298   }
299
300   m_mode = CameraResources::None;
301
302   return true;
303 }
304
305 void CameraResourcesWorker::setAcquired(bool acquired) {
306   if (m_acquired != acquired) {
307     m_acquired = acquired;
308     emit acquiredChanged();
309   }
310 }
311
312 void CameraResourcesWorker::setHijacked(bool hijacked) {
313   if (m_hijacked != hijacked) {
314     m_hijacked = hijacked;
315     emit hijackedChanged();
316   }
317 }
318
319 void CameraResourcesWorker::isResourceGranted(bool *ok, int resource) {
320
321   ResourcePolicy::ResourceType rt = (ResourcePolicy::ResourceType)resource;
322
323   ResourcePolicy::Resource *r = m_set->resource(rt);
324   if (r) {
325     *ok = r->isGranted();
326   }
327 }