indicate ongoing call. fixes #3675

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java             | 34 
src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java      | 44 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java | 18 
src/main/res/drawable-hdpi/ic_phone_in_talk_black_18dp.png                    |  0 
src/main/res/drawable-hdpi/ic_phone_in_talk_white_18dp.png                    |  0 
src/main/res/drawable-hdpi/ic_phone_in_talk_white_24dp.png                    |  0 
src/main/res/drawable-mdpi/ic_phone_in_talk_black_18dp.png                    |  0 
src/main/res/drawable-mdpi/ic_phone_in_talk_white_18dp.png                    |  0 
src/main/res/drawable-mdpi/ic_phone_in_talk_white_24dp.png                    |  0 
src/main/res/drawable-xhdpi/ic_phone_in_talk_black_18dp.png                   |  0 
src/main/res/drawable-xhdpi/ic_phone_in_talk_white_18dp.png                   |  0 
src/main/res/drawable-xhdpi/ic_phone_in_talk_white_24dp.png                   |  0 
src/main/res/drawable-xxhdpi/ic_phone_in_talk_black_18dp.png                  |  0 
src/main/res/drawable-xxhdpi/ic_phone_in_talk_white_18dp.png                  |  0 
src/main/res/drawable-xxhdpi/ic_phone_in_talk_white_24dp.png                  |  0 
src/main/res/drawable-xxxhdpi/ic_phone_in_talk_black_18dp.png                 |  0 
src/main/res/drawable-xxxhdpi/ic_phone_in_talk_white_18dp.png                 |  0 
src/main/res/drawable-xxxhdpi/ic_phone_in_talk_white_24dp.png                 |  0 
src/main/res/menu/fragment_conversation.xml                                   |  6 
src/main/res/values/attrs.xml                                                 |  2 
src/main/res/values/strings.xml                                               |  1 
src/main/res/values/themes.xml                                                |  4 
22 files changed, 89 insertions(+), 20 deletions(-)

Detailed changes

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

@@ -52,6 +52,8 @@ import android.widget.PopupMenu;
 import android.widget.TextView.OnEditorActionListener;
 import android.widget.Toast;
 
+import com.google.common.base.Optional;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -117,6 +119,7 @@ import eu.siacs.conversations.utils.TimeframeUtils;
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import eu.siacs.conversations.xmpp.chatstate.ChatState;
+import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
 import eu.siacs.conversations.xmpp.jingle.JingleFileTransferConnection;
 import eu.siacs.conversations.xmpp.jingle.RtpCapability;
 import rocks.xmpp.addr.Jid;
@@ -956,6 +959,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
         final MenuItem menuMute = menu.findItem(R.id.action_mute);
         final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
         final MenuItem menuCall = menu.findItem(R.id.action_call);
+        final MenuItem menuOngoingCall = menu.findItem(R.id.action_ongoing_call);
         final MenuItem menuVideoCall = menu.findItem(R.id.action_video_call);
 
 
@@ -965,10 +969,18 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
                 menuInviteContact.setVisible(conversation.getMucOptions().canInvite());
                 menuMucDetails.setTitle(conversation.getMucOptions().isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details);
                 menuCall.setVisible(false);
+                menuOngoingCall.setVisible(false);
             } else {
-                final RtpCapability.Capability rtpCapability = RtpCapability.check(conversation.getContact());
-                menuCall.setVisible(rtpCapability != RtpCapability.Capability.NONE);
-                menuVideoCall.setVisible(rtpCapability == RtpCapability.Capability.VIDEO);
+                final Optional<AbstractJingleConnection.Id> ongoingRtpSession = activity.xmppConnectionService.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact());
+                if (ongoingRtpSession.isPresent()) {
+                    menuOngoingCall.setVisible(true);
+                    menuCall.setVisible(false);
+                } else {
+                    menuOngoingCall.setVisible(false);
+                    final RtpCapability.Capability rtpCapability = RtpCapability.check(conversation.getContact());
+                    menuCall.setVisible(rtpCapability != RtpCapability.Capability.NONE);
+                    menuVideoCall.setVisible(rtpCapability == RtpCapability.Capability.VIDEO);
+                }
                 menuContactDetails.setVisible(!this.conversation.withSelf());
                 menuMucDetails.setVisible(false);
                 final XmppConnectionService service = activity.xmppConnectionService;
@@ -1245,12 +1257,28 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
             case R.id.action_video_call:
                 checkPermissionAndTriggerVideoCall();
                 break;
+            case R.id.action_ongoing_call:
+                returnToOngoingCall();
+                break;
             default:
                 break;
         }
         return super.onOptionsItemSelected(item);
     }
 
+    private void returnToOngoingCall() {
+        final Optional<AbstractJingleConnection.Id> ongoingRtpSession = activity.xmppConnectionService.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact());
+        if (ongoingRtpSession.isPresent()) {
+            final AbstractJingleConnection.Id id = ongoingRtpSession.get();
+            final Intent intent = new Intent(getActivity(), RtpSessionActivity.class);
+            intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString());
+            intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
+            intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
+            startActivity(intent);
+        }
+
+    }
+
     private void checkPermissionAndTriggerAudioCall() {
         if (activity.mUseTor || conversation.getAccount().isOnion()) {
             Toast.makeText(activity, R.string.disable_tor_to_make_call, Toast.LENGTH_SHORT).show();

src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java 🔗

@@ -9,11 +9,14 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.google.common.base.Optional;
+
 import java.util.List;
 
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.ConversationListRowBinding;
 import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Conversational;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.ui.ConversationFragment;
 import eu.siacs.conversations.ui.XmppActivity;
@@ -22,6 +25,7 @@ import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.EmojiWrapper;
 import eu.siacs.conversations.utils.IrregularUnicodeDetector;
 import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
 import rocks.xmpp.addr.Jid;
 
 public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapter.ConversationViewHolder> {
@@ -160,21 +164,35 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte
             }
         }
 
-        long muted_till = conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
-        if (muted_till == Long.MAX_VALUE) {
-            viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
-            int ic_notifications_off = activity.getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp);
-            viewHolder.binding.notificationStatus.setImageResource(ic_notifications_off);
-        } else if (muted_till >= System.currentTimeMillis()) {
-            viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
-            int ic_notifications_paused = activity.getThemeResource(R.attr.icon_notifications_paused, R.drawable.ic_notifications_paused_black_24dp);
-            viewHolder.binding.notificationStatus.setImageResource(ic_notifications_paused);
-        } else if (conversation.alwaysNotify()) {
-            viewHolder.binding.notificationStatus.setVisibility(View.GONE);
+
+        final Optional<AbstractJingleConnection.Id> ongoingCall;
+        if (conversation.getMode() == Conversational.MODE_MULTI) {
+            ongoingCall = Optional.absent();
         } else {
+            ongoingCall = activity.xmppConnectionService.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact());
+        }
+
+        if (ongoingCall.isPresent()) {
             viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
-            int ic_notifications_none = activity.getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp);
-            viewHolder.binding.notificationStatus.setImageResource(ic_notifications_none);
+                final int ic_ongoing_call = activity.getThemeResource(R.attr.ic_ongoing_call_hint, R.drawable.ic_phone_in_talk_black_18dp);
+                viewHolder.binding.notificationStatus.setImageResource(ic_ongoing_call);
+        } else {
+            final long muted_till = conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
+            if (muted_till == Long.MAX_VALUE) {
+                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
+                int ic_notifications_off = activity.getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp);
+                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_off);
+            } else if (muted_till >= System.currentTimeMillis()) {
+                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
+                int ic_notifications_paused = activity.getThemeResource(R.attr.icon_notifications_paused, R.drawable.ic_notifications_paused_black_24dp);
+                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_paused);
+            } else if (conversation.alwaysNotify()) {
+                viewHolder.binding.notificationStatus.setVisibility(View.GONE);
+            } else {
+                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
+                int ic_notifications_none = activity.getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp);
+                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_none);
+            }
         }
 
         long timestamp;

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

@@ -1,19 +1,16 @@
 package eu.siacs.conversations.xmpp.jingle;
 
-import android.os.SystemClock;
 import android.util.Base64;
 import android.util.Log;
 
-import com.google.common.base.Function;
 import com.google.common.base.Objects;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableSet;
 
-import org.checkerframework.checker.nullness.compatqual.NullableDecl;
-
 import java.lang.ref.WeakReference;
 import java.security.SecureRandom;
 import java.util.Collection;
@@ -108,6 +105,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
                 return;
             }
             connections.put(id, connection);
+            mXmppConnectionService.updateConversationUi();
             connection.deliverPacket(packet);
         } else {
             Log.d(Config.LOGTAG, "unable to route jingle packet: " + packet);
@@ -353,6 +351,18 @@ public class JingleConnectionManager extends AbstractConnectionManager {
         connection.init(message);
     }
 
+    public Optional<AbstractJingleConnection.Id> getOngoingRtpConnection(final Contact contact) {
+        for(final Map.Entry<AbstractJingleConnection.Id,AbstractJingleConnection> entry : this.connections.entrySet()) {
+            if (entry.getValue() instanceof JingleRtpConnection) {
+                final AbstractJingleConnection.Id id = entry.getKey();
+                if (id.account == contact.getAccount() && id.with.asBareJid().equals(contact.getJid().asBareJid())) {
+                    return Optional.of(id);
+                }
+            }
+        }
+        return Optional.absent();
+    }
+
     void finishConnection(final AbstractJingleConnection connection) {
         this.connections.remove(connection.getId());
     }

src/main/res/menu/fragment_conversation.xml 🔗

@@ -60,6 +60,12 @@
                 android:title="@string/send_location" />
         </menu>
     </item>
+    <item
+        android:id="@+id/action_ongoing_call"
+        android:icon="?attr/icon_ongoing_call"
+        android:orderInCategory="34"
+        android:title="@string/return_to_ongoing_call"
+        app:showAsAction="always" />
     <item
         android:id="@+id/action_call"
         android:icon="?attr/icon_call"

src/main/res/values/attrs.xml 🔗

@@ -91,6 +91,8 @@
     <attr name="icon_new_attachment" format="reference"/>
     <attr name="icon_not_secure" format="reference"/>
     <attr name="icon_call" format="reference"/>
+    <attr name="icon_ongoing_call" format="reference"/>
+    <attr name="ic_ongoing_call_hint" format="reference"/>
     <attr name="icon_quote" format="reference"/>
     <attr name="icon_refresh" format="reference"/>
     <attr name="icon_remove" format="reference"/>

src/main/res/values/strings.xml 🔗

@@ -919,6 +919,7 @@
     <string name="video_call">Video call</string>
     <string name="microphone_unavailable">Your microphone is unavailable</string>
     <string name="only_one_call_at_a_time">You can only have one call at a time.</string>
+    <string name="return_to_ongoing_call">Return to ongoing call</string>
     <plurals name="view_users">
         <item quantity="one">View %1$d Participant</item>
         <item quantity="other">View %1$d Participants</item>

src/main/res/values/themes.xml 🔗

@@ -99,6 +99,8 @@
         <item type="reference" name="icon_new_attachment">@drawable/ic_attach_file_white_24dp</item>
         <item type="reference" name="icon_not_secure">@drawable/ic_lock_open_white_24dp</item>
         <item type="reference" name="icon_call">@drawable/ic_call_white_24dp</item>
+        <item type="reference" name="icon_ongoing_call">@drawable/ic_phone_in_talk_white_24dp</item>
+        <item type="reference" name="ic_ongoing_call_hint">@drawable/ic_phone_in_talk_black_18dp</item>
         <item type="reference" name="icon_remove">@drawable/ic_delete_black_24dp</item>
         <item type="reference" name="icon_search">@drawable/ic_search_white_24dp</item>
         <item type="reference" name="icon_secure">@drawable/ic_lock_open_white_24dp</item>
@@ -219,6 +221,8 @@
         <item type="reference" name="icon_new_attachment">@drawable/ic_attach_file_white_24dp</item>
         <item type="reference" name="icon_not_secure">@drawable/ic_lock_open_white_24dp</item>
         <item type="reference" name="icon_call">@drawable/ic_call_white_24dp</item>
+        <item type="reference" name="icon_ongoing_call">@drawable/ic_phone_in_talk_white_24dp</item>
+        <item type="reference" name="ic_ongoing_call_hint">@drawable/ic_phone_in_talk_white_18dp</item>
         <item type="reference" name="icon_remove">@drawable/ic_delete_white_24dp</item>
         <item type="reference" name="icon_search">@drawable/ic_search_white_24dp</item>
         <item type="reference" name="icon_secure">@drawable/ic_lock_open_white_24dp</item>