Add support for rejecting Telecom call with a specified reason.
Piping through the reject with reason API.
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: I6782a502c62f1d0c6b6a8802bf17ea9b62621b34
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index e158230..b23e198 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -59,7 +59,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.IVideoProvider;
import com.android.internal.util.Preconditions;
-import com.android.server.telecom.ui.DisconnectedCallNotifier;
import com.android.server.telecom.ui.ToastFactory;
import java.io.IOException;
@@ -2274,6 +2273,38 @@
}
/**
+ * Reject this Telecom call with the user-indicated reason.
+ * @param rejectReason The user-indicated reason fore rejecting the call.
+ */
+ public void reject(@android.telecom.Call.RejectReason int rejectReason) {
+ if (mState == CallState.SIMULATED_RINGING) {
+ // This handles the case where the user manually rejects a call that's in simulated
+ // ringing. Since the call is already active on the connectionservice side, we want to
+ // hangup, not reject.
+ // Since its simulated reason we can't pass along the reject reason.
+ setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.REJECTED));
+ if (mConnectionService != null) {
+ mConnectionService.disconnect(this);
+ } else {
+ Log.e(this, new NullPointerException(),
+ "reject call failed due to null CS callId=%s", getId());
+ }
+ Log.addEvent(this, LogUtils.Events.REQUEST_REJECT);
+ } else if (isRinging("reject")) {
+ // Ensure video state history tracks video state at time of rejection.
+ mVideoStateHistory |= mVideoState;
+
+ if (mConnectionService != null) {
+ mConnectionService.rejectWithReason(this, rejectReason);
+ } else {
+ Log.e(this, new NullPointerException(),
+ "reject call failed due to null CS callId=%s", getId());
+ }
+ Log.addEvent(this, LogUtils.Events.REQUEST_REJECT, rejectReason);
+ }
+ }
+
+ /**
* Puts the call on hold if it is currently active.
*/
@VisibleForTesting
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 024a863..0643d3a 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -2364,6 +2364,25 @@
}
/**
+ * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call
+ * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
+ * the user opting to reject said call.
+ */
+ @VisibleForTesting
+ public void rejectCall(Call call, @android.telecom.Call.RejectReason int rejectReason) {
+ if (!mCalls.contains(call)) {
+ Log.i(this, "Request to reject a non-existent call %s", call);
+ } else {
+ for (CallsManagerListener listener : mListeners) {
+ listener.onIncomingCallRejected(call, false /* rejectWithMessage */,
+ null /* textMessage */);
+ }
+ call.reject(rejectReason);
+ }
+ }
+
+
+ /**
* Instructs Telecom to play the specified DTMF tone within the specified call.
*
* @param digit The DTMF digit to play.
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index ca513da..248374d 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -1551,6 +1551,19 @@
}
}
+ /** @see IConnectionService#reject(String, Session.Info) */
+ void rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("rejectReason")) {
+ try {
+ logOutgoing("rejectReason %s, %d", callId, rejectReason);
+
+ mServiceInterface.rejectWithReason(callId, rejectReason, Log.getExternalSession());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
/** @see IConnectionService#playDtmfTone(String, char, Session.Info) */
void playDtmfTone(Call call, char digit) {
final String callId = mCallIdMapper.getCallId(call);
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index 0c4c1db..3e2fa12 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -126,6 +126,32 @@
}
@Override
+ public void rejectCallWithReason(String callId,
+ @android.telecom.Call.RejectReason int rejectReason) {
+ try {
+ Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageName);
+
+ int callingUid = Binder.getCallingUid();
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Log.d(this, "rejectCallWithReason(%s,%d)", callId, rejectReason);
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ mCallsManager.rejectCall(call, rejectReason);
+ } else {
+ Log.w(this, "rejectCallWithReason, unknown call id: %s", callId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void playDtmfTone(String callId, char digit) {
try {
Log.startSession("ICA.pDT", mOwnerPackageName);
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index bcac5f1..315b074 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -306,6 +306,11 @@
rejectedCallIds.add(callId);
}
+ @Override public void rejectWithReason(java.lang.String callId, int rejectReason,
+ android.telecom.Logging.Session.Info sessionInfo) throws RemoteException {
+ rejectedCallIds.add(callId);
+ }
+
@Override
public void rejectWithMessage(String callId, String message,
Session.Info info) throws RemoteException {