Reworked CameraResources to be synchronous.
[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 CameraResources::CameraResources(QObject *parent) :
26   QObject(parent),
27   m_worker(new CameraResourcesWorker) {
28
29   m_worker->moveToThread(&m_thread);
30   DBUSConnectionEventLoop::getInstance().moveToThread(&m_thread);
31
32   QObject::connect(&m_thread, SIGNAL(started()), m_worker, SLOT(init()));
33   m_thread.start();
34
35   qRegisterMetaType<CameraResources::Mode>("CameraResources::Mode");
36   qRegisterMetaType<CameraResources::ResourceType>("CameraResources::ResourceType");
37   qRegisterMetaType<bool *>("bool *");
38
39   QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(acquiredChanged()));
40   QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(hijackedChanged()));
41 }
42
43 CameraResources::~CameraResources() {
44   m_thread.quit();
45   m_thread.wait();
46
47   delete m_worker;
48   m_worker = 0;
49 }
50
51 bool CameraResources::isResourceGranted(const ResourceType& resource) {
52   bool ok = false;
53
54   QMetaObject::invokeMethod(m_worker, "isResourceGranted", Qt::BlockingQueuedConnection,
55                             Q_ARG(bool *, &ok), Q_ARG(CameraResources::ResourceType, resource));
56
57   return ok;
58 }
59
60 bool CameraResources::acquire(const Mode& mode) {
61   bool ok = false;
62
63   QMetaObject::invokeMethod(m_worker, "acquire", Qt::BlockingQueuedConnection,
64                             Q_ARG(bool *, &ok), Q_ARG(CameraResources::Mode, mode));
65
66   return ok;
67 }
68
69 bool CameraResources::acquired() const {
70   bool ok = false;
71
72   QMetaObject::invokeMethod(m_worker, "acquired", Qt::BlockingQueuedConnection,
73                             Q_ARG(bool *, &ok));
74
75   return ok;
76 }
77
78 bool CameraResources::hijacked() const {
79   bool ok = false;
80
81   QMetaObject::invokeMethod(m_worker, "hijacked", Qt::BlockingQueuedConnection,
82                             Q_ARG(bool *, &ok));
83
84   return ok;
85 }
86
87 CameraResourcesWorker::CameraResourcesWorker(QObject *parent) :
88   QObject(parent),
89   m_set(0),
90   m_mode(CameraResources::None),
91   m_acquired(false),
92   m_acquiring(false),
93   m_hijacked(false) {
94
95 }
96
97 CameraResourcesWorker::~CameraResourcesWorker() {
98   bool ok;
99
100   acquire(&ok, CameraResources::None);
101 }
102
103 void CameraResourcesWorker::init() {
104   m_set = new ResourcePolicy::ResourceSet("camera", this);
105   m_set->setAlwaysReply();
106
107   QObject::connect(m_set, SIGNAL(resourcesReleased()), this, SLOT(resourcesReleased()));
108   QObject::connect(m_set, SIGNAL(lostResources()), this, SLOT(lostResources()));
109   QObject::connect(m_set, SIGNAL(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)),
110                    this, SLOT(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)));
111   QObject::connect(m_set, SIGNAL(resourcesDenied()), this, SLOT(resourcesDenied()));
112
113   if (!m_set->initAndConnect()) {
114     qCritical() << "Failed to connect to resource policy engine";
115   }
116 }
117
118 void CameraResourcesWorker::resourcesReleased() {
119   setHijacked(false);
120   setAcquired(false);
121
122   m_acquiring = false;
123 }
124
125 void CameraResourcesWorker::lostResources() {
126   setAcquired(false);
127   setHijacked(true);
128
129   m_acquiring = false;
130 }
131
132 void CameraResourcesWorker::resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional) {
133   Q_UNUSED(optional);
134
135   m_acquiring = false;
136
137   setAcquired(true);
138   setHijacked(false);
139 }
140
141 void CameraResourcesWorker::resourcesDenied() {
142   setAcquired(false);
143   setHijacked(true);
144
145   m_acquiring = false;
146 }
147
148 QList<ResourcePolicy::ResourceType> CameraResourcesWorker::listSet() {
149   QList<ResourcePolicy::Resource *> resources = m_set->resources();
150
151   QList<ResourcePolicy::ResourceType> set;
152
153   foreach (ResourcePolicy::Resource *r, resources) {
154     set << r->type();
155   }
156
157   return set;
158 }
159
160 void CameraResourcesWorker::acquire(bool *ok, const CameraResources::Mode& mode) {
161   if (mode == m_mode) {
162     *ok = true;
163     return;
164   }
165
166   m_mode = mode;
167
168   *ok = false;
169
170   switch (m_mode) {
171   case CameraResources::None:
172     *ok = release();
173     break;
174
175   case CameraResources::Image:
176     *ok = updateSet(QList<ResourcePolicy::ResourceType>()
177                     << ResourcePolicy::VideoPlaybackType
178                     << ResourcePolicy::VideoRecorderType
179                     << ResourcePolicy::ScaleButtonType
180                     << ResourcePolicy::SnapButtonType);
181     break;
182
183   case CameraResources::Video:
184     *ok = updateSet(QList<ResourcePolicy::ResourceType>()
185                     << ResourcePolicy::VideoPlaybackType
186                     << ResourcePolicy::VideoRecorderType
187                     << ResourcePolicy::ScaleButtonType
188                     << ResourcePolicy::SnapButtonType);
189     break;
190
191   case CameraResources::Recording:
192     *ok = updateSet(QList<ResourcePolicy::ResourceType>()
193                     << ResourcePolicy::VideoPlaybackType
194                     << ResourcePolicy::VideoRecorderType
195                     << ResourcePolicy::ScaleButtonType
196                     << ResourcePolicy::SnapButtonType,
197                     QList<ResourcePolicy::ResourceType>()
198                     << ResourcePolicy::AudioRecorderType
199                     << ResourcePolicy::AudioPlaybackType);
200     break;
201
202   case CameraResources::PostCapture:
203     *ok = updateSet(QList<ResourcePolicy::ResourceType>()
204                     << ResourcePolicy::VideoPlaybackType
205                     << ResourcePolicy::ScaleButtonType,
206                     QList<ResourcePolicy::ResourceType>()
207                     << ResourcePolicy::AudioPlaybackType);
208     break;
209
210   default:
211     qWarning() << "Unknown mode" << mode;
212
213     *ok = false;
214   }
215 }
216
217 void CameraResourcesWorker::acquired(bool *ok) {
218   *ok = m_acquired;
219 }
220
221 void CameraResourcesWorker::hijacked(bool *ok) {
222   *ok = m_hijacked;
223 }
224
225 bool CameraResourcesWorker::updateSet(const QList<ResourcePolicy::ResourceType>& required,
226                                       const QList<ResourcePolicy::ResourceType>& optional) {
227
228
229   QList<ResourcePolicy::ResourceType> set = listSet();
230
231   foreach (ResourcePolicy::ResourceType r, set) {
232     if (required.indexOf(r) != -1) {
233       m_set->resource(r)->setOptional(false);
234     }
235     else if (optional.indexOf(r) != -1) {
236       m_set->resource(r)->setOptional(true);
237     }
238     else {
239       m_set->deleteResource(r);
240     }
241   }
242
243   foreach (ResourcePolicy::ResourceType r, required) {
244     m_set->addResource(r);
245   }
246
247   foreach (ResourcePolicy::ResourceType r, optional) {
248     m_set->addResource(r);
249     ResourcePolicy::Resource *res = m_set->resource(r);
250     if (res) {
251       res->setOptional(true);
252     }
253   }
254
255   if (m_set->contains(ResourcePolicy::AudioPlaybackType)) {
256     bool isOptional = m_set->resource(ResourcePolicy::AudioPlaybackType)->isOptional();
257
258     ResourcePolicy::AudioResource *audio = new ResourcePolicy::AudioResource("camera");
259     audio->setProcessID(QCoreApplication::applicationPid());
260     audio->setOptional(isOptional);
261     m_set->addResourceObject(audio);
262   }
263
264   m_acquiring = true;
265
266   m_set->update();
267   m_set->acquire();
268
269   while (m_acquiring) {
270     QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
271   }
272
273   return m_acquired;
274 }
275
276 bool CameraResourcesWorker::release() {
277   m_acquiring = true;
278
279   m_set->release();
280
281   while (m_acquiring) {
282     QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
283   }
284
285   m_mode = CameraResources::None;
286
287   return true;
288 }
289
290 void CameraResourcesWorker::setAcquired(bool acquired) {
291   if (m_acquired != acquired) {
292     m_acquired = acquired;
293     emit acquiredChanged();
294   }
295 }
296
297 void CameraResourcesWorker::setHijacked(bool hijacked) {
298   if (m_hijacked != hijacked) {
299     m_hijacked = hijacked;
300     emit hijackedChanged();
301   }
302 }
303
304 void CameraResourcesWorker::isResourceGranted(bool *ok,
305                                               const CameraResources::ResourceType& resource) {
306
307   ResourcePolicy::ResourceType rt = (ResourcePolicy::ResourceType)resource;
308
309   ResourcePolicy::Resource *r = m_set->resource(rt);
310   if (r) {
311     *ok = r->isGranted();
312   }
313 }