Better cooperation between call integration and dialler integration

Stephen Paul Weber created

Change summary

src/cheogram/java/com/cheogram/android/ConnectionService.java                       | 10 
src/main/java/eu/siacs/conversations/services/CallIntegrationConnectionService.java | 46 
src/main/java/eu/siacs/conversations/services/NotificationService.java              | 74 
3 files changed, 57 insertions(+), 73 deletions(-)

Detailed changes

src/cheogram/java/com/cheogram/android/ConnectionService.java 🔗

@@ -46,6 +46,7 @@ import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.services.CallIntegration;
+import eu.siacs.conversations.services.CallIntegrationConnectionService;
 import eu.siacs.conversations.services.AvatarService;
 import eu.siacs.conversations.services.EventReceiver;
 import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
@@ -179,10 +180,11 @@ public class ConnectionService extends android.telecom.ConnectionService {
 
 	@Override
 	public Connection onCreateIncomingConnection(PhoneAccountHandle handle, ConnectionRequest request) {
-		Bundle extras = request.getExtras();
-		String accountJid = extras.getString("account");
-		String withJid = extras.getString("with");
-		String sessionId = extras.getString("sessionId");
+		final var extras = request.getExtras();
+		final var extraExtras = extras.getBundle(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
+		final var accountJid = extraExtras == null ? null : extraExtras.getString("account");
+		final var withJid = extraExtras == null ? null : extraExtras.getString("with");
+		final String sessionId = extraExtras == null ? null : extraExtras.getString(CallIntegrationConnectionService.EXTRA_SESSION_ID);
 
 		if (xmppConnectionService == null) {
 			return Connection.createFailedConnection(

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

@@ -10,6 +10,7 @@ import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.preference.PreferenceManager;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
 import android.telecom.ConnectionService;
@@ -54,7 +55,7 @@ import java.util.concurrent.TimeoutException;
 public class CallIntegrationConnectionService extends ConnectionService {
 
     private static final String EXTRA_ADDRESS = "eu.siacs.conversations.address";
-    private static final String EXTRA_SESSION_ID = "eu.siacs.conversations.sid";
+    public static final String EXTRA_SESSION_ID = "eu.siacs.conversations.sid";
 
     private static final ExecutorService ACCOUNT_REGISTRATION_EXECUTOR =
             Executors.newSingleThreadExecutor();
@@ -381,8 +382,46 @@ public class CallIntegrationConnectionService extends ConnectionService {
         }
     }
 
+    private static PhoneAccountHandle findPhoneAccount(final Context context, final AbstractJingleConnection.Id id) {
+        final var def = CallIntegrationConnectionService.getHandle(context, id.account);
+        if (Build.VERSION.SDK_INT < 23) return def;
+
+        final var prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        if (!prefs.getBoolean("dialler_integration_incoming", true)) return def;
+
+        if (context.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
+            // We cannot request audio permission in Dialer UI
+            // when Dialer is shown over keyguard, the user cannot even necessarily
+            // see notifications.
+            return def;
+        }
+
+        /* Are video calls really coming in from a PSTN gateway?
+        if (media.size() != 1 || !media.contains(Media.AUDIO)) {
+            // Currently our ConnectionService only handles single audio calls
+            Log.w(Config.LOGTAG, "only audio calls can be handled by cheogram connection service");
+            return def;
+        }*/
+
+        for (Contact contact : id.account.getRoster().getContacts()) {
+            if (!contact.getJid().getDomain().equals(id.with.getDomain())) {
+                continue;
+            }
+
+            if (!contact.getPresences().anyIdentity("gateway", "pstn")) {
+                continue;
+            }
+
+            final var handle = contact.phoneAccountHandle();
+            if (handle != null) return handle;
+        }
+
+        return def;
+    }
+
     public static boolean addNewIncomingCall(
             final Context context, final AbstractJingleConnection.Id id) {
+        if (NotificationService.isQuietHours(context, id.getContact().getAccount())) return false;
         if (CallIntegration.notSelfManaged(context)) {
             Log.d(
                     Config.LOGTAG,
@@ -393,14 +432,15 @@ public class CallIntegrationConnectionService extends ConnectionService {
                             + ")");
             return true;
         }
-        final var phoneAccountHandle =
-                CallIntegrationConnectionService.getHandle(context, id.account);
+        final var phoneAccountHandle = findPhoneAccount(context, id);
         final var bundle = new Bundle();
         bundle.putString(
                 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
                 CallIntegration.address(id.with).toString());
         final var extras = new Bundle();
         extras.putString(EXTRA_SESSION_ID, id.sessionId);
+        extras.putString("account", id.account.getJid().toString());
+        extras.putString("with", id.with.toString());
         bundle.putBundle(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
         try {
             context.getSystemService(TelecomManager.class)

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

@@ -405,14 +405,16 @@ public class NotificationService {
     }
 
     private boolean isQuietHours(Account account) {
-        if (mXmppConnectionService.getAccounts().size() < 2) account = null;
-        final String suffix = account == null ? "" : ":" + account.getUuid();
-        if (!mXmppConnectionService.getBooleanPreference(
-                "enable_quiet_hours" + suffix, R.bool.enable_quiet_hours)) {
+        return isQuietHours(mXmppConnectionService, account);
+    }
+
+    public static boolean isQuietHours(Context context, Account account) {
+        // if (mXmppConnectionService.getAccounts().size() < 2) account = null;
+        final var suffix = account == null ? "" : ":" + account.getUuid();
+        final var preferences = PreferenceManager.getDefaultSharedPreferences(context);
+        if (!preferences.getBoolean("enable_quiet_hours" + suffix, context.getResources().getBoolean(R.bool.enable_quiet_hours))) {
             return false;
         }
-        final SharedPreferences preferences =
-                PreferenceManager.getDefaultSharedPreferences(mXmppConnectionService);
         final long startTime =
                 TimePreference.minutesToTimestamp(
                         preferences.getLong("quiet_hours_start" + suffix, TimePreference.DEFAULT_VALUE));
@@ -580,69 +582,9 @@ public class NotificationService {
         notify(DELIVERY_FAILED_NOTIFICATION_ID, summaryNotification);
     }
 
-    private synchronized boolean tryRingingWithDialerUI(final AbstractJingleConnection.Id id, final Set<Media> media) {
-        if (Build.VERSION.SDK_INT < 23) return false;
-
-        if (!mXmppConnectionService.getPreferences().getBoolean("dialler_integration_incoming", true)) return false;
-
-        if (mXmppConnectionService.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
-            // We cannot request audio permission in Dialer UI
-            // when Dialer is shown over keyguard, the user cannot even necessarily
-            // see notifications.
-            return false;
-        }
-
-        if (media.size() != 1 || !media.contains(Media.AUDIO)) {
-            // Currently our ConnectionService only handles single audio calls
-            Log.w(Config.LOGTAG, "only audio calls can be handled by cheogram connection service");
-            return false;
-        }
-
-        PhoneAccountHandle handle = null;
-        for (Contact contact : id.account.getRoster().getContacts()) {
-            if (!contact.getJid().getDomain().equals(id.with.getDomain())) {
-                continue;
-            }
-
-            if (!contact.getPresences().anyIdentity("gateway", "pstn")) {
-                continue;
-            }
-
-            handle = contact.phoneAccountHandle();
-            break;
-        }
-
-        if (handle == null) {
-            Log.w(Config.LOGTAG, "Could not find phone account handle for " + id.account.getJid().toString());
-            return false;
-        }
-
-        Bundle callInfo = new Bundle();
-        callInfo.putString("account", id.account.getJid().toString());
-        callInfo.putString("with", id.with.toString());
-        callInfo.putString("sessionId", id.sessionId);
-
-        TelecomManager telecomManager = mXmppConnectionService.getSystemService(TelecomManager.class);
-
-        try {
-            telecomManager.addNewIncomingCall(handle, callInfo);
-        } catch (SecurityException e) {
-            // If the account is not registered or enabled, it could result in a security exception
-            // Just fall back to the built-in UI in this case.
-            Log.w(Config.LOGTAG, e);
-            return false;
-        }
-
-        return true;
-    }
-
     public synchronized void startRinging(final AbstractJingleConnection.Id id, final Set<Media> media) {
         if (isQuietHours(id.getContact().getAccount())) return;
 
-        if (tryRingingWithDialerUI(id, media)) {
-            return;
-        }
-
         showIncomingCallNotification(id, media, false);
     }