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: I6f25fafa2b2620e2839e5d3a9fb986f1130fa165
This commit is contained in:
Tyler Gunn
2020-01-23 13:10:37 -08:00
parent 0ab00030a2
commit facfdee122
8 changed files with 104 additions and 0 deletions

View File

@@ -43500,6 +43500,7 @@ package android.telecom {
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, String);
method public void reject(int);
method public void removeExtras(java.util.List<java.lang.String>);
method public void removeExtras(java.lang.String...);
method public void respondToRttRequest(int, boolean);
@@ -43515,6 +43516,8 @@ package android.telecom {
field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
field public static final int REJECT_REASON_DECLINED = 1; // 0x1
field public static final int REJECT_REASON_UNWANTED = 2; // 0x2
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_AUDIO_PROCESSING = 12; // 0xc
field public static final int STATE_CONNECTING = 9; // 0x9
@@ -43782,6 +43785,7 @@ package android.telecom {
method public void onPostDialContinue(boolean);
method public void onPullExternalCall();
method public void onReject();
method public void onReject(int);
method public void onReject(String);
method public void onSeparate();
method public void onShowIncomingCallUi();

View File

@@ -265,6 +265,29 @@ public final class Call {
public static final String EVENT_HANDOVER_FAILED =
"android.telecom.event.HANDOVER_FAILED";
/**
* 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)
@@ -1519,6 +1542,16 @@ public final class Call {
mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
}
/**
* Instructs the {@link ConnectionService} providing this {@link #STATE_RINGING} call that the
* user has chosen to reject the call and has indicated a reason why the call is being rejected.
*
* @param rejectReason the reason the call is being rejected.
*/
public void reject(@RejectReason int rejectReason) {
mInCallAdapter.rejectCall(mTelecomCallId, rejectReason);
}
/**
* Instructs this {@code Call} to disconnect.
*/

View File

@@ -3036,6 +3036,17 @@ public abstract class Connection extends Conferenceable {
*/
public void onReject() {}
/**
* Notifies this Connection, which is in {@link #STATE_RINGING}, of a request to reject.
* <p>
* For managed {@link ConnectionService}s, this will be called when the user rejects a call via
* the default dialer's {@link InCallService} using {@link Call#reject(int)}.
* @param rejectReason the reason the user provided for rejecting the call.
*/
public void onReject(@android.telecom.Call.RejectReason int rejectReason) {
// to be implemented by ConnectionService.
}
/**
* Notifies this Connection, which is in {@link #STATE_RINGING}, of
* a request to reject with a message.

View File

@@ -194,6 +194,7 @@ public abstract class ConnectionService extends Service {
private static final int MSG_CREATE_CONFERENCE = 35;
private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36;
private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
private static final int MSG_REJECT_WITH_REASON = 38;
private static Connection sNullConnection;
@@ -449,6 +450,21 @@ public abstract class ConnectionService extends Service {
}
}
@Override
public void rejectWithReason(String callId,
@android.telecom.Call.RejectReason int rejectReason, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_REJECT);
try {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.argi1 = rejectReason;
args.arg2 = Log.createSubsession();
mHandler.obtainMessage(MSG_REJECT_WITH_REASON, args).sendToTarget();
} finally {
Log.endSession();
}
}
@Override
public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE);
@@ -1053,6 +1069,17 @@ public abstract class ConnectionService extends Service {
}
break;
}
case MSG_REJECT_WITH_REASON: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
try {
reject((String) args.arg1, args.argi1);
} finally {
args.recycle();
Log.endSession();
}
break;
}
case MSG_REJECT_WITH_MESSAGE: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg3,
@@ -1981,6 +2008,11 @@ public abstract class ConnectionService extends Service {
findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
}
private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) {
Log.d(this, "reject %s with reason %d", callId, rejectReason);
findConnectionForAction(callId, "reject").onReject(rejectReason);
}
private void silence(String callId) {
Log.d(this, "silence %s", callId);
findConnectionForAction(callId, "silence").onSilence();

View File

@@ -88,6 +88,19 @@ public final class InCallAdapter {
}
}
/**
* Instructs Telecom to reject the specified call.
*
* @param callId The identifier of the call to reject.
* @param rejectReason The reason the call was rejected.
*/
public void rejectCall(String callId, @Call.RejectReason int rejectReason) {
try {
mAdapter.rejectCallWithReason(callId, rejectReason);
} catch (RemoteException e) {
}
}
/**
* Instructs Telecom to disconnect the specified call.
*

View File

@@ -77,6 +77,8 @@ oneway interface IConnectionService {
void reject(String callId, in Session.Info sessionInfo);
void rejectWithReason(String callId, int rejectReason, in Session.Info sessionInfo);
void rejectWithMessage(String callId, String message, in Session.Info sessionInfo);
void disconnect(String callId, in Session.Info sessionInfo);

View File

@@ -34,6 +34,8 @@ oneway interface IInCallAdapter {
void rejectCall(String callId, boolean rejectWithMessage, String textMessage);
void rejectCallWithReason(String callId, int rejectReason);
void disconnectCall(String callId);
void holdCall(String callId);

View File

@@ -410,6 +410,13 @@ public class ImsCallSessionImplBase implements AutoCloseable {
* Rejects an incoming call or session update.
*
* @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
* The {@link android.telecom.InCallService} (dialer app) can use the
* {@link android.telecom.Call#reject(int)} API to reject a call while specifying
* a user-indicated reason for rejecting the call.
* Normal call declines ({@link android.telecom.Call#REJECT_REASON_DECLINED}) will
* map to {@link ImsReasonInfo#CODE_USER_DECLINE}.
* Unwanted calls ({@link android.telecom.Call#REJECT_REASON_UNWANTED}) will map
* to {@link ImsReasonInfo#CODE_SIP_USER_MARKED_UNWANTED}.
* {@link ImsCallSession.Listener#callSessionStartFailed}
*/
public void reject(int reason) {