Rename CallServiceWrapper to ConnectionServiceWrapper

Change-Id: I5a082e50dafea0104174cb97d3ae8af168944fc3
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 2be3355..3d4771b 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -23,9 +23,9 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.ContactsContract.Contacts;
-import android.telecomm.CallInfo;
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.CallState;
+import android.telecomm.ConnectionRequest;
 import android.telecomm.GatewayInfo;
 import android.telecomm.PhoneAccount;
 import android.telecomm.Response;
@@ -63,7 +63,7 @@
         void onSuccessfulOutgoingCall(Call call);
         void onFailedOutgoingCall(Call call, int errorCode, String errorMsg);
         void onCancelledOutgoingCall(Call call);
-        void onSuccessfulIncomingCall(Call call, CallInfo callInfo);
+        void onSuccessfulIncomingCall(Call call);
         void onFailedIncomingCall(Call call);
         void onRequestingRingback(Call call, boolean requestingRingback);
         void onPostDialWait(Call call, String remaining);
@@ -86,7 +86,7 @@
         @Override
         public void onCancelledOutgoingCall(Call call) {}
         @Override
-        public void onSuccessfulIncomingCall(Call call, CallInfo callInfo) {}
+        public void onSuccessfulIncomingCall(Call call) {}
         @Override
         public void onFailedIncomingCall(Call call) {}
         @Override
@@ -166,15 +166,9 @@
     private Uri mHandle;
 
     /**
-     * The call service which is attempted or already connecting this call.
+     * The connection service which is attempted or already connecting this call.
      */
-    private CallServiceWrapper mCallService;
-
-    /**
-     * The set of call services that were attempted in the process of placing/switching this call
-     * but turned out unsuitable.  Only used in the context of call switching.
-     */
-    private Set<CallServiceWrapper> mIncompatibleCallServices;
+    private ConnectionServiceWrapper mConnectionService;
 
     private boolean mIsEmergencyCall;
 
@@ -187,11 +181,11 @@
     private int mDisconnectCause = DisconnectCause.NOT_VALID;
 
     /**
-     * Additional disconnect information provided by the call service.
+     * Additional disconnect information provided by the connection service.
      */
     private String mDisconnectMessage;
 
-    /** Info used by the call services. */
+    /** Info used by the connection services. */
     private Bundle mExtras = Bundle.EMPTY;
 
     /** Set of listeners on this call. */
@@ -211,8 +205,8 @@
     /** Whether this call is requesting that Telecomm play the ringback tone on its behalf. */
     private boolean mRequestingRingback = false;
 
-    /** Incoming call-info to use when direct-to-voicemail query finishes. */
-    private CallInfo mPendingDirectToVoicemailCallInfo;
+    /** Whether direct-to-voicemail query is pending. */
+    private boolean mDirectToVoicemailQueryPending;
 
     private boolean mIsConferenceCapable = false;
 
@@ -272,8 +266,8 @@
     /** {@inheritDoc} */
     @Override public String toString() {
         String component = null;
-        if (mCallService != null && mCallService.getComponentName() != null) {
-            component = mCallService.getComponentName().flattenToShortString();
+        if (mConnectionService != null && mConnectionService.getComponentName() != null) {
+            component = mConnectionService.getComponentName().flattenToShortString();
         }
         return String.format(Locale.US, "[%s, %s, %s]", mState, component, Log.piiHandle(mHandle));
     }
@@ -435,48 +429,36 @@
         return mChildCalls;
     }
 
-    CallServiceWrapper getCallService() {
-        return mCallService;
+    ConnectionServiceWrapper getConnectionService() {
+        return mConnectionService;
     }
 
-    void setCallService(CallServiceWrapper callService) {
-        setCallService(callService, null);
+    void setConnectionService(ConnectionServiceWrapper service) {
+        Preconditions.checkNotNull(service);
+
+        clearConnectionService();
+
+        service.incrementAssociatedCallCount();
+        mConnectionService = service;
+        mConnectionService.addCall(this);
     }
 
     /**
-     * Changes the call service this call is associated with. If callToReplace is non-null then this
-     * call takes its place within the call service.
+     * Clears the associated connection service.
      */
-    void setCallService(CallServiceWrapper callService, Call callToReplace) {
-        Preconditions.checkNotNull(callService);
-
-        clearCallService();
-
-        callService.incrementAssociatedCallCount();
-        mCallService = callService;
-        if (callToReplace == null) {
-            mCallService.addCall(this);
-        } else {
-            mCallService.replaceCall(this, callToReplace);
-        }
-    }
-
-    /**
-     * Clears the associated call service.
-     */
-    void clearCallService() {
-        if (mCallService != null) {
-            CallServiceWrapper callServiceTemp = mCallService;
-            mCallService = null;
-            callServiceTemp.removeCall(this);
+    void clearConnectionService() {
+        if (mConnectionService != null) {
+            ConnectionServiceWrapper serviceTemp = mConnectionService;
+            mConnectionService = null;
+            serviceTemp.removeCall(this);
 
             // Decrementing the count can cause the service to unbind, which itself can trigger the
             // service-death code.  Since the service death code tries to clean up any associated
             // calls, we need to make sure to remove that information (e.g., removeCall()) before
             // we decrement. Technically, invoking removeCall() prior to decrementing is all that is
-            // necessary, but cleaning up mCallService prior to triggering an unbind is good to do.
-            // If you change this, make sure to update {@link clearCallServiceSelector} as well.
-            decrementAssociatedCallCount(callServiceTemp);
+            // necessary, but cleaning up mConnectionService prior to triggering an unbind is good
+            // to do.
+            decrementAssociatedCallCount(serviceTemp);
         }
     }
 
@@ -498,17 +480,15 @@
      * the result of the query will determine if the call is rejected or passed through to the
      * in-call UI.
      */
-    void handleVerifiedIncoming(CallInfo callInfo) {
-        Preconditions.checkState(callInfo.getState() == CallState.RINGING);
-
-        // We do not handle incoming calls immediately when they are verified by the call service.
-        // We allow the caller-info-query code to execute first so that we can read the
+    void handleVerifiedIncoming(ConnectionRequest request) {
+        // We do not handle incoming calls immediately when they are verified by the connection
+        // service. We allow the caller-info-query code to execute first so that we can read the
         // direct-to-voicemail property before deciding if we want to show the incoming call to the
         // user or if we want to reject the call.
-        mPendingDirectToVoicemailCallInfo = callInfo;
+        mDirectToVoicemailQueryPending = true;
 
         // Setting the handle triggers the caller info lookup code.
-        setHandle(callInfo.getHandle());
+        setHandle(request.getHandle());
 
         // Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
         // showing the user the incoming call screen.
@@ -521,7 +501,7 @@
     }
 
     void processDirectToVoicemail() {
-        if (mPendingDirectToVoicemailCallInfo != null) {
+        if (mDirectToVoicemailQueryPending) {
             if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
                 Log.i(this, "Directing call to voicemail: %s.", this);
                 // TODO(santoscordon): Once we move State handling from CallsManager to Call, we
@@ -534,16 +514,16 @@
 
                 // TODO(santoscordon): Replace this with state transition to RINGING.
                 for (Listener l : mListeners) {
-                    l.onSuccessfulIncomingCall(this, mPendingDirectToVoicemailCallInfo);
+                    l.onSuccessfulIncomingCall(this);
                 }
             }
 
-            mPendingDirectToVoicemailCallInfo = null;
+            mDirectToVoicemailQueryPending = false;
         }
     }
 
     void handleFailedIncoming() {
-        clearCallService();
+        clearConnectionService();
 
         // TODO: Needs more specific disconnect error for this case.
         setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED, null);
@@ -557,7 +537,7 @@
 
     /**
      * Starts the outgoing call sequence.  Upon completion, there should exist an active connection
-     * through a call service (or the call will have failed).
+     * through a connection service (or the call will have failed).
      */
     void startOutgoing() {
         Preconditions.checkState(mOutgoingCallProcessor == null);
@@ -583,7 +563,7 @@
             l.onFailedOutgoingCall(this, code, msg);
         }
 
-        clearCallService();
+        clearConnectionService();
         mOutgoingCallProcessor = null;
     }
 
@@ -594,45 +574,19 @@
             l.onCancelledOutgoingCall(this);
         }
 
-        clearCallService();
+        clearConnectionService();
         mOutgoingCallProcessor = null;
     }
 
     /**
-     * Adds the specified call service to the list of incompatible services.  The set is used when
-     * attempting to switch a phone call between call services such that incompatible services can
-     * be avoided.
-     *
-     * @param callService The incompatible call service.
-     */
-    void addIncompatibleCallService(CallServiceWrapper callService) {
-        if (mIncompatibleCallServices == null) {
-            mIncompatibleCallServices = Sets.newHashSet();
-        }
-        mIncompatibleCallServices.add(callService);
-    }
-
-    /**
-     * Checks whether or not the specified callService was identified as incompatible in the
-     * context of this call.
-     *
-     * @param callService The call service to evaluate.
-     * @return True upon incompatible call services and false otherwise.
-     */
-    boolean isIncompatibleCallService(CallServiceWrapper callService) {
-        return mIncompatibleCallServices != null &&
-                mIncompatibleCallServices.contains(callService);
-    }
-
-    /**
      * Plays the specified DTMF tone.
      */
     void playDtmfTone(char digit) {
-        if (mCallService == null) {
-            Log.w(this, "playDtmfTone() request on a call without a call service.");
+        if (mConnectionService == null) {
+            Log.w(this, "playDtmfTone() request on a call without a connection service.");
         } else {
-            Log.i(this, "Send playDtmfTone to call service for call %s", this);
-            mCallService.playDtmfTone(this, digit);
+            Log.i(this, "Send playDtmfTone to connection service for call %s", this);
+            mConnectionService.playDtmfTone(this, digit);
         }
     }
 
@@ -640,29 +594,29 @@
      * Stops playing any currently playing DTMF tone.
      */
     void stopDtmfTone() {
-        if (mCallService == null) {
-            Log.w(this, "stopDtmfTone() request on a call without a call service.");
+        if (mConnectionService == null) {
+            Log.w(this, "stopDtmfTone() request on a call without a connectino service.");
         } else {
-            Log.i(this, "Send stopDtmfTone to call service for call %s", this);
-            mCallService.stopDtmfTone(this);
+            Log.i(this, "Send stopDtmfTone to connection service for call %s", this);
+            mConnectionService.stopDtmfTone(this);
         }
     }
 
     /**
-     * Attempts to disconnect the call through the call service.
+     * Attempts to disconnect the call through the connection service.
      */
     void disconnect() {
         if (mState == CallState.NEW) {
             Log.v(this, "Aborting call %s", this);
             abort();
         } else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) {
-            Preconditions.checkNotNull(mCallService);
+            Preconditions.checkNotNull(mConnectionService);
 
-            Log.i(this, "Send disconnect to call service for call: %s", this);
-            // The call isn't officially disconnected until the call service confirms that the call
-            // was actually disconnected. Only then is the association between call and call service
-            // severed, see {@link CallsManager#markCallAsDisconnected}.
-            mCallService.disconnect(this);
+            Log.i(this, "Send disconnect to connection service for call: %s", this);
+            // The call isn't officially disconnected until the connection service confirms that the
+            // call was actually disconnected. Only then is the association between call and
+            // connection service severed, see {@link CallsManager#markCallAsDisconnected}.
+            mConnectionService.disconnect(this);
         }
     }
 
@@ -676,16 +630,16 @@
      * Answers the call if it is ringing.
      */
     void answer() {
-        Preconditions.checkNotNull(mCallService);
+        Preconditions.checkNotNull(mConnectionService);
 
         // Check to verify that the call is still in the ringing state. A call can change states
         // between the time the user hits 'answer' and Telecomm receives the command.
         if (isRinging("answer")) {
-            // At this point, we are asking the call service to answer but we don't assume that
-            // it will work. Instead, we wait until confirmation from the call service that the
-            // call is in a non-RINGING state before changing the UI. See
-            // {@link CallServiceAdapter#setActive} and other set* methods.
-            mCallService.answer(this);
+            // At this point, we are asking the connection service to answer but we don't assume
+            // that it will work. Instead, we wait until confirmation from the connectino service
+            // that the call is in a non-RINGING state before changing the UI. See
+            // {@link ConnectionServiceAdapter#setActive} and other set* methods.
+            mConnectionService.answer(this);
         }
     }
 
@@ -696,12 +650,12 @@
      * @param textMessage An optional text message to send as part of the rejection.
      */
     void reject(boolean rejectWithMessage, String textMessage) {
-        Preconditions.checkNotNull(mCallService);
+        Preconditions.checkNotNull(mConnectionService);
 
         // Check to verify that the call is still in the ringing state. A call can change states
         // between the time the user hits 'reject' and Telecomm receives the command.
         if (isRinging("reject")) {
-            mCallService.reject(this);
+            mConnectionService.reject(this);
         }
     }
 
@@ -709,10 +663,10 @@
      * Puts the call on hold if it is currently active.
      */
     void hold() {
-        Preconditions.checkNotNull(mCallService);
+        Preconditions.checkNotNull(mConnectionService);
 
         if (mState == CallState.ACTIVE) {
-            mCallService.hold(this);
+            mConnectionService.hold(this);
         }
     }
 
@@ -720,37 +674,13 @@
      * Releases the call from hold if it is currently active.
      */
     void unhold() {
-        Preconditions.checkNotNull(mCallService);
+        Preconditions.checkNotNull(mConnectionService);
 
         if (mState == CallState.ON_HOLD) {
-            mCallService.unhold(this);
+            mConnectionService.unhold(this);
         }
     }
 
-    /**
-     * @return An object containing read-only information about this call.
-     */
-    CallInfo toCallInfo(String callId) {
-        CallServiceDescriptor descriptor = null;
-        if (mCallService != null) {
-            descriptor = mCallService.getDescriptor();
-        }
-        Bundle extras = mExtras;
-        if (mGatewayInfo != null && mGatewayInfo.getGatewayProviderPackageName() != null &&
-                mGatewayInfo.getOriginalHandle() != null) {
-            extras = (Bundle) mExtras.clone();
-            extras.putString(
-                    NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
-                    mGatewayInfo.getGatewayProviderPackageName());
-            extras.putParcelable(
-                    NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
-                    mGatewayInfo.getOriginalHandle());
-
-        }
-        return new CallInfo(callId, mState, mHandle, mGatewayInfo, mAccount,
-                extras, descriptor);
-    }
-
     /** Checks if this is a live call or not. */
     boolean isAlive() {
         switch (mState) {
@@ -794,25 +724,25 @@
     }
 
     void postDialContinue(boolean proceed) {
-        getCallService().onPostDialContinue(this, proceed);
+        mConnectionService.onPostDialContinue(this, proceed);
     }
 
     void phoneAccountClicked() {
-        getCallService().onPhoneAccountClicked(this);
+        mConnectionService.onPhoneAccountClicked(this);
     }
 
     void conferenceInto(Call conferenceCall) {
-        if (mCallService == null) {
-            Log.w(this, "conference requested on a call without a call service.");
+        if (mConnectionService == null) {
+            Log.w(this, "conference requested on a call without a connection service.");
         } else {
-            mCallService.conference(conferenceCall, this);
+            mConnectionService.conference(conferenceCall, this);
         }
     }
 
     void expireConference() {
         // The conference call expired before we got a confirmation of the conference from the
-        // call service...so start shutting down.
-        clearCallService();
+        // connection service...so start shutting down.
+        clearConnectionService();
         for (Listener l : mListeners) {
             l.onExpiredConferenceCall(this);
         }
diff --git a/src/com/android/telecomm/CallActivity.java b/src/com/android/telecomm/CallActivity.java
index 2868216..0e66d32 100644
--- a/src/com/android/telecomm/CallActivity.java
+++ b/src/com/android/telecomm/CallActivity.java
@@ -97,8 +97,8 @@
     }
 
     /**
-     * Processes INCOMING_CALL intents. Grabs the call service informations from the intent extra
-     * and forwards that to the CallsManager to start the incoming call flow.
+     * Processes INCOMING_CALL intents. Grabs the connection service informations from the intent
+     * extra and forwards that to the CallsManager to start the incoming call flow.
      *
      * @param intent The incoming call intent.
      */
@@ -115,7 +115,7 @@
             clientExtras = intent.getBundleExtra(TelecommConstants.EXTRA_INCOMING_CALL_EXTRAS);
         }
 
-        Log.d(this, "Processing incoming call from call service [%s]", descriptor);
+        Log.d(this, "Processing incoming call from connection service [%s]", descriptor);
         mCallsManager.processIncomingCallIntent(descriptor, clientExtras);
     }
 }
diff --git a/src/com/android/telecomm/CallAudioManager.java b/src/com/android/telecomm/CallAudioManager.java
index 865e3ca..35de0cc 100644
--- a/src/com/android/telecomm/CallAudioManager.java
+++ b/src/com/android/telecomm/CallAudioManager.java
@@ -396,8 +396,8 @@
 
     private void updateAudioForForegroundCall() {
         Call call = CallsManager.getInstance().getForegroundCall();
-        if (call != null && call.getCallService() != null) {
-            call.getCallService().onAudioStateChanged(call, mAudioState);
+        if (call != null && call.getConnectionService() != null) {
+            call.getConnectionService().onAudioStateChanged(call, mAudioState);
         }
     }
 
diff --git a/src/com/android/telecomm/CallIdMapper.java b/src/com/android/telecomm/CallIdMapper.java
index 9f803c6..2366343 100644
--- a/src/com/android/telecomm/CallIdMapper.java
+++ b/src/com/android/telecomm/CallIdMapper.java
@@ -85,8 +85,8 @@
     void checkValidCallId(String callId) {
         // Note, no need for thread check, this method is thread safe.
         if (!isValidCallId(callId)) {
-            // TODO(santoscordon): Re-enable this once we stop getting updates to CallServiceWrapper
-            // for remote connections.
+            // TODO(santoscordon): Re-enable this once we stop getting updates to
+            // ConnectionServiceWrapper for remote connections.
             //throw new IllegalArgumentException(
             //        "Invalid call ID for " + mCallIdPrefix + ": " + callId);
         }
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index af4098c..e1feb0f 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -33,19 +33,19 @@
 import java.util.Set;
 
 /**
- * Searches for and returns call services.
+ * Searches for and returns connection services.
  */
-class CallServiceRepository extends BaseRepository<CallServiceWrapper> {
+class CallServiceRepository extends BaseRepository<ConnectionServiceWrapper> {
     /**
      * The representation of a single lookup. Maintains lookup state and invokes the "complete"
      * callback when finished.
      */
     private final class CallServiceLookup {
         final Set<ComponentName> mOutstandingProviders = Sets.newHashSet();
-        final Set<CallServiceWrapper> mServices = Sets.newHashSet();
-        final LookupCallback<CallServiceWrapper> mCallback;
+        final Set<ConnectionServiceWrapper> mServices = Sets.newHashSet();
+        final LookupCallback<ConnectionServiceWrapper> mCallback;
 
-        CallServiceLookup(LookupCallback<CallServiceWrapper> callback) {
+        CallServiceLookup(LookupCallback<ConnectionServiceWrapper> callback) {
             mCallback = callback;
         }
 
@@ -141,7 +141,8 @@
             ComponentName providerName = provider.getComponentName();
             if (mOutstandingProviders.remove(providerName)) {
                 if (callServiceDescriptors != null) {
-                    // Add all the call services from this provider to the call-service cache.
+                    // Add all the connection services from this provider to the connection-service
+                    // cache.
                     for (CallServiceDescriptor descriptor : callServiceDescriptors) {
                         mServices.add(getService(descriptor.getServiceComponent(), descriptor));
                     }
@@ -151,7 +152,7 @@
                     finishLookup();
                 }
             } else {
-                Log.i(this, "Unexpected call services from %s in lookup.", providerName);
+                Log.i(this, "Unexpected connection services from %s in lookup.", providerName);
             }
         }
 
@@ -169,23 +170,24 @@
     }
 
     /**
-     * Returns the call service implementation specified by the descriptor.
+     * Returns the connection service implementation specified by the descriptor.
      *
      * @param descriptor The call-service descriptor.
      */
-    CallServiceWrapper getService(CallServiceDescriptor descriptor) {
+    ConnectionServiceWrapper getService(CallServiceDescriptor descriptor) {
         return getService(descriptor.getServiceComponent(), descriptor);
     }
 
     /** {@inheritDoc} */
     @Override
-    protected void onLookupServices(LookupCallback<CallServiceWrapper> callback) {
+    protected void onLookupServices(LookupCallback<ConnectionServiceWrapper> callback) {
         new CallServiceLookup(callback).start();
     }
 
     @Override
-    protected CallServiceWrapper onCreateNewServiceWrapper(ComponentName componentName,
+    protected ConnectionServiceWrapper onCreateNewServiceWrapper(ComponentName componentName,
             Object param) {
-        return new CallServiceWrapper((CallServiceDescriptor) param, mIncomingCallsManager, this);
+        return new ConnectionServiceWrapper(
+                (CallServiceDescriptor) param, mIncomingCallsManager, this);
     }
 }
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
deleted file mode 100644
index 1414e0a..0000000
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ /dev/null
@@ -1,878 +0,0 @@
-/*
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.telecomm;
-
-import android.content.ComponentName;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telecomm.CallAudioState;
-import android.telecomm.CallInfo;
-import android.telecomm.CallService;
-import android.telecomm.CallServiceDescriptor;
-import android.telecomm.ConnectionRequest;
-import android.telecomm.TelecommConstants;
-import android.telephony.DisconnectCause;
-
-import com.android.internal.os.SomeArgs;
-
-import com.android.internal.telecomm.ICallService;
-import com.android.internal.telecomm.ICallServiceAdapter;
-import com.android.internal.telecomm.ICallServiceProvider;
-import com.android.internal.telecomm.ICallVideoProvider;
-import com.android.internal.telecomm.RemoteServiceCallback;
-import com.android.telecomm.BaseRepository.LookupCallback;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-import org.apache.http.conn.ClientConnectionRequest;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
- * when the object can safely be unbound. Other classes should not use {@link ICallService} directly
- * and instead should use this class to invoke methods of {@link ICallService}.
- */
-final class CallServiceWrapper extends ServiceBinder<ICallService> {
-    private static final String TAG = CallServiceWrapper.class.getSimpleName();
-
-    private final class Adapter extends ICallServiceAdapter.Stub {
-        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_ON_POST_DIAL_WAIT = 11;
-        private static final int MSG_CAN_CONFERENCE = 12;
-        private static final int MSG_SET_IS_CONFERENCED = 13;
-        private static final int MSG_ADD_CONFERENCE_CALL = 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_FEATURES = 17;
-
-        private final Handler mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                Call call;
-                switch (msg.what) {
-                    case MSG_NOTIFY_INCOMING_CALL:
-                        CallInfo clientCallInfo = (CallInfo) msg.obj;
-                        call = mCallIdMapper.getCall(clientCallInfo.getId());
-                        if (call != null && mPendingIncomingCalls.remove(call) &&
-                                call.isIncoming()) {
-                            CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
-                                    clientCallInfo.getHandle());
-                            mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
-                        } else {
-                            // TODO(santoscordon): For this an the other commented logging, we need
-                            // to reenable it.  At the moment all CallServiceAdapters 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, clientCallInfo.getId());
-                        }
-                        break;
-                    case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
-                        String callId = (String) msg.obj;
-                        if (mPendingOutgoingCalls.containsKey(callId)) {
-                            mPendingOutgoingCalls.remove(callId).onOutgoingCallSuccess();
-                        } else {
-                            //Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
-                        }
-                        break;
-                    }
-                    case MSG_HANDLE_FAILED_OUTGOING_CALL: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            String callId = (String) 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(callId)) {
-                                mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
-                                        statusCode, statusMsg);
-                                mCallIdMapper.removeCall(callId);
-                            } else {
-                                //Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_CANCEL_OUTGOING_CALL: {
-                        String callId = (String) msg.obj;
-                        if (mPendingOutgoingCalls.containsKey(callId)) {
-                            mPendingOutgoingCalls.remove(callId).onOutgoingCallCancel();
-                        } else {
-                            //Log.w(this, "cancelOutgoingCall, unknown call: %s", callId);
-                        }
-                        break;
-                    }
-                    case MSG_SET_ACTIVE:
-                        call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null) {
-                            mCallsManager.markCallAsActive(call);
-                        } else {
-                            //Log.w(this, "setActive, unknown call id: %s", msg.obj);
-                        }
-                        break;
-                    case MSG_SET_RINGING:
-                        call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null) {
-                            mCallsManager.markCallAsRinging(call);
-                        } else {
-                            //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
-                        }
-                        break;
-                    case MSG_SET_DIALING:
-                        call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null) {
-                            mCallsManager.markCallAsDialing(call);
-                        } else {
-                            //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
-                        }
-                        break;
-                    case MSG_SET_DISCONNECTED: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            call = mCallIdMapper.getCall(args.arg1);
-                            String disconnectMessage = (String) args.arg2;
-                            int disconnectCause = args.argi1;
-                            if (call != null) {
-                                mCallsManager.markCallAsDisconnected(call, disconnectCause,
-                                        disconnectMessage);
-                            } else {
-                                //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_SET_ON_HOLD:
-                        call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null) {
-                            mCallsManager.markCallAsOnHold(call);
-                        } else {
-                            //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
-                        }
-                        break;
-                    case MSG_SET_REQUESTING_RINGBACK: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            call = mCallIdMapper.getCall(args.arg1);
-                            boolean ringback = (boolean) args.arg2;
-                            if (call != null) {
-                                call.setRequestingRingback(ringback);
-                            } else {
-                                //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_ON_POST_DIAL_WAIT: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            call = mCallIdMapper.getCall(args.arg1);
-                            if (call != null) {
-                                String remaining = (String) args.arg2;
-                                call.onPostDialWait(remaining);
-                            } else {
-                                //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_CAN_CONFERENCE: {
-                        call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null) {
-                            call.setIsConferenceCapable(msg.arg1 == 1);
-                        } else {
-                            //Log.w(CallServiceWrapper.this, "canConference, unknown call id: %s",
-                            //        msg.obj);
-                        }
-                        break;
-                    }
-                    case MSG_SET_IS_CONFERENCED: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            Call childCall = mCallIdMapper.getCall(args.arg1);
-                            if (childCall != null) {
-                                String conferenceCallId = (String) args.arg2;
-                                if (conferenceCallId == null) {
-                                    childCall.setParentCall(null);
-                                } else {
-                                    Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
-                                    if (conferenceCall != null &&
-                                            !mPendingConferenceCalls.contains(conferenceCall)) {
-                                        childCall.setParentCall(conferenceCall);
-                                    } else {
-                                        //Log.w(this, "setIsConferenced, unknown conference id %s",
-                                        //        conferenceCallId);
-                                    }
-                                }
-                            } else {
-                                //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_ADD_CONFERENCE_CALL: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            String callId = (String) args.arg1;
-                            Call conferenceCall = mCallIdMapper.getCall(callId);
-                            if (mPendingConferenceCalls.remove(conferenceCall)) {
-                                Log.v(this, "confirming conf call %s", conferenceCall);
-                                conferenceCall.confirmConference();
-                            } else {
-                                //Log.w(this, "addConference, unknown call id: %s", callId);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_QUERY_REMOTE_CALL_SERVICES: {
-                        CallServiceWrapper.this.queryRemoteConnectionServices(
-                                (RemoteServiceCallback) msg.obj);
-                        break;
-                    }
-                    case MSG_SET_CALL_VIDEO_PROVIDER: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            call = mCallIdMapper.getCall(args.arg1);
-                            ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
-                            if (call != null) {
-                                call.setCallVideoProvider(callVideoProvider);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_SET_FEATURES: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            call = mCallIdMapper.getCall(args.arg1);
-                            int features = (int) args.arg2;
-                            if (call != null) {
-                                call.setFeatures(features);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                }
-            }
-        };
-
-        /** {@inheritDoc} */
-        @Override
-        public void notifyIncomingCall(CallInfo callInfo) {
-            logIncoming("notifyIncomingCall %s", callInfo);
-            mCallIdMapper.checkValidCallId(callInfo.getId());
-            mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void handleSuccessfulOutgoingCall(String callId) {
-            logIncoming("handleSuccessfulOutgoingCall %s", callId);
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void handleFailedOutgoingCall(
-                ConnectionRequest request,
-                int errorCode,
-                String errorMsg) {
-            logIncoming("handleFailedOutgoingCall %s %d %s", request, errorCode, errorMsg);
-            mCallIdMapper.checkValidCallId(request.getCallId());
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = request.getCallId();
-            args.argi1 = errorCode;
-            args.arg2 = errorMsg;
-            mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void cancelOutgoingCall(String callId) {
-            logIncoming("cancelOutgoingCall %s", callId);
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, callId).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setActive(String callId) {
-            logIncoming("setActive %s", callId);
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setRinging(String callId) {
-            logIncoming("setRinging %s", callId);
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
-            logIncoming("setCallVideoProvider %s", callId);
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = callVideoProvider;
-            mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setDialing(String callId) {
-            logIncoming("setDialing %s", callId);
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setDisconnected(
-                String callId, int disconnectCause, String disconnectMessage) {
-            logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = disconnectMessage;
-            args.argi1 = disconnectCause;
-            mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setOnHold(String callId) {
-            logIncoming("setOnHold %s", callId);
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setRequestingRingback(String callId, boolean ringback) {
-            logIncoming("setRequestingRingback %s %b", callId, ringback);
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = ringback;
-            mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, args).sendToTarget();
-        }
-
-        /** ${inheritDoc} */
-        @Override
-        public void removeCall(String callId) {
-            logIncoming("removeCall %s", callId);
-        }
-
-        /** ${inheritDoc} */
-        @Override
-        public void setCanConference(String callId, boolean canConference) {
-            logIncoming("setCanConference %s %b", callId, canConference);
-            mHandler.obtainMessage(MSG_CAN_CONFERENCE, canConference ? 1 : 0, 0, callId)
-                    .sendToTarget();
-        }
-
-        /** ${inheritDoc} */
-        @Override
-        public void setIsConferenced(String callId, String conferenceCallId) {
-            logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = conferenceCallId;
-            mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
-        }
-
-        /** ${InheritDoc} */
-        @Override
-        public void addConferenceCall(String callId, CallInfo callInfo) {
-            logIncoming("addConferenceCall %s %s", callId, callInfo);
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = callInfo;
-            mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, args).sendToTarget();
-        }
-
-        @Override
-        public void onPostDialWait(String callId, String remaining) throws RemoteException {
-            logIncoming("onPostDialWait %s %s", callId, remaining);
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = remaining;
-            mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
-        }
-
-        /** ${inheritDoc} */
-        @Override
-        public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
-            logIncoming("queryRemoteCSs");
-            mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
-        }
-
-        @Override
-        public void setFeatures(String callId, int features) {
-            logIncoming("setFeatures %s %d", callId, features);
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = features;
-            mHandler.obtainMessage(MSG_SET_FEATURES, args).sendToTarget();
-        }
-    }
-
-    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 CallServiceDescriptor mDescriptor;
-    private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
-    private final IncomingCallsManager mIncomingCallsManager;
-    private final Map<String, OutgoingCallResponse> mPendingOutgoingCalls = new HashMap<>();
-    private final Handler mHandler = new Handler();
-
-    private Binder mBinder = new Binder();
-    private ICallService mServiceInterface;
-    private final CallServiceRepository mCallServiceRepository;
-
-    /**
-     * Creates a call-service for the specified descriptor.
-     *
-     * @param descriptor The call-service descriptor from
-     *            {@link ICallServiceProvider#lookupCallServices}.
-     * @param incomingCallsManager Manages the incoming call initialization flow.
-     * @param callServiceRepository Call service repository.
-     */
-    CallServiceWrapper(
-            CallServiceDescriptor descriptor,
-            IncomingCallsManager incomingCallsManager,
-            CallServiceRepository callServiceRepository) {
-        super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
-        mDescriptor = descriptor;
-        mIncomingCallsManager = incomingCallsManager;
-        mCallServiceRepository = callServiceRepository;
-    }
-
-    CallServiceDescriptor getDescriptor() {
-        return mDescriptor;
-    }
-
-    /** See {@link ICallService#setCallServiceAdapter}. */
-    private void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
-        if (isServiceValid("setCallServiceAdapter")) {
-            try {
-                logOutgoing("setCallServiceAdapter %s", callServiceAdapter);
-                mServiceInterface.setCallServiceAdapter(callServiceAdapter);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /**
-     * Attempts to place the specified call, see {@link ICallService#call}. Returns the result
-     * asynchronously through the specified callback.
-     */
-    void call(final Call call, final OutgoingCallResponse callResponse) {
-        Log.d(this, "call(%s) via %s.", call, getComponentName());
-        BindCallback callback = new BindCallback() {
-            @Override
-            public void onSuccess() {
-                String callId = mCallIdMapper.getCallId(call);
-                mPendingOutgoingCalls.put(callId, callResponse);
-
-                try {
-                    CallInfo callInfo = call.toCallInfo(callId);
-                    logOutgoing("call %s", callInfo);
-                    mServiceInterface.call(callInfo);
-                } catch (RemoteException e) {
-                    Log.e(this, e, "Failure to call -- %s", getDescriptor());
-                    mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
-                            DisconnectCause.ERROR_UNSPECIFIED, e.toString());
-                }
-            }
-
-            @Override
-            public void onFailure() {
-                Log.e(this, new Exception(), "Failure to call %s", getDescriptor());
-                callResponse.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
-            }
-        };
-
-        mBinder.bind(callback);
-    }
-
-    /** @see CallService#abort(String) */
-    void abort(Call call) {
-        // Clear out any pending outgoing call data
-        String callId = mCallIdMapper.getCallId(call);
-
-        // If still bound, tell the call service to abort.
-        if (isServiceValid("abort")) {
-            try {
-                logOutgoing("abort %s", callId);
-                mServiceInterface.abort(callId);
-            } catch (RemoteException e) {
-            }
-        }
-
-        removeCall(call);
-    }
-
-    /** @see CallService#hold(String) */
-    void hold(Call call) {
-        if (isServiceValid("hold")) {
-            try {
-                logOutgoing("hold %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.hold(mCallIdMapper.getCallId(call));
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /** @see CallService#unhold(String) */
-    void unhold(Call call) {
-        if (isServiceValid("unhold")) {
-            try {
-                logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.unhold(mCallIdMapper.getCallId(call));
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /** @see CallService#onAudioStateChanged(String,CallAudioState) */
-    void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
-        if (isServiceValid("onAudioStateChanged")) {
-            try {
-                logOutgoing("onAudioStateChanged %s %s",
-                        mCallIdMapper.getCallId(activeCall), audioState);
-                mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
-                        audioState);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /**
-     * Starts retrieval of details for an incoming call. Details are returned through the
-     * call-service adapter using the specified call ID. Upon failure, the specified error callback
-     * is invoked. Can be invoked even when the call service is unbound. See
-     * {@link ICallService#setIncomingCallId}.
-     *
-     * @param call The call used for the incoming call.
-     * @param extras The {@link CallService}-provided extras which need to be sent back.
-     * @param errorCallback The callback to invoke upon failure.
-     */
-    void setIncomingCallId(final Call call, final Bundle extras, final Runnable errorCallback) {
-        Log.d(this, "setIncomingCall(%s) via %s.", call, getComponentName());
-        BindCallback callback = new BindCallback() {
-            @Override
-            public void onSuccess() {
-                if (isServiceValid("setIncomingCallId")) {
-                    mPendingIncomingCalls.add(call);
-                    try {
-                        logOutgoing("setIncomingCallId %s %s",
-                                mCallIdMapper.getCallId(call), extras);
-                        mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
-                                extras);
-                    } catch (RemoteException e) {
-                    }
-                }
-            }
-
-            @Override
-            public void onFailure() {
-                errorCallback.run();
-            }
-        };
-
-        mBinder.bind(callback);
-    }
-
-    /** @see CallService#disconnect(String) */
-    void disconnect(Call call) {
-        if (isServiceValid("disconnect")) {
-            try {
-                logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /** @see CallService#answer(String) */
-    void answer(Call call) {
-        if (isServiceValid("answer")) {
-            try {
-                logOutgoing("answer %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.answer(mCallIdMapper.getCallId(call));
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /** @see CallService#reject(String) */
-    void reject(Call call) {
-        if (isServiceValid("reject")) {
-            try {
-                logOutgoing("reject %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.reject(mCallIdMapper.getCallId(call));
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /** @see CallService#playDtmfTone(String,char) */
-    void playDtmfTone(Call call, char digit) {
-        if (isServiceValid("playDtmfTone")) {
-            try {
-                logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
-                mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    /** @see CallService#stopDtmfTone(String) */
-    void stopDtmfTone(Call call) {
-        if (isServiceValid("stopDtmfTone")) {
-            try {
-                logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    void addCall(Call call) {
-        if (mCallIdMapper.getCallId(call) == null) {
-            mCallIdMapper.addCall(call);
-        }
-    }
-
-    /**
-     * Associates newCall with this call service by replacing callToReplace.
-     */
-    void replaceCall(Call newCall, Call callToReplace) {
-        Preconditions.checkState(callToReplace.getCallService() == this);
-        mCallIdMapper.replaceCall(newCall, callToReplace);
-    }
-
-    void removeCall(Call call) {
-        mPendingIncomingCalls.remove(call);
-
-        OutgoingCallResponse outgoingResultCallback =
-                mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
-        if (outgoingResultCallback != null) {
-            outgoingResultCallback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
-        }
-
-        mCallIdMapper.removeCall(call);
-    }
-
-    void onPostDialContinue(Call call, boolean proceed) {
-        if (isServiceValid("onPostDialContinue")) {
-            try {
-                logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
-                mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    void onPhoneAccountClicked(Call call) {
-        if (isServiceValid("onPhoneAccountClicked")) {
-            try {
-                logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    void conference(final Call conferenceCall, Call call) {
-        if (isServiceValid("conference")) {
-            try {
-                conferenceCall.setCallService(this);
-                mPendingConferenceCalls.add(conferenceCall);
-                mHandler.postDelayed(new Runnable() {
-                    @Override public void run() {
-                        if (mPendingConferenceCalls.remove(conferenceCall)) {
-                            conferenceCall.expireConference();
-                            Log.i(this, "Conference call expired: %s", conferenceCall);
-                        }
-                    }
-                }, Timeouts.getConferenceCallExpireMillis());
-
-                logOutgoing("conference %s %s",
-                        mCallIdMapper.getCallId(conferenceCall),
-                        mCallIdMapper.getCallId(call));
-                mServiceInterface.conference(
-                        mCallIdMapper.getCallId(conferenceCall),
-                        mCallIdMapper.getCallId(call));
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    void splitFromConference(Call call) {
-        if (isServiceValid("splitFromConference")) {
-            try {
-                logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
-                mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void setServiceInterface(IBinder binder) {
-        if (binder == null) {
-            // We have lost our service connection. Notify the world that this call service is done.
-            // We must notify the adapter before CallsManager. The adapter will force any pending
-            // outgoing calls to try the next call service. This needs to happen before CallsManager
-            // tries to clean up any calls still associated with this call service.
-            handleCallServiceDeath();
-            CallsManager.getInstance().handleCallServiceDeath(this);
-            mServiceInterface = null;
-        } else {
-            mServiceInterface = ICallService.Stub.asInterface(binder);
-            setCallServiceAdapter(mAdapter);
-        }
-    }
-
-    /**
-     * Called when the associated call service dies.
-     */
-    private void handleCallServiceDeath() {
-        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();
-            }
-        }
-
-        mCallIdMapper.clear();
-    }
-
-    private void logIncoming(String msg, Object... params) {
-        Log.d(this, "CallService -> Telecomm: " + msg, params);
-    }
-
-    private void logOutgoing(String msg, Object... params) {
-        Log.d(this, "Telecomm -> CallService: " + msg, params);
-    }
-
-    private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
-        final List<IBinder> callServices = new ArrayList<>();
-        final List<ComponentName> components = new ArrayList<>();
-
-        mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
-            private int mRemainingResponses;
-
-            /** ${inheritDoc} */
-            @Override
-            public void onComplete(Collection<CallServiceWrapper> services) {
-                mRemainingResponses = services.size() - 1;
-                for (CallServiceWrapper cs : services) {
-                    if (cs != CallServiceWrapper.this) {
-                        final CallServiceWrapper currentCallService = cs;
-                        cs.mBinder.bind(new BindCallback() {
-                            @Override
-                            public void onSuccess() {
-                                Log.d(this, "Adding ***** %s", currentCallService.getDescriptor());
-                                callServices.add(currentCallService.mServiceInterface.asBinder());
-                                components.add(currentCallService.getComponentName());
-                                maybeComplete();
-                            }
-
-                            @Override
-                            public void onFailure() {
-                                // add null so that we always add up to totalExpected even if
-                                // some of the call services fail to bind.
-                                maybeComplete();
-                            }
-
-                            private void maybeComplete() {
-                                if (--mRemainingResponses == 0) {
-                                    try {
-                                        callback.onResult(components, callServices);
-                                    } catch (RemoteException ignored) {
-                                    }
-                                }
-                            }
-                        });
-                    }
-                }
-            }
-        });
-    }
-}
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 28e264a..f78fb7c 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -19,7 +19,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.telecomm.CallAudioState;
-import android.telecomm.CallInfo;
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.CallState;
 import android.telecomm.GatewayInfo;
@@ -51,10 +50,10 @@
         void onCallAdded(Call call);
         void onCallRemoved(Call call);
         void onCallStateChanged(Call call, CallState oldState, CallState newState);
-        void onCallServiceChanged(
+        void onConnectionServiceChanged(
                 Call call,
-                CallServiceWrapper oldCallService,
-                CallServiceWrapper newCallService);
+                ConnectionServiceWrapper oldService,
+                ConnectionServiceWrapper newService);
         void onIncomingCallAnswered(Call call);
         void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage);
         void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall);
@@ -123,9 +122,9 @@
     public void onSuccessfulOutgoingCall(Call call) {
         Log.v(this, "onSuccessfulOutgoingCall, %s", call);
         if (mCalls.contains(call)) {
-            // The call's CallService has been updated.
+            // The call's ConnectionService has been updated.
             for (CallsManagerListener listener : mListeners) {
-                listener.onCallServiceChanged(call, null, call.getCallService());
+                listener.onConnectionServiceChanged(call, null, call.getConnectionService());
             }
         } else {
             Log.wtf(this, "unexpected successful call notification: %s", call);
@@ -150,9 +149,9 @@
     }
 
     @Override
-    public void onSuccessfulIncomingCall(Call call, CallInfo callInfo) {
+    public void onSuccessfulIncomingCall(Call call) {
         Log.d(this, "onSuccessfulIncomingCall");
-        setCallState(call, callInfo.getState());
+        setCallState(call, CallState.RINGING);
         addCall(call);
     }
 
@@ -264,13 +263,13 @@
      * specified call; using the specified call service descriptor. Upon success, execution returns
      * to {@link #onSuccessfulIncomingCall} to start the in-call UI.
      *
-     * @param descriptor The descriptor of the call service to use for this incoming call.
+     * @param descriptor The descriptor of the connection service to use for this incoming call.
      * @param extras The optional extras Bundle passed with the intent used for the incoming call.
      */
     void processIncomingCallIntent(CallServiceDescriptor descriptor, Bundle extras) {
         Log.d(this, "processIncomingCallIntent");
         // Create a call with no handle. Eventually, switchboard will update the call with
-        // additional information from the call service, but for now we just need one to pass
+        // additional information from the connection service, but for now we just need one to pass
         // around.
         Call call = new Call(true /* isIncoming */, false /* isConference */);
         // TODO(santoscordon): Move this to be a part of addCall()
@@ -516,15 +515,15 @@
     }
 
     /**
-     * Cleans up any calls currently associated with the specified call service when the
+     * Cleans up any calls currently associated with the specified connection service when the
      * call-service binder disconnects unexpectedly.
      *
-     * @param callService The call service that disconnected.
+     * @param service The connection service that disconnected.
      */
-    void handleCallServiceDeath(CallServiceWrapper callService) {
-        Preconditions.checkNotNull(callService);
+    void handleConnectionServiceDeath(ConnectionServiceWrapper service) {
+        Preconditions.checkNotNull(service);
         for (Call call : ImmutableList.copyOf(mCalls)) {
-            if (call.getCallService() == callService) {
+            if (call.getConnectionService() == service) {
                 markCallAsDisconnected(call, DisconnectCause.ERROR_UNSPECIFIED, null);
             }
         }
@@ -630,7 +629,7 @@
         Log.v(this, "removeCall(%s)", call);
 
         call.removeListener(this);
-        call.clearCallService();
+        call.clearConnectionService();
 
         boolean shouldNotify = false;
         if (mCalls.contains(call)) {
@@ -684,8 +683,8 @@
         Call newForegroundCall = null;
         for (Call call : mCalls) {
             // TODO(santoscordon): Foreground-ness needs to be explicitly set. No call, regardless
-            // of its state will be foreground by default and instead the call service should be
-            // notified when its calls enter and exit foreground state. Foreground will mean that
+            // of its state will be foreground by default and instead the connection service should
+            // be notified when its calls enter and exit foreground state. Foreground will mean that
             // the call should play audio and listen to microphone if it wants.
 
             // Active calls have priority.
diff --git a/src/com/android/telecomm/CallsManagerListenerBase.java b/src/com/android/telecomm/CallsManagerListenerBase.java
index a5320a4..f34bdad 100644
--- a/src/com/android/telecomm/CallsManagerListenerBase.java
+++ b/src/com/android/telecomm/CallsManagerListenerBase.java
@@ -38,10 +38,10 @@
     }
 
     @Override
-    public void onCallServiceChanged(
+    public void onConnectionServiceChanged(
             Call call,
-            CallServiceWrapper oldCallServiceWrapper,
-            CallServiceWrapper newCallService) {
+            ConnectionServiceWrapper oldService,
+            ConnectionServiceWrapper newService) {
     }
 
     @Override
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
new file mode 100644
index 0000000..0ae8d20
--- /dev/null
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telecomm;
+
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telecomm.CallAudioState;
+import android.telecomm.ConnectionService;
+import android.telecomm.CallServiceDescriptor;
+import android.telecomm.ConnectionRequest;
+import android.telecomm.GatewayInfo;
+import android.telecomm.TelecommConstants;
+import android.telephony.DisconnectCause;
+
+import com.android.internal.os.SomeArgs;
+
+import com.android.internal.telecomm.IConnectionService;
+import com.android.internal.telecomm.IConnectionServiceAdapter;
+import com.android.internal.telecomm.ICallServiceProvider;
+import com.android.internal.telecomm.ICallVideoProvider;
+import com.android.internal.telecomm.RemoteServiceCallback;
+import com.android.telecomm.BaseRepository.LookupCallback;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import org.apache.http.conn.ClientConnectionRequest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
+ * track of when the object can safely be unbound. Other classes should not use
+ * {@link IConnectionService} directly and instead should use this class to invoke methods of
+ * {@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_CAN_CONFERENCE = 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_FEATURES = 18;
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            Call call;
+            switch (msg.what) {
+                case MSG_NOTIFY_INCOMING_CALL: {
+                    ConnectionRequest request = (ConnectionRequest) msg.obj;
+                    call = mCallIdMapper.getCall(request.getCallId());
+                    if (call != null && mPendingIncomingCalls.remove(call) &&
+                            call.isIncoming()) {
+                        mIncomingCallsManager.handleSuccessfulIncomingCall(call, 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());
+                    }
+                    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: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        ConnectionRequest request = (ConnectionRequest) msg.obj;
+                        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);
+                            mCallIdMapper.removeCall(request.getCallId());
+                        } else {
+                            //Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_CANCEL_OUTGOING_CALL: {
+                    ConnectionRequest request = (ConnectionRequest) msg.obj;
+                    if (mPendingOutgoingCalls.containsKey(request.getCallId())) {
+                        mPendingOutgoingCalls.remove(
+                                request.getCallId()).onOutgoingCallCancel();
+                    } else {
+                        //Log.w(this, "cancelOutgoingCall, unknown call: %s", callId);
+                    }
+                    break;
+                }
+                case MSG_SET_ACTIVE:
+                    call = mCallIdMapper.getCall(msg.obj);
+                    if (call != null) {
+                        mCallsManager.markCallAsActive(call);
+                    } else {
+                        //Log.w(this, "setActive, unknown call id: %s", msg.obj);
+                    }
+                    break;
+                case MSG_SET_RINGING:
+                    call = mCallIdMapper.getCall(msg.obj);
+                    if (call != null) {
+                        mCallsManager.markCallAsRinging(call);
+                    } else {
+                        //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
+                    }
+                    break;
+                case MSG_SET_DIALING:
+                    call = mCallIdMapper.getCall(msg.obj);
+                    if (call != null) {
+                        mCallsManager.markCallAsDialing(call);
+                    } else {
+                        //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
+                    }
+                    break;
+                case MSG_SET_DISCONNECTED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        call = mCallIdMapper.getCall(args.arg1);
+                        String disconnectMessage = (String) args.arg2;
+                        int disconnectCause = args.argi1;
+                        if (call != null) {
+                            mCallsManager.markCallAsDisconnected(call, disconnectCause,
+                                    disconnectMessage);
+                        } else {
+                            //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_SET_ON_HOLD:
+                    call = mCallIdMapper.getCall(msg.obj);
+                    if (call != null) {
+                        mCallsManager.markCallAsOnHold(call);
+                    } else {
+                        //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
+                    }
+                    break;
+                case MSG_SET_REQUESTING_RINGBACK: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        call = mCallIdMapper.getCall(args.arg1);
+                        boolean ringback = (boolean) args.arg2;
+                        if (call != null) {
+                            call.setRequestingRingback(ringback);
+                        } else {
+                            //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_CAN_CONFERENCE: {
+                    call = mCallIdMapper.getCall(msg.obj);
+                    if (call != null) {
+                        call.setIsConferenceCapable(msg.arg1 == 1);
+                    } else {
+                        //Log.w(ConnectionServiceWrapper.this,
+                        //      "canConference, unknown call id: %s", msg.obj);
+                    }
+                    break;
+                }
+                case MSG_SET_IS_CONFERENCED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        Call childCall = mCallIdMapper.getCall(args.arg1);
+                        if (childCall != null) {
+                            String conferenceCallId = (String) args.arg2;
+                            if (conferenceCallId == null) {
+                                childCall.setParentCall(null);
+                            } else {
+                                Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
+                                if (conferenceCall != null &&
+                                        !mPendingConferenceCalls.contains(conferenceCall)) {
+                                    childCall.setParentCall(conferenceCall);
+                                } else {
+                                    //Log.w(this, "setIsConferenced, unknown conference id %s",
+                                    //        conferenceCallId);
+                                }
+                            }
+                        } else {
+                            //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_ADD_CONFERENCE_CALL: {
+                    Call conferenceCall = mCallIdMapper.getCall(msg.obj);
+                    if (mPendingConferenceCalls.remove(conferenceCall)) {
+                        Log.v(this, "confirming conf call %s", conferenceCall);
+                        conferenceCall.confirmConference();
+                    } else {
+                        //Log.w(this, "addConference, unknown call id: %s", callId);
+                    }
+                    break;
+                }
+                case MSG_REMOVE_CALL:
+                    break;
+                case MSG_ON_POST_DIAL_WAIT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        call = mCallIdMapper.getCall(args.arg1);
+                        if (call != null) {
+                            String remaining = (String) args.arg2;
+                            call.onPostDialWait(remaining);
+                        } else {
+                            //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_QUERY_REMOTE_CALL_SERVICES: {
+                    ConnectionServiceWrapper.this.queryRemoteConnectionServices(
+                            (RemoteServiceCallback) msg.obj);
+                    break;
+                }
+                case MSG_SET_CALL_VIDEO_PROVIDER: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        call = mCallIdMapper.getCall(args.arg1);
+                        ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
+                        if (call != null) {
+                            call.setCallVideoProvider(callVideoProvider);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_SET_FEATURES: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        call = mCallIdMapper.getCall(args.arg1);
+                        int features = (int) args.arg2;
+                        if (call != null) {
+                            call.setFeatures(features);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+            }
+        }
+    };
+
+    private final class Adapter extends IConnectionServiceAdapter.Stub {
+        /** {@inheritDoc} */
+        @Override
+        public void notifyIncomingCall(ConnectionRequest request) {
+            logIncoming("notifyIncomingCall %s", request);
+            mCallIdMapper.checkValidCallId(request.getCallId());
+            mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, request).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void handleSuccessfulOutgoingCall(ConnectionRequest request) {
+            logIncoming("handleSuccessfulOutgoingCall %s", request);
+            mCallIdMapper.checkValidCallId(request.getCallId());
+            mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, request).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void handleFailedOutgoingCall(
+                ConnectionRequest request,
+                int errorCode,
+                String errorMsg) {
+            logIncoming("handleFailedOutgoingCall %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();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void cancelOutgoingCall(ConnectionRequest request) {
+            logIncoming("cancelOutgoingCall %s", request);
+            mCallIdMapper.checkValidCallId(request.getCallId());
+            mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, request).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setActive(String callId) {
+            logIncoming("setActive %s", callId);
+            mCallIdMapper.checkValidCallId(callId);
+            mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setRinging(String callId) {
+            logIncoming("setRinging %s", callId);
+            mCallIdMapper.checkValidCallId(callId);
+            mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
+            logIncoming("setCallVideoProvider %s", callId);
+            mCallIdMapper.checkValidCallId(callId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = callVideoProvider;
+            mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setDialing(String callId) {
+            logIncoming("setDialing %s", callId);
+            mCallIdMapper.checkValidCallId(callId);
+            mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setDisconnected(
+                String callId, int disconnectCause, String disconnectMessage) {
+            logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
+            mCallIdMapper.checkValidCallId(callId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = disconnectMessage;
+            args.argi1 = disconnectCause;
+            mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setOnHold(String callId) {
+            logIncoming("setOnHold %s", callId);
+            mCallIdMapper.checkValidCallId(callId);
+            mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setRequestingRingback(String callId, boolean ringback) {
+            logIncoming("setRequestingRingback %s %b", callId, ringback);
+            mCallIdMapper.checkValidCallId(callId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = ringback;
+            mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, args).sendToTarget();
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void removeCall(String callId) {
+            logIncoming("removeCall %s", callId);
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void setCanConference(String callId, boolean canConference) {
+            logIncoming("setCanConference %s %b", callId, canConference);
+            mHandler.obtainMessage(MSG_CAN_CONFERENCE, canConference ? 1 : 0, 0, callId)
+                    .sendToTarget();
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void setIsConferenced(String callId, String conferenceCallId) {
+            logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = conferenceCallId;
+            mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
+        }
+
+        /** ${InheritDoc} */
+        @Override
+        public void addConferenceCall(String callId) {
+            logIncoming("addConferenceCall %s", callId);
+            mCallIdMapper.checkValidCallId(callId);
+            mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
+        }
+
+        @Override
+        public void onPostDialWait(String callId, String remaining) throws RemoteException {
+            logIncoming("onPostDialWait %s %s", callId, remaining);
+            mCallIdMapper.checkValidCallId(callId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = remaining;
+            mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
+            logIncoming("queryRemoteCSs");
+            mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
+        }
+
+        @Override
+        public void setFeatures(String callId, int features) {
+            logIncoming("setFeatures %s %d", callId, features);
+            mCallIdMapper.checkValidCallId(callId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = features;
+            mHandler.obtainMessage(MSG_SET_FEATURES, args).sendToTarget();
+        }
+    }
+
+    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 CallServiceDescriptor mDescriptor;
+    private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
+    private final IncomingCallsManager mIncomingCallsManager;
+    private final Map<String, OutgoingCallResponse> mPendingOutgoingCalls = new HashMap<>();
+
+    private Binder mBinder = new Binder();
+    private IConnectionService mServiceInterface;
+    private final CallServiceRepository mCallServiceRepository;
+
+    /**
+     * Creates a call-service for the specified descriptor.
+     *
+     * @param descriptor The call-service descriptor from
+     *            {@link ICallServiceProvider#lookupCallServices}.
+     * @param incomingCallsManager Manages the incoming call initialization flow.
+     * @param callServiceRepository Connection service repository.
+     */
+    ConnectionServiceWrapper(
+            CallServiceDescriptor descriptor,
+            IncomingCallsManager incomingCallsManager,
+            CallServiceRepository callServiceRepository) {
+        super(TelecommConstants.ACTION_CONNECTION_SERVICE, descriptor.getServiceComponent());
+        mDescriptor = descriptor;
+        mIncomingCallsManager = incomingCallsManager;
+        mCallServiceRepository = callServiceRepository;
+    }
+
+    CallServiceDescriptor getDescriptor() {
+        return mDescriptor;
+    }
+
+    /** See {@link IConnectionService#addConnectionServiceAdapter}. */
+    private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
+        if (isServiceValid("addConnectionServiceAdapter")) {
+            try {
+                logOutgoing("addConnectionServiceAdapter%s", adapter);
+                mServiceInterface.addConnectionServiceAdapter(adapter);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Attempts to place the specified call, see {@link IConnectionService#call}. Returns the result
+     * asynchronously through the specified callback.
+     */
+    void call(final Call call, final OutgoingCallResponse callResponse) {
+        Log.d(this, "call(%s) via %s.", call, getComponentName());
+        BindCallback callback = new BindCallback() {
+            @Override
+            public void onSuccess() {
+                String callId = mCallIdMapper.getCallId(call);
+                mPendingOutgoingCalls.put(callId, callResponse);
+
+                GatewayInfo gatewayInfo = call.getGatewayInfo();
+                Bundle extras = call.getExtras();
+                if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
+                        gatewayInfo.getOriginalHandle() != null) {
+                    extras = (Bundle) extras.clone();
+                    extras.putString(
+                            NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
+                            gatewayInfo.getGatewayProviderPackageName());
+                    extras.putParcelable(
+                            NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
+                            gatewayInfo.getOriginalHandle());
+                }
+                ConnectionRequest request = new ConnectionRequest(callId, call.getHandle(), extras);
+
+                try {
+                    mServiceInterface.call(request);
+                } catch (RemoteException e) {
+                    Log.e(this, e, "Failure to call -- %s", getDescriptor());
+                    mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
+                            DisconnectCause.ERROR_UNSPECIFIED, e.toString());
+                }
+            }
+
+            @Override
+            public void onFailure() {
+                Log.e(this, new Exception(), "Failure to call %s", getDescriptor());
+                callResponse.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
+            }
+        };
+
+        mBinder.bind(callback);
+    }
+
+    /** @see ConnectionService#abort(String) */
+    void abort(Call call) {
+        // Clear out any pending outgoing call data
+        String callId = mCallIdMapper.getCallId(call);
+
+        // If still bound, tell the connection service to abort.
+        if (isServiceValid("abort")) {
+            try {
+                logOutgoing("abort %s", callId);
+                mServiceInterface.abort(callId);
+            } catch (RemoteException e) {
+            }
+        }
+
+        removeCall(call);
+    }
+
+    /** @see ConnectionService#hold(String) */
+    void hold(Call call) {
+        if (isServiceValid("hold")) {
+            try {
+                logOutgoing("hold %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.hold(mCallIdMapper.getCallId(call));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /** @see ConnectionService#unhold(String) */
+    void unhold(Call call) {
+        if (isServiceValid("unhold")) {
+            try {
+                logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.unhold(mCallIdMapper.getCallId(call));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
+    void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
+        if (isServiceValid("onAudioStateChanged")) {
+            try {
+                logOutgoing("onAudioStateChanged %s %s",
+                        mCallIdMapper.getCallId(activeCall), audioState);
+                mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
+                        audioState);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Starts retrieval of details for an incoming call. Details are returned through the
+     * call-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 extras The {@link ConnectionService}-provided extras which need to be sent back.
+     * @param errorCallback The callback to invoke upon failure.
+     */
+    void createIncomingCall(final Call call, final Bundle extras, 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 %s", callId, extras);
+                    ConnectionRequest request = new ConnectionRequest(
+                            callId, call.getHandle(), extras);
+                    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")) {
+            try {
+                logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /** @see ConnectionService#answer(String) */
+    void answer(Call call) {
+        if (isServiceValid("answer")) {
+            try {
+                logOutgoing("answer %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.answer(mCallIdMapper.getCallId(call));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /** @see ConnectionService#reject(String) */
+    void reject(Call call) {
+        if (isServiceValid("reject")) {
+            try {
+                logOutgoing("reject %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.reject(mCallIdMapper.getCallId(call));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /** @see ConnectionService#playDtmfTone(String,char) */
+    void playDtmfTone(Call call, char digit) {
+        if (isServiceValid("playDtmfTone")) {
+            try {
+                logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
+                mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /** @see ConnectionService#stopDtmfTone(String) */
+    void stopDtmfTone(Call call) {
+        if (isServiceValid("stopDtmfTone")) {
+            try {
+                logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    void addCall(Call call) {
+        if (mCallIdMapper.getCallId(call) == null) {
+            mCallIdMapper.addCall(call);
+        }
+    }
+
+    /**
+     * Associates newCall with this connection service by replacing callToReplace.
+     */
+    void replaceCall(Call newCall, Call callToReplace) {
+        Preconditions.checkState(callToReplace.getConnectionService() == this);
+        mCallIdMapper.replaceCall(newCall, callToReplace);
+    }
+
+    void removeCall(Call call) {
+        mPendingIncomingCalls.remove(call);
+
+        OutgoingCallResponse outgoingResultCallback =
+                mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
+        if (outgoingResultCallback != null) {
+            outgoingResultCallback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
+        }
+
+        mCallIdMapper.removeCall(call);
+    }
+
+    void onPostDialContinue(Call call, boolean proceed) {
+        if (isServiceValid("onPostDialContinue")) {
+            try {
+                logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
+                mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    void onPhoneAccountClicked(Call call) {
+        if (isServiceValid("onPhoneAccountClicked")) {
+            try {
+                logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    void conference(final Call conferenceCall, Call call) {
+        if (isServiceValid("conference")) {
+            try {
+                conferenceCall.setConnectionService(this);
+                mPendingConferenceCalls.add(conferenceCall);
+                mHandler.postDelayed(new Runnable() {
+                    @Override public void run() {
+                        if (mPendingConferenceCalls.remove(conferenceCall)) {
+                            conferenceCall.expireConference();
+                            Log.i(this, "Conference call expired: %s", conferenceCall);
+                        }
+                    }
+                }, Timeouts.getConferenceCallExpireMillis());
+
+                logOutgoing("conference %s %s",
+                        mCallIdMapper.getCallId(conferenceCall),
+                        mCallIdMapper.getCallId(call));
+                mServiceInterface.conference(
+                        mCallIdMapper.getCallId(conferenceCall),
+                        mCallIdMapper.getCallId(call));
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    void splitFromConference(Call call) {
+        if (isServiceValid("splitFromConference")) {
+            try {
+                logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
+                mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setServiceInterface(IBinder binder) {
+        if (binder == null) {
+            // We have lost our service connection. Notify the world that this service is done.
+            // We must notify the adapter before CallsManager. The adapter will force any pending
+            // outgoing calls to try the next service. This needs to happen before CallsManager
+            // tries to clean up any calls still associated with this service.
+            handleConnectionServiceDeath();
+            CallsManager.getInstance().handleConnectionServiceDeath(this);
+            mServiceInterface = null;
+        } else {
+            mServiceInterface = IConnectionService.Stub.asInterface(binder);
+            addConnectionServiceAdapter(mAdapter);
+        }
+    }
+
+    /**
+     * 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();
+            }
+        }
+
+        mCallIdMapper.clear();
+    }
+
+    private void logIncoming(String msg, Object... params) {
+        Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
+    }
+
+    private void logOutgoing(String msg, Object... params) {
+        Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
+    }
+
+    private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
+        final List<IBinder> connectionServices = new ArrayList<>();
+        final List<ComponentName> components = new ArrayList<>();
+
+        mCallServiceRepository.lookupServices(new LookupCallback<ConnectionServiceWrapper>() {
+            private int mRemainingResponses;
+
+            /** ${inheritDoc} */
+            @Override
+            public void onComplete(Collection<ConnectionServiceWrapper> services) {
+                mRemainingResponses = services.size() - 1;
+                for (ConnectionServiceWrapper cs : services) {
+                    if (cs != ConnectionServiceWrapper.this) {
+                        final ConnectionServiceWrapper currentConnectionService = cs;
+                        cs.mBinder.bind(new BindCallback() {
+                            @Override
+                            public void onSuccess() {
+                                Log.d(this, "Adding ***** %s",
+                                        currentConnectionService.getDescriptor());
+                                connectionServices.add(
+                                        currentConnectionService.mServiceInterface.asBinder());
+                                components.add(currentConnectionService.getComponentName());
+                                maybeComplete();
+                            }
+
+                            @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) {
+                                    try {
+                                        callback.onResult(components, connectionServices);
+                                    } catch (RemoteException ignored) {
+                                    }
+                                }
+                            }
+                        });
+                    }
+                }
+            }
+        });
+    }
+}
diff --git a/src/com/android/telecomm/InCallController.java b/src/com/android/telecomm/InCallController.java
index c1c8eaf..d1215ae 100644
--- a/src/com/android/telecomm/InCallController.java
+++ b/src/com/android/telecomm/InCallController.java
@@ -103,10 +103,10 @@
     }
 
     @Override
-    public void onCallServiceChanged(
+    public void onConnectionServiceChanged(
             Call call,
-            CallServiceWrapper oldCallServiceWrapper,
-            CallServiceWrapper newCallService) {
+            ConnectionServiceWrapper oldService,
+            ConnectionServiceWrapper newService) {
         updateCall(call);
     }
 
@@ -261,8 +261,8 @@
 
     private InCallCall toInCallCall(Call call) {
         String callId = mCallIdMapper.getCallId(call);
-        CallServiceDescriptor descriptor =
-                call.getCallService() != null ? call.getCallService().getDescriptor() : null;
+        CallServiceDescriptor descriptor = call.getConnectionService() != null ?
+                call.getConnectionService().getDescriptor() : null;
 
         int capabilities = CallCapabilities.HOLD | CallCapabilities.MUTE;
         if (CallsManager.getInstance().isAddCallCapable(call)) {
diff --git a/src/com/android/telecomm/IncomingCallsManager.java b/src/com/android/telecomm/IncomingCallsManager.java
index 5a874ea..197f699 100644
--- a/src/com/android/telecomm/IncomingCallsManager.java
+++ b/src/com/android/telecomm/IncomingCallsManager.java
@@ -17,8 +17,8 @@
 package com.android.telecomm;
 
 import android.os.Bundle;
-import android.telecomm.CallInfo;
-import android.telecomm.CallService;
+import android.telecomm.ConnectionService;
+import android.telecomm.ConnectionRequest;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
@@ -34,11 +34,12 @@
     private final Set<Call> mPendingIncomingCalls = Sets.newLinkedHashSet();
 
     /**
-     * Retrieves details of an incoming call through its associated call service.
+     * Retrieves details of an incoming call through its associated connection service.
      *
      * @param call The call object.
      * @param extras The optional extras passed with the incoming call intent (to be returned to
-     *     the call service via {@link CallService#setIncomingCallId(String, android.os.Bundle)}).
+     *     the connection service via
+     *     {@link ConnectionService#createIncomingCall(ConnectionRequest)}.
      */
     void retrieveIncomingCall(final Call call, Bundle extras) {
         ThreadUtil.checkOnMainThread();
@@ -55,22 +56,22 @@
             }
         };
 
-        call.getCallService().setIncomingCallId(call, extras, errorCallback);
+        call.getConnectionService().createIncomingCall(call, extras, errorCallback);
     }
 
     /**
      * Notifies the incoming call of success after removing it from the pending
      * list.
      *
-     * @param callInfo The details of the call.
+     * @param request The details of the call.
      */
-    void handleSuccessfulIncomingCall(Call call, CallInfo callInfo) {
+    void handleSuccessfulIncomingCall(Call call, ConnectionRequest request) {
         ThreadUtil.checkOnMainThread();
 
         if (mPendingIncomingCalls.contains(call)) {
             Log.d(this, "Incoming call %s found.", call);
             mPendingIncomingCalls.remove(call);
-            call.handleVerifiedIncoming(callInfo);
+            call.handleVerifiedIncoming(request);
         }
     }
 
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index 9d1f008..c33b17e 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -35,11 +35,9 @@
 import java.util.Set;
 
 /**
- * Utility class to place a call using the specified set of call-services and ordered selectors.
- * Iterates through the selectors and gets a sorted list of supported call-service descriptors
- * for each selector. Upon receiving each sorted list (one list per selector), each of the
- * corresponding call services is then attempted until either the outgoing call is placed, the
- * attempted call is aborted, or the list is exhausted -- whichever occurs first.
+ * Utility class to place a call using the specified set of call-services. Each of the connection
+ * services is then attempted until either the outgoing call is placed, the attempted call is
+ * aborted, or the list is exhausted -- whichever occurs first.
  *
  * Except for the abort case, all other scenarios should terminate with the call notified
  * of the result.
@@ -54,13 +52,13 @@
     /**
      * The map of currently-available call-service implementations keyed by call-service ID.
      */
-    private final Map<String, CallServiceWrapper> mCallServicesById = Maps.newHashMap();
+    private final Map<String, ConnectionServiceWrapper> mConnectionServicesById = Maps.newHashMap();
 
     /**
-     * The set of attempted call services, used to ensure services are attempted at most once per
-     * outgoing-call attempt.
+     * The set of attempted connection services, used to ensure services are attempted at most once
+     * per outgoing-call attempt.
      */
-    private final Set<CallServiceWrapper> mAttemptedCallServices = Sets.newHashSet();
+    private final Set<ConnectionServiceWrapper> mAttemptedConnectionServices = Sets.newHashSet();
 
     private final CallServiceRepository mCallServiceRepository;
 
@@ -84,8 +82,8 @@
 
     /**
      * Persists the specified parameters and iterates through the prioritized list of call
-     * services. Stops once a matching call service is found. Calls with no matching
-     * call service will eventually be killed by the cleanup/monitor switchboard handler.
+     * services. Stops once a matching connection service is found. Calls with no matching
+     * connection service will eventually be killed by the cleanup/monitor switchboard handler.
      *
      * @param call The call to place.
      * @param callServiceRepository
@@ -109,11 +107,11 @@
     void process() {
         Log.v(this, "process, mIsAborted: %b", mIsAborted);
         if (!mIsAborted) {
-            // Lookup call services
-            mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
+            // Lookup connection services
+            mCallServiceRepository.lookupServices(new LookupCallback<ConnectionServiceWrapper>() {
                 @Override
-                public void onComplete(Collection<CallServiceWrapper> services) {
-                    setCallServices(services);
+                public void onComplete(Collection<ConnectionServiceWrapper> services) {
+                    setConnectionServices(services);
                 }
             });
         }
@@ -129,14 +127,15 @@
         if (!mIsAborted && mResultCallback != null) {
             mIsAborted = true;
 
-            // On an abort, we need to check if we already told the call service to place the
+            // On an abort, we need to check if we already told the connection service to place the
             // call. If so, we need to tell it to abort.
-            // TODO(santoscordon): The call service is saved with the call and so we have to query
-            // the call to get it, which is a bit backwards.  Ideally, the call service would be
-            // saved inside this class until the whole thing is complete and then set on the call.
-            CallServiceWrapper callService = mCall.getCallService();
-            if (callService != null) {
-                callService.abort(mCall);
+            // TODO(santoscordon): The conneciton service is saved with the call and so we have to
+            // query the call to get it, which is a bit backwards.  Ideally, the connection service
+            // would be saved inside this class until the whole thing is complete and then set on
+            // the call.
+            ConnectionServiceWrapper service = mCall.getConnectionService();
+            if (service != null) {
+                service.abort(mCall);
             }
 
             // We consider a deliberate abort to be a "normal" disconnect, not
@@ -150,17 +149,16 @@
     }
 
     /**
-     * Completes the outgoing call sequence by setting the call service on the call object. This is
-     * invoked when the call service adapter receives positive confirmation that the call service
-     * placed the call.
+     * Completes the outgoing call sequence by setting the connection service on the call object.
+     * This is invoked when the connection service adapter receives positive confirmation that the
+     * connection service placed the call.
      */
-    void handleSuccessfulCallAttempt(CallServiceWrapper callService) {
+    void handleSuccessfulCallAttempt(ConnectionServiceWrapper service) {
         Log.v(this, "handleSuccessfulCallAttempt");
         ThreadUtil.checkOnMainThread();
 
         if (mIsAborted) {
-            // TODO(gilad): Ask the call service to drop the call?
-            callService.abort(mCall);
+            service.abort(mCall);
             return;
         }
 
@@ -168,8 +166,8 @@
     }
 
     /**
-     * Attempts the next call service if the specified call service is the one currently being
-     * attempted.
+     * Attempts the next connection service if the specified connection service is the one currently
+    * being attempted.
      *
      * @param errorCode The reason for the failure, one of {@link DisconnectCause}.
      * @param errorMsg Optional text reason for the failure.
@@ -182,91 +180,90 @@
         mLastErrorMsg = errorMsg;
         if (!mIsAborted) {
             ThreadUtil.checkOnMainThread();
-            attemptNextCallService();
+            attemptNextConnectionService();
         }
     }
 
     /**
-     * Sets the call services to attempt for this outgoing call.
+     * Sets the connection services to attempt for this outgoing call.
      *
-     * @param callServices The call services.
+     * @param services The connection services.
      */
-    private void setCallServices(Collection<CallServiceWrapper> callServices) {
+    private void setConnectionServices(Collection<ConnectionServiceWrapper> services) {
         mCallServiceDescriptors = new ArrayList<>();
 
-        // Populate the list and map of call-service descriptors.  The list is needed since
-        // it's being passed down to selectors.
-        for (CallServiceWrapper callService : callServices) {
-            CallServiceDescriptor descriptor = callService.getDescriptor();
+        // Populate the list and map of call-service descriptors.
+        for (ConnectionServiceWrapper service : services) {
+            CallServiceDescriptor descriptor = service.getDescriptor();
             // TODO(sail): Remove once there's a way to pick the service.
             if (descriptor.getServiceComponent().getPackageName().equals(
                     "com.google.android.talk")) {
-                Log.i(this, "Moving call service %s to top of list", descriptor);
+                Log.i(this, "Moving connection service %s to top of list", descriptor);
                 mCallServiceDescriptors.add(0, descriptor);
             } else {
                 mCallServiceDescriptors.add(descriptor);
             }
-            mCallServicesById.put(descriptor.getCallServiceId(), callService);
+            mConnectionServicesById.put(descriptor.getConnectionServiceId(), service);
         }
 
         adjustCallServiceDescriptorsForEmergency();
 
         mCallServiceDescriptorIterator = mCallServiceDescriptors.iterator();
-        attemptNextCallService();
+        attemptNextConnectionService();
     }
 
     /**
-     * Attempts to place the call using the call service specified by the next call-service
+     * Attempts to place the call using the connection service specified by the next call-service
      * descriptor of mCallServiceDescriptorIterator.
      */
-    private void attemptNextCallService() {
-        Log.v(this, "attemptNextCallService, mIsAborted: %b", mIsAborted);
+    private void attemptNextConnectionService() {
+        Log.v(this, "attemptNextConnectionService, mIsAborted: %b", mIsAborted);
         if (mIsAborted) {
             return;
         }
 
         if (mCallServiceDescriptorIterator != null && mCallServiceDescriptorIterator.hasNext()) {
             CallServiceDescriptor descriptor = mCallServiceDescriptorIterator.next();
-            final CallServiceWrapper callService =
-                    mCallServicesById.get(descriptor.getCallServiceId());
+            final ConnectionServiceWrapper service =
+                    mConnectionServicesById.get(descriptor.getConnectionServiceId());
 
-            if (callService == null || mAttemptedCallServices.contains(callService)) {
-                // The next call service is either null or has already been attempted, fast forward
-                // to the next.
-                attemptNextCallService();
+            if (service == null || mAttemptedConnectionServices.contains(service)) {
+                // The next connection service is either null or has already been attempted, fast
+                // forward to the next.
+                attemptNextConnectionService();
             } else {
-                mAttemptedCallServices.add(callService);
-                mCall.setCallService(callService);
+                mAttemptedConnectionServices.add(service);
+                mCall.setConnectionService(service);
 
                 // Increment the associated call count until we get a result. This prevents the call
                 // service from unbinding while we are using it.
-                callService.incrementAssociatedCallCount();
+                service.incrementAssociatedCallCount();
 
-                Log.i(this, "Attempting to call from %s", callService.getDescriptor());
-                callService.call(mCall, new OutgoingCallResponse() {
+                Log.i(this, "Attempting to call from %s", service.getDescriptor());
+                service.call(mCall, new OutgoingCallResponse() {
                     @Override
                     public void onOutgoingCallSuccess() {
-                        handleSuccessfulCallAttempt(callService);
-                        callService.decrementAssociatedCallCount();
+                        handleSuccessfulCallAttempt(service);
+                        service.decrementAssociatedCallCount();
                     }
 
                     @Override
                     public void onOutgoingCallFailure(int code, String msg) {
                         handleFailedCallAttempt(code, msg);
-                        callService.decrementAssociatedCallCount();
+                        service.decrementAssociatedCallCount();
                     }
 
                     @Override
                     public void onOutgoingCallCancel() {
                         abort();
-                        callService.decrementAssociatedCallCount();
+                        service.decrementAssociatedCallCount();
                     }
                 });
             }
         } else {
-            Log.v(this, "attemptNextCallService, no more service descriptors, failing");
+            Log.v(this, "attemptNextConnectionService, no more service descriptors, failing");
             mCallServiceDescriptorIterator = null;
-            mCall.clearCallService();
+            mCall.clearConnectionService();
             sendResult(false, mLastErrorCode, mLastErrorMsg);
         }
     }
@@ -287,11 +284,11 @@
     }
 
     // If we are possibly attempting to call a local emergency number, ensure that the
-    // plain PSTN call service, if it exists, is attempted first.
+    // plain PSTN connection service, if it exists, is attempted first.
     private void adjustCallServiceDescriptorsForEmergency()  {
         for (int i = 0; i < mCallServiceDescriptors.size(); i++) {
             if (shouldProcessAsEmergency(mCall.getHandle())) {
-                if (TelephonyUtil.isPstnCallService(mCallServiceDescriptors.get(i))) {
+                if (TelephonyUtil.isPstnConnectionService(mCallServiceDescriptors.get(i))) {
                     mCallServiceDescriptors.add(0, mCallServiceDescriptors.remove(i));
                     return;
                 }
diff --git a/src/com/android/telecomm/PhoneStateBroadcaster.java b/src/com/android/telecomm/PhoneStateBroadcaster.java
index d6f1a38..4dee4bb 100644
--- a/src/com/android/telecomm/PhoneStateBroadcaster.java
+++ b/src/com/android/telecomm/PhoneStateBroadcaster.java
@@ -18,8 +18,8 @@
 
 import android.Manifest;
 import android.content.Intent;
-import android.telecomm.CallService;
 import android.telecomm.CallState;
+import android.telecomm.ConnectionService;
 import android.telecomm.TelecommConstants;
 import android.telephony.DisconnectCause;
 import android.telephony.TelephonyManager;
@@ -68,9 +68,11 @@
         }
 
         // TODO: Replace these with real constants once this API has been vetted.
-        CallServiceWrapper callService = call.getCallService();
-        if (callService != null) {
-            intent.putExtra(CallService.class.getName(), callService.getComponentName());
+        ConnectionServiceWrapper connectionService = call.getConnectionService();
+        if (connectionService != null) {
+            intent.putExtra(
+                    TelecommConstants.EXTRA_CONNECTION_SERVICE,
+                    connectionService.getComponentName());
         }
 
         // TODO: Replace these with real constants once this API has been vetted.
diff --git a/src/com/android/telecomm/RingbackPlayer.java b/src/com/android/telecomm/RingbackPlayer.java
index 8fd6697..bfd5f62 100644
--- a/src/com/android/telecomm/RingbackPlayer.java
+++ b/src/com/android/telecomm/RingbackPlayer.java
@@ -60,16 +60,15 @@
     }
 
     @Override
-    public void onCallServiceChanged(
+    public void onConnectionServiceChanged(
             Call call,
-            CallServiceWrapper oldCallServiceWrapper,
-            CallServiceWrapper newCallService) {
+            ConnectionServiceWrapper oldService,
+            ConnectionServiceWrapper newService) {
 
-        super.onCallServiceChanged(call, oldCallServiceWrapper, newCallService);
         // Treat as ending or begining dialing based on the state transition.
         if (shouldStartRinging(call)) {
             startRingbackForCall(call);
-        } else if (newCallService == null) {
+        } else if (newService == null) {
             stopRingbackForCall(call);
         }
     }
diff --git a/src/com/android/telecomm/ServiceBinder.java b/src/com/android/telecomm/ServiceBinder.java
index 55e39f0..e918593 100644
--- a/src/com/android/telecomm/ServiceBinder.java
+++ b/src/com/android/telecomm/ServiceBinder.java
@@ -81,7 +81,7 @@
                 Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
                 ServiceConnection connection = new ServiceBinderConnection();
 
-                Log.d(ServiceBinder.this, "Binding to call service with intent: %s", serviceIntent);
+                Log.d(ServiceBinder.this, "Binding to service with intent: %s", serviceIntent);
                 if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
                     handleFailedConnection();
                     return;
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 7c6d44d..b7a7e9e 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -20,7 +20,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.telecomm.CallInfo;
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
 
@@ -34,7 +33,7 @@
 import java.util.Set;
 
 /**
- * Switchboard is responsible for gathering the {@link CallServiceWrapper}s through
+ * Switchboard is responsible for gathering the {@link ConnectionServiceWrapper}s through
  *       which to place outgoing calls
  */
 final class Switchboard {
@@ -75,8 +74,8 @@
      */
     void retrieveIncomingCall(Call call, CallServiceDescriptor descriptor, Bundle extras) {
         Log.d(this, "retrieveIncomingCall");
-        CallServiceWrapper callService = mCallServiceRepository.getService(descriptor);
-        call.setCallService(callService);
+        ConnectionServiceWrapper service = mCallServiceRepository.getService(descriptor);
+        call.setConnectionService(service);
         mIncomingCallsManager.retrieveIncomingCall(call, extras);
     }
 }
diff --git a/src/com/android/telecomm/TelephonyUtil.java b/src/com/android/telecomm/TelephonyUtil.java
index 83303c7..783b427 100644
--- a/src/com/android/telecomm/TelephonyUtil.java
+++ b/src/com/android/telecomm/TelephonyUtil.java
@@ -35,7 +35,7 @@
 
     private TelephonyUtil() {}
 
-    static boolean isPstnCallService(CallServiceDescriptor descriptor) {
+    static boolean isPstnConnectionService(CallServiceDescriptor descriptor) {
         final ComponentName pstnComponentName = new ComponentName(
                 TELEPHONY_PACKAGE_NAME, PSTN_CALL_SERVICE_CLASS_NAME);
         return pstnComponentName.equals(descriptor.getServiceComponent());
@@ -47,26 +47,27 @@
      */
     static boolean isCurrentlyPSTNCall(Call call) {
         if (Log.DEBUG) {
-            verifyCallServiceExists(PSTN_CALL_SERVICE_CLASS_NAME);
+            verifyConnectionServiceExists(PSTN_CALL_SERVICE_CLASS_NAME);
         }
 
-        CallServiceWrapper callService = call.getCallService();
-        if (callService == null) {
+        ConnectionServiceWrapper service = call.getConnectionService();
+        if (service == null) {
             return false;
         }
-        return isPstnCallService(callService.getDescriptor());
+        return isPstnConnectionService(service.getDescriptor());
     }
 
-    private static void verifyCallServiceExists(String serviceName) {
+    private static void verifyConnectionServiceExists(String serviceName) {
         PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
         try {
             ServiceInfo info = packageManager.getServiceInfo(
                     new ComponentName(TELEPHONY_PACKAGE_NAME, serviceName), 0);
             if (info == null) {
-                Log.wtf(TAG, "Error, unable to find call service: %s", serviceName);
+                Log.wtf(TAG, "Error, unable to find connection service: %s", serviceName);
             }
         } catch (PackageManager.NameNotFoundException e) {
-            Log.wtf(TAG, e, "Error, exception while trying to find call service: %s", serviceName);
+            Log.wtf(TAG, e, "Error, exception while trying to find connection service: %s",
+                    serviceName);
         }
     }
 }
diff --git a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
index 6364377..ff52157 100644
--- a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
+++ b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
@@ -111,7 +111,7 @@
         log("Creating incoming call pending intent.");
         // Build descriptor for TestConnectionService.
         CallServiceDescriptor.Builder descriptorBuilder = CallServiceDescriptor.newBuilder(context);
-        descriptorBuilder.setCallService(TestConnectionService.class);
+        descriptorBuilder.setConnectionService(TestConnectionService.class);
         descriptorBuilder.setNetworkType(CallServiceDescriptor.FLAG_WIFI);
 
         // Create intent for adding an incoming call.
diff --git a/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java b/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java
index b1d32a3..41a893e 100644
--- a/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java
+++ b/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java
@@ -24,7 +24,7 @@
 import com.google.common.collect.Lists;
 
 /**
- * Service which provides fake calls to test the ICallService interface.
+ * Service which provides fake calls to test the IConnectionService interface.
  * TODO(santoscordon): Build more dummy providers for more CallServiceDescriptor.FLAG_* types.
  */
 public class TestCallServiceProvider extends CallServiceProvider {
@@ -34,7 +34,7 @@
         log("lookupCallServices");
 
         CallServiceDescriptor.Builder builder = CallServiceDescriptor.newBuilder(this);
-        builder.setCallService(TestConnectionService.class);
+        builder.setConnectionService(TestConnectionService.class);
         builder.setNetworkType(CallServiceDescriptor.FLAG_WIFI);
 
         response.setCallServiceDescriptors(Lists.newArrayList(builder.build()));
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionService.java b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
index 241f8ee..4ada090 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionService.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
@@ -74,6 +74,11 @@
             }
 
             @Override
+            public void onFeaturesChanged(RemoteConnection connection, int features) {
+                setFeatures(features);
+            }
+
+            @Override
             public void onDestroyed(RemoteConnection connection) {
                 setDestroyed();
             }