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