InCallService
public
abstract
class
InCallService
extends Service
java.lang.Object | ||||
↳ | android.content.Context | |||
↳ | android.content.ContextWrapper | |||
↳ | android.app.Service | |||
↳ | android.telecom.InCallService |
This service is implemented by an app that wishes to provide functionality for managing phone calls.
Becoming the Default Phone App
The default dialer/phone app is one which provides the in-call user interface while the device is in a call. It also provides the user with a means to initiate calls and see a history of calls on their device. A device is bundled with a system provided default dialer/phone app. The user may choose a single app to take over this role from the system app. An app which wishes to fulfill this role uses theRoleManager
to request that they fill the
RoleManager.ROLE_DIALER
role.
The default phone app provides a user interface while the device is in a call, and the device is
not in car mode (i.e. UiModeManager#getCurrentModeType()
is not
Configuration.UI_MODE_TYPE_CAR
).
In order to fill the RoleManager.ROLE_DIALER
role, an app must meet a
number of requirements:
- It must handle the
Intent#ACTION_DIAL
intent. This means the app must provide a dial pad UI for the user to initiate outgoing calls. - It must fully implement the
InCallService
API and provide both an incoming call UI, as well as an ongoing call UI.
Note: If the app filling the RoleManager.ROLE_DIALER
returns a
null
InCallService
during binding, the Telecom framework will automatically fall
back to using the dialer app preloaded on the device. The system will display a notification to
the user to let them know that their call was continued using the preloaded dialer app. Your
app should never return a null
binding; doing so means it does not fulfil the
requirements of RoleManager.ROLE_DIALER
.
Note: If your app fills RoleManager.ROLE_DIALER
and makes changes at
runtime which cause it to no longer fulfil the requirements of this role,
RoleManager
will automatically remove your app from the role and close
your app. For example, if you use
PackageManager.setComponentEnabledSetting(ComponentName, int, int)
to
programmatically disable the InCallService
your app declares in its manifest, your app
will no longer fulfil the requirements expected of
RoleManager.ROLE_DIALER
.
The preloaded dialer will ALWAYS be used when the user places an emergency call, even if your
app fills the RoleManager.ROLE_DIALER
role. To ensure an optimal
experience when placing an emergency call, the default dialer should ALWAYS use
TelecomManager.placeCall(Uri, Bundle)
to place calls (including
emergency calls). This ensures that the platform is able to verify that the request came from
the default dialer. If a non-preloaded dialer app uses Intent#ACTION_CALL
to place an
emergency call, it will be raised to the preloaded dialer app using Intent#ACTION_DIAL
for confirmation; this is a suboptimal user experience.
Below is an example manifest registration for an InCallService
. The meta-data
TelecomManager#METADATA_IN_CALL_SERVICE_UI
indicates that this particular
InCallService
implementation intends to replace the built-in in-call UI.
The meta-data TelecomManager#METADATA_IN_CALL_SERVICE_RINGING
indicates that this
InCallService
will play the ringtone for incoming calls. See
below for more information on showing the incoming call
UI and playing the ringtone in your app.
<service android:name="your.package.YourInCallServiceImplementation"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:exported="true">
<meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
<meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
android:value="true" />
<intent-filter>
<action android:name="android.telecom.InCallService"/>
</intent-filter>
</service>
Note: You should NOT mark your InCallService
with the attribute
android:exported="false"
; doing so can result in a failure to bind to your implementation
during calls.
In addition to implementing the InCallService
API, you must also declare an activity in
your manifest which handles the Intent#ACTION_DIAL
intent. The example below illustrates
how this is done:
<activity android:name="your.package.YourDialerActivity"
android:label="@string/yourDialerActivityLabel">
<intent-filter>
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
</activity>
When a user installs your application and runs it for the first time, you should use the
RoleManager
to prompt the user to see if they would like your app to
be the new default phone app.
The code below shows how your app can request to become the default phone/dialer app:
private static final int REQUEST_ID = 1;
public void requestRole() {
RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
startActivityForResult(intent, REQUEST_ID);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ID) {
if (resultCode == android.app.Activity.RESULT_OK) {
// Your app is now the default dialer app
} else {
// Your app is not the default dialer app
}
}
}
Access to InCallService for Wearable Devices
-
If your app is a third-party companion app and wants to access InCallService APIs, what your
app could do are:
- Declare MANAGE_ONGOING_CALLS permission in your manifest
- Associate with a physical wearable device via the
CompanionDeviceManager
API as a companion app. See: https://developer.android.com/guide/topics/connectivity/companion-device-pairing - Implement this InCallService with BIND_INCALL_SERVICE permission
Showing the Incoming Call Notification
When your app receives a new incoming call viaInCallService#onCallAdded(Call)
, it is
responsible for displaying an incoming call UI for the incoming call. It should do this using
NotificationManager
APIs to post a new incoming call notification.
Where your app declares the meta-data TelecomManager#METADATA_IN_CALL_SERVICE_RINGING
, it
is responsible for playing the ringtone for incoming calls. Your app should create a
NotificationChannel
which specifies the desired ringtone. For example:
NotificationChannel channel = new NotificationChannel(YOUR_CHANNEL_ID, "Incoming Calls",
NotificationManager.IMPORTANCE_MAX);
// other channel setup stuff goes here.
// We'll use the default system ringtone for our incoming call notification channel. You can
// use your own audio resource here.
Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
channel.setSound(ringtoneUri, new AudioAttributes.Builder()
// Setting the AudioAttributes is important as it identifies the purpose of your
// notification sound.
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build());
NotificationManager mgr = getSystemService(NotificationManager.class);
mgr.createNotificationChannel(channel);
When your app receives a new incoming call, it creates a Notification
for the
incoming call and associates it with your incoming call notification channel. You can specify a
PendingIntent
on the notification which will launch your full screen
incoming call UI. The notification manager framework will display your notification as a
heads-up notification if the user is actively using the phone. When the user is not using the
phone, your full-screen incoming call UI is used instead.
For example:
// Create an intent which triggers your fullscreen incoming call user interface.
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(context, YourIncomingCallActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
// Build the notification as an ongoing high priority item; this ensures it will show as
// a heads up notification which slides down over top of the current content.
final Notification.Builder builder = new Notification.Builder(context);
builder.setOngoing(true);
builder.setPriority(Notification.PRIORITY_HIGH);
// Set notification content intent to take user to the fullscreen UI if user taps on the
// notification body.
builder.setContentIntent(pendingIntent);
// Set full screen intent to trigger display of the fullscreen UI when the notification
// manager deems it appropriate.
builder.setFullScreenIntent(pendingIntent, true);
// Setup notification content.
builder.setSmallIcon( yourIconResourceId );
builder.setContentTitle("Your notification title");
builder.setContentText("Your notification content.");
// Use builder.addAction(..) to add buttons to answer or reject the call.
NotificationManager notificationManager = mContext.getSystemService(
NotificationManager.class);
notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
Summary
Nested classes | |
---|---|
class |
InCallService.VideoCall
Used to issue commands to the |
Constants | |
---|---|
String |
SERVICE_INTERFACE
The |
Inherited constants |
---|
Public constructors | |
---|---|
InCallService()
|
Public methods | |
---|---|
final
boolean
|
canAddCall()
Returns if the device can support additional calls. |
final
CallAudioState
|
getCallAudioState()
This method was deprecated
in API level 34.
Use |
final
List<Call>
|
getCalls()
Obtains the current list of |
final
CallEndpoint
|
getCurrentCallEndpoint()
Obtains the current CallEndpoint. |
void
|
onAvailableCallEndpointsChanged(List<CallEndpoint> availableEndpoints)
Called when the available CallEndpoint changes. |
IBinder
|
onBind(Intent intent)
Return the communication channel to the service. |
void
|
onBringToForeground(boolean showDialpad)
Called to bring the in-call screen to the foreground. |
void
|
onCallAdded(Call call)
Called when a |
void
|
onCallAudioStateChanged(CallAudioState audioState)
This method was deprecated
in API level 34.
Use |
void
|
onCallEndpointChanged(CallEndpoint callEndpoint)
Called when the current CallEndpoint changes. |
void
|
onCallRemoved(Call call)
Called when a |
void
|
onCanAddCallChanged(boolean canAddCall)
Called when the ability to add more calls changes. |
void
|
onConnectionEvent(Call call, String event, Bundle extras)
Unused; to handle connection events issued by a |
void
|
onMuteStateChanged(boolean isMuted)
Called when the mute state changes. |
void
|
onSilenceRinger()
Called to silence the ringer if a ringing call exists. |
boolean
|
onUnbind(Intent intent)
Called when all clients have disconnected from a particular interface published by the service. |
final
void
|
requestBluetoothAudio(BluetoothDevice bluetoothDevice)
This method was deprecated
in API level 34.
Use |
final
void
|
requestCallEndpointChange(CallEndpoint endpoint, Executor executor, OutcomeReceiver<Void, CallEndpointException> callback)
Request audio routing to a specific CallEndpoint. |
final
void
|
setAudioRoute(int route)
This method was deprecated
in API level 34.
Use |
final
void
|
setMuted(boolean state)
Sets the microphone mute state. |
Inherited methods | |
---|---|
Constants
SERVICE_INTERFACE
public static final String SERVICE_INTERFACE
The Intent
that must be declared as handled by the service.
Constant Value: "android.telecom.InCallService"
Public constructors
Public methods
canAddCall
public final boolean canAddCall ()
Returns if the device can support additional calls.
Returns | |
---|---|
boolean |
Whether the phone supports adding more calls. |
getCallAudioState
public final CallAudioState getCallAudioState ()
This method was deprecated
in API level 34.
Use getCurrentCallEndpoint()
,
onAvailableCallEndpointsChanged(java.util.List)
and
onMuteStateChanged(boolean)
instead.
Obtains the current phone call audio state.
Returns | |
---|---|
CallAudioState |
An object encapsulating the audio state. Returns null if the service is not fully initialized. |
getCalls
public final List<Call> getCalls ()
Obtains the current list of Call
s to be displayed by this in-call service.
Returns | |
---|---|
List<Call> |
A list of the relevant Call s. |
getCurrentCallEndpoint
public final CallEndpoint getCurrentCallEndpoint ()
Obtains the current CallEndpoint.
Returns | |
---|---|
CallEndpoint |
An object encapsulating the CallEndpoint.
This value cannot be null . |
onAvailableCallEndpointsChanged
public void onAvailableCallEndpointsChanged (List<CallEndpoint> availableEndpoints)
Called when the available CallEndpoint changes.
Parameters | |
---|---|
availableEndpoints |
List : The set of available CallEndpoint CallEndpoint .
This value cannot be null . |
onBind
public IBinder onBind (Intent intent)
Return the communication channel to the service. May return null if
clients can not bind to the service. The returned
IBinder
is usually for a complex interface
that has been described using
aidl.
Note that unlike other application components, calls on to the IBinder interface returned here may not happen on the main thread of the process. More information about the main thread can be found in Processes and Threads.
Parameters | |
---|---|
intent |
Intent : The Intent that was used to bind to this service,
as given to Context.bindService . Note that any extras that were included with
the Intent at that point will not be seen here. |
Returns | |
---|---|
IBinder |
Return an IBinder through which clients can call on to the service. |
onBringToForeground
public void onBringToForeground (boolean showDialpad)
Called to bring the in-call screen to the foreground. The in-call experience should
respond immediately by coming to the foreground to inform the user of the state of
ongoing Call
s.
Parameters | |
---|---|
showDialpad |
boolean : If true, put up the dialpad when the screen is shown. |
onCallAdded
public void onCallAdded (Call call)
Called when a Call
has been added to this in-call session. The in-call user
experience should add necessary state listeners to the specified Call
and
immediately start to show the user information about the existence
and nature of this Call
. Subsequent invocations of getCalls()
will
include this Call
.
Parameters | |
---|---|
call |
Call : A newly added Call . |
onCallAudioStateChanged
public void onCallAudioStateChanged (CallAudioState audioState)
This method was deprecated
in API level 34.
Use onCallEndpointChanged(android.telecom.CallEndpoint)
,
onAvailableCallEndpointsChanged(java.util.List)
and
onMuteStateChanged(boolean)
instead.
Called when the audio state changes.
Parameters | |
---|---|
audioState |
CallAudioState : The new CallAudioState . |
onCallEndpointChanged
public void onCallEndpointChanged (CallEndpoint callEndpoint)
Called when the current CallEndpoint changes.
Parameters | |
---|---|
callEndpoint |
CallEndpoint : The current CallEndpoint CallEndpoint .
This value cannot be null . |
onCallRemoved
public void onCallRemoved (Call call)
Called when a Call
has been removed from this in-call session. The in-call user
experience should remove any state listeners from the specified Call
and
immediately stop displaying any information about this Call
.
Subsequent invocations of getCalls()
will no longer include this Call
.
Parameters | |
---|---|
call |
Call : A newly removed Call . |
onCanAddCallChanged
public void onCanAddCallChanged (boolean canAddCall)
Called when the ability to add more calls changes. If the phone cannot
support more calls then canAddCall
is set to false
. If it can, then it
is set to true
. This can be used to control the visibility of UI to add more calls.
Parameters | |
---|---|
canAddCall |
boolean : Indicates whether an additional call can be added. |
onConnectionEvent
public void onConnectionEvent (Call call, String event, Bundle extras)
Unused; to handle connection events issued by a ConnectionService
, implement the
Call.Callback.onConnectionEvent(Call, String, Bundle)
callback.
See Connection#sendConnectionEvent(String, Bundle)
.
Parameters | |
---|---|
call |
Call : The call the event is associated with. |
event |
String : The event. |
extras |
Bundle : Any associated extras. |
onMuteStateChanged
public void onMuteStateChanged (boolean isMuted)
Called when the mute state changes.
Parameters | |
---|---|
isMuted |
boolean : The current mute state. |
onSilenceRinger
public void onSilenceRinger ()
Called to silence the ringer if a ringing call exists.
onUnbind
public boolean onUnbind (Intent intent)
Called when all clients have disconnected from a particular interface published by the service. The default implementation does nothing and returns false.
Parameters | |
---|---|
intent |
Intent : The Intent that was used to bind to this service,
as given to Context.bindService . Note that any extras that were included with
the Intent at that point will not be seen here. |
Returns | |
---|---|
boolean |
Return true if you would like to have the service's
onRebind(Intent) method later called when new clients bind to it. |
requestBluetoothAudio
public final void requestBluetoothAudio (BluetoothDevice bluetoothDevice)
This method was deprecated
in API level 34.
Use requestCallEndpointChange(android.telecom.CallEndpoint, java.util.concurrent.Executor, android.os.OutcomeReceiver)
instead.
Request audio routing to a specific bluetooth device. Calling this method may result in
the device routing audio to a different bluetooth device than the one specified if the
bluetooth stack is unable to route audio to the requested device.
A list of available devices can be obtained via
CallAudioState#getSupportedBluetoothDevices()
Parameters | |
---|---|
bluetoothDevice |
BluetoothDevice : The bluetooth device to connect to.
This value cannot be null . |
requestCallEndpointChange
public final void requestCallEndpointChange (CallEndpoint endpoint, Executor executor, OutcomeReceiver<Void, CallEndpointException> callback)
Request audio routing to a specific CallEndpoint. Clients should not define their own
CallEndpoint when requesting a change. Instead, the new endpoint should be one of the valid
endpoints provided by onAvailableCallEndpointsChanged(java.util.List)
.
When this request is honored, there will be change to the getCurrentCallEndpoint()
.
Parameters | |
---|---|
endpoint |
CallEndpoint : The call endpoint to use.
This value cannot be null . |
executor |
Executor : The executor of where the callback will execute.
This value cannot be null .
Callback and listener events are dispatched through this
Executor , providing an easy way to control which thread is
used. To dispatch events through the main thread of your
application, you can use
Context.getMainExecutor() .
Otherwise, provide an Executor that dispatches to an appropriate thread. |
callback |
OutcomeReceiver : The callback to notify the result of the endpoint change.
This value cannot be null . |
setAudioRoute
public final void setAudioRoute (int route)
This method was deprecated
in API level 34.
Use requestCallEndpointChange(android.telecom.CallEndpoint, java.util.concurrent.Executor, android.os.OutcomeReceiver)
instead.
Sets the audio route (speaker, bluetooth, etc...). When this request is honored, there will
be change to the getCallAudioState()
.
Parameters | |
---|---|
route |
int : The audio route to use. |
setMuted
public final void setMuted (boolean state)
Sets the microphone mute state. When this request is honored, there will be change to
the getCallAudioState()
.
Parameters | |
---|---|
state |
boolean : true if the microphone should be muted; false otherwise. |
Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
Last updated 2024-06-18 UTC.