create temporary RtpSessionPropsoal as placeholder before we can create actual session

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/generator/MessageGenerator.java          | 10 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java             | 26 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java | 65 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java     |  8 
4 files changed, 95 insertions(+), 14 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/generator/MessageGenerator.java 🔗

@@ -18,6 +18,7 @@ import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xml.Namespace;
 import eu.siacs.conversations.xmpp.chatstate.ChatState;
+import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
 import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 import rocks.xmpp.addr.Jid;
 
@@ -231,4 +232,13 @@ public class MessageGenerator extends AbstractGenerator {
 		packet.addChild("store", "urn:xmpp:hints");
 		return packet;
 	}
+
+	public MessagePacket sessionProposal(JingleConnectionManager.RtpSessionProposal proposal) {
+		final MessagePacket packet = new MessagePacket();
+		packet.setTo(proposal.with);
+		final Element propose = packet.addChild("propose", Namespace.JINGLE_MESSAGE);
+		propose.setAttribute("id", proposal.sessionId);
+		propose.addChild("description", Namespace.JINGLE_APPS_RTP);
+		return packet;
+	}
 }

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -199,7 +199,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
     private OnClickListener acceptJoin = new OnClickListener() {
         @Override
         public void onClick(View v) {
-            conversation.setAttribute("accept_non_anonymous",true);
+            conversation.setAttribute("accept_non_anonymous", true);
             activity.xmppConnectionService.updateConversation(conversation);
             activity.xmppConnectionService.joinMuc(conversation);
         }
@@ -1127,7 +1127,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
                 showErrorMessage.setVisible(true);
             }
             final String mime = m.isFileOrImage() ? m.getMimeType() : null;
-            if ((m.isGeoUri() && GeoHelper.openInOsmAnd(getActivity(),m)) || (mime != null && mime.startsWith("audio/"))) {
+            if ((m.isGeoUri() && GeoHelper.openInOsmAnd(getActivity(), m)) || (mime != null && mime.startsWith("audio/"))) {
                 openWith.setVisible(true);
             }
         }
@@ -1232,12 +1232,20 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
                     BlockContactDialog.show((XmppActivity) activity, conversation);
                 }
                 break;
+            case R.id.action_call:
+                triggerRtpSession();
+                break;
             default:
                 break;
         }
         return super.onOptionsItemSelected(item);
     }
 
+    private void triggerRtpSession() {
+        final Contact contact = conversation.getContact();
+        activity.xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(conversation.getAccount(), contact);
+    }
+
     private void handleAttachmentSelection(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.attach_choose_picture:
@@ -1431,7 +1439,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
         } else if (message.treatAsDownloadable() || message.hasFileOnRemoteHost() || MessageUtils.unInitiatedButKnownSize(message)) {
             createNewConnection(message);
         } else {
-            Log.d(Config.LOGTAG,message.getConversation().getAccount()+": unable to start downloadable");
+            Log.d(Config.LOGTAG, message.getConversation().getAccount() + ": unable to start downloadable");
         }
     }
 
@@ -1621,7 +1629,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
 
     private void openWith(final Message message) {
         if (message.isGeoUri()) {
-            GeoHelper.view(getActivity(),message);
+            GeoHelper.view(getActivity(), message);
         } else {
             final DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message);
             ViewUtil.view(activity, file);
@@ -1641,8 +1649,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
         }
         builder.setMessage(displayError);
         builder.setNegativeButton(R.string.copy_to_clipboard, (dialog, which) -> {
-            activity.copyTextToClipboard(displayError,R.string.error_message);
-            Toast.makeText(activity,R.string.error_message_copied_to_clipboard, Toast.LENGTH_SHORT).show();
+            activity.copyTextToClipboard(displayError, R.string.error_message);
+            Toast.makeText(activity, R.string.error_message_copied_to_clipboard, Toast.LENGTH_SHORT).show();
         });
         builder.setPositiveButton(R.string.confirm, null);
         builder.create().show();
@@ -2744,10 +2752,10 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
             Log.e(Config.LOGTAG, "cleared pending photo uri");
         }
         if (pendingConversationsUuid.clear()) {
-            Log.e(Config.LOGTAG,"cleared pending conversations uuid");
+            Log.e(Config.LOGTAG, "cleared pending conversations uuid");
         }
         if (pendingMediaPreviews.clear()) {
-            Log.e(Config.LOGTAG,"cleared pending media previews");
+            Log.e(Config.LOGTAG, "cleared pending media previews");
         }
     }
 
@@ -2765,7 +2773,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
         }
         final PopupMenu popupMenu = new PopupMenu(getActivity(), v);
         final Contact contact = message.getContact();
-        if (message.getStatus() <= Message.STATUS_RECEIVED && (contact == null  || !contact.isSelf())) {
+        if (message.getStatus() <= Message.STATUS_RECEIVED && (contact == null || !contact.isSelf())) {
             if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
                 final Jid cp = message.getCounterpart();
                 if (cp == null || cp.isBareJid()) {

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java 🔗

@@ -2,15 +2,19 @@ package eu.siacs.conversations.xmpp.jingle;
 
 import android.util.Log;
 
+import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.Transferable;
 import eu.siacs.conversations.services.AbstractConnectionManager;
@@ -22,10 +26,12 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
 import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription;
 import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
 import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 import rocks.xmpp.addr.Jid;
 
 public class JingleConnectionManager extends AbstractConnectionManager {
-    private Map<AbstractJingleConnection.Id, AbstractJingleConnection> connections = new ConcurrentHashMap<>();
+    private final Set<RtpSessionProposal> rtpSessionProposals = new HashSet<>();
+    private final Map<AbstractJingleConnection.Id, AbstractJingleConnection> connections = new ConcurrentHashMap<>();
 
     private HashMap<Jid, JingleCandidate> primaryCandidates = new HashMap<>();
 
@@ -95,6 +101,22 @@ public class JingleConnectionManager extends AbstractConnectionManager {
             } else {
                 Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to react to proposed " + namespace + " session");
             }
+        } else if ("proceed".equals(message.getName())) {
+            if (!with.equals(from)) {
+                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignore carbon copied proceed");
+                return;
+            }
+            final RtpSessionProposal proposal = new RtpSessionProposal(account, with.asBareJid(), sessionId);
+            synchronized (rtpSessionProposals) {
+                if (rtpSessionProposals.remove(proposal)) {
+                    final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, account.getJid());
+                    this.connections.put(id, rtpConnection);
+                    rtpConnection.transitionOrThrow(AbstractJingleConnection.State.PROPOSED);
+                    rtpConnection.deliveryMessage(from, message);
+                } else {
+                    Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": no rtp session proposal found for " + with);
+                }
+            }
         } else {
             Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retrieved out of order jingle message");
         }
@@ -165,6 +187,16 @@ public class JingleConnectionManager extends AbstractConnectionManager {
         }
     }
 
+    public void proposeJingleRtpSession(final Account account, final Contact contact) {
+        final RtpSessionProposal proposal = RtpSessionProposal.of(account, contact.getJid().asBareJid());
+        synchronized (this.rtpSessionProposals) {
+            this.rtpSessionProposals.add(proposal);
+            final MessagePacket messagePacket = mXmppConnectionService.getMessageGenerator().sessionProposal(proposal);
+            Log.d(Config.LOGTAG,messagePacket.toString());
+            mXmppConnectionService.sendMessagePacket(account, messagePacket);
+        }
+    }
+
     static String nextRandomId() {
         return UUID.randomUUID().toString();
     }
@@ -211,4 +243,35 @@ public class JingleConnectionManager extends AbstractConnectionManager {
             }*/
         }
     }
+
+    public static class RtpSessionProposal {
+        private final Account account;
+        public final Jid with;
+        public final String sessionId;
+
+        private RtpSessionProposal(Account account, Jid with, String sessionId) {
+            this.account = account;
+            this.with = with;
+            this.sessionId = sessionId;
+        }
+
+        public static RtpSessionProposal of(Account account, Jid with) {
+            return new RtpSessionProposal(account, with, UUID.randomUUID().toString());
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            RtpSessionProposal proposal = (RtpSessionProposal) o;
+            return Objects.equal(account.getJid(), proposal.account.getJid()) &&
+                    Objects.equal(with, proposal.with) &&
+                    Objects.equal(sessionId, proposal.sessionId);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(account.getJid(), with, sessionId);
+        }
+    }
 }

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java 🔗

@@ -128,7 +128,7 @@ public class JingleRtpConnection extends AbstractJingleConnection {
     private void receiveProceed(final Jid from, final Element proceed) {
         if (from.equals(id.with)) {
             if (isInitiator()) {
-                if (transition(State.SESSION_INITIALIZED)) {
+                if (transition(State.PROCEED)) {
                     this.sendSessionInitiate();
                 } else {
                     Log.d(Config.LOGTAG, String.format("%s: ignoring proceed because already in %s", id.account.getJid().asBareJid(), this.state));
@@ -142,7 +142,7 @@ public class JingleRtpConnection extends AbstractJingleConnection {
     }
 
     private void sendSessionInitiate() {
-
+        Log.d(Config.LOGTAG,id.account.getJid().asBareJid()+": sending session-initiate");
     }
 
     private void sendSessionAccept() {
@@ -167,7 +167,7 @@ public class JingleRtpConnection extends AbstractJingleConnection {
         final MessagePacket messagePacket = new MessagePacket();
         messagePacket.setTo(id.with);
         //Note that Movim needs 'accept', correct is 'proceed' https://github.com/movim/movim/issues/916
-        messagePacket.addChild("accept", Namespace.JINGLE_MESSAGE).setAttribute("id", id.sessionId);
+        messagePacket.addChild("proceed", Namespace.JINGLE_MESSAGE).setAttribute("id", id.sessionId);
         Log.d(Config.LOGTAG, messagePacket.toString());
         xmppConnectionService.sendMessagePacket(id.account, messagePacket);
     }
@@ -187,7 +187,7 @@ public class JingleRtpConnection extends AbstractJingleConnection {
         }
     }
 
-    private void transitionOrThrow(final State target) {
+    public void transitionOrThrow(final State target) {
         if (!transition(target)) {
             throw new IllegalStateException(String.format("Unable to transition from %s to %s", this.state, target));
         }