/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.telecom; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.ParcelFileDescriptor; import com.android.internal.telecom.IVideoProvider; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; /** * Represents an ongoing phone call that the in-call app should present to the user. */ public final class Call { /** * The state of a {@code Call} when newly created. */ public static final int STATE_NEW = 0; /** * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected. */ public static final int STATE_DIALING = 1; /** * The state of an incoming {@code Call} when ringing locally, but not yet connected. */ public static final int STATE_RINGING = 2; /** * The state of a {@code Call} when in a holding state. */ public static final int STATE_HOLDING = 3; /** * The state of a {@code Call} when actively supporting conversation. */ public static final int STATE_ACTIVE = 4; /** * The state of a {@code Call} when no further voice or other communication is being * transmitted, the remote side has been or will inevitably be informed that the {@code Call} * is no longer active, and the local data transport has or inevitably will release resources * associated with this {@code Call}. */ public static final int STATE_DISCONNECTED = 7; /** * The state of an outgoing {@code Call} when waiting on user to select a * {@link PhoneAccount} through which to place the call. */ public static final int STATE_SELECT_PHONE_ACCOUNT = 8; /** * @hide * @deprecated use STATE_SELECT_PHONE_ACCOUNT. */ @Deprecated @SystemApi public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT; /** * The initial state of an outgoing {@code Call}. * Common transitions are to {@link #STATE_DIALING} state for a successful call or * {@link #STATE_DISCONNECTED} if it failed. */ public static final int STATE_CONNECTING = 9; /** * The state of a {@code Call} when the user has initiated a disconnection of the call, but the * call has not yet been disconnected by the underlying {@code ConnectionService}. The next * state of the call is (potentially) {@link #STATE_DISCONNECTED}. */ public static final int STATE_DISCONNECTING = 10; /** * The state of an external call which is in the process of being pulled from a remote device to * the local device. *
* A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call. *
* An {@link InCallService} will only see this state if it has the * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its * manifest. */ public static final int STATE_PULLING_CALL = 11; /** * The state of a call that is active with the network, but the audio from the call is * being intercepted by an app on the local device. Telecom does not hold audio focus in this * state, and the call will be invisible to the user except for a persistent notification. */ public static final int STATE_AUDIO_PROCESSING = 12; /** * The state of a call that is being presented to the user after being in * {@link #STATE_AUDIO_PROCESSING}. The call is still active with the network in this case, and * Telecom will hold audio focus and play a ringtone if appropriate. */ public static final int STATE_SIMULATED_RINGING = 13; /** * @hide */ @IntDef(prefix = { "STATE_" }, value = { STATE_NEW, STATE_DIALING, STATE_RINGING, STATE_HOLDING, STATE_ACTIVE, STATE_DISCONNECTED, STATE_SELECT_PHONE_ACCOUNT, STATE_CONNECTING, STATE_DISCONNECTING, STATE_PULLING_CALL, STATE_AUDIO_PROCESSING, STATE_SIMULATED_RINGING }) @Retention(RetentionPolicy.SOURCE) public @interface CallState {}; /** * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call * extras. Used to pass the phone accounts to display on the front end to the user in order to * select phone accounts to (for example) place a call. * @deprecated Use the list from {@link #EXTRA_SUGGESTED_PHONE_ACCOUNTS} instead. */ @Deprecated public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts"; /** * Key for extra used to pass along a list of {@link PhoneAccountSuggestion}s to the in-call * UI when a call enters the {@link #STATE_SELECT_PHONE_ACCOUNT} state. The list included here * will have the same length and be in the same order as the list passed with * {@link #AVAILABLE_PHONE_ACCOUNTS}. */ public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS"; /** * Extra key used to indicate the time (in milliseconds since midnight, January 1, 1970 UTC) * when the last outgoing emergency call was made. This is used to identify potential emergency * callbacks. */ public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS"; /** * Extra key used to indicate whether a {@link CallScreeningService} has requested to silence * the ringtone for a call. If the {@link InCallService} declares * {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} in its manifest, it should not * play a ringtone for an incoming call with this extra key set. */ public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED"; /** * Call event sent from a {@link Call} via {@link #sendCallEvent(String, Bundle)} to inform * Telecom that the user has requested that the current {@link Call} should be handed over * to another {@link ConnectionService}. *
* The caller must specify the {@link #EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE} to indicate to * Telecom which {@link PhoneAccountHandle} the {@link Call} should be handed over to. * @hide * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated * APIs instead. */ public static final String EVENT_REQUEST_HANDOVER = "android.telecom.event.REQUEST_HANDOVER"; /** * Extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event. Specifies the * {@link PhoneAccountHandle} to which a call should be handed over to. * @hide * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated * APIs instead. */ public static final String EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.HANDOVER_PHONE_ACCOUNT_HANDLE"; /** * Integer extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event. Specifies the * video state of the call when it is handed over to the new {@link PhoneAccount}. *
* Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, * {@link VideoProfile#STATE_BIDIRECTIONAL}, {@link VideoProfile#STATE_RX_ENABLED}, and * {@link VideoProfile#STATE_TX_ENABLED}. * @hide * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated * APIs instead. */ public static final String EXTRA_HANDOVER_VIDEO_STATE = "android.telecom.extra.HANDOVER_VIDEO_STATE"; /** * Extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event. Used by the * {@link InCallService} initiating a handover to provide a {@link Bundle} with extra * information to the handover {@link ConnectionService} specified by * {@link #EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE}. *
* This {@link Bundle} is not interpreted by Telecom, but passed as-is to the * {@link ConnectionService} via the request extras when * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} * is called to initate the handover. * @hide * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated * APIs instead. */ public static final String EXTRA_HANDOVER_EXTRAS = "android.telecom.extra.HANDOVER_EXTRAS"; /** * Call event sent from Telecom to the handover {@link ConnectionService} via * {@link Connection#onCallEvent(String, Bundle)} to inform a {@link Connection} that a handover * to the {@link ConnectionService} has completed successfully. *
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event. * @hide * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated * APIs instead. */ public static final String EVENT_HANDOVER_COMPLETE = "android.telecom.event.HANDOVER_COMPLETE"; /** * Call event sent from Telecom to the handover destination {@link ConnectionService} via * {@link Connection#onCallEvent(String, Bundle)} to inform the handover destination that the * source connection has disconnected. The {@link Bundle} parameter for the call event will be * {@code null}. *
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event. * @hide * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated * APIs instead. */ public static final String EVENT_HANDOVER_SOURCE_DISCONNECTED = "android.telecom.event.HANDOVER_SOURCE_DISCONNECTED"; /** * Call event sent from Telecom to the handover {@link ConnectionService} via * {@link Connection#onCallEvent(String, Bundle)} to inform a {@link Connection} that a handover * to the {@link ConnectionService} has failed. *
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event. * @hide * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated * APIs instead. */ public static final String EVENT_HANDOVER_FAILED = "android.telecom.event.HANDOVER_FAILED"; /** * Event reported from the Telecom stack to report an in-call diagnostic message which the * dialer app may opt to display to the user. A diagnostic message is used to communicate * scenarios the device has detected which may impact the quality of the ongoing call. *
* For example a problem with a bluetooth headset may generate a recommendation for the user to * try using the speakerphone instead, or if the device detects it has entered a poor service * area, the user might be warned so that they can finish their call prior to it dropping. *
* A diagnostic message is considered persistent in nature. When the user enters a poor service * area, for example, the accompanying diagnostic message persists until they leave the area * of poor service. Each message is accompanied with a {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID} * which uniquely identifies the diagnostic condition being reported. The framework raises a * call event of type {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE} when the condition reported has * been cleared. The dialer app should display the diagnostic message until it is cleared. * If multiple diagnostic messages are sent with different IDs (which have not yet been cleared) * the dialer app should prioritize the most recently received message, but still provide the * user with a means to review past messages. *
* The text of the message is found in {@link #EXTRA_DIAGNOSTIC_MESSAGE} in the form of a human * readable {@link CharSequence} which is intended for display in the call UX. *
* The telecom framework audibly notifies the user of the presence of a diagnostic message, so * the dialer app needs only to concern itself with visually displaying the message. *
* The dialer app receives this event via * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}. */ public static final String EVENT_DISPLAY_DIAGNOSTIC_MESSAGE = "android.telecom.event.DISPLAY_DIAGNOSTIC_MESSAGE"; /** * Event reported from the telecom framework when a diagnostic message previously raised with * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE} has cleared and is no longer pertinent. *
* The {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID} indicates the diagnostic message which has been * cleared. *
* The dialer app receives this event via * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}. */ public static final String EVENT_CLEAR_DIAGNOSTIC_MESSAGE = "android.telecom.event.CLEAR_DIAGNOSTIC_MESSAGE"; /** * Integer extra representing a message ID for a message posted via * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}. Used to ensure that the dialer app knows when * the message in question has cleared via {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE}. */ public static final String EXTRA_DIAGNOSTIC_MESSAGE_ID = "android.telecom.extra.DIAGNOSTIC_MESSAGE_ID"; /** * {@link CharSequence} extra used with {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}. This is the * diagnostic message the dialer app should display. */ public static final String EXTRA_DIAGNOSTIC_MESSAGE = "android.telecom.extra.DIAGNOSTIC_MESSAGE"; /** * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this * call because they have declined to answer it. This typically means that they are unable * to answer the call at this time and would prefer it be sent to voicemail. */ public static final int REJECT_REASON_DECLINED = 1; /** * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this * call because it is an unwanted call. This allows the user to indicate that they are * rejecting a call because it is likely a nuisance call. */ public static final int REJECT_REASON_UNWANTED = 2; /** * @hide */ @IntDef(prefix = { "REJECT_REASON_" }, value = {REJECT_REASON_DECLINED, REJECT_REASON_UNWANTED}) @Retention(RetentionPolicy.SOURCE) public @interface RejectReason {}; public static class Details { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( prefix = { "DIRECTION_" }, value = {DIRECTION_UNKNOWN, DIRECTION_INCOMING, DIRECTION_OUTGOING}) public @interface CallDirection {} /** * Indicates that the call is neither and incoming nor an outgoing call. This can be the * case for calls reported directly by a {@link ConnectionService} in special cases such as * call handovers. */ public static final int DIRECTION_UNKNOWN = -1; /** * Indicates that the call is an incoming call. */ public static final int DIRECTION_INCOMING = 0; /** * Indicates that the call is an outgoing call. */ public static final int DIRECTION_OUTGOING = 1; /** Call can currently be put on hold or unheld. */ public static final int CAPABILITY_HOLD = 0x00000001; /** Call supports the hold feature. */ public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; /** * Calls within a conference can be merged. A {@link ConnectionService} has the option to * add a {@link Conference} call before the child {@link Connection}s are merged. This is how * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this * capability allows a merge button to be shown while the conference call is in the foreground * of the in-call UI. *
* This is only intended for use by a {@link Conference}. */ public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; /** * Calls within a conference can be swapped between foreground and background. * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. *
* This is only intended for use by a {@link Conference}. */ public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; /** * @hide */ public static final int CAPABILITY_UNUSED_1 = 0x00000010; /** Call supports responding via text option. */ public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; /** Call can be muted. */ public static final int CAPABILITY_MUTE = 0x00000040; /** * Call supports conference call management. This capability only applies to {@link Conference} * calls which can have {@link Connection}s as children. */ public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; /** * Local device supports receiving video. */ public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100; /** * Local device supports transmitting video. */ public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200; /** * Local device supports bidirectional video calling. */ public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX; /** * Remote device supports receiving video. */ public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400; /** * Remote device supports transmitting video. */ public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800; /** * Remote device supports bidirectional video calling. */ public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX; /** * Call is able to be separated from its parent {@code Conference}, if any. */ public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; /** * Call is able to be individually disconnected when in a {@code Conference}. */ public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; /** * Speed up audio setup for MT call. * @hide */ public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000; /** * Call can be upgraded to a video call. * @hide * @deprecated Use {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL} to indicate for a call * whether or not video calling is supported. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 119305590) public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000; /** * For video calls, indicates whether the outgoing video for the call can be paused using * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState. */ public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000; /** * Call sends responses through connection. * @hide */ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000; /** * When set, prevents a video {@code Call} from being downgraded to an audio-only call. *
* Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be * downgraded from a video call back to a VideoState of * {@link VideoProfile#STATE_AUDIO_ONLY}. *
* Intuitively, a call which can be downgraded to audio should also have local and remote * video * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}). */ public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000; /** * When set for an external call, indicates that this {@code Call} can be pulled from a * remote device to the current device. *
* Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set. *
* An {@link InCallService} will only see calls with this capability if it has the * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} * in its manifest. *
* See {@link Connection#CAPABILITY_CAN_PULL_CALL} and * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. */ public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000; /** Call supports the deflect feature. */ public static final int CAPABILITY_SUPPORT_DEFLECT = 0x01000000; /** * Call supports adding participants to the call via * {@link #addConferenceParticipants(List)}. Once participants are added, the call becomes * an adhoc conference call ({@link #PROPERTY_IS_ADHOC_CONFERENCE}). */ public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000; /** * When set for a call, indicates that this {@code Call} can be transferred to another * number. * Call supports the confirmed and unconfirmed call transfer feature. * * @hide */ public static final int CAPABILITY_TRANSFER = 0x04000000; /** * When set for a call, indicates that this {@code Call} can be transferred to another * ongoing call. * Call supports the consultative call transfer feature. * * @hide */ public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x08000000; /** * Indicates whether the remote party supports RTT or not to the UI. */ public static final int CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT = 0x10000000; //****************************************************************************************** // Next CAPABILITY value: 0x40000000 //****************************************************************************************** /** * Whether the call is currently a conference. */ public static final int PROPERTY_CONFERENCE = 0x00000001; /** * Whether the call is a generic conference, where we do not know the precise state of * participants in the conference (eg. on CDMA). */ public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002; /** * Whether the call is made while the device is in emergency callback mode. */ public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004; /** * Connection is using WIFI. */ public static final int PROPERTY_WIFI = 0x00000008; /** * When set, the UI should indicate to the user that a call is using high definition * audio. *
* The underlying {@link ConnectionService} is responsible for reporting this * property. It is important to note that this property is not intended to report the * actual audio codec being used for a Call, but whether the call should be indicated * to the user as high definition. *
* The Android Telephony stack reports this property for calls based on a number * of factors, including which audio codec is used and whether a call is using an HD * codec end-to-end. Some mobile operators choose to suppress display of an HD indication, * and in these cases this property will not be set for a call even if the underlying audio * codec is in fact "high definition". */ public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010; /** * Whether the call is associated with the work profile. */ public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020; /** * When set, indicates that this {@code Call} does not actually exist locally for the * {@link ConnectionService}. *
* Consider, for example, a scenario where a user has two phones with the same phone number. * When a user places a call on one device, the telephony stack can represent that call on * the other device by adding it to the {@link ConnectionService} with the * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set. *
* An {@link InCallService} will only see calls with this property if it has the * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} * in its manifest. *
* See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. */ public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040; /** * Indicates that the call has CDMA Enhanced Voice Privacy enabled. */ public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080; /** * Indicates that the call is from a self-managed {@link ConnectionService}. *
* See also {@link Connection#PROPERTY_SELF_MANAGED} */ public static final int PROPERTY_SELF_MANAGED = 0x00000100; /** * Indicates the call used Assisted Dialing. * * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING */ public static final int PROPERTY_ASSISTED_DIALING = 0x00000200; /** * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the * {@link RttCall} object that is used to send and receive text. */ public static final int PROPERTY_RTT = 0x00000400; /** * Indicates that the call has been identified as the network as an emergency call. This * property may be set for both incoming and outgoing calls which the network identifies as * emergency calls. */ public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 0x00000800; /** * Indicates that the call is using VoIP audio mode. *
* When this property is set, the {@link android.media.AudioManager} audio mode for this * call will be {@link android.media.AudioManager#MODE_IN_COMMUNICATION}. When this * property is not set, the audio mode for this call will be * {@link android.media.AudioManager#MODE_IN_CALL}. *
* This property reflects changes made using {@link Connection#setAudioModeIsVoip(boolean)}. *
* You can use this property to determine whether an un-answered incoming call or a held * call will use VoIP audio mode (if the call does not currently have focus, the system * audio mode may not reflect the mode the call will use). */ public static final int PROPERTY_VOIP_AUDIO_MODE = 0x00001000; /** * Indicates that the call is an adhoc conference call. This property can be set for both * incoming and outgoing calls. An adhoc conference call is formed using * {@link #addConferenceParticipants(List)}, * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}, or * {@link TelecomManager#startConference(List, Bundle)}, rather than by merging existing * call using {@link #conference(Call)}. */ public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000; /** * Connection is using cross sim technology. *
* Indicates that the {@link Connection} is using a cross sim technology which would * register IMS over internet APN of default data subscription. *
*/
public static final int PROPERTY_CROSS_SIM = 0x00004000;
/**
* Connection is a tethered external call.
* Indicates that the {@link Connection} is fixed on this device but the audio streams are
* re-routed to another device.
*/
public static final int PROPERTY_TETHERED_CALL = 0x00008000;
//******************************************************************************************
// Next PROPERTY value: 0x00010000
//******************************************************************************************
private final @CallState int mState;
private final String mTelecomCallId;
private final Uri mHandle;
private final int mHandlePresentation;
private final String mCallerDisplayName;
private final int mCallerDisplayNamePresentation;
private final PhoneAccountHandle mAccountHandle;
private final int mCallCapabilities;
private final int mCallProperties;
private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
private final DisconnectCause mDisconnectCause;
private final long mConnectTimeMillis;
private final GatewayInfo mGatewayInfo;
private final int mVideoState;
private final StatusHints mStatusHints;
private final Bundle mExtras;
private final Bundle mIntentExtras;
private final long mCreationTimeMillis;
private final String mContactDisplayName;
private final @CallDirection int mCallDirection;
private final @Connection.VerificationStatus int mCallerNumberVerificationStatus;
private final CallEndpoint mActiveCallEndpoint;
private final Set
* This is the name as reported by the {@link ConnectionService} associated with this call.
*
* @return The display name for the caller.
*/
public String getCallerDisplayName() {
return mCallerDisplayName;
}
/**
* @return The presentation requirements for the caller display name. See
* {@link TelecomManager} for valid values.
*/
public int getCallerDisplayNamePresentation() {
return mCallerDisplayNamePresentation;
}
/**
* @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
* routed.
*/
public PhoneAccountHandle getAccountHandle() {
return mAccountHandle;
}
/**
* @return A bitmask of the capabilities of the {@code Call}, as defined by the various
* {@code CAPABILITY_*} constants in this class.
*/
public int getCallCapabilities() {
return mCallCapabilities;
}
/**
* @return A bitmask of the properties of the {@code Call}, as defined by the various
* {@code PROPERTY_*} constants in this class.
*/
public int getCallProperties() {
return mCallProperties;
}
/**
* @return a bitmask of the audio routes available for the call.
*
* @hide
*/
public int getSupportedAudioRoutes() {
return mSupportedAudioRoutes;
}
/**
* @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
* by {@link android.telecom.DisconnectCause}.
*/
public DisconnectCause getDisconnectCause() {
return mDisconnectCause;
}
/**
* Returns the time the {@link Call} connected (i.e. became active). This information is
* updated periodically, but user interfaces should not rely on this to display the "call
* time clock". For the time when the call was first added to Telecom, see
* {@link #getCreationTimeMillis()}.
*
* @return The time the {@link Call} connected in milliseconds since the epoch.
*/
public final long getConnectTimeMillis() {
return mConnectTimeMillis;
}
/**
* @return Information about any calling gateway the {@code Call} may be using.
*/
public GatewayInfo getGatewayInfo() {
return mGatewayInfo;
}
/**
* @return The video state of the {@code Call}.
*/
public int getVideoState() {
return mVideoState;
}
/**
* @return The current {@link android.telecom.StatusHints}, or {@code null} if none
* have been set.
*/
public StatusHints getStatusHints() {
return mStatusHints;
}
/**
* @return The extras associated with this call.
*/
public Bundle getExtras() {
return mExtras;
}
/**
* @return The extras used with the original intent to place this call.
*/
public Bundle getIntentExtras() {
return mIntentExtras;
}
/**
* Returns the time when the call was first created and added to Telecom. This is the same
* time that is logged as the start time in the Call Log (see
* {@link android.provider.CallLog.Calls#DATE}). To determine when the call was connected
* (became active), see {@link #getConnectTimeMillis()}.
*
* @return The creation time of the call, in millis since the epoch.
*/
public long getCreationTimeMillis() {
return mCreationTimeMillis;
}
/**
* Returns the name of the caller on the remote end, as derived from a
* {@link android.provider.ContactsContract} lookup of the call's handle.
* @return The name of the caller, or {@code null} if the lookup is not yet complete, if
* there's no contacts entry for the caller, or if the {@link InCallService} does
* not hold the {@link android.Manifest.permission#READ_CONTACTS} permission.
*/
public @Nullable String getContactDisplayName() {
return mContactDisplayName;
}
/**
* Indicates whether the call is an incoming or outgoing call.
* @return The call's direction.
*/
public @CallDirection int getCallDirection() {
return mCallDirection;
}
/**
* Gets the verification status for the phone number of an incoming call as identified in
* ATIS-1000082.
*
* For incoming calls, the number verification status indicates whether the device was
* able to verify the authenticity of the calling number using the STIR process outlined
* in ATIS-1000082. {@link Connection#VERIFICATION_STATUS_NOT_VERIFIED} indicates that
* the network was not able to use STIR to verify the caller's number (i.e. nothing is
* known regarding the authenticity of the number.
* {@link Connection#VERIFICATION_STATUS_PASSED} indicates that the network was able to
* use STIR to verify the caller's number. This indicates that the network has a high
* degree of confidence that the incoming call actually originated from the indicated
* number. {@link Connection#VERIFICATION_STATUS_FAILED} indicates that the network's
* STIR verification did not pass. This indicates that the incoming call may not
* actually be from the indicated number. This could occur if, for example, the caller
* is using an impersonated phone number.
*
* A {@link CallScreeningService} can use this information to help determine if an
* incoming call is potentially an unwanted call. A verification status of
* {@link Connection#VERIFICATION_STATUS_FAILED} indicates that an incoming call may not
* actually be from the number indicated on the call (i.e. impersonated number) and that it
* should potentially be blocked. Likewise,
* {@link Connection#VERIFICATION_STATUS_PASSED} can be used as a positive signal to
* help clarify that the incoming call is originating from the indicated number and it
* is less likely to be an undesirable call.
*
* An {@link InCallService} can use this information to provide a visual indicator to the
* user regarding the verification status of a call and to help identify calls from
* potentially impersonated numbers.
* @return the verification status.
*/
public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
return mCallerNumberVerificationStatus;
}
/**
* Return set of available {@link CallEndpoint} which can be used to push or answer this
* call via {@link #pushCall(CallEndpoint)} or {@link #answerCall(CallEndpoint, int)}.
* @return Set of available call endpoints.
*/
public @NonNull Set
* You can handle these callbacks by extending the {@link Callback} class and overriding the
* callbacks that your {@link InCallService} is interested in. The callback methods include the
* {@link Call} for which the callback applies, allowing reuse of a single instance of your
* {@link Callback} implementation, if desired.
*
* Use {@link Call#registerCallback(Callback)} to register your callback(s). Ensure
* {@link Call#unregisterCallback(Callback)} is called when you no longer require callbacks
* (typically in {@link InCallService#onCallRemoved(Call)}).
* Note: Callbacks which occur before you call {@link Call#registerCallback(Callback)} will not
* reach your implementation of {@link Callback}, so it is important to register your callback
* as soon as your {@link InCallService} is notified of a new call via
* {@link InCallService#onCallAdded(Call)}.
*/
public static abstract class Callback {
/**
* @hide
*/
@IntDef(prefix = { "HANDOVER_" },
value = {HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_NOT_SUPPORTED,
HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL,
HANDOVER_FAILURE_UNKNOWN})
@Retention(RetentionPolicy.SOURCE)
public @interface HandoverFailureErrors {}
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app
* to handover the call to rejects the handover request.
*
* Will be returned when {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} is called
* and the destination {@link PhoneAccountHandle}'s {@link ConnectionService} returns a
* {@code null} {@link Connection} from
* {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle,
* ConnectionRequest)}.
*
* For more information on call handovers, see
* {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1;
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
* is initiated but the source or destination app does not support handover.
*
* Will be returned when a handover is requested via
* {@link #handoverTo(PhoneAccountHandle, int, Bundle)} and the destination
* {@link PhoneAccountHandle} does not declare
* {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}. May also be returned when a handover is
* requested at the {@link PhoneAccountHandle} for the current call (i.e. the source call's
* {@link Details#getAccountHandle()}) does not declare
* {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}.
*
* For more information on call handovers, see
* {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
public static final int HANDOVER_FAILURE_NOT_SUPPORTED = 2;
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the remote
* user rejects the handover request.
*
* For more information on call handovers, see
* {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
public static final int HANDOVER_FAILURE_USER_REJECTED = 3;
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
* is ongoing emergency call.
*
* This error code is returned when {@link #handoverTo(PhoneAccountHandle, int, Bundle)} is
* called on an emergency call, or if any other call is an emergency call.
*
* Handovers are not permitted while there are ongoing emergency calls.
*
* For more information on call handovers, see
* {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
public static final int HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL = 4;
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
* fails for an unknown reason.
*
* For more information on call handovers, see
* {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
public static final int HANDOVER_FAILURE_UNKNOWN = 5;
/**
* @hide
*/
@IntDef(prefix = { "PUSH_FAILED_" },
value = {PUSH_FAILED_UNKNOWN_REASON, PUSH_FAILED_ENDPOINT_UNAVAILABLE,
PUSH_FAILED_ENDPOINT_TIMEOUT, PUSH_FAILED_ENDPOINT_REJECTED})
@Retention(RetentionPolicy.SOURCE)
public @interface PushFailedReason {}
/**
* Answer failure reason returned via {@link #onAnswerFailed(CallEndpoint, int)} when a push
* fails due to unknown reason.
*
* For more information on push call, see {@link #pushCall(CallEndpoint)}.
*/
public static final int PUSH_FAILED_UNKNOWN_REASON = 0;
/**
* Push failure reason returned via {@link #onCallPushFailed(CallEndpoint, int)} when a push
* fails due to requested endpoint is unavailable.
*
* For more information on push call, see {@link #pushCall(CallEndpoint)}.
*/
public static final int PUSH_FAILED_ENDPOINT_UNAVAILABLE = 1;
/**
* Push failure reason returned via {@link #onCallPushFailed(CallEndpoint, int)} when a push
* fails due to requested endpoint takes too long to handle the request.
*
* For more information on push call, see {@link #pushCall(CallEndpoint)}.
*/
public static final int PUSH_FAILED_ENDPOINT_TIMEOUT = 2;
/**
* Push failure reason returned via {@link #onCallPushFailed(CallEndpoint, int)} when a push
* fails due to endpoint rejected the request.
*
* For more information on push call, see {@link #pushCall(CallEndpoint)}.
*/
public static final int PUSH_FAILED_ENDPOINT_REJECTED = 3;
/**
* @hide
*/
@IntDef(prefix = { "ANSWER_FAILED_" },
value = {ANSWER_FAILED_UNKNOWN_REASON, ANSWER_FAILED_ENDPOINT_UNAVAILABLE,
ANSWER_FAILED_ENDPOINT_TIMEOUT, ANSWER_FAILED_ENDPOINT_REJECTED})
@Retention(RetentionPolicy.SOURCE)
public @interface AnswerFailedReason {}
/**
* Answer failure reason returned via {@link #onAnswerFailed(CallEndpoint, int)} when it
* fails due to unknown reason.
*
* For more information on answer call, see {@link #answerCall(CallEndpoint, int)}.
*/
public static final int ANSWER_FAILED_UNKNOWN_REASON = 0;
/**
* Answer failure reason returned via {@link #onAnswerFailed(CallEndpoint, int)} when it
* fails due to requested endpoint is unavailable.
*
* For more information on answer call, see {@link #answerCall(CallEndpoint, int)}.
*/
public static final int ANSWER_FAILED_ENDPOINT_UNAVAILABLE = 1;
/**
* Answer failure reason returned via {@link #onAnswerFailed(CallEndpoint, int)} when it
* fails due to requested endpoint takes too long to handle the request.
*
* For more information on answer call, see {@link #answerCall(CallEndpoint, int)}.
*/
public static final int ANSWER_FAILED_ENDPOINT_TIMEOUT = 2;
/**
* Answer failure reason returned via {@link #onAnswerFailed(CallEndpoint, int)} when it
* fails due to endpoint rejected the request.
*
* For more information on answer call, see {@link #answerCall(CallEndpoint, int)}.
*/
public static final int ANSWER_FAILED_ENDPOINT_REJECTED = 3;
/**
* @hide
*/
@IntDef(prefix = { "PULL_FAILED_" },
value = {PULL_FAILED_UNKNOWN_REASON, PULL_FAILED_ENDPOINT_TIMEOUT,
PULL_FAILED_ENDPOINT_REJECTED})
@Retention(RetentionPolicy.SOURCE)
public @interface PullFailedReason {}
/**
* Pull failure reason returned via {@link #onCallPullFailed(int)} when it fails due to
* unknown reason.
*
* For more information on pull call, see {@link #pullCall()}.
*/
public static final int PULL_FAILED_UNKNOWN_REASON = 0;
/**
* Pull failure reason returned via {@link #onCallPullFailed(int)} when it fails due to
* requested endpoint takes too long to handle the request.
*
* For more information on pull call, see {@link #pullCall()}.
*/
public static final int PULL_FAILED_ENDPOINT_TIMEOUT = 1;
/**
* Pull failure reason returned via {@link #onCallPullFailed(int)} when it fails due to
* endpoint rejected the request.
*
* For more information on pull call, see {@link #pullCall()}.
*/
public static final int PULL_FAILED_ENDPOINT_REJECTED = 2;
/**
* Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
*
* @param call The {@code Call} invoking this method.
* @param state The new state of the {@code Call}.
*/
public void onStateChanged(Call call, @CallState int state) {}
/**
* Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
*
* @param call The {@code Call} invoking this method.
* @param parent The new parent of the {@code Call}.
*/
public void onParentChanged(Call call, Call parent) {}
/**
* Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
*
* @param call The {@code Call} invoking this method.
* @param children The new children of the {@code Call}.
*/
public void onChildrenChanged(Call call, List
* Where possible, the Call should make an attempt to handle {@link Connection} events which
* are part of the {@code android.telecom.*} namespace. The Call should ignore any events
* it does not wish to handle. Unexpected events should be handled gracefully, as it is
* possible that a {@link ConnectionService} has defined its own Connection events which a
* Call is not aware of.
*
* See {@link Connection#sendConnectionEvent(String, Bundle)},
* {@link Conference#sendConferenceEvent(String, Bundle)}.
*
* @param call The {@code Call} receiving the event.
* @param event The event.
* @param extras Extras associated with the connection event.
*/
public void onConnectionEvent(Call call, String event, Bundle extras) {}
/**
* Invoked when the RTT mode changes for this call.
* @param call The call whose RTT mode has changed.
* @param mode the new RTT mode, one of
* {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
* or {@link RttCall#RTT_MODE_VCO}
*/
public void onRttModeChanged(Call call, int mode) {}
/**
* Invoked when the call's RTT status changes, either from off to on or from on to off.
* @param call The call whose RTT status has changed.
* @param enabled whether RTT is now enabled or disabled
* @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
* on, null otherwise.
*/
public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
/**
* Invoked when the remote end of the connection has requested that an RTT communication
* channel be opened. A response to this should be sent via {@link #respondToRttRequest}
* with the same ID that this method is invoked with.
* @param call The call which the RTT request was placed on
* @param id The ID of the request.
*/
public void onRttRequest(Call call, int id) {}
/**
* Invoked when the RTT session failed to initiate for some reason, including rejection
* by the remote party.
* @param call The call which the RTT initiation failure occurred on.
* @param reason One of the status codes defined in
* {@link android.telecom.Connection.RttModifyStatus}, with the exception of
* {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
*/
public void onRttInitiationFailure(Call call, int reason) {}
/**
* Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
* has completed successfully.
*
* For a full discussion of the handover process and the APIs involved, see
* {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
*
* @param call The call which had initiated handover.
*/
public void onHandoverComplete(Call call) {}
/**
* Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
* has failed.
*
* For a full discussion of the handover process and the APIs involved, see
* {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
*
* @param call The call which had initiated handover.
* @param failureReason Error reason for failure.
*/
public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {}
/**
* Invoked when call push request via {@link #pushCall(CallEndpoint)} has failed.
*
* @param endpoint The endpoint requested to push the call to.
* @param reason Failed reason.
*/
public void onCallPushFailed(@NonNull CallEndpoint endpoint, @PushFailedReason int reason)
{}
/**
* Invoked when answer call request via {@link #answerCall(CallEndpoint, int)} has failed.
*
* @param endpoint The endpoint requested to answer the call.
* @param reason Failed reason
*/
public void onAnswerFailed(@NonNull CallEndpoint endpoint, @AnswerFailedReason int reason)
{}
/**
* Invoked when pull call request via {@link #pullCall()} has failed.
*
* @param reason Failed reason
*/
public void onCallPullFailed(@PullFailedReason int reason) {}
}
/**
* A class that holds the state that describes the state of the RTT channel to the remote
* party, if it is active.
*/
public static final class RttCall {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
public @interface RttAudioMode {}
/**
* For metrics use. Default value in the proto.
* @hide
*/
public static final int RTT_MODE_INVALID = 0;
/**
* Indicates that there should be a bidirectional audio stream between the two parties
* on the call.
*/
public static final int RTT_MODE_FULL = 1;
/**
* Indicates that the local user should be able to hear the audio stream from the remote
* user, but not vice versa. Equivalent to muting the microphone.
*/
public static final int RTT_MODE_HCO = 2;
/**
* Indicates that the remote user should be able to hear the audio stream from the local
* user, but not vice versa. Equivalent to setting the volume to zero.
*/
public static final int RTT_MODE_VCO = 3;
private static final int READ_BUFFER_SIZE = 1000;
private InputStreamReader mReceiveStream;
private OutputStreamWriter mTransmitStream;
private int mRttMode;
private final InCallAdapter mInCallAdapter;
private final String mTelecomCallId;
private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
/**
* @hide
*/
public RttCall(String telecomCallId, InputStreamReader receiveStream,
OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter) {
mTelecomCallId = telecomCallId;
mReceiveStream = receiveStream;
mTransmitStream = transmitStream;
mRttMode = mode;
mInCallAdapter = inCallAdapter;
}
/**
* Returns the current RTT audio mode.
* @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
* {@link #RTT_MODE_HCO}.
*/
public int getRttAudioMode() {
return mRttMode;
}
/**
* Sets the RTT audio mode. The requested mode change will be communicated through
* {@link Callback#onRttModeChanged(Call, int)}.
* @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
* {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
*/
public void setRttMode(@RttAudioMode int mode) {
mInCallAdapter.setRttMode(mTelecomCallId, mode);
}
/**
* Writes the string {@param input} into the outgoing text stream for this RTT call. Since
* RTT transmits text in real-time, this method should be called once for each user action.
* For example, when the user enters text as discrete characters using the keyboard, this
* method should be called once for each character. However, if the user enters text by
* pasting or autocomplete, the entire contents of the pasted or autocompleted text should
* be sent in one call to this method.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
* @param input The message to send to the remote user.
*/
public void write(String input) throws IOException {
mTransmitStream.write(input);
mTransmitStream.flush();
}
/**
* Reads a string from the remote user, blocking if there is no data available. Returns
* {@code null} if the RTT conversation has been terminated and there is no further data
* to read.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
* @return A string containing text sent by the remote user, or {@code null} if the
* conversation has been terminated or if there was an error while reading.
*/
public String read() {
try {
int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
if (numRead < 0) {
return null;
}
return new String(mReadBuffer, 0, numRead);
} catch (IOException e) {
Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
return null;
}
}
/**
* Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to
* be read.
* @return A string containing text entered by the user, or {@code null} if the user has
* not entered any new text yet.
*/
public String readImmediately() throws IOException {
if (mReceiveStream.ready()) {
int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
if (numRead < 0) {
return null;
}
return new String(mReadBuffer, 0, numRead);
} else {
return null;
}
}
/**
* Closes the underlying file descriptors
* @hide
*/
public void close() {
try {
mReceiveStream.close();
} catch (IOException e) {
// ignore
}
try {
mTransmitStream.close();
} catch (IOException e) {
// ignore
}
}
}
/**
* @deprecated Use {@code Call.Callback} instead.
* @hide
*/
@Deprecated
@SystemApi
public static abstract class Listener extends Callback { }
private final Phone mPhone;
private final String mTelecomCallId;
private final InCallAdapter mInCallAdapter;
private final List
* This method can be called either when the call is in {@link #STATE_RINGING} or
* {@link #STATE_ACTIVE}. After Telecom acknowledges the request by setting the call's state to
* {@link #STATE_AUDIO_PROCESSING}, your app may setup the audio paths with the audio stack in
* order to capture and play audio on the call stream.
*
* This method can only be called by the default dialer app.
*
* Apps built with SDK version {@link android.os.Build.VERSION_CODES#R} or later which are using
* the microphone as part of audio processing should specify the foreground service type using
* the attribute {@link android.R.attr#foregroundServiceType} in the {@link InCallService}
* service element of the app's manifest file.
* The {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE} attribute should be specified.
* @see
* the Android Developer Site for more information.
* @hide
*/
@SystemApi
public void enterBackgroundAudioProcessing() {
if (mState != STATE_ACTIVE && mState != STATE_RINGING) {
throw new IllegalStateException("Call must be active or ringing");
}
mInCallAdapter.enterBackgroundAudioProcessing(mTelecomCallId);
}
/**
* Instructs Telecom to come out of the background audio processing state requested by
* {@link #enterBackgroundAudioProcessing()} or from the call screening service.
*
* This method can only be called when the call is in {@link #STATE_AUDIO_PROCESSING}.
*
* @param shouldRing If true, Telecom will put the call into the
* {@link #STATE_SIMULATED_RINGING} state and notify other apps that there is
* a ringing call. Otherwise, the call will go into {@link #STATE_ACTIVE}
* immediately.
* @hide
*/
@SystemApi
public void exitBackgroundAudioProcessing(boolean shouldRing) {
if (mState != STATE_AUDIO_PROCESSING) {
throw new IllegalStateException("Call must in the audio processing state");
}
mInCallAdapter.exitBackgroundAudioProcessing(mTelecomCallId, shouldRing);
}
/**
* Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
*
* Any other currently playing DTMF tone in the specified call is immediately stopped.
*
* @param digit A character representing the DTMF digit for which to play the tone. This
* value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
*/
public void playDtmfTone(char digit) {
mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
}
/**
* Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
* currently playing.
*
* DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
* currently playing, this method will do nothing.
*/
public void stopDtmfTone() {
mInCallAdapter.stopDtmfTone(mTelecomCallId);
}
/**
* Instructs this {@code Call} to continue playing a post-dial DTMF string.
*
* A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
* that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
*
* If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
* {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
*
* If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
* {@code Call} will pause playing the tones and notify callbacks via
* {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
* should display to the user an indication of this state and an affordance to continue
* the postdial sequence. When the user decides to continue the postdial sequence, the in-call
* app should invoke the {@link #postDialContinue(boolean)} method.
*
* @param proceed Whether or not to continue with the post-dial sequence.
*/
public void postDialContinue(boolean proceed) {
mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
}
/**
* Notifies this {@code Call} that an account has been selected and to proceed with placing
* an outgoing call. Optionally sets this account as the default account.
*/
public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
}
/**
* Instructs this {@code Call} to enter a conference.
*
* @param callToConferenceWith The other call with which to conference.
*/
public void conference(Call callToConferenceWith) {
if (callToConferenceWith != null) {
mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
}
}
/**
* Instructs this {@code Call} to split from any conference call with which it may be
* connected.
*/
public void splitFromConference() {
mInCallAdapter.splitFromConference(mTelecomCallId);
}
/**
* Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
*/
public void mergeConference() {
mInCallAdapter.mergeConference(mTelecomCallId);
}
/**
* Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
*/
public void swapConference() {
mInCallAdapter.swapConference(mTelecomCallId);
}
/**
* Pulls participants to existing call by forming a conference call.
* See {@link Details#CAPABILITY_ADD_PARTICIPANT}.
*
* @param participants participants to be pulled to existing call.
*/
public void addConferenceParticipants(@NonNull List
* Calls to this method are ignored if the call does not have the
* {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set.
*
* An {@link InCallService} will only see calls which support this method if it has the
* {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
* in its manifest.
*/
public void pullCall() {
pullExternalCall();
}
/**
* Initiates a request to the {@link ConnectionService} to push a call to a
* {@link CallEndpoint}.
*
*
* @param endpoint The call endpoint to which the call will be pushed.
*/
public void pushCall(@NonNull CallEndpoint endpoint) {
mInCallAdapter.pushCall(mTelecomCallId, endpoint);
}
/**
* Initiates a request to the {@link ConnectionService} to answer a call to a
* {@link CallEndpoint}.
*
* Calls to this method are ignored if the call does not have the
* {@link Call.Details#CAPABILITY_CAN_PULL_CALL} capability set.
*
* @param endpoint The call endpoint on which to answer the call.
* @param videoState The video state in which to answer the call.
*/
public void answerCall(@NonNull CallEndpoint endpoint,
@VideoProfile.VideoState int videoState) {
mInCallAdapter.answerCall(mTelecomCallId, endpoint, videoState);
}
/**
* Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in
* the {@link ConnectionService}.
*
* Call events are used to communicate point in time information from an {@link InCallService}
* to a {@link ConnectionService}. A {@link ConnectionService} implementation could define
* events which enable the {@link InCallService}, for example, toggle a unique feature of the
* {@link ConnectionService}.
*
* A {@link ConnectionService} can communicate to the {@link InCallService} using
* {@link Connection#sendConnectionEvent(String, Bundle)}.
*
* Events are exposed to {@link ConnectionService} implementations via
* {@link android.telecom.Connection#onCallEvent(String, Bundle)}.
*
* No assumptions should be made as to how a {@link ConnectionService} will handle these events.
* The {@link InCallService} must assume that the {@link ConnectionService} could chose to
* ignore some events altogether.
*
* Events should be fully qualified (e.g., {@code com.example.event.MY_EVENT}) to avoid
* conflicts between {@link InCallService} implementations. Further, {@link InCallService}
* implementations shall not re-purpose events in the {@code android.*} namespace, nor shall
* they define their own event types in this namespace. When defining a custom event type,
* ensure the contents of the extras {@link Bundle} is clearly defined. Extra keys for this
* bundle should be named similar to the event type (e.g. {@code com.example.extra.MY_EXTRA}).
*
* When defining events and the associated extras, it is important to keep their behavior
* consistent when the associated {@link InCallService} is updated. Support for deprecated
* events/extras should me maintained to ensure backwards compatibility with older
* {@link ConnectionService} implementations which were built to support the older behavior.
*
* @param event The connection event.
* @param extras Bundle containing extra information associated with the event.
*/
public void sendCallEvent(String event, Bundle extras) {
mInCallAdapter.sendCallEvent(mTelecomCallId, event, mTargetSdkVersion, extras);
}
/**
* Sends an RTT upgrade request to the remote end of the connection. Success is not
* guaranteed, and notification of success will be via the
* {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
public void sendRttRequest() {
mInCallAdapter.sendRttRequest(mTelecomCallId);
}
/**
* Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
* callback.
* The ID used here should be the same as the ID that was received via the callback.
* @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
* @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
*/
public void respondToRttRequest(int id, boolean accept) {
mInCallAdapter.respondToRttRequest(mTelecomCallId, id, accept);
}
/**
* Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
* by {@code toHandle}. The videoState specified indicates the desired video state after the
* handover.
*
* A call handover is the process where an ongoing call is transferred from one app (i.e.
* {@link ConnectionService} to another app. The user could, for example, choose to continue a
* mobile network call in a video calling app. The mobile network call via the Telephony stack
* is referred to as the source of the handover, and the video calling app is referred to as the
* destination.
*
* When considering a handover scenario the device this method is called on is considered the
* initiating device (since the user initiates the handover from this device), and the
* other device is considered the receiving device.
*
* When this method is called on the initiating device, the Telecom framework will bind
* to the {@link ConnectionService} defined by the {@code toHandle} {@link PhoneAccountHandle}
* and invoke
* {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle,
* ConnectionRequest)} to inform the destination app that a request has been made to handover a
* call to it. The app returns an instance of {@link Connection} to represent the handover call
* At this point the app should display UI to indicate to the user that a call
* handover is in process.
*
* The destination app is responsible for communicating the handover request from the
* initiating device to the receiving device.
*
* When the app on the receiving device receives the handover request, it calls
* {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} to continue the handover
* process from the initiating device to the receiving device. At this point
* the destination app on the receiving device should show UI to allow the user to
* choose whether they want to continue their call in the destination app.
*
* When the destination app on the receiving device calls
* {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}, Telecom will bind to its
* {@link ConnectionService} and call
* {@link ConnectionService#onCreateIncomingHandoverConnection(PhoneAccountHandle,
* ConnectionRequest)} to inform it of the handover request. The app returns an instance of
* {@link Connection} to represent the handover call.
*
* If the user of the receiving device accepts the handover, the app calls
* {@link Connection#setActive()} to complete the handover process; Telecom will disconnect the
* original call. If the user rejects the handover, the app calls
* {@link Connection#setDisconnected(DisconnectCause)} and specifies a {@link DisconnectCause}
* of {@link DisconnectCause#CANCELED} to indicate that the handover has been cancelled.
*
* Telecom will only allow handovers from {@link PhoneAccount}s which declare
* {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}. Similarly, the {@link PhoneAccount}
* specified by {@code toHandle} must declare {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}.
*
* Errors in the handover process are reported to the {@link InCallService} via
* {@link Callback#onHandoverFailed(Call, int)}. Errors in the handover process are reported to
* the involved {@link ConnectionService}s via
* {@link ConnectionService#onHandoverFailed(ConnectionRequest, int)}.
*
* @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover
* this call to.
* @param videoState Indicates the video state desired after the handover (see the
* {@code STATE_*} constants defined in {@link VideoProfile}).
* @param extras Bundle containing extra information to be passed to the
* {@link ConnectionService}
*/
public void handoverTo(PhoneAccountHandle toHandle, @VideoProfile.VideoState int videoState,
Bundle extras) {
mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras);
}
/**
* Terminate the RTT session on this call. The resulting state change will be notified via
* the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
public void stopRtt() {
mInCallAdapter.stopRtt(mTelecomCallId);
}
/**
* Adds some extras to this {@link Call}. Existing keys are replaced and new ones are
* added.
*
* No assumptions should be made as to how an In-Call UI or service will handle these
* extras. Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
*
* @param extras The extras to add.
*/
public final void putExtras(Bundle extras) {
if (extras == null) {
return;
}
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putAll(extras);
mInCallAdapter.putExtras(mTelecomCallId, extras);
}
/**
* Adds a boolean extra to this {@link Call}.
*
* @param key The extra key.
* @param value The value.
* @hide
*/
public final void putExtra(String key, boolean value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putBoolean(key, value);
mInCallAdapter.putExtra(mTelecomCallId, key, value);
}
/**
* Adds an integer extra to this {@link Call}.
*
* @param key The extra key.
* @param value The value.
* @hide
*/
public final void putExtra(String key, int value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putInt(key, value);
mInCallAdapter.putExtra(mTelecomCallId, key, value);
}
/**
* Adds a string extra to this {@link Call}.
*
* @param key The extra key.
* @param value The value.
* @hide
*/
public final void putExtra(String key, String value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putString(key, value);
mInCallAdapter.putExtra(mTelecomCallId, key, value);
}
/**
* Removes extras from this {@link Call}.
*
* @param keys The keys of the extras to remove.
*/
public final void removeExtras(List
* Note: Since canned responses may be loaded from the file system, they are not
* guaranteed to be present when this {@link Call} is first added to the {@link InCallService}
* via {@link InCallService#onCallAdded(Call)}. The callback
* {@link Call.Callback#onCannedTextResponsesLoaded(Call, List)} will be called when/if canned
* responses for the call become available.
*
* @see #reject(boolean, String)
*
* @return A list of canned text message responses.
*/
public List
* Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}.
*
* @param event
* @param extras
*/
private void fireOnConnectionEvent(final String event, final Bundle extras) {
for (CallbackRecord