Ask user for microphone permission from dialler integration

Stephen Paul Weber created

We can't ask them for it directly.  The library I am using here will first check
if the permission is already granted.  If so onPermissionGranted will fire and
we will start the call.  If not, the Connection will be created in a dialling
state and a notification will appear saying that the app needs additional
permissions.

Once the user taps the notification they will then be asked to allow microphone
access.  If they say yes, the call will proceed.  If they deny, the call will terminate.

Change summary

build.gradle                                                  |  1 
src/cheogram/java/com/cheogram/android/ConnectionService.java | 44 +++-
2 files changed, 35 insertions(+), 10 deletions(-)

Detailed changes

build.gradle 🔗

@@ -91,6 +91,7 @@ dependencies {
 
     implementation 'com.google.guava:guava:30.1.1-android'
     implementation 'io.michaelrocks:libphonenumber-android:8.12.36'
+    implementation 'io.github.nishkarsh:android-permissions:2.0.54'
     implementation urlFile('https://cloudflare-ipfs.com/ipfs/QmeqMiLxHi8AAjXobxr3QTfa1bSSLyAu86YviAqQnjxCjM/libwebrtc.aar', 'libwebrtc.aar')
     // INSERT
 }

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

@@ -2,6 +2,7 @@ package com.cheogram.android;
 
 import java.lang.ref.WeakReference;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 import java.util.Stack;
 
@@ -17,9 +18,12 @@ import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
 
+import android.Manifest;
+import androidx.core.content.ContextCompat;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.ServiceConnection;
 import android.net.Uri;
 import android.os.Bundle;
@@ -27,6 +31,9 @@ import android.os.IBinder;
 import android.os.Parcel;
 import android.util.Log;
 
+import com.intentfilter.androidpermissions.PermissionManager;
+import com.intentfilter.androidpermissions.models.DeniedPermissions;
+
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.services.AppRTCAudioManager;
 import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
@@ -96,13 +103,27 @@ public class ConnectionService extends android.telecom.ConnectionService {
 
 		Account account = xmppConnectionService.findAccountByJid(Jid.of(gateway[0]));
 		Jid with = Jid.ofLocalAndDomain(tel, gateway[1]);
-		String sessionId = xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(
-			account,
-			with,
-			ImmutableSet.of(Media.AUDIO)
-		);
+		CheogramConnection connection = new CheogramConnection(account, with, postDial);
+
+		PermissionManager permissionManager = PermissionManager.getInstance(this);
+		Set<String> permissions = new HashSet();
+		permissions.add(Manifest.permission.RECORD_AUDIO);
+		permissionManager.checkPermissions(permissions, new PermissionManager.PermissionRequestListener() {
+			@Override
+			public void onPermissionGranted() {
+				connection.setSessionId(xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(
+					account,
+					with,
+					ImmutableSet.of(Media.AUDIO)
+				));
+			}
+
+			@Override
+			public void onPermissionDenied(DeniedPermissions deniedPermissions) {
+				connection.setDisconnected(new DisconnectCause(DisconnectCause.ERROR));
+			}
+		});
 
-		Connection connection = new CheogramConnection(account, with, sessionId, postDial);
 		connection.setAddress(
 			Uri.fromParts("tel", tel, null), // Normalized tel as tel: URI
 			TelecomManager.PRESENTATION_ALLOWED
@@ -128,15 +149,14 @@ public class ConnectionService extends android.telecom.ConnectionService {
 	public class CheogramConnection extends Connection implements XmppConnectionService.OnJingleRtpConnectionUpdate {
 		protected Account account;
 		protected Jid with;
-		protected String sessionId;
+		protected String sessionId = null;
 		protected Stack<String> postDial = new Stack();
 		protected WeakReference<JingleRtpConnection> rtpConnection = null;
 
-		CheogramConnection(Account account, Jid with, String sessionId, String postDialString) {
+		CheogramConnection(Account account, Jid with, String postDialString) {
 			super();
 			this.account = account;
 			this.with = with;
-			this.sessionId = sessionId;
 
 			if (postDialString != null) {
 				for (int i = postDialString.length() - 1; i >= 0; i--) {
@@ -145,9 +165,13 @@ public class ConnectionService extends android.telecom.ConnectionService {
 			}
 		}
 
+		public void setSessionId(final String sessionId) {
+			this.sessionId = sessionId;
+		}
+
 		@Override
 		public void onJingleRtpConnectionUpdate(final Account account, final Jid with, final String sessionId, final RtpEndUserState state) {
-			if (!sessionId.equals(this.sessionId)) return;
+			if (sessionId == null || !sessionId.equals(this.sessionId)) return;
 			if (rtpConnection == null) {
 				this.with = with; // Store full JID of connection
 				rtpConnection = xmppConnectionService.getJingleConnectionManager().findJingleRtpConnection(account, with, sessionId);