diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js index 19288a762..5514ac171 100644 --- a/js/ui/notificationDaemon.js +++ b/js/ui/notificationDaemon.js @@ -190,10 +190,11 @@ NotificationDaemon.prototype = { actions, hints, timeout) { let id; - // Filter out chat, presence and invitation notifications from Empathy, since we - // handle that information from telepathyClient.js + // Filter out chat, presence, calls and invitation notifications from + // Empathy, since we handle that information from telepathyClient.js if (appName == 'Empathy' && (hints['category'] == 'im.received' || hints['category'] == 'x-empathy.im.room-invitation' || + hints['category'] == 'x-empathy.call.incoming' || hints['category'] == 'presence.online' || hints['category'] == 'presence.offline')) { // Ignore replacesId since we already sent back a diff --git a/js/ui/telepathyClient.js b/js/ui/telepathyClient.js index 5738a334f..d0c92ab26 100644 --- a/js/ui/telepathyClient.js +++ b/js/ui/telepathyClient.js @@ -230,6 +230,16 @@ Client.prototype = { _approveChannels: function(approver, account, conn, channels, dispatchOp, context) { let channel = channels[0]; + let chanType = channel.get_channel_type(); + + if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT) + this._approveTextChannel(account, conn, channel, dispatchOp, context); + else if (chanType == Tp.IFACE_CHANNEL_TYPE_STREAMED_MEDIA || + chanType == 'org.freedesktop.Telepathy.Channel.Type.Call.DRAFT') + this._approveCall(account, conn, channel, dispatchOp, context); + }, + + _approveTextChannel: function(account, conn, channel, dispatchOp, context) { let [targetHandle, targetHandleType] = channel.get_handle(); if (targetHandleType == Tp.HandleType.CONTACT) { @@ -249,6 +259,37 @@ Client.prototype = { } }, + _approveCall: function(account, conn, channel, dispatchOp, context) { + let [targetHandle, targetHandleType] = channel.get_handle(); + + Shell.get_tp_contacts(conn, [targetHandle], + contactFeatures, + Lang.bind(this, this._createAudioVideoSource, channel, context, dispatchOp)); + }, + + _createAudioVideoSource: function(connection, contacts, failed, channel, context, dispatchOp) { + if (contacts.length < 1) { + Shell.decline_dispatch_op(context, 'Failed to get inviter'); + return; + } + + let isVideo = false; + + let props = channel.borrow_immutable_properties(); + + if (props['org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo'] || + props[Tp.PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO]) + isVideo = true; + + // We got the TpContact + let source = new ApproverSource(dispatchOp, _("Call"), isVideo ? 'camera-web' : 'audio-input-microphone'); + Main.messageTray.add(source); + + let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo); + source.notify(notif); + context.accept(); + }, + _handleChannels: function(handler, account, conn, channels, requests, user_action_time, context) { this._handlingChannels(account, conn, channels); @@ -884,3 +925,49 @@ RoomInviteNotification.prototype = { })); } }; + +// Audio Video +function AudioVideoNotification(source, dispatchOp, channel, contact, isVideo) { + this._init(source, dispatchOp, channel, contact, isVideo); +} + +AudioVideoNotification.prototype = { + __proto__: MessageTray.Notification.prototype, + + _init: function(source, dispatchOp, channel, contact, isVideo) { + let title = ''; + + if (isVideo) + /* translators: argument is a contact name like Alice for example. */ + title = _("Video call from %s").format(contact.get_alias()); + else + /* translators: argument is a contact name like Alice for example. */ + title = _("Call from %s").format(contact.get_alias()); + + MessageTray.Notification.prototype._init.call(this, + source, + title, + null, + { customContent: true }); + this.setResident(true); + + this.addButton('reject', _("Reject")); + this.addButton('answer', _("Answer")); + + this.connect('action-invoked', Lang.bind(this, function(self, action) { + switch (action) { + case 'reject': + dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, + '', function(src, result) { + src.leave_channels_finish(result)}); + break; + case 'answer': + dispatchOp.handle_with_time_async('', global.get_current_time(), + function(src, result) { + src.handle_with_time_finish(result)}); + break; + } + this.destroy(); + })); + } +}; diff --git a/src/shell-tp-client.c b/src/shell-tp-client.c index 018f233e5..bce0cbba7 100644 --- a/src/shell-tp-client.c +++ b/src/shell-tp-client.c @@ -110,6 +110,23 @@ shell_tp_client_init (ShellTpClient *self) TP_HANDLE_TYPE_ROOM, NULL)); + /* Approve calls (StreameMedia and Call.DRAFT). We let Empathy handle the + * call itself. */ + tp_base_client_take_approver_filter (TP_BASE_CLIENT (self), + tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, + NULL)); + + /* FIXME: use TP_IFACE_CHANNEL_TYPE_CALL once API is undrafted (fdo #24936) */ + tp_base_client_take_approver_filter (TP_BASE_CLIENT (self), + tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + "org.freedesktop.Telepathy.Channel.Type.Call.DRAFT", + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, + NULL)); + /* Handler */ tp_base_client_add_handler_filter (TP_BASE_CLIENT (self), filter);