How to have the caller ID displayed on a smartwatch call notification using the ConnectionService API?

1.4k Views Asked by At

I have a problem integrating a VoIP application with Android smartwatch (any model). Our app uses Android ConnectionService API. The caller name is not displayed at the watch's incoming call notification - it simply writes "Unknown" or the caller id (4-digit extension), never the actual app contact name (app contact, not device contact). However, regular GSM calls are properly displayed (it resolves against the contact name) and also, if someone from my device contacts calls me, their name & avatar are being displayed correctly.

To assign the name I'm using android.telecom.Connection.setCallerDisplayName(displayName, TelecomManager.PRESENTATION_ALLOWED), but to no avail.

1

There are 1 best solutions below

1
On

I had the same exact issue with Samsung Gear smartwatch. You see "Unknown" because the caller's name is resolved against device contacts (hence regular GSM calls work as expected). The solution is following:

  1. I assume that you know the displayName (caller's name) and address (caller's phone number). The address is the Uri which might look like sip:1234567 or tel:+1234567, it doesn't really matter.
  2. You need to create a temporary contact with your caller's displayName and phoneNumber. The phoneNumber here should be Uri.schemeSpecificPart of the address (the part after :). The avatar/icon can also be added.
ContentProviderOperation.newInsert(Data.CONTENT_URI)
                        .withValueBackReference(Data.RAW_CONTACT_ID, 0)
                        .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
                        .withValue(StructuredName.GIVEN_NAME, displayName)
                        .build()
ContentProviderOperation.newInsert(Data.CONTENT_URI)
                        .withValueBackReference(Data.RAW_CONTACT_ID, 0)
                        .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                        .withValue(Phone.NUMBER, phoneNumber)
                        .build()
  1. After adding this contact you need to let ConnectionService know that there is now a contact that corresponds to the Connection you created for your VoIP call. contactManager is my class where aforementioned operations are executed, accountHandle is a android.telecom.AccountHandle that is used to register PhoneAccount (via telecomManager.registerPhoneAccount()), address is our Uri with phone number.
contactManager.createOrUpdateTempContact(address.schemeSpecificPart, displayName)

telecomManager.addNewIncomingCall(accountHandle, bundleOf("key.call.address" to address))
  1. After calling addNewIncomingCall the ConnectionService::onCreateIncomingConnection() callback will be triggered, and in this function you should set the address:
override fun onCreateIncomingConnection(
    connectionManagerPhoneAccount: PhoneAccountHandle?, 
    request: ConnectionRequest?
): Connection {

    val newConnection = // Instantiate your Connection class implementation

    request?.let{
        newConnection.setAddress(request.extras.getParcelable("key.call.address") as? Uri, TelecomManager.PRESENTATION_ALLOWED)
        newConnection.extras = request.extras
    }

    // Setting up newConnection further (set audioModeIsVoip, connectionProperties, etc.)

    return newConnection
}
  1. You can safely remove the temp contact after the call was answered/rejected.

N.B.

  • I omitted posting the whole create/update/delete temp contact code for brevity.
  • ConnectionRequest.address returns null for me in onCreateIncomingConnection(), that's why I pass it in extras.
  • I played with setCallerDisplayName() function and the common sense says that it should be there, but the fix was not related to it.
  • In my experience sometimes the incoming call UI on the smartwatch shows phone number first and only after few seconds the name of the contact is displayed. I still didn't manage to fix this delay.