21

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.

leRobot
  • 1,497
  • 1
  • 18
  • 30
  • For your question # 1, does `android.intent.action.PHONE_STATE` broadcast not work ? – Sharp Edge Jan 20 '17 at 16:01
  • @SharpEdge you get notified of "a call" but you don't know which android.telecom.Call - https://developer.android.com/reference/android/telecom/Call.html With such an instance I could actually just Call#answer(int videoState) and get 2. sorted out – leRobot Jan 20 '17 at 16:03
  • There does not seem to be a lot of info out there - the comments in this question may help though: http://stackoverflow.com/q/34861910/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. – Mick Jan 24 '17 at 10:55
  • @Mick 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! – leRobot Jan 24 '17 at 18:02

4 Answers4

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

arekolek
  • 9,128
  • 3
  • 58
  • 79
  • 1
    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 show – leRobot Apr 16 '18 at 15:39
  • 2
    @arekolek Is possible to use INCALL SERVICE (your example on Github) without replace SYSTEM UI? – pudnivec74 Jul 28 '18 at 14:50
  • @pudnivec74 I don't understand what you would want to do. Maybe better post it as a separate question? – arekolek Jul 28 '18 at 15:03
  • @arekolek I need to receive calls through a standard system UI while managing the received calls from my application – pudnivec74 Jul 28 '18 at 15:07
  • 1
    @pudnivec74 you don't need the `InCallService` then – arekolek Jul 28 '18 at 15:12
  • @arekolek 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. – pudnivec74 Jul 28 '18 at 15:28
  • @arekolek Your example receives incoming calls only if METADATA_IN_CALL_SERVICE_UI is set to True. Then must use own UI. – pudnivec74 Jul 28 '18 at 17:06
  • 1
    @pudnivec74 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. – arekolek Jul 28 '18 at 17:46
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/176944/discussion-between-pudnivec74-and-arekolek). – pudnivec74 Jul 28 '18 at 18:31
  • 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. – Mateen Chaudhry Sep 02 '18 at 03:12
  • 1
    @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 etc – leRobot Oct 09 '18 at 08:49
  • 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. @arekolek – Aram Feb 02 '19 at 06:25
  • @Aram 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. – arekolek Feb 03 '19 at 11:02
  • 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. – Aram Feb 04 '19 at 05:07
  • @Aram read my comment again. I compared `false` to no entry in the manifest. Not to setting it to `true` – arekolek Feb 04 '19 at 12:14
  • 1
    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. – Aram Feb 05 '19 at 04:56
  • Here's [documentation](https://developer.android.com/reference/android/telecom/TelecomManager.html#METADATA_IN_CALL_SERVICE_UI), here's the [implementation](https://android.googlesource.com/platform/packages/services/Telecomm/+/nougat-release/src/com/android/server/telecom/InCallController.java#786) (for non-system apps `false` is the same as no `InCallService` at all, or not being set as default Phone app) – arekolek Feb 05 '19 at 08:38
  • @arekolek it is not working is xiaomi devices. https://github.com/arekolek/simple-phone/issues/9 – Giru Bhai Aug 09 '19 at 07:21
  • Hi @arekolek , 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?? – Smit.Satodia Jun 19 '20 at 07:02
  • @Smit.Satodia Sorry, I haven't dug that deep into it unfortunately. – arekolek Jun 20 '20 at 10:20
  • 1
    @arekolek 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 ? – j2emanue Apr 27 '21 at 18:36
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!

Community
  • 1
  • 1
user5806139
  • 531
  • 6
  • 14
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.

leRobot
  • 1,497
  • 1
  • 18
  • 30
  • This answer is off-topic. You don't need that API if you are implementing an `InCallService`, you can answer calls with API 23. – arekolek Apr 15 '18 at 08:48
  • 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 https://developer.android.com/reference/android/telecom/TelecomManager.html#acceptRingingCall() - "added in api level 26". Also, a simple google search for "extends InCallService" shows well the state of things... – leRobot Apr 16 '18 at 09:45
  • 2
    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. – arekolek May 16 '18 at 22:05
1

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

Nur Alam
  • 192
  • 2
  • 8