15

I'm trying to make a new PhoneAccount to use my implementation of ConnectionService. In the documentation it says I need to register a new PhoneAccount with TelecomManager and then select it in my phone-app's settings.

Here's my code:

TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);

ComponentName componentName = newComponentName("se.example.connectionservicestandalonetest", "se.example.connectionservicestandalonetest.MyConnectionService");
PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(componentName, "Admin");
PhoneAccount phoneAccount = PhoneAccount.builder(phoneAccountHandle, "Admin").build();

telecomManager.registerPhoneAccount(phoneAccount);

As you can see, it creates a new ComponentName that points towards my implementation of ConnectionService, then creates a new PhoneAccountHandle where I supply the ComponentName and a unique account-name. I then supply the PhoneAccountHandle in the PhoneAccount buildes, as well as label (a name?), to create a new PhoneAccount. Lastly I register the account in the telecomManager.

When I open up the phone app, nothing has changed. I see no where I could possibly change the PhoneAccount... Any ideas?

Thanks!

ProfessorChaos
  • 201
  • 3
  • 12
  • 3
    Finally got it to work. It seems like the emulator doesn't provide a way of chosing what Phone account to use. Using a Xperia Z3 I was able to find it under Settings > Call > Calling Accounts. Please note that you need to provide a capability (as the default is none, and the account would therefor not show) in the builder. – ProfessorChaos Apr 26 '16 at 12:54
  • Update: it is possible to change in the emulator as well with the TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS intent. – ProfessorChaos Apr 27 '16 at 09:17
  • 1
    Which capabilities are required to make it work on the phone? – BTR Naidu Aug 24 '16 at 09:54
  • 2
    I faced the same problem and only `PhoneAccount.CAPABILITY_CALL_PROVIDER` worked. After I used it, the account appeared on the list and I was able to enable it. – ntoskrnl Dec 18 '19 at 17:58

3 Answers3

13

I've got some information that I'll just leave here for posterity.

When building your PhoneAccount, you must add CAPABILITY_CALL_PROVIDER if you make and receive calls on your own, or CAPABILITY_CONNECTION_MANAGER if you want to make or receive calls using the builtin PhoneAccount. Without either, you won't show up in the UI.

As far as I can tell, there is no dedicated API for checking whether the user has enabled your PhoneAccount. However, you can use TelecomManager.addNewIncomingCall for this purpose. Simply provide a Bundle containing a boolean extra (named whatever you want) and set that boolean to true if you're really receiving a call or false if you just want to do a permission check (or vice-versa). Then your implementation of ConnectionService.onCreateIncomingConnection can check your extra and return Connection.createCanceledConnection if you're just doing a permission check. This does not register as a call in the call log, and the ringtone never plays. addNewIncomingCall will throw if your PhoneAccount is not enabled, and succeed if it is.

As noted in the comments above, you can prompt the user to enable your PhoneAccount using TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS. Because the user can enable or disable your PhoneAccount at any time, all operations that require an enabled PhoneAccount (like addNewIncomingCall) should be placed in a try block.

j__m
  • 9,392
  • 1
  • 32
  • 56
  • thanks for sharing this. I wasn't sure how to check to see if a PhoneAccount is enabled or not, but your method is a great solution. – David Marcus Aug 30 '17 at 00:42
  • To check if the user has enabled your phone account, you can use telecomManager.getPhoneAccount() passing in your PhoneAccountHandle. If this returns null, you haven't registered your PhoneAccount yet. Otherwise it will return an instance of your PhoneAccount that you can call isEnabled() on. – Rabbit Aug 28 '20 at 19:48
8

Here is a little more info that might be helpful to others. After you have configured your phone account, the user needs to enable permission for your app. Getting the user to that screen should be easier. I've only seen the TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS action, but it doesn't take you to the proper screen to enable the permission. You have to select "All calling accounts" after launching that activity.

If you would like to take the user directly to the "Calling accounts" screen, I've found that this Intent will take you there.

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.server.telecom","com.android.server.telecom.settings.EnableAccountPreferenceActivity"));
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);

I've tested this with a Motorola G5S Plus and it should also work with mostly stock devices like Nexus and Pixel devices. I'm not sure if it will work with Samsung devices.

TALE
  • 960
  • 13
  • 22
  • Thanks for the addon information. It helped. However, do you know if there is any way to programatically enable the phone account, even if it requires a new permission? What is bothering me is that same code was working earlier and we were able to receive calls but now in our new release where the call receving code still remains same, it has started to show this screen because the phone account that we are registering is by default disabled. – vikas Feb 21 '23 at 09:22
  • The app I'm working on uses the ConnectionService for VoIP calls. If you are using the capability "CAPABILITY_SELF_MANAGED" when you register your PhoneAccount with the telecom manager it doesn't require your user to enable the permission. – TALE May 30 '23 at 15:33
3

As an addendum to j__m's answer: I found a way to check if the phone account is activated without setting up a call:

private boolean checkAccountConnection(Context context) {
    boolean isConnected = false;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
            final List<PhoneAccountHandle> enabledAccounts = telecomManager.getCallCapablePhoneAccounts();
            for (PhoneAccountHandle account : enabledAccounts) {
                if (account.getComponentName().getClassName().equals(MyConnectionService.class.getCanonicalName())) {
                    isConnected = true;
                    break;
                }
            }
        }

    }
    return isConnected;
}

As stated in the Javadoc to android.telecom.TelecomManager.getCallCapablePhoneAccounts()

Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone calls. The returned list includes only those accounts which have been explicitly enabled by the user.

  • PermissionHelper - not found – Vineesh TP May 18 '17 at 02:44
  • This is a good way to go if you already need `READ_PHONE_STATE` permission, though I hope no one is requiring that permission just to do this check. – j__m May 24 '17 at 06:00
  • @VineeshTP: I replaced the utility class PermissionHelper with the actual code which it executes. The code sample should be consistent now. – Chris Koepke May 31 '17 at 09:26
  • @j__m: I agree, though if you are dealing with phone accounts in your app it is highly likely you already need `READ_PHONE_STATE` for other parts. – Chris Koepke May 31 '17 at 09:31
  • At the very least you'd need `READ_PHONE_STATE` to implement a `CAPABILITY_CONNECTION_MANAGER`. A `CAPABILITY_CALL_PROVIDER` may or may not need such access. – j__m Jun 04 '17 at 07:50
  • How does a phone account get deactivated? Anyone has steps to disable such phone account so we can test the code above! Thank you – Yannick G Jul 05 '22 at 18:27