Add support for remote incoming calls: impl
This CL changes how incoming calls are routed. We now
treat incoming calls the same as outgoing calls.
This allows a ConnectionService to attach to a incoming call
using a remote connection.
Change-Id: I5232d062ad3b559f4fe7c8224e7234b2c6bf8431
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
index 1b0dcdf..870d61c 100644
--- a/src/com/android/telecomm/ConnectionServiceWrapper.java
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -56,87 +56,67 @@
* {@link IConnectionService}.
*/
final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
- private static final int MSG_NOTIFY_INCOMING_CALL = 1;
- private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
- private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
- private static final int MSG_CANCEL_OUTGOING_CALL = 4;
- private static final int MSG_SET_ACTIVE = 5;
- private static final int MSG_SET_RINGING = 6;
- private static final int MSG_SET_DIALING = 7;
- private static final int MSG_SET_DISCONNECTED = 8;
- private static final int MSG_SET_ON_HOLD = 9;
- private static final int MSG_SET_REQUESTING_RINGBACK = 10;
- private static final int MSG_SET_CALL_CAPABILITIES = 11;
- private static final int MSG_SET_IS_CONFERENCED = 12;
- private static final int MSG_ADD_CONFERENCE_CALL = 13;
- private static final int MSG_REMOVE_CALL = 14;
- private static final int MSG_ON_POST_DIAL_WAIT = 15;
- private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 16;
- private static final int MSG_SET_CALL_VIDEO_PROVIDER = 17;
- private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 18;
- private static final int MSG_SET_STATUS_HINTS = 19;
- private static final int MSG_SET_HANDLE = 20;
- private static final int MSG_SET_CALLER_DISPLAY_NAME = 21;
+ private static final int MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL = 1;
+ private static final int MSG_HANDLE_CREATE_CONNECTION_FAILED = 2;
+ private static final int MSG_HANDLE_CREATE_CONNECTION_CANCELLED = 3;
+ private static final int MSG_SET_ACTIVE = 4;
+ private static final int MSG_SET_RINGING = 5;
+ private static final int MSG_SET_DIALING = 6;
+ private static final int MSG_SET_DISCONNECTED = 7;
+ private static final int MSG_SET_ON_HOLD = 8;
+ private static final int MSG_SET_REQUESTING_RINGBACK = 9;
+ private static final int MSG_SET_CALL_CAPABILITIES = 10;
+ private static final int MSG_SET_IS_CONFERENCED = 11;
+ private static final int MSG_ADD_CONFERENCE_CALL = 12;
+ private static final int MSG_REMOVE_CALL = 13;
+ private static final int MSG_ON_POST_DIAL_WAIT = 14;
+ private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
+ private static final int MSG_SET_CALL_VIDEO_PROVIDER = 16;
+ private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 17;
+ private static final int MSG_SET_STATUS_HINTS = 18;
+ private static final int MSG_SET_HANDLE = 19;
+ private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Call call;
switch (msg.what) {
- case MSG_NOTIFY_INCOMING_CALL: {
+ case MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL: {
ConnectionRequest request = (ConnectionRequest) msg.obj;
- call = mCallIdMapper.getCall(request.getCallId());
- if (call != null && mPendingIncomingCalls.remove(call) &&
- call.isIncoming()) {
- mIncomingCallsManager.handleSuccessfulIncomingCall(call, request);
+ if (mPendingResponses.containsKey(request.getCallId())) {
+ mPendingResponses.remove(
+ request.getCallId()).handleCreateConnectionSuccessful(request);
} else {
- // TODO(santoscordon): For this an the other commented logging, we need
- // to reenable it. At the moment all ConnectionServiceAdapters receive
- // notification of changes to all calls, even calls which it may not own
- // (ala remote connections). We need to fix that and then uncomment the
- // logging calls here.
- //Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
- // call, request.getId());
+ //Log.w(this, "handleCreateConnectionSuccessful, unknown call: %s", callId);
}
break;
}
- case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
- ConnectionRequest request = (ConnectionRequest) msg.obj;
- if (mPendingOutgoingCalls.containsKey(request.getCallId())) {
- mPendingOutgoingCalls.remove(
- request.getCallId()).onOutgoingCallSuccess();
- } else {
- //Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
- }
- break;
- }
- case MSG_HANDLE_FAILED_OUTGOING_CALL: {
+ case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
SomeArgs args = (SomeArgs) msg.obj;
try {
ConnectionRequest request = (ConnectionRequest) args.arg1;
int statusCode = args.argi1;
String statusMsg = (String) args.arg2;
- // TODO(santoscordon): Do something with 'reason' or get rid of it.
-
- if (mPendingOutgoingCalls.containsKey(request.getCallId())) {
- mPendingOutgoingCalls.remove(request.getCallId())
- .onOutgoingCallFailure(statusCode, statusMsg);
+ if (mPendingResponses.containsKey(request.getCallId())) {
+ mPendingResponses.remove(request.getCallId())
+ .handleCreateConnectionFailed(statusCode, statusMsg);
mCallIdMapper.removeCall(request.getCallId());
} else {
- //Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
+ //Log.w(this, "handleCreateConnectionFailed, unknown call: %s", callId);
}
} finally {
args.recycle();
}
break;
}
- case MSG_CANCEL_OUTGOING_CALL: {
+ case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
ConnectionRequest request = (ConnectionRequest) msg.obj;
- if (mPendingOutgoingCalls.containsKey(request.getCallId())) {
- mPendingOutgoingCalls.remove(
- request.getCallId()).onOutgoingCallCancel();
+ if (mPendingResponses.containsKey(request.getCallId())) {
+ mPendingResponses.remove(
+ request.getCallId()).handleCreateConnectionCancelled();
} else {
- //Log.w(this, "cancelOutgoingCall, unknown call: %s", callId);
+ //Log.w(this, "handleCreateConnectionCancelled, unknown call: %s", callId);
}
break;
}
@@ -268,8 +248,7 @@
break;
}
case MSG_QUERY_REMOTE_CALL_SERVICES: {
- ConnectionServiceWrapper.this.queryRemoteConnectionServices(
- (RemoteServiceCallback) msg.obj);
+ queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
break;
}
case MSG_SET_CALL_VIDEO_PROVIDER: {
@@ -335,38 +314,29 @@
private final class Adapter extends IConnectionServiceAdapter.Stub {
@Override
- public void notifyIncomingCall(ConnectionRequest request) {
- logIncoming("notifyIncomingCall %s", request);
+ public void handleCreateConnectionSuccessful(ConnectionRequest request) {
+ logIncoming("handleCreateConnectionSuccessful %s", request);
mCallIdMapper.checkValidCallId(request.getCallId());
- mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, request).sendToTarget();
+ mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, request).sendToTarget();
}
@Override
- public void handleSuccessfulOutgoingCall(ConnectionRequest request) {
- logIncoming("handleSuccessfulOutgoingCall %s", request);
- mCallIdMapper.checkValidCallId(request.getCallId());
- mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, request).sendToTarget();
- }
-
- @Override
- public void handleFailedOutgoingCall(
- ConnectionRequest request,
- int errorCode,
- String errorMsg) {
- logIncoming("handleFailedOutgoingCall %s %d %s", request, errorCode, errorMsg);
+ public void handleCreateConnectionFailed(
+ ConnectionRequest request, int errorCode, String errorMsg) {
+ logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
mCallIdMapper.checkValidCallId(request.getCallId());
SomeArgs args = SomeArgs.obtain();
args.arg1 = request;
args.argi1 = errorCode;
args.arg2 = errorMsg;
- mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
+ mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
}
@Override
- public void cancelOutgoingCall(ConnectionRequest request) {
- logIncoming("cancelOutgoingCall %s", request);
+ public void handleCreateConnectionCancelled(ConnectionRequest request) {
+ logIncoming("handleCreateConnectionCancelled %s", request);
mCallIdMapper.checkValidCallId(request.getCallId());
- mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, request).sendToTarget();
+ mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
}
@Override
@@ -517,11 +487,9 @@
private final Adapter mAdapter = new Adapter();
private final CallsManager mCallsManager = CallsManager.getInstance();
- private final Set<Call> mPendingIncomingCalls = new HashSet<>();
private final Set<Call> mPendingConferenceCalls = new HashSet<>();
private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
- private final IncomingCallsManager mIncomingCallsManager;
- private final Map<String, OutgoingCallResponse> mPendingOutgoingCalls = new HashMap<>();
+ private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
private Binder mBinder = new Binder();
private IConnectionService mServiceInterface;
@@ -531,15 +499,11 @@
* Creates a connection service.
*
* @param componentName The component name of the service with which to bind.
- * @param incomingCallsManager Manages the incoming call initialization flow.
* @param connectionServiceRepository Connection service repository.
*/
ConnectionServiceWrapper(
- ComponentName componentName,
- IncomingCallsManager incomingCallsManager,
- ConnectionServiceRepository connectionServiceRepository) {
+ ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
super(TelecommConstants.ACTION_CONNECTION_SERVICE, componentName);
- mIncomingCallsManager = incomingCallsManager;
mConnectionServiceRepository = connectionServiceRepository;
}
@@ -555,16 +519,15 @@
}
/**
- * Attempts to place the specified call, see {@link IConnectionService#call}. Returns the result
- * asynchronously through the specified callback.
+ * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
*/
- void call(final Call call, final OutgoingCallResponse callResponse) {
- Log.d(this, "call(%s) via %s.", call, getComponentName());
+ void createConnection(final Call call, final CreateConnectionResponse response) {
+ Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
String callId = mCallIdMapper.getCallId(call);
- mPendingOutgoingCalls.put(callId, callResponse);
+ mPendingResponses.put(callId, response);
GatewayInfo gatewayInfo = call.getGatewayInfo();
Bundle extras = call.getExtras();
@@ -587,10 +550,10 @@
call.getVideoState());
try {
- mServiceInterface.call(request);
+ mServiceInterface.createConnection(request, call.isIncoming());
} catch (RemoteException e) {
- Log.e(this, e, "Failure to call -- %s", getComponentName());
- mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
+ Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
+ mPendingResponses.remove(callId).handleCreateConnectionFailed(
DisconnectCause.ERROR_UNSPECIFIED, e.toString());
}
}
@@ -598,7 +561,7 @@
@Override
public void onFailure() {
Log.e(this, new Exception(), "Failure to call %s", getComponentName());
- callResponse.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
+ response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
}
};
@@ -657,47 +620,6 @@
}
}
- /**
- * Starts retrieval of details for an incoming call. Details are returned through the connection
- * service adapter using the specified call ID. Upon failure, the specified error callback is
- * invoked. Can be invoked even when the connection service is unbound. See
- * {@link IConnectionService#createIncomingCall}.
- *
- * @param call The call used for the incoming call.
- * @param errorCallback The callback to invoke upon failure.
- */
- void createIncomingCall(final Call call, final Runnable errorCallback) {
- Log.d(this, "createIncomingCall(%s) via %s.", call, getComponentName());
- BindCallback callback = new BindCallback() {
- @Override
- public void onSuccess() {
- if (isServiceValid("createIncomingCall")) {
- mPendingIncomingCalls.add(call);
- String callId = mCallIdMapper.getCallId(call);
- logOutgoing("createIncomingCall %s", callId);
- ConnectionRequest request = new ConnectionRequest(
- call.getPhoneAccount(),
- callId,
- call.getHandle(),
- call.getHandlePresentation(),
- call.getExtras(),
- call.getVideoState());
- try {
- mServiceInterface.createIncomingCall(request);
- } catch (RemoteException e) {
- }
- }
- }
-
- @Override
- public void onFailure() {
- errorCallback.run();
- }
- };
-
- mBinder.bind(callback);
- }
-
/** @see ConnectionService#disconnect(String) */
void disconnect(Call call) {
if (isServiceValid("disconnect")) {
@@ -768,12 +690,9 @@
}
void removeCall(Call call) {
- mPendingIncomingCalls.remove(call);
-
- OutgoingCallResponse outgoingResultCallback =
- mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
- if (outgoingResultCallback != null) {
- outgoingResultCallback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
+ CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
+ if (response != null) {
+ response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
}
mCallIdMapper.removeCall(call);
@@ -865,27 +784,14 @@
* Called when the associated connection service dies.
*/
private void handleConnectionServiceDeath() {
- if (!mPendingOutgoingCalls.isEmpty()) {
- for (OutgoingCallResponse callback : mPendingOutgoingCalls.values()) {
- callback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
- }
- mPendingOutgoingCalls.clear();
- }
-
- if (!mPendingIncomingCalls.isEmpty()) {
- // Iterate through a copy because the code inside the loop will modify the original
- // list.
- for (Call call : ImmutableList.copyOf(mPendingIncomingCalls)) {
- Preconditions.checkState(call.isIncoming());
- mIncomingCallsManager.handleFailedIncomingCall(call);
- }
-
- if (!mPendingIncomingCalls.isEmpty()) {
- Log.wtf(this, "Pending calls did not get cleared.");
- mPendingIncomingCalls.clear();
+ if (!mPendingResponses.isEmpty()) {
+ CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
+ new CreateConnectionResponse[mPendingResponses.values().size()]);
+ mPendingResponses.clear();
+ for (int i = 0; i < responses.length; i++) {
+ responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
}
}
-
mCallIdMapper.clear();
}
@@ -900,15 +806,16 @@
private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
final List<IBinder> connectionServices = new ArrayList<>();
final List<ComponentName> components = new ArrayList<>();
+ final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
final Collection<ConnectionServiceWrapper> services =
mConnectionServiceRepository.lookupServices();
+ Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
+
for (ConnectionServiceWrapper cs : services) {
if (cs != this) {
final ConnectionServiceWrapper currentConnectionService = cs;
cs.mBinder.bind(new BindCallback() {
- private int mRemainingResponses = services.size() - 1;
-
@Override
public void onSuccess() {
Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
@@ -920,13 +827,12 @@
@Override
public void onFailure() {
- // add null so that we always add up to totalExpected even if
- // some of the connection services fail to bind.
maybeComplete();
}
private void maybeComplete() {
- if (--mRemainingResponses == 0) {
+ servciesAttempted.add(currentConnectionService);
+ if (servciesAttempted.size() == services.size() - 1) {
try {
callback.onResult(components, connectionServices);
} catch (RemoteException ignored) {