Offer to setup dialler integration when relevant

Stephen Paul Weber created

Rather than wait for the user to find the setting.

Change summary

src/cheogram/java/eu/siacs/conversations/ui/WelcomeActivity.java   |  2 
src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java | 73 
2 files changed, 74 insertions(+), 1 deletion(-)

Detailed changes

src/cheogram/java/eu/siacs/conversations/ui/WelcomeActivity.java 🔗

@@ -19,6 +19,7 @@ import androidx.databinding.DataBindingUtil;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.HashSet;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
@@ -118,6 +119,7 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         }
         super.onCreate(savedInstanceState);
+        getPreferences().edit().putStringSet("pstn_gateways", new HashSet<>()).apply();
         ActivityWelcomeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_welcome);
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar(), false);

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

@@ -32,16 +32,19 @@ package eu.siacs.conversations.ui;
 
 import static eu.siacs.conversations.ui.ConversationFragment.REQUEST_DECRYPT_PGP;
 
+import android.Manifest;
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.util.Log;
@@ -60,6 +63,8 @@ import org.openintents.openpgp.util.OpenPgpApi;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import eu.siacs.conversations.Config;
@@ -110,6 +115,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
 
     public static final int REQUEST_OPEN_MESSAGE = 0x9876;
     public static final int REQUEST_PLAY_PAUSE = 0x5432;
+    public static final int REQUEST_MICROPHONE = 0x5432f;
+    public static final int DIALLER_INTEGRATION = 0x5432ff;
 
 
     //secondary fragment (when holding the conversation, must be initialized before refreshing the overview fragment
@@ -121,6 +128,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     private boolean mActivityPaused = true;
     private final AtomicBoolean mRedirectInProcess = new AtomicBoolean(false);
     private boolean refreshForNewCaps = false;
+    private int mRequestCode = -1;
 
     private static boolean isViewOrShareIntent(Intent i) {
         Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction()));
@@ -211,7 +219,9 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
             if (ExceptionHelper.checkForCrash(this)) {
                 return;
             }
-            openBatteryOptimizationDialogIfNeeded();
+            if (!offerToSetupDiallerIntegration()) {
+                openBatteryOptimizationDialogIfNeeded();
+            }
         }
     }
 
@@ -248,6 +258,54 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
         }
     }
 
+    private boolean offerToSetupDiallerIntegration() {
+        if (mRequestCode == DIALLER_INTEGRATION) {
+            mRequestCode = -1;
+            return true;
+        }
+        if (Build.VERSION.SDK_INT < 23) return false;
+        if (Build.VERSION.SDK_INT >= 33) {
+            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELECOM)) return false;
+        } else {
+            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)) return false;
+        }
+
+        Set<String> pstnGateways = new HashSet<>();
+        for (Account account : xmppConnectionService.getAccounts()) {
+            for (Contact contact : account.getRoster().getContacts()) {
+                if (contact.getPresences().anyIdentity("gateway", "pstn")) {
+                    pstnGateways.add(contact.getJid().asBareJid().toEscapedString());
+                }
+            }
+        }
+
+        if (pstnGateways.size() < 1) return false;
+        Set<String> fromPrefs = getPreferences().getStringSet("pstn_gateways", Set.of("UPGRADE"));
+        getPreferences().edit().putStringSet("pstn_gateways", pstnGateways).apply();
+        pstnGateways.removeAll(fromPrefs);
+        if (pstnGateways.size() < 1) return false;
+
+        if (fromPrefs.contains("UPGRADE")) return false;
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle("Dialler Integration");
+        builder.setMessage("Cheogram Android is able to integrate with your system's dialler app to allow dialling calls via your configured gateway " + String.join(", ", pstnGateways) + ".\n\nEnabling this integration will require granting microphone permission to the app.  Would you like to enable it now?");
+        builder.setPositiveButton(R.string.yes, (dialog, which) -> {
+            final String[] permissions;
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                permissions = new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.BLUETOOTH_CONNECT};
+            } else {
+                permissions = new String[]{Manifest.permission.RECORD_AUDIO};
+            }
+            requestPermissions(permissions, REQUEST_MICROPHONE);
+        });
+        builder.setNegativeButton(R.string.no, (dialog, which) -> { });
+        final AlertDialog dialog = builder.create();
+        dialog.setCanceledOnTouchOutside(false);
+        dialog.show();
+        return true;
+    }
+
     private void notifyFragmentOfBackendConnected(@IdRes int id) {
         final Fragment fragment = getFragmentManager().findFragmentById(id);
         if (fragment instanceof OnBackendConnected) {
@@ -288,6 +346,12 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
                     case REQUEST_PLAY_PAUSE:
                         ConversationFragment.startStopPending(this);
                         break;
+                    case REQUEST_MICROPHONE:
+                        Intent intent = new Intent();
+                        intent.setComponent(new ComponentName("com.android.server.telecom",
+                            "com.android.server.telecom.settings.EnableAccountPreferenceActivity"));
+                        startActivityForResult(intent, DIALLER_INTEGRATION);
+                        break;
                 }
             }
         }
@@ -296,6 +360,13 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     @Override
     public void onActivityResult(int requestCode, int resultCode, final Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
+
+        if (requestCode == DIALLER_INTEGRATION) {
+            mRequestCode = requestCode;
+            startActivity(new Intent(android.telecom.TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS));
+            return;
+        }
+
         ActivityResult activityResult = ActivityResult.of(requestCode, resultCode, data);
         if (xmppConnectionService != null) {
             handleActivityResult(activityResult);