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