~rsalveti/telepathy-ofono/improve_pa_event_handling

6 by Tiago Salem Herrmann
add copyright headers
1
/**
19 by Tiago Salem Herrmann
fix copyright year
2
 * Copyright (C) 2013 Canonical, Ltd.
6 by Tiago Salem Herrmann
add copyright headers
3
 *
24.1.2 by Ricardo Salveti de Araujo
* Packaging cleanup
4
 * This program is free software: you can redistribute it and/or modify it under
5
 * the terms of the GNU Lesser General Public License version 3, as published by
6
 * the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10
 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 * Lesser General Public License for more details.
12
 *
13
 * You should have received a copy of the GNU Lesser General Public License
6 by Tiago Salem Herrmann
add copyright headers
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24.1.2 by Ricardo Salveti de Araujo
* Packaging cleanup
15
 *
16
 * Authors: Tiago Salem Herrmann <tiago.herrmann@canonical.com>
6 by Tiago Salem Herrmann
add copyright headers
17
 */
18
1 by Tiago Salem Herrmann
initial commit
19
#include <QDebug>
20
21
#include <TelepathyQt/Constants>
22
#include <TelepathyQt/BaseChannel>
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
23
#include <TelepathyQt/DBusObject>
1 by Tiago Salem Herrmann
initial commit
24
25
// ofono-qt
26
#include <ofonomodem.h>
27
28
// telepathy-ofono
29
#include "connection.h"
51.1.3 by Tiago Salem Herrmann
add PhoneUtils class
30
#include "phoneutils_p.h"
1 by Tiago Salem Herrmann
initial commit
31
#include "protocol.h"
32
34.2.1 by Tiago Salem Herrmann
add initial mms support
33
#include "mmsdmessage.h"
34
#include "mmsdservice.h"
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
35
// audioflinger
36
#ifdef USE_AUDIOFLINGER
37
#include <waudio.h>
38
#endif
39
38.1.1 by David Henningsson
Add PulseAudio backend
40
#ifdef USE_PULSEAUDIO
41
#include "qpulseaudioengine.h"
42
#endif
43
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
44
static void enable_earpiece()
45
{
46
#ifdef USE_AUDIOFLINGER
47
    char parameter[20];
48
    int i;
49
    /* Set the call mode in AudioFlinger */
50
    AudioSystem_setMode(AUDIO_MODE_IN_CALL);
51
    sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_EARPIECE);
52
    /* Try the first 3 threads, as this is not fixed and there's no easy
53
     * way to retrieve the default thread/output from Android */
54
    for (i = 1; i <= 3; i++) {
55
        if (AudioSystem_setParameters(i, parameter) >= 0)
56
            break;
57
    }
58
#endif
38.1.1 by David Henningsson
Add PulseAudio backend
59
#ifdef USE_PULSEAUDIO
60
    QPulseAudioEngine::instance()->setCallMode(true, false);
61
#endif
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
62
}
63
64
static void enable_normal()
65
{
66
#ifdef USE_AUDIOFLINGER
67
    char parameter[20];
68
    int i;
69
    /* Set normal mode in AudioFlinger */
70
    AudioSystem_setMode(AUDIO_MODE_NORMAL);
71
    /* Get device back to speaker mode, as by default in_call
72
     * mode sets up device out to earpiece */
73
    sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_SPEAKER);
74
    /* Try the first 3 threads, as this is not fixed and there's no easy
75
     * way to retrieve the default thread/output from Android */
76
    for (i = 1; i <= 3; i++) {
77
        if (AudioSystem_setParameters(i, parameter) >= 0)
78
            break;
79
    }
80
#endif
38.1.1 by David Henningsson
Add PulseAudio backend
81
#ifdef USE_PULSEAUDIO
82
    QPulseAudioEngine::instance()->setCallMode(false, false);
46.3.1 by Tiago Salem Herrmann
unmute when disconnected
83
    QPulseAudioEngine::instance()->setMicMute(false);
38.1.1 by David Henningsson
Add PulseAudio backend
84
#endif
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
85
}
86
87
static void enable_speaker()
88
{
89
#ifdef USE_AUDIOFLINGER
90
    char parameter[20];
91
    int i;
92
    /* Set the call mode in AudioFlinger */
93
    AudioSystem_setMode(AUDIO_MODE_IN_CALL);
94
    sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_SPEAKER);
95
    /* Try the first 3 threads, as this is not fixed and there's no easy
96
     * way to retrieve the default thread/output from Android */
97
    for (i = 1; i <= 3; i++) {
98
        if (AudioSystem_setParameters(i, parameter) >= 0)
99
            break;
100
    }
101
#endif
38.1.1 by David Henningsson
Add PulseAudio backend
102
#ifdef USE_PULSEAUDIO
103
    QPulseAudioEngine::instance()->setCallMode(true, true);
104
#endif
105
}
106
107
static void enable_ringtone()
108
{
109
#ifdef USE_AUDIOFLINGER
110
    char parameter[20];
111
    int i;
112
    /* Set the call mode in AudioFlinger */
113
    AudioSystem_setMode(AUDIO_MODE_IN_CALL);
114
    sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_SPEAKER);
115
    /* Try the first 3 threads, as this is not fixed and there's no easy
116
     * way to retrieve the default thread/output from Android */
117
    for (i = 1; i <= 3; i++) {
118
        if (AudioSystem_setParameters(i, parameter) >= 0)
119
            break;
120
    }
121
#endif
122
#ifdef USE_PULSEAUDIO
123
    QPulseAudioEngine::instance()->setCallMode(false, true);
124
#endif
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
125
}
34.2.1 by Tiago Salem Herrmann
add initial mms support
126
7 by Tiago Salem Herrmann
add online presence support
127
// miliseconds
128
#define OFONO_REGISTER_RETRY_TIME 5000
129
1 by Tiago Salem Herrmann
initial commit
130
oFonoConnection::oFonoConnection(const QDBusConnection &dbusConnection,
131
                            const QString &cmName,
132
                            const QString &protocolName,
133
                            const QVariantMap &parameters) :
134
    Tp::BaseConnection(dbusConnection, cmName, protocolName, parameters),
135
    mOfonoModemManager(new OfonoModemManager(this)),
136
    mOfonoMessageManager(new OfonoMessageManager(OfonoModem::AutomaticSelect,"")),
137
    mOfonoVoiceCallManager(new OfonoVoiceCallManager(OfonoModem::AutomaticSelect,"")),
2 by Tiago Salem Herrmann
- add call channel support
138
    mOfonoCallVolume(new OfonoCallVolume(OfonoModem::AutomaticSelect,"")),
7 by Tiago Salem Herrmann
add online presence support
139
    mOfonoNetworkRegistration(new OfonoNetworkRegistration(OfonoModem::AutomaticSelect, "")),
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
140
    mOfonoMessageWaiting(new OfonoMessageWaiting(OfonoModem::AutomaticSelect, "")),
7 by Tiago Salem Herrmann
add online presence support
141
    mHandleCount(0),
34.2.1 by Tiago Salem Herrmann
add initial mms support
142
    mRegisterTimer(new QTimer(this)),
34.2.3 by Tiago Salem Herrmann
merge trunk
143
    mMmsdManager(new MMSDManager(this)),
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
144
    mSpeakerMode(false)
1 by Tiago Salem Herrmann
initial commit
145
{
146
    setSelfHandle(newHandle("<SelfHandle>"));
147
148
    setConnectCallback(Tp::memFun(this,&oFonoConnection::connect));
149
    setInspectHandlesCallback(Tp::memFun(this,&oFonoConnection::inspectHandles));
150
    setRequestHandlesCallback(Tp::memFun(this,&oFonoConnection::requestHandles));
151
    setCreateChannelCallback(Tp::memFun(this,&oFonoConnection::createChannel));
152
5 by Tiago Salem Herrmann
- rename some methods
153
    // initialise requests interface (Connection.Interface.Requests)
1 by Tiago Salem Herrmann
initial commit
154
    requestsIface = Tp::BaseConnectionRequestsInterface::create(this);
5 by Tiago Salem Herrmann
- rename some methods
155
156
    // set requestable text channel properties
1 by Tiago Salem Herrmann
initial commit
157
    Tp::RequestableChannelClass text;
158
    text.fixedProperties[TP_QT_IFACE_CHANNEL+".ChannelType"] = TP_QT_IFACE_CHANNEL_TYPE_TEXT;
159
    text.fixedProperties[TP_QT_IFACE_CHANNEL+".TargetHandleType"]  = Tp::HandleTypeContact;
160
    text.allowedProperties.append(TP_QT_IFACE_CHANNEL+".TargetHandle");
161
    text.allowedProperties.append(TP_QT_IFACE_CHANNEL+".TargetID");
162
5 by Tiago Salem Herrmann
- rename some methods
163
    // set requestable call channel properties
1 by Tiago Salem Herrmann
initial commit
164
    Tp::RequestableChannelClass call;
165
    call.fixedProperties[TP_QT_IFACE_CHANNEL+".ChannelType"] = TP_QT_IFACE_CHANNEL_TYPE_CALL;
166
    call.fixedProperties[TP_QT_IFACE_CHANNEL+".TargetHandleType"]  = Tp::HandleTypeContact;
2 by Tiago Salem Herrmann
- add call channel support
167
    call.fixedProperties[TP_QT_IFACE_CHANNEL_TYPE_CALL+".InitialAudio"]  = true;
1 by Tiago Salem Herrmann
initial commit
168
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL+".TargetHandle");
169
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL+".TargetID");
2 by Tiago Salem Herrmann
- add call channel support
170
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL+".InitialAudio");
171
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL+".InitialVideo");
172
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL+".InitialAudioName");
173
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL+".InitialVideoName");
174
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL+".InitialTransport");
175
    call.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL+".HardwareStreaming");
1 by Tiago Salem Herrmann
initial commit
176
177
    requestsIface->requestableChannelClasses << text << call;
178
179
    plugInterface(Tp::AbstractConnectionInterfacePtr::dynamicCast(requestsIface));
180
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
181
    // init presence interface
7 by Tiago Salem Herrmann
add online presence support
182
    simplePresenceIface = Tp::BaseConnectionSimplePresenceInterface::create();
183
    simplePresenceIface->setSetPresenceCallback(Tp::memFun(this,&oFonoConnection::setPresence));
184
    plugInterface(Tp::AbstractConnectionInterfacePtr::dynamicCast(simplePresenceIface));
185
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
186
    // init custom voicemail interface (not provided by telepathy)
187
    voicemailIface = BaseConnectionVoicemailInterface::create();
188
    voicemailIface->setVoicemailCountCallback(Tp::memFun(this,&oFonoConnection::voicemailCount));
189
    voicemailIface->setVoicemailIndicatorCallback(Tp::memFun(this,&oFonoConnection::voicemailIndicator));
190
    voicemailIface->setVoicemailNumberCallback(Tp::memFun(this,&oFonoConnection::voicemailNumber));
191
    plugInterface(Tp::AbstractConnectionInterfacePtr::dynamicCast(voicemailIface));
192
7 by Tiago Salem Herrmann
add online presence support
193
    // Set Presence
194
    Tp::SimpleStatusSpec presenceOnline;
195
    presenceOnline.type = Tp::ConnectionPresenceTypeAvailable;
196
    presenceOnline.maySetOnSelf = true;
197
    presenceOnline.canHaveMessage = false;
198
199
    Tp::SimpleStatusSpec presenceOffline;
200
    presenceOffline.type = Tp::ConnectionPresenceTypeOffline;
201
    presenceOffline.maySetOnSelf = false;
202
    presenceOffline.canHaveMessage = false;
203
204
    Tp::SimpleStatusSpecMap statuses;
205
    statuses.insert(QLatin1String("available"), presenceOnline);
206
    statuses.insert(QLatin1String("offline"), presenceOffline);
207
208
    simplePresenceIface->setStatuses(statuses);
209
    mSelfPresence.type = Tp::ConnectionPresenceTypeOffline;
210
    mRequestedSelfPresence.type = Tp::ConnectionPresenceTypeOffline;
211
212
    bool validModem = false;
213
    if (mOfonoVoiceCallManager->modem()) {
214
        validModem = mOfonoVoiceCallManager->modem()->isValid();
215
        if (validModem) {
216
            QObject::connect(mOfonoVoiceCallManager->modem(), SIGNAL(onlineChanged(bool)), SLOT(onValidityChanged(bool)));
217
        }
218
    }
219
    // force update current presence
220
    onOfonoNetworkRegistrationChanged(mOfonoNetworkRegistration->status());
221
222
    contactsIface = Tp::BaseConnectionContactsInterface::create();
223
    contactsIface->setGetContactAttributesCallback(Tp::memFun(this,&oFonoConnection::getContactAttributes));
224
    contactsIface->setContactAttributeInterfaces(QStringList()
225
                                                 << TP_QT_IFACE_CONNECTION
226
                                                 << TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE);
227
    plugInterface(Tp::AbstractConnectionInterfacePtr::dynamicCast(contactsIface));
228
5 by Tiago Salem Herrmann
- rename some methods
229
    QObject::connect(mOfonoMessageManager, SIGNAL(incomingMessage(QString,QVariantMap)), this, SLOT(onOfonoIncomingMessage(QString,QVariantMap)));
230
    QObject::connect(mOfonoVoiceCallManager, SIGNAL(callAdded(QString,QVariantMap)), SLOT(onOfonoCallAdded(QString, QVariantMap)));
7 by Tiago Salem Herrmann
add online presence support
231
    QObject::connect(mOfonoVoiceCallManager, SIGNAL(validityChanged(bool)), SLOT(onValidityChanged(bool)));
232
    QObject::connect(mOfonoNetworkRegistration, SIGNAL(statusChanged(QString)), SLOT(onOfonoNetworkRegistrationChanged(QString)));
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
233
    QObject::connect(mOfonoMessageWaiting, SIGNAL(voicemailMessageCountChanged(int)), voicemailIface.data(), SLOT(setVoicemailCount(int)));
234
    QObject::connect(mOfonoMessageWaiting, SIGNAL(voicemailWaitingChanged(bool)), voicemailIface.data(), SLOT(setVoicemailIndicator(bool)));
7 by Tiago Salem Herrmann
add online presence support
235
236
    QObject::connect(mRegisterTimer, SIGNAL(timeout()), SLOT(onTryRegister()));
34.2.1 by Tiago Salem Herrmann
add initial mms support
237
238
    QObject::connect(mMmsdManager, SIGNAL(serviceAdded(const QString&)), SLOT(onMMSDServiceAdded(const QString&)));
239
    QObject::connect(mMmsdManager, SIGNAL(serviceRemoved(const QString&)), SLOT(onMMSDServiceRemoved(const QString&)));
240
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
241
    // update audio route
242
    QObject::connect(mOfonoVoiceCallManager, SIGNAL(callAdded(QString,QVariantMap)), SLOT(updateAudioRoute()));
243
    QObject::connect(mOfonoVoiceCallManager, SIGNAL(callRemoved(QString)), SLOT(updateAudioRoute()));
34.2.3 by Tiago Salem Herrmann
merge trunk
244
34.2.4 by Tiago Salem Herrmann
fix comment
245
    // workaround: we can't add services here as tp-ofono interfaces are not exposed on dbus
246
    // todo: use QDBusServiceWatcher
34.2.1 by Tiago Salem Herrmann
add initial mms support
247
    QTimer::singleShot(1000, this, SLOT(onCheckMMSServices()));
248
}
249
250
void oFonoConnection::onCheckMMSServices()
251
{
252
    Q_FOREACH(QString servicePath, mMmsdManager->services()) {
253
        onMMSDServiceAdded(servicePath);
254
    }
255
}
256
257
void oFonoConnection::onMMSDServiceAdded(const QString &path)
258
{
259
    qDebug() << "oFonoConnection::onMMSServiceAdded" << path;
260
    MMSDService *service = new MMSDService(path, this);
261
    mMmsdServices[path] = service;
262
    QObject::connect(service, SIGNAL(messageAdded(const QString&, const QVariantMap&)), SLOT(onMMSAdded(const QString&, const QVariantMap&)));
263
    QObject::connect(service, SIGNAL(messageRemoved(const QString&)), SLOT(onMMSRemoved(const QString&)));
264
    Q_FOREACH(MessageStruct message, service->messages()) {
34.2.5 by Tiago Salem Herrmann
rename addMMStoService to addMMSToService
265
        addMMSToService(message.path.path(), message.properties, service->path());
34.2.1 by Tiago Salem Herrmann
add initial mms support
266
    }
267
}
268
269
void oFonoConnection::onMMSPropertyChanged(QString property, QVariant value)
270
{
271
    qDebug() << "oFonoConnection::onMMSPropertyChanged" << property << value;
272
    if (property == "Status") {
273
        if (value == "sent") {
34.2.5 by Tiago Salem Herrmann
rename addMMStoService to addMMSToService
274
            // FIXME send delivery report
34.2.1 by Tiago Salem Herrmann
add initial mms support
275
        }
276
    }
277
}
278
279
void oFonoConnection::onMMSDServiceRemoved(const QString &path)
280
{
281
    MMSDService *service = mMmsdServices.take(path);
282
    if (!service) {
34.2.7 by Tiago Salem Herrmann
use qWarning to report errors
283
        qWarning() << "oFonoConnection::onMMSServiceRemoved failed" << path;
34.2.1 by Tiago Salem Herrmann
add initial mms support
284
        return;
285
    }
286
287
    // remove all messages from this service
288
    Q_FOREACH(MMSDMessage *message, mServiceMMSList[service->path()]) {
289
        qDebug() << "removing message " <<  message->path() << " from service " << service->path();
290
        message->deleteLater();
291
        mServiceMMSList[service->path()].removeAll(message);
292
    }
293
    mServiceMMSList.remove(service->path());
294
    service->deleteLater();
295
    qDebug() << "oFonoConnection::onMMSServiceRemoved" << path;
296
}
297
34.2.5 by Tiago Salem Herrmann
rename addMMStoService to addMMSToService
298
void oFonoConnection::addMMSToService(const QString &path, const QVariantMap &properties, const QString &servicePath)
34.2.1 by Tiago Salem Herrmann
add initial mms support
299
{
34.2.5 by Tiago Salem Herrmann
rename addMMStoService to addMMSToService
300
    qDebug() << "addMMSToService " << path << properties << servicePath;
34.2.1 by Tiago Salem Herrmann
add initial mms support
301
    MMSDMessage *msg = new MMSDMessage(path, properties);
302
    QObject::connect(msg, SIGNAL(propertyChanged(QString,QVariant)), SLOT(onMMSPropertyChanged(QString,QVariant)));
303
    mServiceMMSList[servicePath].append(msg);
304
    if (properties["Status"] ==  "received") {
51.1.3 by Tiago Salem Herrmann
add PhoneUtils class
305
        const QString normalizedNumber = PhoneUtils::normalizePhoneNumber(properties["Sender"].toString());
34.2.1 by Tiago Salem Herrmann
add initial mms support
306
        // check if there is an open channel for this number and use it
307
        Q_FOREACH(const QString &phoneNumber, mTextChannels.keys()) {
51.1.4 by Tiago Salem Herrmann
revert back to comparePhoneNumbers()
308
            if (PhoneUtils::comparePhoneNumbers(normalizedNumber, phoneNumber)) {
34.2.1 by Tiago Salem Herrmann
add initial mms support
309
                qDebug() << "existing channel" << mTextChannels[phoneNumber];
310
                mTextChannels[phoneNumber]->mmsReceived(path, properties);
311
                return;
312
            }
313
        }
314
315
        Tp::DBusError error;
316
        bool yours;
317
        qDebug() << "new handle" << normalizedNumber;
318
        uint handle = newHandle(normalizedNumber);
319
        ensureChannel(TP_QT_IFACE_CHANNEL_TYPE_TEXT,Tp::HandleTypeContact, handle, yours, handle, false, &error);
320
        if(error.isValid()) {
34.2.6 by Tiago Salem Herrmann
change qDebugs to qCritical
321
            qCritical() << "Error creating channel for incoming message " << error.name() << error.message();
34.2.1 by Tiago Salem Herrmann
add initial mms support
322
            return;
323
        }
324
        mTextChannels[normalizedNumber]->mmsReceived(path, properties);
325
    }
326
}
327
328
void oFonoConnection::onMMSAdded(const QString &path, const QVariantMap &properties)
329
{
330
    qDebug() << "oFonoConnection::onMMSAdded" << path << properties;
331
    MMSDService *service = qobject_cast<MMSDService*>(sender());
332
    if (!service) {
34.2.7 by Tiago Salem Herrmann
use qWarning to report errors
333
        qWarning() << "oFonoConnection::onMMSAdded failed";
34.2.1 by Tiago Salem Herrmann
add initial mms support
334
        return;
335
    }
336
34.2.5 by Tiago Salem Herrmann
rename addMMStoService to addMMSToService
337
    addMMSToService(path, properties, service->path());
34.2.1 by Tiago Salem Herrmann
add initial mms support
338
}
339
340
void oFonoConnection::onMMSRemoved(const QString &path)
341
{
342
    qDebug() << "oFonoConnection::onMMSRemoved" << path;
343
    MMSDService *service = qobject_cast<MMSDService*>(sender());
344
    if (!service) {
34.2.7 by Tiago Salem Herrmann
use qWarning to report errors
345
        qWarning() << "oFonoConnection::onMMSRemoved failed";
34.2.1 by Tiago Salem Herrmann
add initial mms support
346
        return;
347
    }
348
349
    // remove this message from the service
350
    Q_FOREACH(MMSDMessage *message, mServiceMMSList[service->path()]) {
351
        if (message->path() == path) {
352
            message->deleteLater();
353
            mServiceMMSList[service->path()].removeAll(message);
354
            break;
355
        }
356
    }
7 by Tiago Salem Herrmann
add online presence support
357
}
358
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
359
oFonoConnection::~oFonoConnection() {
360
    mOfonoModemManager->deleteLater();
361
    mOfonoMessageManager->deleteLater();
362
    mOfonoVoiceCallManager->deleteLater();
363
    mOfonoCallVolume->deleteLater();
364
    mOfonoNetworkRegistration->deleteLater();
365
    mRegisterTimer->deleteLater();
34.2.1 by Tiago Salem Herrmann
add initial mms support
366
    Q_FOREACH(MMSDService *service, mMmsdServices) {
367
        onMMSDServiceRemoved(service->path());
368
    }
369
   
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
370
}
371
7 by Tiago Salem Herrmann
add online presence support
372
void oFonoConnection::onTryRegister()
373
{
374
    bool networkRegistered = isNetworkRegistered();
375
    if (networkRegistered) {
376
        setOnline(networkRegistered);
377
        mRegisterTimer->stop();
378
        return;
379
    }
380
381
    // if we have modem, check if it is online
382
    OfonoModem *modem = mOfonoNetworkRegistration->modem();
383
    if (modem) {
384
        if (!modem->online()) {
385
            modem->setOnline(true);
386
        }
387
    }
388
}
389
390
bool oFonoConnection::isNetworkRegistered()
391
{
392
    QString status = mOfonoNetworkRegistration->status();
393
    return  !(!mOfonoNetworkRegistration->modem() ||
394
              !mOfonoNetworkRegistration->modem()->online() ||
395
              status == "unregistered" ||
396
              status == "denied" ||
397
              status == "unknown" ||
398
              status == "searching" ||
399
              status.isEmpty());
400
}
401
402
void oFonoConnection::onOfonoNetworkRegistrationChanged(const QString &status)
403
{
404
    qDebug() << "onOfonoNetworkRegistrationChanged" << status << "is network registered: " << isNetworkRegistered();
405
    if (!isNetworkRegistered() && mRequestedSelfPresence.type == Tp::ConnectionPresenceTypeAvailable) {
406
        setOnline(false);
407
        onTryRegister();
408
        mRegisterTimer->setInterval(OFONO_REGISTER_RETRY_TIME);
409
        mRegisterTimer->start();
410
        return;
411
    }
412
    setOnline(isNetworkRegistered());
413
}
414
415
uint oFonoConnection::setPresence(const QString& status, const QString& statusMessage, Tp::DBusError *error)
416
{
417
    qDebug() << "setPresence" << status;
418
    if (status == "available") {
419
        mRequestedSelfPresence.type = Tp::ConnectionPresenceTypeAvailable;
420
        if (!isNetworkRegistered()) {
421
            onTryRegister();
422
            mRegisterTimer->setInterval(OFONO_REGISTER_RETRY_TIME);
423
            mRegisterTimer->start();
424
        }
425
    }
426
    return selfHandle();
427
}
428
429
Tp::ContactAttributesMap oFonoConnection::getContactAttributes(const Tp::UIntList &handles, const QStringList &ifaces, Tp::DBusError *error)
430
{
431
    qDebug() << "getContactAttributes" << handles << ifaces;
432
    Tp::ContactAttributesMap attributesMap;
433
    QVariantMap attributes;
434
    Q_FOREACH(uint handle, handles) {
435
        attributes[TP_QT_IFACE_CONNECTION+"/contact-id"] = inspectHandles(Tp::HandleTypeContact, Tp::UIntList() << handle, error).at(0);
436
        if (ifaces.contains(TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE)) {
437
            attributes[TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE+"/presence"] = QVariant::fromValue(mSelfPresence);
438
        }
439
        attributesMap[handle] = attributes;
440
    }
441
    return attributesMap;
442
}
443
444
void oFonoConnection::onValidityChanged(bool valid)
445
{
446
    qDebug() << "validityChanged" << valid << "is network registered: " << isNetworkRegistered() << mRequestedSelfPresence.type;
447
    QObject::disconnect(mOfonoVoiceCallManager->modem(), 0,0,0);
448
    QObject::connect(mOfonoVoiceCallManager->modem(), SIGNAL(onlineChanged(bool)), SLOT(onValidityChanged(bool)));
449
    if (!isNetworkRegistered() && mRequestedSelfPresence.type == Tp::ConnectionPresenceTypeAvailable) {
450
        setOnline(false);
451
        onTryRegister();
452
        mRegisterTimer->setInterval(OFONO_REGISTER_RETRY_TIME);
453
        mRegisterTimer->start();
454
    }
455
}
456
457
void oFonoConnection::setOnline(bool online)
458
{
459
    qDebug() << "setOnline" << online;
460
    Tp::SimpleContactPresences presences;
461
    if (online) {
462
        mSelfPresence.status = "available";
463
        mSelfPresence.statusMessage = "";
464
        mSelfPresence.type = Tp::ConnectionPresenceTypeAvailable;
465
    } else {
466
        mSelfPresence.status = "offline";
467
        mSelfPresence.statusMessage = "";
468
        mSelfPresence.type = Tp::ConnectionPresenceTypeOffline;
469
    }
470
    presences[selfHandle()] = mSelfPresence;
471
    simplePresenceIface->setPresences(presences);
1 by Tiago Salem Herrmann
initial commit
472
}
473
474
uint oFonoConnection::newHandle(const QString &identifier)
475
{
476
    mHandles[++mHandleCount] = identifier;
477
    return mHandleCount;
478
}
479
480
QStringList oFonoConnection::inspectHandles(uint handleType, const Tp::UIntList& handles, Tp::DBusError *error)
481
{
482
    QStringList identifiers;
483
484
    if( handleType != Tp::HandleTypeContact ) {
485
        error->set(TP_QT_ERROR_INVALID_ARGUMENT,"Not supported");
486
        return QStringList();
487
    }
488
489
    qDebug() << "oFonoConnection::inspectHandles " << handles;
490
    Q_FOREACH( uint handle, handles) {
491
        if (mHandles.keys().contains(handle)) {
492
            identifiers.append(mHandles.value(handle));
493
        } else {
494
            error->set(TP_QT_ERROR_INVALID_HANDLE, "Handle not found");
495
            return QStringList();
496
        }
497
    }
2 by Tiago Salem Herrmann
- add call channel support
498
    qDebug() << "oFonoConnection::inspectHandles " << identifiers;
1 by Tiago Salem Herrmann
initial commit
499
    return identifiers;
500
}
501
502
void oFonoConnection::connect(Tp::DBusError *error) {
503
    qDebug() << "oFonoConnection::connect";
504
    setStatus(Tp::ConnectionStatusConnected, Tp::ConnectionStatusReasonRequested);
505
}
506
507
Tp::UIntList oFonoConnection::requestHandles(uint handleType, const QStringList& identifiers, Tp::DBusError* error)
508
{
2 by Tiago Salem Herrmann
- add call channel support
509
    qDebug() << "requestHandles";
1 by Tiago Salem Herrmann
initial commit
510
    Tp::UIntList handles;
511
512
    if( handleType != Tp::HandleTypeContact ) {
513
        error->set(TP_QT_ERROR_INVALID_ARGUMENT, "Not supported");
514
        return Tp::UIntList();
515
    }
516
517
    Q_FOREACH( const QString& identifier, identifiers) {
51.1.3 by Tiago Salem Herrmann
add PhoneUtils class
518
        const QString normalizedNumber = PhoneUtils::normalizePhoneNumber(identifier);
1 by Tiago Salem Herrmann
initial commit
519
        if (mHandles.values().contains(normalizedNumber)) {
520
            handles.append(mHandles.key(normalizedNumber));
51.1.3 by Tiago Salem Herrmann
add PhoneUtils class
521
        } else if (PhoneUtils::isPhoneNumber(normalizedNumber)) {
1 by Tiago Salem Herrmann
initial commit
522
            handles.append(newHandle(normalizedNumber));
523
        } else {
51.1.1 by Tiago Salem Herrmann
accept non numeric ids
524
            handles.append(newHandle(identifier));
1 by Tiago Salem Herrmann
initial commit
525
        }
526
    }
2 by Tiago Salem Herrmann
- add call channel support
527
    qDebug() << "requestHandles" << handles;
1 by Tiago Salem Herrmann
initial commit
528
    return handles;
529
}
530
5 by Tiago Salem Herrmann
- rename some methods
531
Tp::BaseChannelPtr oFonoConnection::createTextChannel(uint targetHandleType,
532
                                               uint targetHandle, Tp::DBusError *error)
533
{
534
    Q_UNUSED(targetHandleType);
535
    Q_UNUSED(error);
536
537
    QString newPhoneNumber = mHandles.value(targetHandle);
538
539
    Q_FOREACH(const QString &phoneNumber, mTextChannels.keys()) {
51.1.4 by Tiago Salem Herrmann
revert back to comparePhoneNumbers()
540
        if (PhoneUtils::comparePhoneNumbers(phoneNumber, newPhoneNumber)) {
5 by Tiago Salem Herrmann
- rename some methods
541
            return mTextChannels[phoneNumber]->baseChannel();
542
        }
543
    }
544
545
    mTextChannels[newPhoneNumber] = new oFonoTextChannel(this, newPhoneNumber, targetHandle);
34.2.1 by Tiago Salem Herrmann
add initial mms support
546
    QObject::connect(mTextChannels[newPhoneNumber], SIGNAL(messageRead(QString)), SLOT(onMessageRead(QString)));
5 by Tiago Salem Herrmann
- rename some methods
547
    QObject::connect(mTextChannels[newPhoneNumber], SIGNAL(destroyed()), SLOT(onTextChannelClosed()));
548
    qDebug() << mTextChannels[newPhoneNumber];
549
    return mTextChannels[newPhoneNumber]->baseChannel();
550
}
551
34.2.1 by Tiago Salem Herrmann
add initial mms support
552
void oFonoConnection::onMessageRead(const QString &id)
553
{
554
    Q_FOREACH(QList<MMSDMessage*> messages, mServiceMMSList.values()) {
555
        Q_FOREACH(MMSDMessage* message, messages) {
556
            if (message->path() == id) {
557
                message->markRead();
558
                message->remove();
559
                return;
560
            }
561
        }
562
    }
563
}
564
5 by Tiago Salem Herrmann
- rename some methods
565
Tp::BaseChannelPtr oFonoConnection::createCallChannel(uint targetHandleType,
566
                                               uint targetHandle, Tp::DBusError *error)
567
{
568
    Q_UNUSED(targetHandleType);
569
16 by Tiago Salem Herrmann
check errors on dial() and sendMessage()
570
    bool success = true;
5 by Tiago Salem Herrmann
- rename some methods
571
    QString newPhoneNumber = mHandles.value(targetHandle);
572
573
    Q_FOREACH(const QString &phoneNumber, mCallChannels.keys()) {
51.1.4 by Tiago Salem Herrmann
revert back to comparePhoneNumbers()
574
        if (PhoneUtils::comparePhoneNumbers(phoneNumber, newPhoneNumber)) {
5 by Tiago Salem Herrmann
- rename some methods
575
            return mCallChannels[phoneNumber]->baseChannel();
576
        }
577
    }
578
579
    bool isOngoingCall = false;
580
    QDBusObjectPath objpath;
581
    Q_FOREACH(const QString &callId, mOfonoVoiceCallManager->getCalls()) {
582
        // check if this is an ongoing call
583
        OfonoVoiceCall *call = new OfonoVoiceCall(callId);
51.1.4 by Tiago Salem Herrmann
revert back to comparePhoneNumbers()
584
        if (PhoneUtils::comparePhoneNumbers(call->lineIdentification(), newPhoneNumber)) {
5 by Tiago Salem Herrmann
- rename some methods
585
            isOngoingCall = true;
586
        }
587
        call->deleteLater();
588
        if (isOngoingCall) {
589
            objpath.setPath(callId);
590
            break;
591
        }
592
    }
593
594
    if (!isOngoingCall) {
16 by Tiago Salem Herrmann
check errors on dial() and sendMessage()
595
        objpath = mOfonoVoiceCallManager->dial(newPhoneNumber, "", success);
5 by Tiago Salem Herrmann
- rename some methods
596
    }
16 by Tiago Salem Herrmann
check errors on dial() and sendMessage()
597
    qDebug() << "success " << success;
598
    if (objpath.path().isEmpty() || !success) {
599
        if (!success) {
600
            error->set(TP_QT_ERROR_NOT_AVAILABLE, mOfonoVoiceCallManager->errorMessage());
601
        } else {
602
            error->set(TP_QT_ERROR_NOT_AVAILABLE, "Channel could not be created");
603
        }
5 by Tiago Salem Herrmann
- rename some methods
604
        return Tp::BaseChannelPtr();
605
    }
606
607
    mCallChannels[newPhoneNumber] = new oFonoCallChannel(this, newPhoneNumber, targetHandle,objpath.path());
608
    QObject::connect(mCallChannels[newPhoneNumber], SIGNAL(destroyed()), SLOT(onCallChannelClosed()));
609
    qDebug() << mCallChannels[newPhoneNumber];
610
    return mCallChannels[newPhoneNumber]->baseChannel();
611
612
}
613
1 by Tiago Salem Herrmann
initial commit
614
Tp::BaseChannelPtr oFonoConnection::createChannel(const QString& channelType, uint targetHandleType,
615
                                               uint targetHandle, Tp::DBusError *error)
616
{
2 by Tiago Salem Herrmann
- add call channel support
617
    qDebug() << "oFonoConnection::createChannel" << targetHandle;
1 by Tiago Salem Herrmann
initial commit
618
    if( (targetHandleType != Tp::HandleTypeContact) || targetHandle == 0 || !mHandles.keys().contains(targetHandle)) {
619
        error->set(TP_QT_ERROR_INVALID_HANDLE, "Handle not found");
620
        return Tp::BaseChannelPtr();
621
    }
622
7 by Tiago Salem Herrmann
add online presence support
623
    if (mSelfPresence.type != Tp::ConnectionPresenceTypeAvailable) {
624
        error->set(TP_QT_ERROR_NETWORK_ERROR, "No network available");
625
        return Tp::BaseChannelPtr();
626
    }
627
5 by Tiago Salem Herrmann
- rename some methods
628
    if (channelType == TP_QT_IFACE_CHANNEL_TYPE_TEXT) {
629
        return createTextChannel(targetHandleType, targetHandle, error);
630
    } else if (channelType == TP_QT_IFACE_CHANNEL_TYPE_CALL) {
631
        return createCallChannel(targetHandleType, targetHandle, error);
632
    } else {
1 by Tiago Salem Herrmann
initial commit
633
        error->set(TP_QT_ERROR_NOT_IMPLEMENTED, "Channel type not available");
634
    }
635
636
    return Tp::BaseChannelPtr();
637
}
638
2 by Tiago Salem Herrmann
- add call channel support
639
OfonoMessageManager *oFonoConnection::messageManager()
1 by Tiago Salem Herrmann
initial commit
640
{
641
    return mOfonoMessageManager;
642
}
643
2 by Tiago Salem Herrmann
- add call channel support
644
OfonoVoiceCallManager *oFonoConnection::voiceCallManager()
1 by Tiago Salem Herrmann
initial commit
645
{
646
    return mOfonoVoiceCallManager;
647
}
648
2 by Tiago Salem Herrmann
- add call channel support
649
OfonoCallVolume *oFonoConnection::callVolume()
650
{
651
    return mOfonoCallVolume;
652
}
653
5 by Tiago Salem Herrmann
- rename some methods
654
void oFonoConnection::onOfonoIncomingMessage(const QString &message, const QVariantMap &info)
1 by Tiago Salem Herrmann
initial commit
655
{
51.1.3 by Tiago Salem Herrmann
add PhoneUtils class
656
    const QString normalizedNumber = PhoneUtils::normalizePhoneNumber(info["Sender"].toString());
51.1.1 by Tiago Salem Herrmann
accept non numeric ids
657
    // check if there is an open channel for this sender and use it
2 by Tiago Salem Herrmann
- add call channel support
658
    Q_FOREACH(const QString &phoneNumber, mTextChannels.keys()) {
51.1.4 by Tiago Salem Herrmann
revert back to comparePhoneNumbers()
659
        if (PhoneUtils::comparePhoneNumbers(normalizedNumber, phoneNumber)) {
2 by Tiago Salem Herrmann
- add call channel support
660
            mTextChannels[phoneNumber]->messageReceived(message, info);
1 by Tiago Salem Herrmann
initial commit
661
            return;
662
        }
663
    }
664
665
    Tp::DBusError error;
666
    bool yours;
667
    uint handle = newHandle(normalizedNumber);
668
    ensureChannel(TP_QT_IFACE_CHANNEL_TYPE_TEXT,Tp::HandleTypeContact, handle, yours, handle, false, &error);
669
    if(error.isValid()) {
34.2.7 by Tiago Salem Herrmann
use qWarning to report errors
670
        qWarning() << "Error creating channel for incoming message" << error.name() << error.message();
1 by Tiago Salem Herrmann
initial commit
671
        return;
672
    }
673
    mTextChannels[normalizedNumber]->messageReceived(message, info);
674
}
675
676
void oFonoConnection::onTextChannelClosed()
677
{
678
    oFonoTextChannel *channel = static_cast<oFonoTextChannel*>(sender());
679
    if (channel) {
680
        QString key = mTextChannels.key(channel);
681
        qDebug() << "text channel closed for number " << key;
682
        mTextChannels.remove(key);
683
    }
684
}
685
2 by Tiago Salem Herrmann
- add call channel support
686
void oFonoConnection::onCallChannelClosed()
687
{
688
    qDebug() << "onCallChannelClosed()";
689
    oFonoCallChannel *channel = static_cast<oFonoCallChannel*>(sender());
690
    if (channel) {
691
        QString key = mCallChannels.key(channel);
692
        qDebug() << "call channel closed for number " << key;
693
        mCallChannels.remove(key);
694
    }
695
}
696
697
uint oFonoConnection::ensureHandle(const QString &phoneNumber)
698
{
51.1.3 by Tiago Salem Herrmann
add PhoneUtils class
699
    const QString normalizedNumber = PhoneUtils::normalizePhoneNumber(phoneNumber);
2 by Tiago Salem Herrmann
- add call channel support
700
701
    Q_FOREACH(const QString &phone, mHandles.values()) {
51.1.4 by Tiago Salem Herrmann
revert back to comparePhoneNumbers()
702
        if (PhoneUtils::comparePhoneNumbers(normalizedNumber, phone)) {
2 by Tiago Salem Herrmann
- add call channel support
703
            // this user already exists
704
            return mHandles.key(phone);
705
        }
706
    }
707
    return newHandle(normalizedNumber);
708
}
709
5 by Tiago Salem Herrmann
- rename some methods
710
void oFonoConnection::onOfonoCallAdded(const QString &call, const QVariantMap &properties)
1 by Tiago Salem Herrmann
initial commit
711
{
2 by Tiago Salem Herrmann
- add call channel support
712
    qDebug() << "new call" << call << properties;
713
714
    bool yours;
715
    Tp::DBusError error;
51.1.1 by Tiago Salem Herrmann
accept non numeric ids
716
    const QString lineIdentification = properties["LineIdentification"].toString();
51.1.3 by Tiago Salem Herrmann
add PhoneUtils class
717
    const QString normalizedNumber = PhoneUtils::normalizePhoneNumber(lineIdentification);
2 by Tiago Salem Herrmann
- add call channel support
718
    // check if there is an open channel for this number, if so, ignore it
719
    Q_FOREACH(const QString &phoneNumber, mCallChannels.keys()) {
51.1.4 by Tiago Salem Herrmann
revert back to comparePhoneNumbers()
720
        if (PhoneUtils::comparePhoneNumbers(normalizedNumber, phoneNumber)) {
34.2.7 by Tiago Salem Herrmann
use qWarning to report errors
721
            qWarning() << "call channel for this number already exists: " << phoneNumber;
2 by Tiago Salem Herrmann
- add call channel support
722
            return;
723
        }
724
    }
725
726
    uint handle = ensureHandle(normalizedNumber);
727
    uint initiatorHandle = 0;
728
    if (properties["State"] == "incoming" || properties["State"] == "waiting") {
729
        initiatorHandle = handle;
730
    } else {
731
        initiatorHandle = selfHandle();
732
    }
733
734
    qDebug() << "initiatorHandle " <<initiatorHandle;
735
    qDebug() << "handle" << handle;
736
737
    Tp::BaseChannelPtr channel  = ensureChannel(TP_QT_IFACE_CHANNEL_TYPE_CALL, Tp::HandleTypeContact, handle, yours, initiatorHandle, false, &error);
738
    if (error.isValid() || channel.isNull()) {
34.2.7 by Tiago Salem Herrmann
use qWarning to report errors
739
        qWarning() << "error creating the channel " << error.name() << error.message();
2 by Tiago Salem Herrmann
- add call channel support
740
        return;
741
    }
1 by Tiago Salem Herrmann
initial commit
742
}
8 by Tiago Salem Herrmann
- add presence interface (and connect it to ofono NetworkRegistration interface)
743
744
uint oFonoConnection::voicemailCount(Tp::DBusError *error)
745
{
746
    return mOfonoMessageWaiting->voicemailMessageCount();
747
}
748
749
QString oFonoConnection::voicemailNumber(Tp::DBusError *error)
750
{
751
    return mOfonoMessageWaiting->voicemailMailboxNumber();
752
}
753
754
bool oFonoConnection::voicemailIndicator(Tp::DBusError *error)
755
{
756
    return mOfonoMessageWaiting->voicemailWaiting();
757
}
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
758
759
bool oFonoConnection::speakerMode()
760
{
761
    return mSpeakerMode;
762
}
763
764
void oFonoConnection::setSpeakerMode(bool active)
765
{
766
    if (mSpeakerMode != active) {
767
        mSpeakerMode = active;
768
        updateAudioRoute();
769
        Q_EMIT speakerModeChanged(active);
770
    }
771
}
772
773
void oFonoConnection::updateAudioRoute()
774
{
34.1.2 by Tiago Salem Herrmann
enable speaker phone mode on incoming calls.
775
    int currentCalls = mOfonoVoiceCallManager->getCalls().size();
776
    if (currentCalls != 0) {
777
        if (currentCalls == 1) {
778
            // if we have only one call, check if it's incoming and
779
            // enable speaker mode so the ringtone is audible
780
            OfonoVoiceCall *call = new OfonoVoiceCall(mOfonoVoiceCallManager->getCalls().first());
781
            if (call) {
782
                if (call->state() == "incoming") {
38.1.1 by David Henningsson
Add PulseAudio backend
783
                    enable_ringtone();
34.1.2 by Tiago Salem Herrmann
enable speaker phone mode on incoming calls.
784
                    call->deleteLater();
785
                    return;
786
                }
42.1.1 by Tiago Salem Herrmann
avoid changing to the wrong audio route on "disconnect"
787
                if (call->state() == "disconnected") {
788
                    enable_normal();
789
                    call->deleteLater();
790
                    return;
791
                }
792
                if (call->state().isEmpty()) {
793
                    call->deleteLater();
794
                    return;
795
                }
34.1.2 by Tiago Salem Herrmann
enable speaker phone mode on incoming calls.
796
                call->deleteLater();
797
            }
798
        }
34.1.1 by Tiago Salem Herrmann
use audioflinger and implement speaker mode
799
        if(mSpeakerMode) {
800
            enable_speaker();
801
        } else {
802
            enable_earpiece();
803
        }
804
    } else {
805
        enable_normal();
806
        setSpeakerMode(false);
807
    }
808
809
}
810