Add support for rejecting Telecom call with a specified reason.
Adding a new Call API which supports passing a user-specified call
rejection reason down to the lower layers for reporting to the network.
Part of the VERSTAT spec involves support for this type of signaling, so
it makes sense to also support it here as well.
There are two potential types of reject reason:
declined - user declined the call because they want it to go to voicemail
or don't want to talk to the caller right now.
unwanted - this is a nuisance call and the user never wanted to receive it.
Bug: 135929421
Test: Added new CTS test to validate API pathways.
Test: Ran existing telecom and telephony unit tests.
Test: Modified test dialer app to use the new reject API and verified that
the reject reason signals down to the modem and translates to the correct
reject cause.
Change-Id: I67a1fc2619a989703d41a720426423b662be60aa
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index dd000ce..f5f5c66 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -540,7 +540,7 @@
if (mConferenceHost == null) {
return;
}
- mConferenceHost.performReject();
+ mConferenceHost.performReject(android.telecom.Call.REJECT_REASON_DECLINED);
}
/**
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index f2b2244..2f5e2a6 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -113,6 +113,7 @@
private static final int MSG_SET_CALL_RADIO_TECH = 18;
private static final int MSG_ON_CONNECTION_EVENT = 19;
private static final int MSG_REDIAL_CONNECTION_CHANGED = 20;
+ private static final int MSG_REJECT = 21;
private List<Uri> mParticipants;
private boolean mIsAdhocConferenceCall;
@@ -273,6 +274,10 @@
int cause = (int) msg.obj;
hangup(cause);
break;
+ case MSG_REJECT:
+ int rejectReason = (int) msg.obj;
+ reject(rejectReason);
+ break;
case MSG_SET_CALL_RADIO_TECH:
int vrat = (int) msg.obj;
@@ -926,13 +931,18 @@
@Override
public void onReject() {
- performReject();
+ performReject(android.telecom.Call.REJECT_REASON_DECLINED);
}
- public void performReject() {
+ @Override
+ public void onReject(@android.telecom.Call.RejectReason int rejectReason) {
+ performReject(rejectReason);
+ }
+
+ public void performReject(int rejectReason) {
Log.v(this, "performReject");
if (isValidRingingCall()) {
- mHandler.obtainMessage(MSG_HANGUP, android.telephony.DisconnectCause.INCOMING_REJECTED)
+ mHandler.obtainMessage(MSG_REJECT, rejectReason)
.sendToTarget();
}
super.onReject();
@@ -1678,6 +1688,46 @@
}
}
+ protected void reject(@android.telecom.Call.RejectReason int rejectReason) {
+ if (mOriginalConnection != null) {
+ mHangupDisconnectCause = android.telephony.DisconnectCause.INCOMING_REJECTED;
+ try {
+ // Hanging up a ringing call requires that we invoke call.hangup() as opposed to
+ // connection.hangup(). Without this change, the party originating the call
+ // will not get sent to voicemail if the user opts to reject the call.
+ if (isValidRingingCall()) {
+ Call call = getCall();
+ if (call != null) {
+ call.hangup(rejectReason);
+ } else {
+ Log.w(this, "Attempting to hangup a connection without backing call.");
+ }
+ } else {
+ // We still prefer to call connection.hangup() for non-ringing calls
+ // in order to support hanging-up specific calls within a conference call.
+ // If we invoked call.hangup() while in a conference, we would end up
+ // hanging up the entire conference call instead of the specific connection.
+ mOriginalConnection.hangup();
+ }
+ } catch (CallStateException e) {
+ Log.e(this, e, "Call to Connection.hangup failed with exception");
+ }
+ } else {
+ if (getState() == STATE_DISCONNECTED) {
+ Log.i(this, "hangup called on an already disconnected call!");
+ close();
+ } else {
+ // There are a few cases where mOriginalConnection has not been set yet. For
+ // example, when the radio has to be turned on to make an emergency call,
+ // mOriginalConnection could not be set for many seconds.
+ setTelephonyConnectionDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.LOCAL,
+ "Local Disconnect before connection established."));
+ close();
+ }
+ }
+ }
+
com.android.internal.telephony.Connection getOriginalConnection() {
return mOriginalConnection;
}