Answer incoming call using android.telecom and InCallService
Asked Answered
T

4

22

Since API 21, Google has been adding features to android.telecom in general, especially by implementing more members of TelecomManager and the addition of InCallService. This last one is is supposed to allow non-system, 3rd-party apps to provide and replace the functionality of the system Calls app in-call screen - the Window that pops up and allows action on EXTRA_STATE_OFFHOOK or EXTRA_STATE_RINGING broadcasts (i.e. incoming and outgoing phone calls).

Currently, only this screen has full control of ringing and active calls and associated system callbacks with fine-grained information, by means of the root-restricted MODIFY_PHONE_STATE permission and a lot of secured AOSP code not even accessible by reflection. It's notably one of the most changed pieces of code in different manufacturers' ROM flavours, together with the launcher, contacts and camera.

This is all very pretty but...

How do you actually develop a 3rd-party InCallService?

Namely:

  1. How do you get notified about, and acquire instances of GSM Calls
  2. How does one answer these calls
  3. What is the life-cycle of the callbacks on this class
  4. Does Google provide any actual tutorial for this that I haven't found

I won't ask answers for all of these at once, but any one answer probably associates to the other questions. This is broad but intrinsically it needs to be: there's no example on the web I've stumbled upon other than AOSP-code, and that code is based on the assumption of root-privileges, which makes it unusable for 3rd-party app development purposes.

Toodleoo answered 20/1, 2017 at 15:44 Comment(4)
For your question # 1, does android.intent.action.PHONE_STATE broadcast not work ?Lignin
@SharpEdge you get notified of "a call" but you don't know which android.telecom.Call - developer.android.com/reference/android/telecom/Call.html With such an instance I could actually just Call#answer(int videoState) and get 2. sorted outToodleoo
There does not seem to be a lot of info out there - the comments in this question may help though: https://mcmap.net/q/456022/-replacing-in-call-app/334402. One thing to note just in case it is not clear - this API is to replace the InCallUI - i.e. the user interface to control calls.Cantu
@Cantu yeah not a lot, thus the post. I am very aware the purpose of the API is to replace InCallUI. The thing is the API doesn't really provide the means to do so from what I have been able to discern. That question you post asks many of the same questions as I do, and this is likely gonna be closed as broad too... Dude asked like 2 days before me and is so similar I actually double checked to see if that guy was me, but he's not :P!Toodleoo
N
13

How do you get notified about, and acquire instances of GSM Calls

First, the user will need to select your app as the default Phone app. Refer to Replacing default Phone app on Android 6 and 7 with InCallService for a way to do that.

You also need to define an InCallService implementation the system will bind to and notify you about the call:

<service
    android:name=".CallService"
    android:permission="android.permission.BIND_INCALL_SERVICE">
    <meta-data
        android:name="android.telecom.IN_CALL_SERVICE_UI"
        android:value="true" />
    <intent-filter>
        <action android:name="android.telecom.InCallService" />
    </intent-filter>
</service>

There you should handle at least onCallAdded (set up listeners on Call, start your UI - activity - for the call) and onCallRemoved (remove listeners).

How does one answer these calls

If the user wants to answer the call, you need to invoke the method Call#answer(int) with VideoProfile.STATE_AUDIO_ONLY for example.

What is the life-cycle of the callbacks on this class

Check out Call.Callback for events that can happen with a single call.

Does Google provide any actual tutorial for this that I haven't found

I don't know about Google, but you can check out my simplified example https://github.com/arekolek/simple-phone

Neau answered 16/4, 2018 at 11:48 Comment(21)
took the time to download sample, ran it on an Android Nougat device (should also work on Marshmallow), showed a popup asking to replace dialer (ACTION_CHANGE_DEFAULT_DIALER), received an outbound call, pressed accept, worked as intended. Default (Samsung) dialer didn't showToodleoo
@Neau Is possible to use INCALL SERVICE (your example on Github) without replace SYSTEM UI?Killingsworth
@Killingsworth I don't understand what you would want to do. Maybe better post it as a separate question?Neau
@Neau I need to receive calls through a standard system UI while managing the received calls from my applicationKillingsworth
@Killingsworth you don't need the InCallService thenNeau
@Neau Dialer is for outgoing calls only, if I understand it well. I just need to programmatically accept, hang or silence an incoming call without pressing the buttons.Killingsworth
@Neau Your example receives incoming calls only if METADATA_IN_CALL_SERVICE_UI is set to True. Then must use own UI.Killingsworth
@Killingsworth Then you want the newer APIs from TelecomManager: acceptRingingCall(), endCall() and silenceRinger(). Like I said, you should've asked a separate question, because it totally does not relate to this answer.Neau
Let us continue this discussion in chat.Killingsworth
Can you tell please how i can reject the incoming call using this method? it vibrates a little bit before rejecting by using call.reject() method but i don't want that behavior.Loadstone
@MateenChaudhry I'd say Android does not allow this intentionally. Even if you're the selected user app to handle incoming calls, such an important thing as a ringing call should not be 100% intercepted by third-parties. Google is taking even further steps to remove such control in Android Pie, removing access to the full contact provider, SMS app replacement etcToodleoo
If I set IN_CALL_SERVICE_UI to false, Do I need to handle anything specific in the Service? App works fine with Motorolo (Default) phones. But not sure this will work fine with other vendors. @NeauAtheism
@Atheism I might be mistaken, but I think that setting it to false has the same effect as not having that service in the manifest at all, meaning the system won't bind to it at all. You could post a separate question though, to get a more definite answer hopefully.Neau
No @arekolek. If I set it True and dont implement the UI, Your phone cannot make calls. But If you set to False, Phone can continue to receive and make calls.Atheism
@Atheism read my comment again. I compared false to no entry in the manifest. Not to setting it to trueNeau
Yeah, Got it. Thanks. Do you come across any article about the documentary behaviour when it is set to False? I could not find any.Atheism
Here's documentation, here's the implementation (for non-system apps false is the same as no InCallService at all, or not being set as default Phone app)Neau
@Neau it is not working is xiaomi devices. github.com/arekolek/simple-phone/issues/9Cha
Hi @Neau , I have used your github project and it is working for call connect, discoonect, hold and unhold, I just want to do dial multiple calls and swap the call using incallUI or Telephoney manager can you shade some lights on it??Feodora
@Feodora Sorry, I haven't dug that deep into it unfortunately.Neau
@Neau and team, how would i keep androids UI but still get call backs. i want to completely reuse androids dialer UI but i just control the callbacks. how ?Woodford
G
5

Follow the advice from the second comment of Replacing in call app. In addition you need a service that implements the InCallService interface. When a call arrives the onCallAdded(Call call) method will be called, giving you a reference to the call object.

<service
  android:name=".InCallServiceImplementation"
  android:enabled="true"
  android:exported="true"
  android:permission="android.permission.BIND_INCALL_SERVICE">

  <meta-data
    android:name="android.telecom.IN_CALL_SERVICE_UI"
    android:value="true" />

  <intent-filter>
    <action android:name="android.telecom.InCallService" />
  </intent-filter>
</service>

Once you have the call object, answering it's as simple as call.answer(). I suggest that when you get the stuff above working, run a couple of test calls to get to know when the different callbacks are invoked.

Regarding tutorials, I couldn't find any when I was looking into this, but that was over a year ago...

Hope this helps!

Galang answered 15/2, 2017 at 19:55 Comment(3)
nice, will try a test implementation today and come back with resultsToodleoo
Hi IeRobot, did you tried InCallService, in my case service is not getting invoked for incoming and outgoing calls.Therese
any idea how i can reject the call using this service without letting the mobile vibrate?Loadstone
T
3

I guess Google must've read this question, because apparently on Android 8, a new permission finally allows answering calls through a 3rd party dev-facing permission.

android.permission.ANSWER_PHONE_CALLS (...) allows apps to answer incoming phone calls programmatically

No details yet though, since the documentation for API 26 hasn't been released yet. I'll make sure to update this answer when they do.

EDIT: user arekolek provided an answer that works perfectly on the original API version of this question (at the time of asking, API was 23, even though the question mentions API 21), thus he gets the tick for right answer. Refer to his answer if you want to implement an incall screen that targets minimum SDK of 23. Note you might need API-dependant code or compat library tweaks if you want it to work on more recent APIs that deprecate (or restrict) usage of the provided sample code. the github repo works as I initially intended.

Toodleoo answered 30/3, 2017 at 10:8 Comment(3)
This answer is off-topic. You don't need that API if you are implementing an InCallService, you can answer calls with API 23.Neau
Feel free to improve or add an answer, I am no longer invested in this topic, so I can't make the time to improve the answer to my own question. It is of my understanding that you can only answer calls from Oreo (26) and up, not Marshmallow. See developer.android.com/reference/android/telecom/… - "added in api level 26". Also, a simple google search for "extends InCallService" shows well the state of things...Toodleoo
My understanding is that acceptRingingCall() lets you tell Android to take the call without becoming the default Phone app. Also, as far as I know, none of the APIs used in the repo I linked to are deprecated or restricted on more recent API levels.Neau
L
1

I would recommend you to see this project to build a dialer app for Android. https://github.com/HiddenPirates/Dialer

Labrecque answered 12/4, 2022 at 20:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.