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