Use mapped IDs for calls
With this CL each client gets a unique ID to represent calls.
This has a couple of benefits:
- avoids one client from modifying another clients call
- allows for stricter validation of input
- allows a call to handed off to a different call service
(with a different call ID)
Bug: 13643568
Change-Id: I6e2039aead5723d01f9442a4e54f5e616711a3b3
diff --git a/src/com/android/telecomm/CallServiceAdapter.java b/src/com/android/telecomm/CallServiceAdapter.java
index f61bce9..4bd7743 100644
--- a/src/com/android/telecomm/CallServiceAdapter.java
+++ b/src/com/android/telecomm/CallServiceAdapter.java
@@ -29,11 +29,8 @@
import java.util.Set;
/**
- * Used by call services in order to update state and control calls while the call service is bound
- * to Telecomm. Each call service is given its own instance for the lifetime of the binding between
- * Telecomm and the call service.
- * TODO(santoscordon): Whenever we get any method invocations from the call service, we need to
- * check that the invocation is expected from that call service.
+ * Used by call services to communicate with Telecomm. Each call service is given its own instance
+ * of the adapter for the lifetmie of the binding.
* TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity() in the service methods?
*/
public final class CallServiceAdapter extends ICallServiceAdapter.Stub {
@@ -50,44 +47,46 @@
private final class CallServiceAdapterHandler extends Handler {
@Override
public void handleMessage(Message msg) {
- String callId;
-
+ Call call;
switch (msg.what) {
case MSG_SET_IS_COMPATIBLE_WITH:
- callId = (String) msg.obj;
- if (mPendingOutgoingCallIds.contains(callId)) {
- mOutgoingCallsManager.setIsCompatibleWith(callId,
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null && !call.isIncoming()) {
+ mOutgoingCallsManager.setIsCompatibleWith(call,
msg.arg1 == 1 ? true : false);
} else {
- Log.wtf(this, "Unknown outgoing call: %s", callId);
+ Log.w(this, "Unknown call: %s, id: %s", call, msg.obj);
}
break;
case MSG_NOTIFY_INCOMING_CALL:
- CallInfo callInfo = (CallInfo) msg.obj;
- if (mPendingIncomingCallIds.remove(callInfo.getId())) {
- mIncomingCallsManager.handleSuccessfulIncomingCall(callInfo);
+ CallInfo clientCallInfo = (CallInfo) msg.obj;
+ call = mCallIdMapper.getCall(clientCallInfo.getId());
+ if (call != null && mPendingCalls.remove(call) && call.isIncoming()) {
+ CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
+ clientCallInfo.getHandle());
+ mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
} else {
- Log.wtf(this, "Unknown incoming call: %s", callInfo);
+ Log.w(this, "Unknown incoming call: %s, id: %s", call, msg.obj);
}
break;
case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL:
- callId = (String) msg.obj;
- if (mPendingOutgoingCallIds.remove(callId)) {
- mOutgoingCallsManager.handleSuccessfulCallAttempt(callId);
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
+ mOutgoingCallsManager.handleSuccessfulCallAttempt(call);
} else {
// TODO(gilad): Figure out how to wire up the callService.abort() call.
- Log.wtf(this, "Unknown outgoing call: %s", callId);
+ Log.w(this, "Unknown outgoing call: %s, id: %s", call, msg.obj);
}
break;
case MSG_HANDLE_FAILED_OUTGOING_CALL: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- callId = (String) args.arg1;
+ call = mCallIdMapper.getCall(args.arg1);
String reason = (String) args.arg2;
- if (mPendingOutgoingCallIds.remove(callId)) {
- mOutgoingCallsManager.handleFailedCallAttempt(callId, reason);
+ if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
+ mOutgoingCallsManager.handleFailedCallAttempt(call, reason);
} else {
- Log.wtf(this, "Unknown outgoing call: %s", callId);
+ Log.w(this, "Unknown outgoing call: %s, id: %s", call, msg.obj);
}
} finally {
args.recycle();
@@ -95,33 +94,53 @@
break;
}
case MSG_SET_ACTIVE:
- callId = (String) msg.obj;
- mCallsManager.markCallAsActive(callId);
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsActive(call);
+ } else {
+ Log.w(this, "Unknown call id: %s", msg.obj);
+ }
break;
case MSG_SET_RINGING:
- callId = (String) msg.obj;
- mCallsManager.markCallAsRinging(callId);
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsRinging(call);
+ } else {
+ Log.w(this, "Unknown call id: %s", msg.obj);
+ }
break;
case MSG_SET_DIALING:
- callId = (String) msg.obj;
- mCallsManager.markCallAsDialing(callId);
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsDialing(call);
+ } else {
+ Log.w(this, "Unknown call id: %s", msg.obj);
+ }
break;
case MSG_SET_DISCONNECTED: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- callId = (String) args.arg1;
+ call = mCallIdMapper.getCall(args.arg1);
String disconnectMessage = (String) args.arg2;
int disconnectCause = args.argi1;
- mCallsManager.markCallAsDisconnected(callId, disconnectCause,
- disconnectMessage);
+ if (call != null) {
+ mCallsManager.markCallAsDisconnected(call, disconnectCause,
+ disconnectMessage);
+ } else {
+ Log.w(this, "Unknown call id: %s", msg.obj);
+ }
} finally {
args.recycle();
}
break;
}
case MSG_SET_ON_HOLD:
- callId = (String) msg.obj;
- mCallsManager.markCallAsOnHold(callId);
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsOnHold(call);
+ } else {
+ Log.w(this, "Unknown call id: %s", msg.obj);
+ }
break;
}
}
@@ -131,19 +150,8 @@
private final OutgoingCallsManager mOutgoingCallsManager;
private final IncomingCallsManager mIncomingCallsManager;
private final Handler mHandler = new CallServiceAdapterHandler();
-
- /**
- * The set of pending outgoing call IDs. Any {@link #handleSuccessfulOutgoingCall} and
- * {@link #handleFailedOutgoingCall} invocations with a call ID that is not in this set
- * are ignored.
- */
- private final Set<String> mPendingOutgoingCallIds = Sets.newHashSet();
-
- /**
- * The set of pending incoming call IDs. Any {@link #handleIncomingCall} invocations with
- * a call ID not in this set are ignored.
- */
- private final Set<String> mPendingIncomingCallIds = Sets.newHashSet();
+ private final CallIdMapper mCallIdMapper;
+ private final Set<Call> mPendingCalls = Sets.newHashSet();
/**
* Persists the specified parameters.
@@ -152,17 +160,21 @@
* @param incomingCallsManager Manages the incoming call initialization flow.
*/
CallServiceAdapter(
- OutgoingCallsManager outgoingCallsManager, IncomingCallsManager incomingCallsManager) {
+ OutgoingCallsManager outgoingCallsManager,
+ IncomingCallsManager incomingCallsManager,
+ CallIdMapper callIdMapper) {
ThreadUtil.checkOnMainThread();
mCallsManager = CallsManager.getInstance();
mOutgoingCallsManager = outgoingCallsManager;
mIncomingCallsManager = incomingCallsManager;
+ mCallIdMapper = callIdMapper;
}
/** {@inheritDoc} */
@Override
public void setIsCompatibleWith(String callId, boolean isCompatible) {
- checkValidCallId(callId);
+ Log.v(this, "setIsCompatibleWith id: %d, isCompatible: %b", callId, isCompatible);
+ mCallIdMapper.checkValidCallId(callId);
mHandler.obtainMessage(MSG_SET_IS_COMPATIBLE_WITH, isCompatible ? 1 : 0, 0, callId).
sendToTarget();
}
@@ -170,21 +182,21 @@
/** {@inheritDoc} */
@Override
public void notifyIncomingCall(CallInfo callInfo) {
- checkValidCallId(callInfo.getId());
+ mCallIdMapper.checkValidCallId(callInfo.getId());
mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void handleSuccessfulOutgoingCall(String callId) {
- checkValidCallId(callId);
+ mCallIdMapper.checkValidCallId(callId);
mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void handleFailedOutgoingCall(String callId, String reason) {
- checkValidCallId(callId);
+ mCallIdMapper.checkValidCallId(callId);
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.arg2 = reason;
@@ -194,31 +206,29 @@
/** {@inheritDoc} */
@Override
public void setActive(String callId) {
- checkValidCallId(callId);
+ mCallIdMapper.checkValidCallId(callId);
mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void setRinging(String callId) {
- checkValidCallId(callId);
+ mCallIdMapper.checkValidCallId(callId);
mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void setDialing(String callId) {
- checkValidCallId(callId);
+ mCallIdMapper.checkValidCallId(callId);
mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
}
/** {@inheritDoc} */
- // TODO(gilad): Ensure that any communication from the underlying ICallService
- // implementation is expected (or otherwise suppressed at the adapter level).
@Override
public void setDisconnected(
String callId, int disconnectCause, String disconnectMessage) {
- checkValidCallId(callId);
+ mCallIdMapper.checkValidCallId(callId);
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.arg2 = disconnectMessage;
@@ -229,86 +239,47 @@
/** {@inheritDoc} */
@Override
public void setOnHold(String callId) {
- checkValidCallId(callId);
+ mCallIdMapper.checkValidCallId(callId);
mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
}
/**
- * Adds the specified call ID to the list of pending outgoing call IDs.
- * TODO(gilad): Consider passing the call processor (instead of the ID) both here and in the
- * remove case (same for incoming) such that the detour via the *CallsManager can be avoided.
- *
- * @param callId The ID of the call.
+ * Adds the specified call to the list of pending calls. Only calls in this list which are
+ * outgoing will be handled by {@link #isCompatibleWith}, {@link handleSuccessfulOutgoingCall},
+ * and {@link handleFailedOutgoingCall}. Similarly, only calls in this list which are incoming
+ * will be handled by {@link notifyIncomingCall}.
*/
- void addPendingOutgoingCallId(String callId) {
- mPendingOutgoingCallIds.add(callId);
+ void addPendingCall(Call call) {
+ mPendingCalls.add(call);
}
/**
- * Removes the specified call ID from the list of pending outgoing call IDs.
- *
- * @param callId The ID of the call.
+ * Removes the specified call from the list of pending calls.
*/
- void removePendingOutgoingCallId(String callId) {
- mPendingOutgoingCallIds.remove(callId);
- }
-
- /**
- * Adds a call ID to the list of pending incoming call IDs. Only calls with call IDs in the
- * list will be handled by {@link #handleIncomingCall}.
- *
- * @param callId The ID of the call.
- */
- void addPendingIncomingCallId(String callId) {
- mPendingIncomingCallIds.add(callId);
- }
-
- /**
- * Removes the specified call ID from the list of pending incoming call IDs.
- *
- * @param callId The ID of the call.
- */
- void removePendingIncomingCallId(String callId) {
- mPendingIncomingCallIds.remove(callId);
+ void removePendingCall(Call call) {
+ mPendingCalls.remove(call);
}
/**
* Called when the associated call service dies.
*/
void handleCallServiceDeath() {
- if (!mPendingIncomingCallIds.isEmpty()) {
- // Here and in the for loop below, we need to iterate through a copy because the code
- // inside the loop will modify the original list.
- for (String callId : ImmutableList.copyOf(mPendingIncomingCallIds)) {
- mIncomingCallsManager.handleFailedIncomingCall(callId);
+ if (!mPendingCalls.isEmpty()) {
+ // Iterate through a copy because the code inside the loop will modify the original
+ // list.
+ for (Call call : ImmutableList.copyOf(mPendingCalls)) {
+ if (call.isIncoming()) {
+ mIncomingCallsManager.handleFailedIncomingCall(call);
+ } else {
+ mOutgoingCallsManager.handleFailedCallAttempt(call,
+ "Call service disconnected.");
+ }
}
- if (!mPendingIncomingCallIds.isEmpty()) {
- Log.wtf(this, "Pending incoming calls did not get cleared.");
- mPendingIncomingCallIds.clear();
+ if (!mPendingCalls.isEmpty()) {
+ Log.wtf(this, "Pending calls did not get cleared.");
+ mPendingCalls.clear();
}
}
-
- if (!mPendingOutgoingCallIds.isEmpty()) {
- for (String callId : ImmutableList.copyOf(mPendingOutgoingCallIds)) {
- mOutgoingCallsManager.handleFailedCallAttempt(callId, "Call service disconnected.");
- }
-
- if (!mPendingOutgoingCallIds.isEmpty()) {
- Log.wtf(this, "Pending outgoing calls did not get cleared.");
- mPendingOutgoingCallIds.clear();
- }
- }
- }
-
- /**
- * Throws an IllegalArgumentException if the specified call ID is invalid.
- *
- * @param callId The call ID to check.
- */
- private void checkValidCallId(String callId) {
- if (Strings.isNullOrEmpty(callId)) {
- throw new IllegalArgumentException("Invalid call ID.");
- }
}
}