25

Background

I'm trying to develop a really simple in call app to replace the stock version. Basically, I just want to answer incoming calls and present the user with a really simple customized UI. There is no need for outgoing calls or any fancy stuff.

Searching the web I've found package android.telecom.incallservice (available in API 23). This service is implemented by any app that wishes to provide the user-interface for managing phone calls.

It seems promising but I'm having trouble getting it to work. I've created simple service extending InCallService and declared it in my manifest as described by the docs. However, I would expect to be able to change the default phone app in the settings to my own, but I can only find the stock phone app.

Code

This is the manifest declaration from the docs. I've replaced BIND_IN_CALL_SERVICE with BIND_INCALL_SERVICE since I guess this is a typo.

<service android:name="your.package.YourInCallServiceImplementation" 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>

Questions

  1. Is it even possible for third-party app to replace the default in call app?

  2. Are there any sample implementations using this API out there I may use as a reference? I've found the google implementation, but this is a system app which makes use of some permissions that are not available for other apps (ex: android.permission.MODIFY_PHONE_STATE).

  3. Am I correct in the assumption that after providing a correct InCallService manifest registration and a stub implementation I could expect to find my app under Default Apps -> Phone? Do I need to declare something else?

Thanks.

Shashank Agrawal
  • 25,161
  • 11
  • 89
  • 121
user5806139
  • 531
  • 6
  • 14
  • 8
    I don't know why this question was put on hold. I don't think it's broad at all. I'll answer your question here: The answer is that as of Android Marshmallow, you *can* replace the in-call UI, however, you must replace both the in-call UI and the dialer as a single unit. – santosc Jan 21 '16 at 00:04
  • 7
    To continue, 3 steps are required. 1) You app must be a "Dialer". That means it must have an activity that handles the DIAL intent 2) User must select your app as the default dialer in Settings->apps->[gear]->default apps 3) Android will now use your InCallService to display an in-call UI. – santosc Jan 21 '16 at 00:11
  • 3
    Thank you for taking the time to answer this. I tried to be as specific as I could. Your answer sums up what I've found out by trial and error over the last days. Once you replace both dialer and in call ui it works as expected. Hope this will help someone else in the future. Again, thank you for answering. – user5806139 Jan 25 '16 at 18:49
  • I know the question is closed and all, but since my (very similar question) is still open, and there are developments in Android 8, plesae read my answer there: http://stackoverflow.com/a/43114729/1103974 - the fact they now add this can be an assumption it couldn't be done before by 3rd party apps. – leRobot Mar 30 '17 at 10:14
  • Not sure I understand your comment. I got this working on Android 6. – user5806139 Apr 11 '17 at 19:31
  • Do you have any sample how it will work, when we are using InCallService can we get call backs (Connecting, Connected, hold) – rajahsekar Jun 02 '17 at 12:43
  • Once you get the call object instance from InCallService, register a callback using `registerCallback(callback)`, where "callback" is an instance of a class inheriting from Call.Callback. In this class you should override `onStateChanged()` which will be called whenever there is a state change on the call. Have a look at the call class documentation for details. https://developer.android.com/reference/android/telecom/Call.html – user5806139 Jun 03 '17 at 15:25
  • How can i get call object instance from InCallService, Thanks – rajahsekar Jun 05 '17 at 05:05
  • I have tried above 3 steps, but my service is not getting invoked for outgoing or incoming calls how can i get call object. @santosc – rajahsekar Jun 05 '17 at 10:41
  • I think you should post a new question (including your code) for this specific problem. – user5806139 Jun 06 '17 at 18:43
  • 4
    I really REALLY disagree with the decision to close the question. I see it as very specific – AndreasReiff Sep 05 '17 at 21:17
  • 1
    see this answer from arekolek for actual working code for incall replacement: https://stackoverflow.com/a/49856583/1103974 Hint: look at his github project, it works magically. It can obviously be achieved in (yet) standard Java, but I trust you can translate it even in Kotlin. I actually advise on Kotlin if you are still investing your time in the Android SDK – leRobot Apr 26 '18 at 16:52
  • @santosc If you still wanted to post your comment(s) as an answer to this question, I think you could now – Keara Jun 27 '18 at 05:53

2 Answers2

2
  1. Is it even possible for third-party app to replace the default in call app?

Yes, starting with API 23 it is possible.

  1. Are there any sample implementations using this API out there I may use as a reference? I've found the google implementation, but this is a system app which makes use of some permissions that are not available for other apps (ex: android.permission.MODIFY_PHONE_STATE).

The only one I'm aware of, is the sample I created https://github.com/arekolek/simple-phone that was already mentioned in the other answer as well.

  1. Am I correct in the assumption that after providing a correct InCallService manifest registration and a stub implementation I could expect to find my app under Default Apps -> Phone? Do I need to declare something else?

Actually, no.

Like mentioned in another answer on the topic, you don't need InCallService at all to appear on that list.

What you need though, is to register an activity with two intent filters, one with a tel Uri scheme, and one with an empty scheme (having just one of them is not enough):

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

It is vaguely mentioned in the docs, and stated explicitly in AOSP code.

That is enough to appear on that list. Only then, to provide the UI for the call, will you actually need the InCallService.

arekolek
  • 9,128
  • 3
  • 58
  • 79
0

According to the docs and as you comment yourself, you need to add this in your manifest:

<service android:name="your.package.YourInCallServiceImplementation"
          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>

android:name must be replaced by the class that implements this service.


 <activity android:name="your.package.YourDialerActivity">
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
 </activity>

android:name must be replaced by the class that implements the main activity for your own dialer implementation.

Here you can find more information about this: https://developer.android.com/guide/topics/connectivity/telecom/selfManaged

And here's a sample project that you can use as a guide: https://github.com/arekolek/simple-phone

And this: https://stackoverflow.com/a/49835987/1916449

Óscar
  • 809
  • 1
  • 8
  • 33
  • The self-managed API (`ConnectionService`) you linked to is "for developers of standalone calling apps which do not wish to show their calls within the default phone app, and do not wish to have other calls shown in their user interface". It's very different from replacing the default phone app (which `InCallService` does). – arekolek Jan 24 '19 at 22:49