Updated copyright year
[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 #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   default:
220     qWarning() << "Unknown mode" << mode;
221
222     *ok = false;
223   }
224 }
225
226 void CameraResourcesWorker::acquired(bool *ok) {
227   *ok = m_acquired;
228 }
229
230 void CameraResourcesWorker::hijacked(bool *ok) {
231   *ok = m_hijacked;
232 }
233
234 bool CameraResourcesWorker::updateSet(const QList<ResourcePolicy::ResourceType>& required,
235                                       const QList<ResourcePolicy::ResourceType>& optional) {
236
237
238   QList<ResourcePolicy::ResourceType> set = listSet();
239
240   foreach (ResourcePolicy::ResourceType r, set) {
241     if (required.indexOf(r) != -1) {
242       m_set->resource(r)->setOptional(false);
243     }
244     else if (optional.indexOf(r) != -1) {
245       m_set->resource(r)->setOptional(true);
246     }
247     else {
248       m_set->deleteResource(r);
249     }
250   }
251
252   foreach (ResourcePolicy::ResourceType r, required) {
253     m_set->addResource(r);
254   }
255
256   foreach (ResourcePolicy::ResourceType r, optional) {
257     m_set->addResource(r);
258     ResourcePolicy::Resource *res = m_set->resource(r);
259     if (res) {
260       res->setOptional(true);
261     }
262   }
263
264   if (m_set->contains(ResourcePolicy::AudioPlaybackType)) {
265     bool isOptional = m_set->resource(ResourcePolicy::AudioPlaybackType)->isOptional();
266
267     ResourcePolicy::AudioResource *audio = new ResourcePolicy::AudioResource(APPLICATION_CLASS);
268     audio->setProcessID(QCoreApplication::applicationPid());
269     audio->setOptional(isOptional);
270     m_set->addResourceObject(audio);
271   }
272
273   m_acquiring = true;
274
275   m_set->update();
276   m_set->acquire();
277
278   while (m_acquiring) {
279     QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
280   }
281
282   return m_acquired;
283 }
284
285 bool CameraResourcesWorker::release() {
286   m_acquiring = true;
287
288   m_set->release();
289
290   while (m_acquiring) {
291     QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
292   }
293
294   m_mode = CameraResources::None;
295
296   return true;
297 }
298
299 void CameraResourcesWorker::setAcquired(bool acquired) {
300   if (m_acquired != acquired) {
301     m_acquired = acquired;
302     emit acquiredChanged();
303   }
304 }
305
306 void CameraResourcesWorker::setHijacked(bool hijacked) {
307   if (m_hijacked != hijacked) {
308     m_hijacked = hijacked;
309     emit hijackedChanged();
310   }
311 }
312
313 void CameraResourcesWorker::isResourceGranted(bool *ok, int resource) {
314
315   ResourcePolicy::ResourceType rt = (ResourcePolicy::ResourceType)resource;
316
317   ResourcePolicy::Resource *r = m_set->resource(rt);
318   if (r) {
319     *ok = r->isGranted();
320   }
321 }