4

I am trying to implement a basic dialer app, which should also handle incoming calls. The scenario is that the user sets the app as default dialer, and from then, every incoming and outgoing call should arrive in the app's ConnectionService implementation.

I don't want to override the built-in call UI, I just need to add some extra logic to the Connection callbacks. For example I want to send a broadcast intent, when a Conenction is answered, etc.

Based on this documentation, I figured I should implement a system-managed ConnectionService.

I have implemented the ConnectionService the following way, and it works well, the callbacks are called in case of an incoming or outgoing call:

public class DialerConnectionService extends ConnectionService {

NotificationManagerUtil notificationManager;

public DialerConnectionService() {
    notificationManager = NotificationManagerUtil.getInstance();
}

@Override
public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
    return createConnection(request, false);
}

@Override
public void onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
    notificationManager.createToast(getApplicationContext(), getString(R.string.error_place_outgoing_call));
}

@Override
public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
    return createConnection(request, true);
}

@Override
public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
    notificationManager.createToast(getApplicationContext(), getString(R.string.error_create_incoming_call));
}

private TelecomConnection createConnection(ConnectionRequest request, boolean isIncoming) {
    TelecomConnection connection = new TelecomConnection(getApplicationContext(), isIncoming);
    connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED);
    connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
    String normalizedPhoneNumber = ContactsUtil.getInstance().normalizePhoneNumberFromUri(request.getAddress());
    connection.setNormalizedPhoneNumber(normalizedPhoneNumber);
    connection.setCallerDisplayName(ContactsUtil.getInstance().getContactName(getApplicationContext(), normalizedPhoneNumber), TelecomManager.PRESENTATION_ALLOWED);
    connection.setExtras(request.getExtras());
    if (isIncoming) {
        connection.setRinging();
    } else {
        connection.setDialing();
    }
    connection.setInitializing();
    CallManager.getInstance().addConnection(connection);
    return connection;
}


}

The problem is, that in case I register a PhoneAccount with capabilities of PhoneAccount.CAPABILITY_CONNECTION_MANAGER, the created calls do not become - for lack of a better word - active, but the Connection's callbacks are properly called. So I can initiate an outgoing call, but the other phone will never get the notification for an incoming call. Or if I start a call from the other phone, the device running my app will step into its onCreateIncomingConnection() method, and I will be able to answer that call, but the initiating phone will still be dialing.

I have registered the PhoneAccount the folowing way, and I suspect, that the problem lies somewhere here:

public boolean checkAccountHandler(Context ctx) {
    PhoneAccountHandle phoneAccountHandle = getPhoneAccountHandle(ctx);
    telecomManager = (TelecomManager) ctx.getSystemService(Context.TELECOM_SERVICE);

    PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
    if (phoneAccount == null){
        PhoneAccount account = PhoneAccount.builder(phoneAccountHandle, PHONE_ACCOUNT_LABEL)
                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
                .build();
        telecomManager.registerPhoneAccount(account);
        return false;
    }
    return true;
}

This way the registrated account does not appear in android's settings, so I cannot make the user enable it. Is there a chance, that this is the main cause of the problem?

My manifest uses the following permissions:

<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

And here is the registration of the acctivity and the ConnectionService implementation:

<activity
        android:name=".activity.MainActivity"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <action android:name="android.intent.action.DIAL" />

            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />

            <data android:scheme="tel" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.DIAL" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
</activity>
<service
     android:name=".service.DialerConnectionService"
     android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
     <intent-filter>
     <action android:name="android.telecom.ConnectionService" />
     </intent-filter>
 </service>
halfer
  • 19,824
  • 17
  • 99
  • 186
apropovics
  • 41
  • 4

1 Answers1

0
Bundle extras = new Bundle();
extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, telecomManager.getUserSelectedOutgoingPhoneAccount());//This is the most important thing
telecomManager.placeCall(uri,extras);
mate00
  • 2,727
  • 5
  • 26
  • 34
  • extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, telecomManager.getUserSelectedOutgoingPhoneAccount());//Using this before PlaceCall(); – flyzhangyx Jul 17 '20 at 08:55