diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7075be30e..4052c7f85 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -81,6 +81,8 @@ android:name=".service.ForegroundService" android:exported="false" /> + + diff --git a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java index 04cea807d..baa66f083 100644 --- a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java +++ b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.xmpp.jingle; import android.content.Context; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.base.Preconditions; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; @@ -84,6 +85,14 @@ public abstract class AbstractJingleConnection extends XmppConnection.Delegate { public int hashCode() { return Objects.hashCode(with, sessionId); } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("with", with) + .add("sessionId", sessionId) + .toString(); + } } public enum State { diff --git a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 49380bfea..0cc10008d 100644 --- a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -30,7 +30,9 @@ import im.conversations.android.BuildConfig; import im.conversations.android.axolotl.AxolotlEncryptionException; import im.conversations.android.axolotl.AxolotlService; import im.conversations.android.dns.IP; +import im.conversations.android.notification.OngoingCall; import im.conversations.android.notification.RtpSessionNotification; +import im.conversations.android.service.RtpSessionService; import im.conversations.android.transformer.CallLogTransformation; import im.conversations.android.util.BooleanFutures; import im.conversations.android.xml.Element; @@ -592,7 +594,10 @@ public class JingleRtpConnection extends AbstractJingleConnection this.incomingContentAdd = null; updateEndUserState(); } else { - LOGGER.info("content add summary {} did not match remove summary {}", contentAddSummary, removeSummary); + LOGGER.info( + "content add summary {} did not match remove summary {}", + contentAddSummary, + removeSummary); webRTCWrapper.close(); sendSessionTerminate( Reason.FAILED_APPLICATION, @@ -2424,6 +2429,7 @@ public class JingleRtpConnection extends AbstractJingleConnection this.webRTCWrapper.switchSpeakerPhonePreference( AppRTCAudioManager.SpeakerPhonePreference.of(activeContents.getMedia())); updateEndUserState(); + updateOngoingCallNotification(); } private SessionDescription setLocalSessionDescription() @@ -2505,21 +2511,26 @@ public class JingleRtpConnection extends AbstractJingleConnection private void updateOngoingCallNotification() { final State state = this.state; if (STATES_SHOWING_ONGOING_CALL.contains(state)) { - final boolean reconnecting; + RtpSessionService.updateOngoingCall(context, getAccount().id, id); + } else { + RtpSessionService.stop(context); + } + } + + public OngoingCall getOngoingCall() { + final State state = this.state; + final boolean reconnecting; + if (STATES_SHOWING_ONGOING_CALL.contains(state)) { if (state == State.SESSION_ACCEPTED) { reconnecting = getPeerConnectionStateAsEndUserState() == RtpEndUserState.RECONNECTING; } else { reconnecting = false; } - - // TODO decide what we want to do with ongoing call? create a foreground service of - // RtpSessionService? - - // xmppConnectionService.setOngoingCall(id, getMedia(), reconnecting); } else { - // xmppConnectionService.removeOngoingCall(); + reconnecting = false; } + return new OngoingCall(id, getMedia(), reconnecting); } private void discoverIceServers(final OnIceServersDiscovered onIceServersDiscovered) { diff --git a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/TrackWrapper.java b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/TrackWrapper.java index 2093fbf18..38d4e4c50 100644 --- a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/TrackWrapper.java +++ b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/TrackWrapper.java @@ -38,7 +38,9 @@ class TrackWrapper { final RtpTransceiver transceiver = peerConnection == null ? null : getTransceiver(peerConnection, trackWrapper); if (transceiver == null) { - Log.w(Config.LOGTAG, "unable to detect transceiver for " + trackWrapper.getRtpSenderId()); + Log.w( + Config.LOGTAG, + "unable to detect transceiver for " + trackWrapper.getRtpSenderId()); return Optional.of(trackWrapper.track); } final RtpTransceiver.RtpTransceiverDirection direction = transceiver.getDirection(); @@ -62,10 +64,13 @@ class TrackWrapper { public static RtpTransceiver getTransceiver( @Nonnull final PeerConnection peerConnection, final TrackWrapper trackWrapper) { final String rtpSenderId = trackWrapper.getRtpSenderId(); + if (rtpSenderId == null) { + return null; + } for (final RtpTransceiver transceiver : peerConnection.getTransceivers()) { - if (transceiver.getSender().id().equals(rtpSenderId)) { - return transceiver; - } + if (transceiver.getSender().id().equals(rtpSenderId)) { + return transceiver; + } } return null; } diff --git a/app/src/main/java/im/conversations/android/notification/Channels.java b/app/src/main/java/im/conversations/android/notification/Channels.java index 0477838ba..3cb086e70 100644 --- a/app/src/main/java/im/conversations/android/notification/Channels.java +++ b/app/src/main/java/im/conversations/android/notification/Channels.java @@ -12,7 +12,8 @@ import im.conversations.android.R; public final class Channels { static final String CHANNEL_FOREGROUND = "foreground"; - static final String INCOMING_CALLS_NOTIFICATION_CHANNEL = "incoming_calls_channel"; + static final String CHANNEL_INCOMING_CALL = "incoming_calls_channel"; + static final String CHANNEL_ONGOING_CALL = "ongoing_call"; static final String CHANNEL_GROUP_STATUS = "status"; static final String CHANNEL_GROUP_CALLS = "calls"; private final Application application; @@ -32,9 +33,22 @@ public final class Channels { this.initializeForegroundChannel(notificationManager); this.initializeIncomingCallChannel(notificationManager); + this.initializeOngoingCallChannel(notificationManager); } } + @RequiresApi(api = Build.VERSION_CODES.O) + private void initializeOngoingCallChannel(NotificationManager notificationManager) { + final NotificationChannel ongoingCallsChannel = + new NotificationChannel( + CHANNEL_ONGOING_CALL, + application.getString(R.string.ongoing_calls_channel_name), + NotificationManager.IMPORTANCE_LOW); + ongoingCallsChannel.setShowBadge(false); + ongoingCallsChannel.setGroup(CHANNEL_GROUP_CALLS); + notificationManager.createNotificationChannel(ongoingCallsChannel); + } + @RequiresApi(api = Build.VERSION_CODES.O) private void initializeGroups(NotificationManager notificationManager) { notificationManager.createNotificationChannelGroup( @@ -67,7 +81,7 @@ public final class Channels { private void initializeIncomingCallChannel(final NotificationManager notificationManager) { final NotificationChannel incomingCallsChannel = new NotificationChannel( - INCOMING_CALLS_NOTIFICATION_CHANNEL, + CHANNEL_INCOMING_CALL, application.getString(R.string.incoming_calls_channel_name), NotificationManager.IMPORTANCE_HIGH); incomingCallsChannel.setSound(null, null); diff --git a/app/src/main/java/im/conversations/android/notification/OngoingCall.java b/app/src/main/java/im/conversations/android/notification/OngoingCall.java index 9bb5b4b85..4e34c892f 100644 --- a/app/src/main/java/im/conversations/android/notification/OngoingCall.java +++ b/app/src/main/java/im/conversations/android/notification/OngoingCall.java @@ -1,5 +1,6 @@ package im.conversations.android.notification; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection; import eu.siacs.conversations.xmpp.jingle.Media; @@ -31,4 +32,13 @@ public class OngoingCall { public int hashCode() { return Objects.hashCode(id, media, reconnecting); } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id) + .add("media", media) + .add("reconnecting", reconnecting) + .toString(); + } } diff --git a/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java b/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java index 7b6a6804f..1269862d0 100644 --- a/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java +++ b/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java @@ -15,6 +15,7 @@ import android.net.Uri; import android.os.Build; import android.os.Vibrator; import android.preference.PreferenceManager; +import android.service.notification.StatusBarNotification; import android.util.Log; import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationCompat; @@ -40,6 +41,7 @@ public class RtpSessionNotification extends AbstractNotification { private static final Logger LOGGER = LoggerFactory.getLogger(RtpSessionNotification.class); public static final int INCOMING_CALL_ID = 2; + public static final int ONGOING_CALL_ID = 3; public static final int LED_COLOR = 0xff00ff00; @@ -149,8 +151,7 @@ public class RtpSessionNotification extends AbstractNotification { fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); final NotificationCompat.Builder builder = - new NotificationCompat.Builder( - context, Channels.INCOMING_CALLS_NOTIFICATION_CHANNEL); + new NotificationCompat.Builder(context, Channels.CHANNEL_INCOMING_CALL); if (media.contains(Media.VIDEO)) { builder.setSmallIcon(R.drawable.ic_videocam_24dp); builder.setContentTitle(context.getString(R.string.rtp_state_incoming_video_call)); @@ -181,7 +182,7 @@ public class RtpSessionNotification extends AbstractNotification { R.drawable.ic_call_end_24dp, context.getString(R.string.dismiss_call), createCallAction( - id.sessionId, RtpSessionService.ACTION_DISMISS_CALL, 102)) + account, id, RtpSessionService.ACTION_REJECT_CALL, 102)) .build()); builder.addAction( new NotificationCompat.Action.Builder( @@ -199,7 +200,7 @@ public class RtpSessionNotification extends AbstractNotification { public Notification getOngoingCallNotification(final Account account, OngoingCall ongoingCall) { final AbstractJingleConnection.Id id = ongoingCall.id; final NotificationCompat.Builder builder = - new NotificationCompat.Builder(context, "ongoing_calls"); + new NotificationCompat.Builder(context, Channels.CHANNEL_ONGOING_CALL); if (ongoingCall.media.contains(Media.VIDEO)) { builder.setSmallIcon(R.drawable.ic_videocam_24dp); if (ongoingCall.reconnecting) { @@ -216,7 +217,8 @@ public class RtpSessionNotification extends AbstractNotification { } } // TODO fix me when we have a Contact model - // builder.setContentText(id.account.getRoster().getContact(id.with).getDisplayName()); + builder.setContentText( + "Contact Name"); // id.account.getRoster().getContact(id.with).getDisplayName()); builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); builder.setPriority(NotificationCompat.PRIORITY_HIGH); builder.setCategory(NotificationCompat.CATEGORY_CALL); @@ -227,11 +229,26 @@ public class RtpSessionNotification extends AbstractNotification { R.drawable.ic_call_end_24dp, context.getString(R.string.hang_up), createCallAction( - id.sessionId, RtpSessionService.ACTION_END_CALL, 104)) + account, id, RtpSessionService.ACTION_END_CALL, 104)) .build()); return builder.build(); } + public static boolean isShowingOngoingCallNotification(final Context context) { + final var notificationManager = + ContextCompat.getSystemService(context, NotificationManager.class); + if (notificationManager == null) { + return false; + } + for (final StatusBarNotification statusBarNotification : + notificationManager.getActiveNotifications()) { + if (statusBarNotification.getId() == ONGOING_CALL_ID) { + return true; + } + } + return false; + } + private PendingIntent createPendingRtpSession( final Account account, final AbstractJingleConnection.Id id, @@ -249,11 +266,14 @@ public class RtpSessionNotification extends AbstractNotification { PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); } - private PendingIntent createCallAction(String sessionId, final String action, int requestCode) { + private PendingIntent createCallAction( + Account account, AbstractJingleConnection.Id id, final String action, int requestCode) { final Intent intent = new Intent(context, RtpSessionService.class); intent.setAction(action); intent.setPackage(context.getPackageName()); - intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, sessionId); + intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, account.id); + intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId); + intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toString()); return PendingIntent.getService( context, requestCode, @@ -273,6 +293,8 @@ public class RtpSessionNotification extends AbstractNotification { public void pushMissedCallNow(CallLogTransformation message) {} + public void cancelOngoingCallNotification() {} + private class VibrationRunnable implements Runnable { @Override diff --git a/app/src/main/java/im/conversations/android/service/ForegroundService.java b/app/src/main/java/im/conversations/android/service/ForegroundService.java index 1ee86972b..a5e064e30 100644 --- a/app/src/main/java/im/conversations/android/service/ForegroundService.java +++ b/app/src/main/java/im/conversations/android/service/ForegroundService.java @@ -5,6 +5,7 @@ import android.content.Intent; import androidx.core.content.ContextCompat; import androidx.lifecycle.LifecycleService; import im.conversations.android.notification.ForegroundServiceNotification; +import im.conversations.android.notification.RtpSessionNotification; import im.conversations.android.xmpp.ConnectionPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +20,6 @@ public class ForegroundService extends LifecycleService { @Override public void onCreate() { super.onCreate(); - LOGGER.info("Creating service"); final var pool = ConnectionPool.getInstance(this); startForeground( ForegroundServiceNotification.ID, @@ -39,6 +39,14 @@ public class ForegroundService extends LifecycleService { } public static void start(final Context context) { + if (RtpSessionNotification.isShowingOngoingCallNotification(context)) { + LOGGER.info("Do not start foreground service. Ongoing call."); + return; + } + startForegroundService(context); + } + + static void startForegroundService(final Context context) { try { ContextCompat.startForegroundService( context, new Intent(context, ForegroundService.class)); @@ -46,4 +54,9 @@ public class ForegroundService extends LifecycleService { LOGGER.error("Could not start foreground service", e); } } + + public static void stop(final Context context) { + final var intent = new Intent(context, ForegroundService.class); + context.stopService(intent); + } } diff --git a/app/src/main/java/im/conversations/android/service/RtpSessionService.java b/app/src/main/java/im/conversations/android/service/RtpSessionService.java index a341f6c93..b95a536d4 100644 --- a/app/src/main/java/im/conversations/android/service/RtpSessionService.java +++ b/app/src/main/java/im/conversations/android/service/RtpSessionService.java @@ -1,16 +1,153 @@ package im.conversations.android.service; +import android.app.Service; +import android.content.Context; import android.content.Intent; +import androidx.core.content.ContextCompat; import androidx.lifecycle.LifecycleService; +import com.google.common.base.Strings; +import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection; +import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; +import im.conversations.android.notification.RtpSessionNotification; +import im.conversations.android.ui.activity.RtpSessionActivity; +import im.conversations.android.xmpp.ConnectionPool; +import im.conversations.android.xmpp.manager.JingleConnectionManager; +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class RtpSessionService extends LifecycleService { + private static final Logger LOGGER = LoggerFactory.getLogger(RtpSessionService.class); - public static final String ACTION_DISMISS_CALL = "dismiss_call"; + public static final String ACTION_REJECT_CALL = "dismiss_call"; public static final String ACTION_END_CALL = "end_call"; + public static final String ACTION_UPDATE_ONGOING_CALL = "update_ongoing_call"; + @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { - + if (intent == null) { + LOGGER.info("Intent was null"); + return Service.START_NOT_STICKY; + } + final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID); + final long accountId = intent.getLongExtra(RtpSessionActivity.EXTRA_ACCOUNT, -1); + final String with = intent.getStringExtra(RtpSessionActivity.EXTRA_WITH); + if (Strings.isNullOrEmpty(sessionId) || accountId < 0 || Strings.isNullOrEmpty(with)) { + LOGGER.warn("intent was missing mandatory extras"); + return Service.START_NOT_STICKY; + } + final String action = intent.getAction(); + switch (Strings.nullToEmpty(action)) { + case ACTION_UPDATE_ONGOING_CALL: + updateOngoingCall(accountId, JidCreate.fromOrThrowUnchecked(with), sessionId); + break; + case ACTION_REJECT_CALL: + rejectCall(accountId, JidCreate.fromOrThrowUnchecked(with), sessionId); + break; + case ACTION_END_CALL: + endCall(accountId, JidCreate.fromOrThrowUnchecked(with), sessionId); + break; + default: + LOGGER.error("Service does not know how to handle {} action", action); + } return super.onStartCommand(intent, flags, startId); } + + private void endCall(final long account, final Jid with, final String sessionId) { + final var jmc = + ConnectionPool.getInstance(this) + .getOptional(account) + .transform(xc -> xc.getManager(JingleConnectionManager.class)); + if (jmc.isPresent()) { + endCall(jmc.get(), with, sessionId); + } else { + LOGGER.error("Could not end call. JingleConnectionManager not found"); + } + } + + private void endCall( + final JingleConnectionManager jingleConnectionManager, + final Jid with, + final String sessionId) { + final var rtpConnection = jingleConnectionManager.getJingleRtpConnection(with, sessionId); + if (rtpConnection.isPresent()) { + rtpConnection.get().endCall(); + } else { + LOGGER.error("Could not end {} with {}", sessionId, with); + } + } + + private void rejectCall(long account, Jid with, String sessionId) { + final var jmc = + ConnectionPool.getInstance(this) + .getOptional(account) + .transform(xc -> xc.getManager(JingleConnectionManager.class)); + if (jmc.isPresent()) { + rejectCall(jmc.get(), with, sessionId); + } else { + LOGGER.error("Could not reject call. JingleConnectionManager not found"); + } + } + + private void rejectCall( + JingleConnectionManager jingleConnectionManager, Jid with, String sessionId) { + final var rtpConnection = jingleConnectionManager.getJingleRtpConnection(with, sessionId); + if (rtpConnection.isPresent()) { + rtpConnection.get().rejectCall(); + } else { + LOGGER.error("Could not reject call {} with {}", sessionId, with); + } + } + + private void updateOngoingCall(final long account, final Jid with, final String sessionId) { + final var jmc = + ConnectionPool.getInstance(this) + .getOptional(account) + .transform(xc -> xc.getManager(JingleConnectionManager.class)); + if (jmc.isPresent()) { + updateOngoingCall(jmc.get(), with, sessionId); + } else { + LOGGER.error("JingleConnectionManager not found for {}", account); + } + } + + private void updateOngoingCall( + final JingleConnectionManager jingleConnectionManager, + final Jid with, + final String sessionId) { + final var ongoingCall = + jingleConnectionManager + .getJingleRtpConnection(with, sessionId) + .transform(JingleRtpConnection::getOngoingCall); + if (ongoingCall.isPresent()) { + LOGGER.info("Updating notification for {}", ongoingCall.get()); + ForegroundService.stop(this); + startForeground( + RtpSessionNotification.ONGOING_CALL_ID, + jingleConnectionManager + .getNotificationService() + .getOngoingCallNotification( + jingleConnectionManager.getAccount(), ongoingCall.get())); + } else { + LOGGER.error("JingleRtpConnection not found for {}", sessionId); + } + } + + public static void updateOngoingCall( + final Context context, final long account, final AbstractJingleConnection.Id id) { + final var intent = new Intent(context, RtpSessionService.class); + intent.setAction(ACTION_UPDATE_ONGOING_CALL); + intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, account); + intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toString()); + intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId); + ContextCompat.startForegroundService(context, intent); + } + + public static void stop(final Context context) { + final var intent = new Intent(context, RtpSessionService.class); + context.stopService(intent); + ForegroundService.startForegroundService(context); + } } diff --git a/app/src/main/java/im/conversations/android/ui/activity/MainActivity.java b/app/src/main/java/im/conversations/android/ui/activity/MainActivity.java index 1f3f2942c..28a080b80 100644 --- a/app/src/main/java/im/conversations/android/ui/activity/MainActivity.java +++ b/app/src/main/java/im/conversations/android/ui/activity/MainActivity.java @@ -15,7 +15,6 @@ public class MainActivity extends BaseActivity { @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ForegroundService.start(this); final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); final ViewModelProvider viewModelProvider = @@ -33,4 +32,10 @@ public class MainActivity extends BaseActivity { }); Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); } + + @Override + public void onStart() { + super.onStart(); + ForegroundService.start(this); + } } diff --git a/app/src/main/java/im/conversations/android/ui/activity/RtpSessionActivity.java b/app/src/main/java/im/conversations/android/ui/activity/RtpSessionActivity.java index 28aef0e75..3cdee5472 100644 --- a/app/src/main/java/im/conversations/android/ui/activity/RtpSessionActivity.java +++ b/app/src/main/java/im/conversations/android/ui/activity/RtpSessionActivity.java @@ -732,7 +732,7 @@ public class RtpSessionActivity extends BaseActivity private boolean initializeActivityWithRunningRtpSession( final Account account, Jid with, String sessionId) { final WeakReference reference = - requireJingleConnectionManager().findJingleRtpConnection(with, sessionId); + requireJingleConnectionManager().getWeakJingleRtpConnection(with, sessionId); if (reference == null || reference.get() == null) { final JingleConnectionManager.TerminatedRtpSession terminatedRtpSession = requireJingleConnectionManager().getTerminalSessionState(with, sessionId); diff --git a/app/src/main/java/im/conversations/android/ui/activity/SettingsActivity.java b/app/src/main/java/im/conversations/android/ui/activity/SettingsActivity.java index 550725e4b..1849b9a1a 100644 --- a/app/src/main/java/im/conversations/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/im/conversations/android/ui/activity/SettingsActivity.java @@ -13,7 +13,6 @@ public class SettingsActivity extends BaseActivity { @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ForegroundService.start(this); final ActivitySettingsBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_settings); setSupportActionBar(binding.materialToolbar); @@ -36,4 +35,10 @@ public class SettingsActivity extends BaseActivity { } }); } + + @Override + public void onStart() { + super.onStart(); + ForegroundService.start(this); + } } diff --git a/app/src/main/java/im/conversations/android/xmpp/ConnectionPool.java b/app/src/main/java/im/conversations/android/xmpp/ConnectionPool.java index f6d426d1a..17cc9f5c2 100644 --- a/app/src/main/java/im/conversations/android/xmpp/ConnectionPool.java +++ b/app/src/main/java/im/conversations/android/xmpp/ConnectionPool.java @@ -109,6 +109,10 @@ public class ConnectionPool { reconfigurationExecutor); } + public synchronized Optional getOptional(final long id) { + return Iterables.tryFind(this.connections, c -> id == c.getAccount().id); + } + public synchronized ListenableFuture get(final long id) { final var configured = Iterables.tryFind(this.connections, c -> id == c.getAccount().id); if (configured.isPresent()) { diff --git a/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java b/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java index 4ec440d86..ad46a19a9 100644 --- a/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java +++ b/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java @@ -26,6 +26,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription; import im.conversations.android.IDs; import im.conversations.android.database.model.Account; +import im.conversations.android.notification.OngoingCall; import im.conversations.android.notification.RtpSessionNotification; import im.conversations.android.xml.Element; import im.conversations.android.xml.Namespace; @@ -522,6 +523,18 @@ public class JingleConnectionManager extends AbstractManager { return Optional.absent(); } + public OngoingCall getOngoingCall(final String sessionId) { + for (final Map.Entry entry : + this.connections.entrySet()) { + if (entry.getValue() instanceof JingleRtpConnection + && entry.getKey().sessionId.equals(sessionId)) { + final var jingleRtpConnection = (JingleRtpConnection) entry.getValue(); + return jingleRtpConnection.getOngoingCall(); + } + } + return null; + } + void finishConnection(final AbstractJingleConnection connection) { this.connections.remove(connection.getId()); } @@ -646,13 +659,21 @@ public class JingleConnectionManager extends AbstractManager { resendSessionProposals(); } - public WeakReference findJingleRtpConnection(Jid with, String sessionId) { + public WeakReference getWeakJingleRtpConnection( + Jid with, String sessionId) { + final var jingleRtpConnection = getJingleRtpConnection(with, sessionId); + return jingleRtpConnection.isPresent() + ? new WeakReference<>(jingleRtpConnection.get()) + : null; + } + + public Optional getJingleRtpConnection(Jid with, String sessionId) { final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(with, sessionId); final AbstractJingleConnection connection = connections.get(id); if (connection instanceof JingleRtpConnection) { - return new WeakReference<>((JingleRtpConnection) connection); + return Optional.of((JingleRtpConnection) connection); } - return null; + return Optional.absent(); } private void resendSessionProposals() { @@ -701,34 +722,6 @@ public class JingleConnectionManager extends AbstractManager { } } - public void rejectRtpSession(final String sessionId) { - for (final AbstractJingleConnection connection : this.connections.values()) { - if (connection.getId().sessionId.equals(sessionId)) { - if (connection instanceof JingleRtpConnection) { - try { - ((JingleRtpConnection) connection).rejectCall(); - return; - } catch (final IllegalStateException e) { - Log.w( - Config.LOGTAG, - "race condition on rejecting call from notification", - e); - } - } - } - } - } - - public void endRtpSession(final String sessionId) { - for (final AbstractJingleConnection connection : this.connections.values()) { - if (connection.getId().sessionId.equals(sessionId)) { - if (connection instanceof JingleRtpConnection) { - ((JingleRtpConnection) connection).endCall(); - } - } - } - } - public void failProceed(final Jid with, final String sessionId, final String message) { final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(with, sessionId); final AbstractJingleConnection existingJingleConnection = connections.get(id);