#include "sailfishplatform.h" #include "callchannelobserver.h" #include "organizeradapter.h" #include "syncmonitorclient.h" #include #include #include SailfishPlatform::SailfishPlatform(QObject *parent): PlatformInterface(parent), _pulseBus(NULL), _maxVolume(0) { // Notifications QDBusConnection::sessionBus().registerObject("/org/freedesktop/Notifications", this, QDBusConnection::ExportAllSlots); m_iface = new QDBusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus"); m_iface->call("AddMatch", "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'"); m_iface->call("AddMatch", "interface='org.freedesktop.Notifications',member='CloseNotification',type='method_call',eavesdrop='true'"); // Music QDBusConnectionInterface *iface = QDBusConnection::sessionBus().interface(); const QStringList &services = iface->registeredServiceNames(); foreach (QString service, services) { if (service.startsWith("org.mpris.MediaPlayer2.")) { qDebug() << "have mpris service" << service; m_mprisService = service; fetchMusicMetadata(); QDBusConnection::sessionBus().connect(m_mprisService, "/org/mpris/MediaPlayer2", "", "PropertiesChanged", this, SLOT(mediaPropertiesChanged(QString,QVariantMap,QStringList))); break; } } QDBusMessage call = QDBusMessage::createMethodCall("org.PulseAudio1", "/org/pulseaudio/server_lookup1", "org.freedesktop.DBus.Properties", "Get" ); call << "org.PulseAudio.ServerLookup1" << "Address"; QDBusReply lookupReply = QDBusConnection::sessionBus().call(call); if (lookupReply.isValid()) { // qDebug() << "PulseAudio Bus address: " << lookupReply.value().variant().toString(); _pulseBus = new QDBusConnection(QDBusConnection::connectToPeer(lookupReply.value().variant().toString(), "org.PulseAudio1")); } // Query max volume call = QDBusMessage::createMethodCall("com.Meego.MainVolume2", "/com/meego/mainvolume2", "org.freedesktop.DBus.Properties", "Get"); call << "com.Meego.MainVolume2" << "StepCount"; QDBusReply volumeMaxReply = _pulseBus->call(call); if (volumeMaxReply.isValid()) { _maxVolume = volumeMaxReply.value().variant().toUInt(); qDebug() << "Max volume: " << _maxVolume; } else { qWarning() << "Could not read volume max, cannot adjust volume: " << volumeMaxReply.error().message(); } // Calls m_telepathyMonitor = new TelepathyMonitor(this); connect(m_telepathyMonitor, &TelepathyMonitor::incomingCall, this, &SailfishPlatform::incomingCall); connect(m_telepathyMonitor, &TelepathyMonitor::callStarted, this, &SailfishPlatform::callStarted); connect(m_telepathyMonitor, &TelepathyMonitor::callEnded, this, &SailfishPlatform::callEnded); // Organizer m_organizerAdapter = new OrganizerAdapter(this); m_organizerAdapter->refresh(); connect(m_organizerAdapter, &OrganizerAdapter::itemsChanged, this, &SailfishPlatform::organizerItemsChanged); m_syncMonitorClient = new SyncMonitorClient(this); connect(m_syncMonitorClient, &SyncMonitorClient::stateChanged, [this]() { if (m_syncMonitorClient->state() == "idle") m_organizerAdapter->refresh();}); m_syncTimer.start(1000 * 60 * 60); connect(&m_syncTimer, &QTimer::timeout, [this]() { m_syncMonitorClient->sync({"calendar"});}); m_syncMonitorClient->sync({"calendar"}); } QDBusInterface *SailfishPlatform::interface() const { return m_iface; } uint SailfishPlatform::Notify(const QString &app_name, uint replaces_id, const QString &app_icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantHash &hints, int expire_timeout) { // Lets directly suppress volume change notifications, network password entries and phone call snap decisions here QStringList hiddenNotifications = {"indicator-sound", "indicator-network"}; if (!hiddenNotifications.contains(app_name)) { if (hints.contains("x-canonical-secondary-icon") && hints.value("x-canonical-secondary-icon").toString() == "incoming-call") { qDebug() << "Have a phone call notification. Ignoring it..." << app_name << app_icon; } else { qDebug() << "Notification received" << app_name << replaces_id << app_icon << summary << body << actions << hints << expire_timeout; Notification n(app_name); if (app_name.contains("twitter")) { n.setType(Notification::NotificationTypeTwitter); n.setSourceName("Twitter"); } else if (app_name.contains("dekko")) { n.setType(Notification::NotificationTypeEmail); n.setSourceName("EMail"); } else if (app_name.toLower().contains("gmail")) { n.setType(Notification::NotificationTypeGMail); n.setSourceName("GMail"); } else if (app_name.contains("facebook")) { n.setType(Notification::NotificationTypeFacebook); n.setSourceName("Facebook"); } else if (app_name.toLower().contains("telegram") || app_name.toLower().contains("sailorgram")) { n.setType(Notification::NotificationTypeTelegram); n.setSourceName("Telegram"); } else if (app_name.toLower().contains("hangish")) { n.setType(Notification::NotificationTypeHangout); n.setSourceName("Hangout"); } else if (app_name.contains("indicator-datetime")) { n.setType(Notification::NotificationTypeReminder); n.setSourceName("reminders"); } else { n.setType(Notification::NotificationTypeGeneric); } n.setSender(summary); n.setBody(body); foreach (const QString &action, actions) { if (action.contains(QRegExp("^[a-z]*://"))) { n.setActToken(action); break; } } qDebug() << "have act token" << n.actToken(); emit notificationReceived(n); } } // We never return something. We're just snooping in... setDelayedReply(true); return 0; } void SailfishPlatform::sendMusicControlCommand(MusicControlButton controlButton) { QString method; switch (controlButton) { case MusicControlPlayPause: method = "PlayPause"; break; case MusicControlSkipBack: method = "Previous"; break; case MusicControlSkipNext: method = "Next"; break; default: ; } if (!method.isEmpty()) { QDBusMessage call = QDBusMessage::createMethodCall(m_mprisService, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", method); QDBusError err = QDBusConnection::sessionBus().call(call); if (err.isValid()) { qWarning() << "Error calling mpris method on" << m_mprisService << ":" << err.message(); } return; } if (controlButton == MusicControlVolumeUp || controlButton == MusicControlVolumeDown) { QDBusMessage call = QDBusMessage::createMethodCall("com.Meego.MainVolume2", "/com/meego/mainvolume2", "org.freedesktop.DBus.Properties", "Get"); call << "com.Meego.MainVolume2" << "CurrentStep"; QDBusReply volumeReply = _pulseBus->call(call); if (volumeReply.isValid()) { // Decide the new value for volume, taking limits into account uint volume = volumeReply.value().variant().toUInt(); uint newVolume; qDebug() << "Current volume: " << volumeReply.value().variant().toUInt(); if (controlButton == MusicControlVolumeUp && volume < _maxVolume-1 ) { newVolume = volume + 1; } else if (controlButton == MusicControlVolumeDown && volume > 0) { newVolume = volume - 1; } else { qDebug() << "Volume already at limit"; newVolume = volume; } // If we have a new volume level, change it if (newVolume != volume) { qDebug() << "Setting volume: " << newVolume; call = QDBusMessage::createMethodCall("com.Meego.MainVolume2", "/com/meego/mainvolume2", "org.freedesktop.DBus.Properties", "Set"); call << "com.Meego.MainVolume2" << "CurrentStep" << QVariant::fromValue(QDBusVariant(newVolume)); QDBusError err = _pulseBus->call(call); if (err.isValid()) { qWarning() << err.message(); } } } } } MusicMetaData SailfishPlatform::musicMetaData() const { return m_musicMetaData; } void SailfishPlatform::hangupCall(uint cookie) { m_telepathyMonitor->hangupCall(cookie); } QList SailfishPlatform::organizerItems() const { return m_organizerAdapter->items(); } void SailfishPlatform::actionTriggered(const QString &actToken) { Q_UNUSED(actToken); //url_dispatch_send(actToken.toStdString().c_str(), [] (const char *, boolean, pointer) {}, nullptr); } void SailfishPlatform::fetchMusicMetadata() { if (!m_mprisService.isEmpty()) { QDBusMessage call = QDBusMessage::createMethodCall(m_mprisService, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"); call << "org.mpris.MediaPlayer2.Player" << "Metadata"; QDBusPendingCall pcall = QDBusConnection::sessionBus().asyncCall(call); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &SailfishPlatform::fetchMusicMetadataFinished); } } void SailfishPlatform::fetchMusicMetadataFinished(QDBusPendingCallWatcher *watcher) { watcher->deleteLater(); QDBusReply reply = watcher->reply(); if (reply.isValid()) { QVariantMap curMetadata = qdbus_cast(reply.value().variant().value()); m_musicMetaData.artist = curMetadata.value("xesam:artist").toString(); m_musicMetaData.album = curMetadata.value("xesam:album").toString(); m_musicMetaData.title = curMetadata.value("xesam:title").toString(); emit musicMetadataChanged(m_musicMetaData); } else { qWarning() << reply.error().message(); } } void SailfishPlatform::mediaPropertiesChanged(const QString &interface, const QVariantMap &changedProps, const QStringList &invalidatedProps) { Q_UNUSED(interface) Q_UNUSED(changedProps) Q_UNUSED(invalidatedProps) fetchMusicMetadata(); }