I'm trying to make a custom implementation of a call using TelecomManager between two users who had installed my app on their devices
Following this guide I implemented connection service, subclass of Connection, added permissions, registered a PhoneAccount and so on...
The thing I'm struggling to understand for a third week already how to place a call between users of my app without using telephone number but user name or userId.
Below code starting to make a call from my device but this call never reaches end user device
telecomManager.placeCall(Uri.fromParts(/*tried also with PhoneAccount.SCHEME_SIP and PhoneAccount.SCHEME_TEL*/
TripmateConnectionService.SCHEME_AG, "userId", null), extras)
Need to mention, that in my BroadcastReceiver implementation I can detect incoming calls from other apps, so it's seems that I handling call detection correct and the call from above code is never really send to device of the user it was intended to.
Now is the question. I feel like I missing something vital. How exactly do devices with same app can communicate to each other without phone number? Does it really enough just to pass a user name to a telecomManager.placeCall and it should somehow manage to find right device with installed app and make a call to it? How can telecomManager distinguish where to make a call?
Sorry for unclear question, it's my first time doing something related to calls and I feel I luck understanding of the subject and it hard to make a question more concrete because I don't exactly know what am I missing.
I will put below some code I'm using now
Start an outgoing call
private fun placeSystemCall(myUid: String, peerUid: String, channel: String, role: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val extras = Bundle()
extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, VideoProfile.STATE_BIDIRECTIONAL)
val extraBundle = Bundle()
extraBundle.putString(Constants.CS_KEY_UID, myUid)
extraBundle.putString(Constants.CS_KEY_SUBSCRIBER, peerUid)
extraBundle.putString(Constants.CS_KEY_CHANNEL, channel)
extraBundle.putInt(Constants.CS_KEY_ROLE, Constants.CALL_ID_OUT)
extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extraBundle)
try {
val telecomManager = applicationContext.getSystemService(TELECOM_SERVICE) as TelecomManager
val pa: PhoneAccount = telecomManager.getPhoneAccount(
config().phoneAccountOut?.accountHandle)
extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, pa.accountHandle)
telecomManager.placeCall(Uri.fromParts(
TripmateConnectionService.SCHEME_AG, peerUid, null), extras)
} catch (e: SecurityException) {
e.printStackTrace()
}
}
}
In ConnectionService
override fun onCreateOutgoingConnection(phoneAccount: PhoneAccountHandle?, request: ConnectionRequest): Connection {
Log.i(TAG, "onCreateOutgoingConnection: called. $phoneAccount $request")
val extras = request.extras
val uid = extras.getString(Constants.CS_KEY_UID) ?: "0"
val channel = extras.getString(Constants.CS_KEY_CHANNEL) ?: "0"
val subscriber = extras.getString(Constants.CS_KEY_SUBSCRIBER) ?: "0"
val role = extras.getInt(Constants.CS_KEY_ROLE)
val videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE)
val connection = TripmateConnection(applicationContext, uid, channel, subscriber, role)
connection.setVideoState(videoState)
connection.setAddress(Uri.fromParts(SCHEME_AG, subscriber, null), TelecomManager.PRESENTATION_ALLOWED)
connection.setCallerDisplayName(subscriber, TelecomManager.PRESENTATION_ALLOWED)
connection.setRinging()
TMApplication.getInstance().config().setConnection(connection)
return connection
}
creating PhoneAccounts
private fun registerPhoneAccount(context: Context) {
val telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as? TelecomManager
?: throw RuntimeException("cannot obtain telecom system service")
val accountHandleIn = PhoneAccountHandle(
ComponentName(context, TripmateConnectionService::class.java), Constants.PA_LABEL_CALL_IN)
val accountHandleOut = PhoneAccountHandle(
ComponentName(context, TripmateConnectionService::class.java), Constants.PA_LABEL_CALL_OUT)
try {
var paBuilder: PhoneAccount.Builder = PhoneAccount.builder(accountHandleIn, Constants.PA_LABEL_CALL_IN)
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
val phoneIn = paBuilder.build()
paBuilder = PhoneAccount.builder(accountHandleOut, Constants.PA_LABEL_CALL_OUT)
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
val extra = Bundle()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
extra.putBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, true)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
paBuilder.setExtras(extra)
}
val phoneOut = paBuilder.build()
telecomManager.registerPhoneAccount(phoneIn)
telecomManager.registerPhoneAccount(phoneOut)
if (telecomManager.getPhoneAccount(phoneIn.accountHandle) == null || telecomManager.getPhoneAccount(phoneOut.accountHandle) == null) {
throw RuntimeException("cannot create account");
}
mCallSession = TripmateCallSession()
mCallSession?.phoneAccountIn = phoneIn
mCallSession?.phoneAccountOut = phoneOut
} catch (e: SecurityException) {
throw RuntimeException("cannot create account", e);
}
}
Thank you for your time! Any suggestions and links that could help me to understand more will be highly appreciated!