use foreground service for ongoing call notification

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/NotificationService.java    | 12 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java  | 36 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java |  4 
3 files changed, 38 insertions(+), 14 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/NotificationService.java 🔗

@@ -76,7 +76,7 @@ public class NotificationService {
     private static final int NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 2;
     private static final int ERROR_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 6;
     private static final int INCOMING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 8;
-    private static final int ONGOING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 10;
+    public static final int ONGOING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 10;
     private final XmppConnectionService mXmppConnectionService;
     private final LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<>();
     private final HashMap<Conversation, AtomicInteger> mBacklogMessageCounter = new HashMap<>();
@@ -362,10 +362,10 @@ public class NotificationService {
                 .build());
         final Notification notification = builder.build();
         notification.flags = notification.flags | Notification.FLAG_INSISTENT;
-        notify(INCOMING_CALL_NOTIFICATION_ID, builder.build());
+        notify(INCOMING_CALL_NOTIFICATION_ID, notification);
     }
 
-    public void showOngoingCallNotification(final AbstractJingleConnection.Id id) {
+    public Notification getOngoingCallNotification(final AbstractJingleConnection.Id id) {
         final NotificationCompat.Builder builder = new NotificationCompat.Builder(mXmppConnectionService, "ongoing_calls");
         builder.setSmallIcon(R.drawable.ic_call_white_24dp);
         builder.setContentTitle(mXmppConnectionService.getString(R.string.ongoing_call));
@@ -380,9 +380,7 @@ public class NotificationService {
                 mXmppConnectionService.getString(R.string.hang_up),
                 createCallAction(id.sessionId, XmppConnectionService.ACTION_END_CALL, 104))
                 .build());
-        final Notification notification = builder.build();
-        notification.flags = notification.flags | Notification.FLAG_INSISTENT;
-        notify(ONGOING_CALL_NOTIFICATION_ID, builder.build());
+        return builder.build();
     }
 
     private PendingIntent createPendingRtpSession(final AbstractJingleConnection.Id id, final String action, final int requestCode) {
@@ -1129,7 +1127,7 @@ public class NotificationService {
         }
     }
 
-    private void cancel(int id) {
+    public void cancel(int id) {
         final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mXmppConnectionService);
         try {
             notificationManager.cancel(id);

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -71,6 +71,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
@@ -142,6 +143,7 @@ import eu.siacs.conversations.xmpp.Patches;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import eu.siacs.conversations.xmpp.chatstate.ChatState;
 import eu.siacs.conversations.xmpp.forms.Data;
+import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
 import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
 import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived;
 import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
@@ -209,6 +211,7 @@ public class XmppConnectionService extends Service {
     private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false);
     private AtomicBoolean mForceForegroundService = new AtomicBoolean(false);
     private AtomicBoolean mForceDuringOnCreate = new AtomicBoolean(false);
+    private AtomicReference<AbstractJingleConnection.Id> ongoingCall = new AtomicReference<>();
     private OnMessagePacketReceived mMessageParser = new MessageParser(this);
     private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
     private IqParser mIqParser = new IqParser(this);
@@ -1227,11 +1230,31 @@ public class XmppConnectionService extends Service {
         toggleForegroundService(false);
     }
 
+    public void setOngoingCall(AbstractJingleConnection.Id id) {
+        ongoingCall.set(id);
+        toggleForegroundService(false);
+    }
+
+    public void removeOngoingCall(AbstractJingleConnection.Id id) {
+        if (ongoingCall.compareAndSet(id, null)) {
+            toggleForegroundService(false);
+        }
+    }
+
     private void toggleForegroundService(boolean force) {
         final boolean status;
-        if (force || mForceDuringOnCreate.get() || mForceForegroundService.get() || (Compatibility.keepForegroundService(this) && hasEnabledAccounts())) {
-            final Notification notification = this.mNotificationService.createForegroundNotification();
-            startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, notification);
+        final AbstractJingleConnection.Id ongoing = ongoingCall.get();
+        if (force || mForceDuringOnCreate.get() || mForceForegroundService.get() || ongoing != null || (Compatibility.keepForegroundService(this) && hasEnabledAccounts())) {
+            final Notification notification;
+            if (ongoing != null) {
+                notification = this.mNotificationService.getOngoingCallNotification(ongoing);
+                startForeground(NotificationService.ONGOING_CALL_NOTIFICATION_ID, notification);
+                mNotificationService.cancel(NotificationService.FOREGROUND_NOTIFICATION_ID);
+            } else {
+                notification = this.mNotificationService.createForegroundNotification();
+                startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, notification);
+            }
+
             if (!mForceForegroundService.get()) {
                 mNotificationService.notify(NotificationService.FOREGROUND_NOTIFICATION_ID, notification);
             }
@@ -1241,7 +1264,10 @@ public class XmppConnectionService extends Service {
             status = false;
         }
         if (!mForceForegroundService.get()) {
-            mNotificationService.dismissForcedForegroundNotification(); //if the channel was changed the previous call might fail
+            mNotificationService.cancel(NotificationService.FOREGROUND_NOTIFICATION_ID);
+        }
+        if (ongoing == null) {
+            mNotificationService.cancel(NotificationService.ONGOING_CALL_NOTIFICATION_ID);
         }
         Log.d(Config.LOGTAG, "ForegroundService: " + (status ? "on" : "off"));
     }
@@ -1253,7 +1279,7 @@ public class XmppConnectionService extends Service {
     @Override
     public void onTaskRemoved(final Intent rootIntent) {
         super.onTaskRemoved(rootIntent);
-        if ((Compatibility.keepForegroundService(this) && hasEnabledAccounts()) || mForceForegroundService.get()) {
+        if ((Compatibility.keepForegroundService(this) && hasEnabledAccounts()) || mForceForegroundService.get() || ongoingCall.get() != null) {
             Log.d(Config.LOGTAG, "ignoring onTaskRemoved because foreground service is activated");
         } else {
             this.logoutAndSave(false);

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

@@ -772,9 +772,9 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 
     private void updateOngoingCallNotification() {
         if (STATES_SHOWING_ONGOING_CALL.contains(this.state)) {
-            xmppConnectionService.getNotificationService().showOngoingCallNotification(id);
+            xmppConnectionService.setOngoingCall(id);
         } else {
-            xmppConnectionService.getNotificationService().cancelOngoingCallNotification();
+            xmppConnectionService.removeOngoingCall(id);
         }
     }