Merge "Add TestCallVideoProvider."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c49dca9..2f8fc6f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -166,9 +166,6 @@
             </intent-filter>
         </activity-alias>
 
-        <!-- Selects call services to place emergency calls. -->
-        <service android:name="EmergencyCallServiceSelector" android:exported="false" />
-
         <receiver android:name="TelecommBroadcastReceiver" android:exported="false">
             <intent-filter>
                 <action android:name="com.android.telecomm.ACTION_CALL_BACK_FROM_NOTIFICATION" />
diff --git a/res/drawable-xxhdpi/chat_with_others.png b/res/drawable-xxhdpi/chat_with_others.png
new file mode 100644
index 0000000..6f6b03e
--- /dev/null
+++ b/res/drawable-xxhdpi/chat_with_others.png
Binary files differ
diff --git a/res/drawable-xxhdpi/market_wireless.png b/res/drawable-xxhdpi/market_wireless.png
new file mode 100644
index 0000000..e451fe7
--- /dev/null
+++ b/res/drawable-xxhdpi/market_wireless.png
Binary files differ
diff --git a/res/drawable-xxhdpi/q_mobile.png b/res/drawable-xxhdpi/q_mobile.png
new file mode 100644
index 0000000..cfc0624
--- /dev/null
+++ b/res/drawable-xxhdpi/q_mobile.png
Binary files differ
diff --git a/res/drawable-xxhdpi/talk_to_your_circles.png b/res/drawable-xxhdpi/talk_to_your_circles.png
new file mode 100644
index 0000000..d6bc672
--- /dev/null
+++ b/res/drawable-xxhdpi/talk_to_your_circles.png
Binary files differ
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 747eca7..e85d7b6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -75,4 +75,23 @@
     <!-- "Respond via SMS": Confirmation message shown after sending
         a text response. [CHAR LIMIT=40] -->
     <string name="respond_via_sms_confirmation_format">Message sent to <xliff:g id="phone_number">%s</xliff:g>.</string>
+
+
+    <!-- DO NOT TRANSLATE. Label for test Subscription 0. -->
+    <string name="test_subscription_0_label">Q Mobile</string>
+    <!-- DO NOT TRANSLATE. Label for test Subscription 1. -->
+    <string name="test_subscription_1_label">Market Wireless</string>
+    <!-- DO NOT TRANSLATE. Label for test Subscription 2. -->
+    <string name="test_subscription_2_label">Sonoma Circles Talk Plus</string>
+    <!-- DO NOT TRANSLATE. Label for test Subscription 3. -->
+    <string name="test_subscription_3_label">Bay Voice Chat Pro</string>
+
+    <!-- DO NOT TRANSLATE. Short description for test Subscription 0. -->
+    <string name="test_subscription_0_short_description">Account with Q Mobile</string>
+    <!-- DO NOT TRANSLATE. Short description for test Subscription 1. -->
+    <string name="test_subscription_1_short_description">Account with Market Wireless</string>
+    <!-- DO NOT TRANSLATE. Short description for test Subscription 2. -->
+    <string name="test_subscription_2_short_description">Talk to everyone in your Circles!</string>
+    <!-- DO NOT TRANSLATE. Short description for test Subscription 3. -->
+    <string name="test_subscription_3_short_description">Chat with Chat Network users</string>
 </resources>
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 104ff4e..a6ec347 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -129,11 +129,6 @@
     private CallServiceWrapper mCallService;
 
     /**
-     * The call-service selector for this call.
-     */
-    private CallServiceSelectorWrapper mCallServiceSelector;
-
-    /**
      * 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.
      */
@@ -141,6 +136,8 @@
 
     private boolean mIsEmergencyCall;
 
+    private boolean mSpeakerphoneOn;
+
     /**
      * Disconnect cause for the call. Only valid if the state of the call is DISCONNECTED.
      * See {@link android.telephony.DisconnectCause}.
@@ -177,7 +174,6 @@
 
     // TODO(santoscordon): The repositories should be changed into singleton types.
     private CallServiceRepository mCallServiceRepository;
-    private CallServiceSelectorRepository mSelectorRepository;
 
     /** Caller information retrieved from the latest contact query. */
     private CallerInfo mCallerInfo;
@@ -445,31 +441,6 @@
         }
     }
 
-    CallServiceSelectorWrapper getCallServiceSelector() {
-        return mCallServiceSelector;
-    }
-
-    void setCallServiceSelector(CallServiceSelectorWrapper selector) {
-        Preconditions.checkNotNull(selector);
-
-        clearCallServiceSelector();
-
-        selector.incrementAssociatedCallCount();
-        mCallServiceSelector = selector;
-        mCallServiceSelector.addCall(this);
-    }
-
-    void clearCallServiceSelector() {
-        if (mCallServiceSelector != null) {
-            CallServiceSelectorWrapper selectorTemp = mCallServiceSelector;
-            mCallServiceSelector = null;
-            selectorTemp.removeCall(this);
-
-            // See comment on {@link #clearCallService}.
-            decrementAssociatedCallCount(selectorTemp);
-        }
-    }
-
     /**
      * Starts the incoming call flow through the switchboard. When switchboard completes, it will
      * invoke handle[Un]SuccessfulIncomingCall.
@@ -555,7 +526,6 @@
         mOutgoingCallProcessor = new OutgoingCallProcessor(
                 this,
                 Switchboard.getInstance().getCallServiceRepository(),
-                Switchboard.getInstance().getSelectorRepository(),
                 new AsyncResultCallback<Boolean>() {
                     @Override
                     public void onResult(Boolean wasCallPlaced, int errorCode, String errorMsg) {
@@ -585,7 +555,6 @@
         }
 
         clearCallService();
-        clearCallServiceSelector();
     }
 
     /**
@@ -1037,4 +1006,20 @@
             Log.d(this, "maybeLoadCannedSmsResponses: doing nothing");
         }
     }
+
+    /**
+     * Sets speakerphone option on when call begins.
+     */
+    public void setStartWithSpeakerphoneOn(boolean startWithSpeakerphone) {
+        mSpeakerphoneOn = startWithSpeakerphone;
+    }
+
+    /**
+     * Returns speakerphone option.
+     *
+     * @return Whether or not speakerphone should be set automatically when call begins.
+     */
+    public boolean getStartWithSpeakerphoneOn() {
+        return mSpeakerphoneOn;
+    }
 }
diff --git a/src/com/android/telecomm/CallIdMapper.java b/src/com/android/telecomm/CallIdMapper.java
index e6b5c1f..9f803c6 100644
--- a/src/com/android/telecomm/CallIdMapper.java
+++ b/src/com/android/telecomm/CallIdMapper.java
@@ -85,8 +85,10 @@
     void checkValidCallId(String callId) {
         // Note, no need for thread check, this method is thread safe.
         if (!isValidCallId(callId)) {
-            throw new IllegalArgumentException(
-                    "Invalid call ID for " + mCallIdPrefix + ": " + callId);
+            // TODO(santoscordon): Re-enable this once we stop getting updates to CallServiceWrapper
+            // 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 f6e1164..af4098c 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -186,6 +186,6 @@
     @Override
     protected CallServiceWrapper onCreateNewServiceWrapper(ComponentName componentName,
             Object param) {
-        return new CallServiceWrapper((CallServiceDescriptor) param, mIncomingCallsManager);
+        return new CallServiceWrapper((CallServiceDescriptor) param, mIncomingCallsManager, this);
     }
 }
diff --git a/src/com/android/telecomm/CallServiceSelectorRepository.java b/src/com/android/telecomm/CallServiceSelectorRepository.java
deleted file mode 100644
index 0a8deb6..0000000
--- a/src/com/android/telecomm/CallServiceSelectorRepository.java
+++ /dev/null
@@ -1,95 +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.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.telecomm.TelecommConstants;
-
-import com.android.internal.telecomm.ICallServiceSelector;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Helper class to retrieve {@link ICallServiceSelector} implementations on the device and
- * asynchronously bind to them.
- */
-final class CallServiceSelectorRepository extends BaseRepository<CallServiceSelectorWrapper> {
-
-    /** {@inheritDoc} */
-    @Override
-    protected void onLookupServices(LookupCallback<CallServiceSelectorWrapper> callback) {
-        ThreadUtil.checkOnMainThread();
-
-        List<ComponentName> selectorNames = getSelectorNames();
-        List<CallServiceSelectorWrapper> foundSelectors = Lists.newLinkedList();
-
-        // Register any new selectors.
-        for (ComponentName name : selectorNames) {
-            CallServiceSelectorWrapper selector = getService(name, null);
-
-            if (TelephonyUtil.isTelephonySelector(selector)) {
-                // Add telephony selectors to the end to serve as a fallback.
-                foundSelectors.add(selector);
-            } else {
-                // TODO(sail): Need a way to order selectors.
-                foundSelectors.add(0, selector);
-            }
-        }
-        Log.i(this, "Found %d implementations of ICallServiceSelector", selectorNames.size());
-        callback.onComplete(foundSelectors);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected CallServiceSelectorWrapper onCreateNewServiceWrapper(
-            ComponentName componentName, Object param) {
-
-        return new CallServiceSelectorWrapper(componentName, CallsManager.getInstance());
-    }
-
-    /**
-     * Returns the list containing the (component) names of all known ICallServiceSelector
-     * implementations or the empty list upon no available selectors.
-     */
-    private List<ComponentName> getSelectorNames() {
-        // The list of selector names to return to the caller, may be populated below.
-        List<ComponentName> selectorNames = Lists.newArrayList();
-
-        PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
-        Intent intent = new Intent(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR);
-        for (ResolveInfo entry : packageManager.queryIntentServices(intent, 0)) {
-            ServiceInfo serviceInfo = entry.serviceInfo;
-            if (serviceInfo != null) {
-                // The entry resolves to a proper service, add it to the list of selector names.
-                ComponentName componentName =
-                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
-                selectorNames.add(componentName);
-            }
-        }
-
-        return selectorNames;
-    }
-}
diff --git a/src/com/android/telecomm/CallServiceSelectorWrapper.java b/src/com/android/telecomm/CallServiceSelectorWrapper.java
deleted file mode 100644
index 05d540a..0000000
--- a/src/com/android/telecomm/CallServiceSelectorWrapper.java
+++ /dev/null
@@ -1,273 +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.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telecomm.CallInfo;
-import android.telecomm.CallServiceDescriptor;
-import android.telecomm.TelecommConstants;
-import android.telephony.DisconnectCause;
-
-import com.android.internal.os.SomeArgs;
-import com.android.internal.telecomm.ICallServiceSelector;
-import com.android.internal.telecomm.ICallServiceSelectorAdapter;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Wrapper for {@link ICallServiceSelector}s, handles binding and keeps track of when the object can
- * safely be unbound.
- */
-final class CallServiceSelectorWrapper extends ServiceBinder<ICallServiceSelector> {
-
-    private final class Adapter extends ICallServiceSelectorAdapter.Stub {
-        private static final int MSG_SET_SELECTED_CALL_SERVICES = 0;
-        private static final int MSG_CANCEL_OUTGOING_CALL = 1;
-        private static final int MSG_SET_HANDOFF_INFO = 2;
-
-        private final Handler mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case MSG_SET_SELECTED_CALL_SERVICES: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            String callId = (String) args.arg1;
-                            if (mPendingSelects.containsKey(callId)) {
-                                @SuppressWarnings("unchecked")
-                                List<CallServiceDescriptor> descriptors =
-                                        (List<CallServiceDescriptor>) args.arg2;
-                                mPendingSelects.remove(callId).onResult(descriptors, 0, null);
-                            } else {
-                                Log.w(this, "setSelectedCallServices: unknown call: %s, id: %s",
-                                        callId, args.arg1);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                    case MSG_CANCEL_OUTGOING_CALL: {
-                        Call call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null) {
-                            call.abort();
-                        } else {
-                            Log.w(this, "cancelOutgoingCall: unknown call: %s, id: %s", call,
-                                    msg.obj);
-                        }
-                        break;
-                    }
-                    case MSG_SET_HANDOFF_INFO: {
-                        SomeArgs args = (SomeArgs) msg.obj;
-                        try {
-                            Call call = mCallIdMapper.getCall(args.arg1);
-                            Uri handle = (Uri) args.arg2;
-                            Bundle extras = (Bundle) args.arg3;
-                            if (call != null) {
-                                mCallsManager.setHandoffInfo(call, handle, extras);
-                            } else {
-                                Log.w(this, "setHandoffInfo: unknown call: %s, id: %s",
-                                        call, args.arg1);
-                            }
-                        } finally {
-                            args.recycle();
-                        }
-                        break;
-                    }
-                }
-            }
-        };
-
-        @Override
-        public void setSelectedCallServices(String callId,
-                List<CallServiceDescriptor> descriptors) {
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = descriptors;
-            mHandler.obtainMessage(MSG_SET_SELECTED_CALL_SERVICES, args).sendToTarget();
-        }
-
-        @Override
-        public void cancelOutgoingCall(String callId) {
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, callId).sendToTarget();
-        }
-
-        @Override
-        public void setHandoffInfo(String callId, Uri handle, Bundle extras) {
-            mCallIdMapper.checkValidCallId(callId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = handle;
-            args.arg3 = extras;
-            mHandler.obtainMessage(MSG_SET_HANDOFF_INFO, args).sendToTarget();
-        }
-    }
-
-    private final Binder mBinder = new Binder();
-    private final CallIdMapper mCallIdMapper = new CallIdMapper("CallServiceSelector");
-    private final Adapter mAdapter = new Adapter();
-    private final CallsManager mCallsManager;
-    private final Map<String, AsyncResultCallback<List<CallServiceDescriptor>>> mPendingSelects =
-            new HashMap<>();
-
-    private ICallServiceSelector mSelectorInterface;
-
-    /**
-     * Creates a call-service selector for the specified component using the specified action to
-     * bind to it.
-     *
-     * @param action The action used to bind to the selector.
-     * @param componentName The component name of the service.
-     * @param callsManager The calls manager.
-     */
-    CallServiceSelectorWrapper(
-            String action, ComponentName componentName, CallsManager callsManager) {
-
-        super(action, componentName);
-        mCallsManager = callsManager;
-    }
-
-    /**
-     * Creates a call-service selector for specified component and uses
-     * {@link TelecommConstants#ACTION_CALL_SERVICE_SELECTOR} as the action to bind.
-     *
-     * @param componentName The component name of the service.
-     * @param callsManager The calls manager.
-     */
-    CallServiceSelectorWrapper(ComponentName componentName, CallsManager callsManager) {
-        this(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR, componentName, callsManager);
-    }
-
-    /**
-     * Retrieves the sorted set of call services that are preferred by this selector. Upon failure,
-     * the error callback is invoked. Can be invoked even when the call service is unbound.
-     *
-     * @param call The call being placed using the {@link CallService}s.
-     * @param descriptors The descriptors of the available {@link CallService}s with which to place
-     *            the call.
-     * @param resultCallback The callback on which to return the result.
-     */
-    void select(
-            final Call call,
-            final List<CallServiceDescriptor> descriptors,
-            final AsyncResultCallback<List<CallServiceDescriptor>> resultCallback) {
-
-        BindCallback callback = new BindCallback() {
-            @Override
-            public void onSuccess() {
-                String callId = mCallIdMapper.getCallId(call);
-                mPendingSelects.put(callId, resultCallback);
-
-                try {
-                    CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
-                    mSelectorInterface.select(callInfo, descriptors);
-                } catch (RemoteException e) {
-                    mCallIdMapper.removeCall(call);
-                    mPendingSelects.get(callId).onResult(
-                            null, DisconnectCause.ERROR_UNSPECIFIED, e.toString());
-                }
-            }
-
-            @Override
-            public void onFailure() {
-                resultCallback.onResult(null, DisconnectCause.ERROR_UNSPECIFIED, null);
-            }
-        };
-
-        mBinder.bind(callback);
-    }
-
-    void addCall(Call call) {
-        mCallIdMapper.addCall(call);
-        onCallUpdated(call.toCallInfo(mCallIdMapper.getCallId(call)));
-    }
-
-    void removeCall(Call call) {
-        String callId = mCallIdMapper.getCallId(call);
-        mCallIdMapper.removeCall(call);
-        onCallRemoved(callId);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void setServiceInterface(IBinder binder) {
-        if (binder == null) {
-            mSelectorInterface = null;
-        } else {
-            mSelectorInterface = ICallServiceSelector.Stub.asInterface(binder);
-            setCallServiceSelectorAdapter(mAdapter);
-        }
-    }
-
-    private void setCallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
-        if (isServiceValid("setCallServiceSelectorAdapter")) {
-            try {
-                mSelectorInterface.setCallServiceSelectorAdapter(adapter);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    private void onCallUpdated(final CallInfo callInfo) {
-        BindCallback callback = new BindCallback() {
-            @Override
-            public void onSuccess() {
-                if (isServiceValid("onCallUpdated")) {
-                    try {
-                        mSelectorInterface.onCallUpdated(callInfo);
-                    } catch (RemoteException e) {
-                    }
-                }
-            }
-
-            @Override
-            public void onFailure() {
-            }
-        };
-        mBinder.bind(callback);
-    }
-
-    private void onCallRemoved(final String callId) {
-        BindCallback callback = new BindCallback() {
-            @Override
-            public void onSuccess() {
-                if (isServiceValid("onCallRemoved")) {
-                    try {
-                        mSelectorInterface.onCallRemoved(callId);
-                    } catch (RemoteException e) {
-                    }
-                }
-            }
-
-            @Override
-            public void onFailure() {
-            }
-        };
-        mBinder.bind(callback);
-    }
-}
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 4462cff..5d7b47a 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -16,6 +16,7 @@
 
 package com.android.telecomm;
 
+import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -33,11 +34,15 @@
 import com.android.internal.telecomm.ICallService;
 import com.android.internal.telecomm.ICallServiceAdapter;
 import com.android.internal.telecomm.ICallServiceProvider;
+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;
@@ -67,6 +72,7 @@
         private static final int MSG_SET_IS_CONFERENCED = 12;
         private static final int MSG_ADD_CONFERENCE_CALL = 13;
         private static final int MSG_HANDOFF_CALL = 14;
+        private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
 
         private final Handler mHandler = new Handler() {
             @Override
@@ -82,8 +88,13 @@
                                     clientCallInfo.getHandle());
                             mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
                         } else {
-                            Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
-                                    call, clientCallInfo.getId());
+                            // 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: {
@@ -91,7 +102,7 @@
                         if (mPendingOutgoingCalls.containsKey(callId)) {
                             mPendingOutgoingCalls.remove(callId).onResult(true, 0, null);
                         } else {
-                            Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
+                            //Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
                         }
                         break;
                     }
@@ -108,7 +119,7 @@
                                         false, statusCode, statusMsg);
                                 mCallIdMapper.removeCall(callId);
                             } else {
-                                Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
+                                //Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
                             }
                         } finally {
                             args.recycle();
@@ -120,7 +131,7 @@
                         if (call != null) {
                             mCallsManager.markCallAsActive(call);
                         } else {
-                            Log.w(this, "setActive, unknown call id: %s", msg.obj);
+                            //Log.w(this, "setActive, unknown call id: %s", msg.obj);
                         }
                         break;
                     case MSG_SET_RINGING:
@@ -128,7 +139,7 @@
                         if (call != null) {
                             mCallsManager.markCallAsRinging(call);
                         } else {
-                            Log.w(this, "setRinging, unknown call id: %s", msg.obj);
+                            //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
                         }
                         break;
                     case MSG_SET_DIALING:
@@ -136,7 +147,7 @@
                         if (call != null) {
                             mCallsManager.markCallAsDialing(call);
                         } else {
-                            Log.w(this, "setDialing, unknown call id: %s", msg.obj);
+                            //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
                         }
                         break;
                     case MSG_SET_DISCONNECTED: {
@@ -149,7 +160,7 @@
                                 mCallsManager.markCallAsDisconnected(call, disconnectCause,
                                         disconnectMessage);
                             } else {
-                                Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
+                                //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
                             }
                         } finally {
                             args.recycle();
@@ -161,7 +172,7 @@
                         if (call != null) {
                             mCallsManager.markCallAsOnHold(call);
                         } else {
-                            Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
+                            //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
                         }
                         break;
                     case MSG_SET_REQUESTING_RINGBACK: {
@@ -172,7 +183,7 @@
                             if (call != null) {
                                 call.setRequestingRingback(ringback);
                             } else {
-                                Log.w(this, "setRingback, unknown call id: %s", args.arg1);
+                                //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
                             }
                         } finally {
                             args.recycle();
@@ -187,7 +198,7 @@
                                 String remaining = (String) args.arg2;
                                 call.onPostDialWait(remaining);
                             } else {
-                                Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
+                                //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
                             }
                         } finally {
                             args.recycle();
@@ -199,7 +210,7 @@
                         if (call != null) {
                             mCallsManager.startHandoffForCall(call);
                         } else {
-                            Log.w(this, "handoffCall, unknown call id: %s", msg.obj);
+                            //Log.w(this, "handoffCall, unknown call id: %s", msg.obj);
                         }
                         break;
                     case MSG_CAN_CONFERENCE: {
@@ -207,8 +218,8 @@
                         if (call != null) {
                             call.setIsConferenceCapable(msg.arg1 == 1);
                         } else {
-                            Log.w(CallServiceWrapper.this, "canConference, unknown call id: %s",
-                                    msg.obj);
+                            //Log.w(CallServiceWrapper.this, "canConference, unknown call id: %s",
+                            //        msg.obj);
                         }
                         break;
                     }
@@ -218,8 +229,6 @@
                             Call childCall = mCallIdMapper.getCall(args.arg1);
                             if (childCall != null) {
                                 String conferenceCallId = (String) args.arg2;
-                                Log.d(this, "setIsConferenced %s, %s", childCall, conferenceCallId);
-
                                 if (conferenceCallId == null) {
                                     childCall.setParentCall(null);
                                 } else {
@@ -228,12 +237,12 @@
                                             !mPendingConferenceCalls.contains(conferenceCall)) {
                                         childCall.setParentCall(conferenceCall);
                                     } else {
-                                        Log.w(this, "setIsConferenced, unknown conference id %s",
-                                                conferenceCallId);
+                                        //Log.w(this, "setIsConferenced, unknown conference id %s",
+                                        //        conferenceCallId);
                                     }
                                 }
                             } else {
-                                Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
+                                //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
                             }
                         } finally {
                             args.recycle();
@@ -244,34 +253,30 @@
                         SomeArgs args = (SomeArgs) msg.obj;
                         try {
                             String callId = (String) args.arg1;
-                            Log.d(this, "addConferenceCall attempt %s, %s",
-                                    callId, mPendingConferenceCalls);
-
                             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);
+                                //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);
+                    }
                 }
             }
         };
 
         /** {@inheritDoc} */
         @Override
-        public void setIsCompatibleWith(String callId, boolean isCompatible) {
-            Log.wtf(this, "Not expected.");
-        }
-
-        /** {@inheritDoc} */
-        @Override
         public void notifyIncomingCall(CallInfo callInfo) {
+            logIncoming("notifyIncomingCall %s", callInfo);
             mCallIdMapper.checkValidCallId(callInfo.getId());
             mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
         }
@@ -279,7 +284,7 @@
         /** {@inheritDoc} */
         @Override
         public void handleSuccessfulOutgoingCall(String callId) {
-            Log.d(this, "handleSuccessfulOutgoingCall %s", callId);
+            logIncoming("handleSuccessfulOutgoingCall %s", callId);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
         }
@@ -290,8 +295,8 @@
                 ConnectionRequest request,
                 int errorCode,
                 String errorMsg) {
+            logIncoming("handleFailedOutgoingCall %s %d %s", request, errorCode, errorMsg);
             mCallIdMapper.checkValidCallId(request.getCallId());
-            Log.d(this, "handleFailedOutgoingCall %s", request.getCallId());
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = request.getCallId();
             args.argi1 = errorCode;
@@ -302,6 +307,7 @@
         /** {@inheritDoc} */
         @Override
         public void setActive(String callId) {
+            logIncoming("setActive %s", callId);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
         }
@@ -309,6 +315,7 @@
         /** {@inheritDoc} */
         @Override
         public void setRinging(String callId) {
+            logIncoming("setRinging %s", callId);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
         }
@@ -316,6 +323,7 @@
         /** {@inheritDoc} */
         @Override
         public void setDialing(String callId) {
+            logIncoming("setDialing %s", callId);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
         }
@@ -324,6 +332,7 @@
         @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;
@@ -335,6 +344,7 @@
         /** {@inheritDoc} */
         @Override
         public void setOnHold(String callId) {
+            logIncoming("setOnHold %s", callId);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
         }
@@ -342,6 +352,7 @@
         /** {@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;
@@ -352,12 +363,13 @@
         /** ${inheritDoc} */
         @Override
         public void removeCall(String callId) {
+            logIncoming("removeCall %s", callId);
         }
 
         /** ${inheritDoc} */
         @Override
         public void setCanConference(String callId, boolean canConference) {
-            Log.d(this, "setCanConference(%s, %b)", callId, canConference);
+            logIncoming("setCanConference %s %b", callId, canConference);
             mHandler.obtainMessage(MSG_CAN_CONFERENCE, canConference ? 1 : 0, 0, callId)
                     .sendToTarget();
         }
@@ -365,6 +377,7 @@
         /** ${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;
@@ -374,6 +387,7 @@
         /** ${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;
@@ -383,6 +397,7 @@
 
         @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;
@@ -393,9 +408,17 @@
         /** {@inheritDoc} */
         @Override
         public void handoffCall(String callId) {
+            logIncoming("handoffCall %s", callId);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_HANDOFF_CALL, callId).sendToTarget();
         }
+
+        /** ${inheritDoc} */
+        @Override
+        public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
+            logIncoming("queryRemoteCSs");
+            mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
+        }
     }
 
     private final Adapter mAdapter = new Adapter();
@@ -410,6 +433,7 @@
 
     private Binder mBinder = new Binder();
     private ICallService mServiceInterface;
+    private final CallServiceRepository mCallServiceRepository;
 
     /**
      * Creates a call-service for the specified descriptor.
@@ -417,13 +441,16 @@
      * @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) {
+            IncomingCallsManager incomingCallsManager,
+            CallServiceRepository callServiceRepository) {
         super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
         mDescriptor = descriptor;
         mIncomingCallsManager = incomingCallsManager;
+        mCallServiceRepository = callServiceRepository;
     }
 
     CallServiceDescriptor getDescriptor() {
@@ -434,6 +461,7 @@
     private void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
         if (isServiceValid("setCallServiceAdapter")) {
             try {
+                logOutgoing("setCallServiceAdapter %s", callServiceAdapter);
                 mServiceInterface.setCallServiceAdapter(callServiceAdapter);
             } catch (RemoteException e) {
             }
@@ -454,8 +482,10 @@
 
                 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).onResult(
                             false, DisconnectCause.ERROR_UNSPECIFIED, e.toString());
                 }
@@ -463,6 +493,7 @@
 
             @Override
             public void onFailure() {
+                Log.e(this, new Exception(), "Failure to call %s", getDescriptor());
                 resultCallback.onResult(false, DisconnectCause.ERROR_UNSPECIFIED, null);
             }
         };
@@ -478,6 +509,7 @@
         // If still bound, tell the call service to abort.
         if (isServiceValid("abort")) {
             try {
+                logOutgoing("abort %s", callId);
                 mServiceInterface.abort(callId);
             } catch (RemoteException e) {
             }
@@ -490,6 +522,7 @@
     void hold(Call call) {
         if (isServiceValid("hold")) {
             try {
+                logOutgoing("hold %s", mCallIdMapper.getCallId(call));
                 mServiceInterface.hold(mCallIdMapper.getCallId(call));
             } catch (RemoteException e) {
             }
@@ -500,6 +533,7 @@
     void unhold(Call call) {
         if (isServiceValid("unhold")) {
             try {
+                logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
                 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
             } catch (RemoteException e) {
             }
@@ -510,6 +544,8 @@
     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) {
@@ -535,6 +571,8 @@
                 if (isServiceValid("setIncomingCallId")) {
                     mPendingIncomingCalls.add(call);
                     try {
+                        logOutgoing("setIncomingCallId %s %s",
+                                mCallIdMapper.getCallId(call), extras);
                         mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
                                 extras);
                     } catch (RemoteException e) {
@@ -555,6 +593,7 @@
     void disconnect(Call call) {
         if (isServiceValid("disconnect")) {
             try {
+                logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
                 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
             } catch (RemoteException e) {
             }
@@ -565,6 +604,7 @@
     void answer(Call call) {
         if (isServiceValid("answer")) {
             try {
+                logOutgoing("answer %s", mCallIdMapper.getCallId(call));
                 mServiceInterface.answer(mCallIdMapper.getCallId(call));
             } catch (RemoteException e) {
             }
@@ -575,6 +615,7 @@
     void reject(Call call) {
         if (isServiceValid("reject")) {
             try {
+                logOutgoing("reject %s", mCallIdMapper.getCallId(call));
                 mServiceInterface.reject(mCallIdMapper.getCallId(call));
             } catch (RemoteException e) {
             }
@@ -585,6 +626,7 @@
     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) {
             }
@@ -595,6 +637,7 @@
     void stopDtmfTone(Call call) {
         if (isServiceValid("stopDtmfTone")) {
             try {
+                logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
                 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
             } catch (RemoteException e) {
             }
@@ -630,6 +673,7 @@
     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) {
             }
@@ -650,6 +694,9 @@
                     }
                 }, Timeouts.getConferenceCallExpireMillis());
 
+                logOutgoing("conference %s %s",
+                        mCallIdMapper.getCallId(conferenceCall),
+                        mCallIdMapper.getCallId(call));
                 mServiceInterface.conference(
                         mCallIdMapper.getCallId(conferenceCall),
                         mCallIdMapper.getCallId(call));
@@ -661,6 +708,7 @@
     void splitFromConference(Call call) {
         if (isServiceValid("splitFromConference")) {
             try {
+                logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
                 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
             } catch (RemoteException ignored) {
             }
@@ -711,4 +759,57 @@
 
         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 5e5f710..d5ddedc 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -278,8 +278,10 @@
      * @param contactInfo Information about the entity being called.
      * @param gatewayInfo Optional gateway information that can be used to route the call to the
      *         actual dialed handle via a gateway provider. May be null.
+     * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects.
      */
-    void placeOutgoingCall(Uri handle, ContactInfo contactInfo, GatewayInfo gatewayInfo) {
+    void placeOutgoingCall(Uri handle, ContactInfo contactInfo, GatewayInfo gatewayInfo,
+            boolean speakerphoneOn) {
         final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayHandle();
 
         if (gatewayInfo == null) {
@@ -291,6 +293,7 @@
 
         Call call = new Call(
                 uriHandle, gatewayInfo, false /* isIncoming */, false /* isConference */);
+        call.setStartWithSpeakerphoneOn(speakerphoneOn);
 
         // TODO(santoscordon): Move this to be a part of addCall()
         call.addListener(this);
@@ -472,7 +475,6 @@
                 originalCall.getHandoffHandle(), originalCall.getGatewayInfo(), false, false);
         tempCall.setOriginalCall(originalCall);
         tempCall.setExtras(originalCall.getExtras());
-        tempCall.setCallServiceSelector(originalCall.getCallServiceSelector());
         mPendingHandoffCalls.add(tempCall);
         tempCall.addListener(this);
 
@@ -505,6 +507,9 @@
         if (mPendingHandoffCalls.contains(call)) {
             completeHandoff(call, true);
         }
+        if (call.getStartWithSpeakerphoneOn()) {
+            setAudioRoute(CallAudioState.ROUTE_SPEAKER);
+        }
     }
 
     void markCallAsOnHold(Call call) {
@@ -674,7 +679,6 @@
 
         call.removeListener(this);
         call.clearCallService();
-        call.clearCallServiceSelector();
 
         boolean shouldNotify = false;
         if (mCalls.contains(call)) {
diff --git a/src/com/android/telecomm/EmergencyCallServiceSelector.java b/src/com/android/telecomm/EmergencyCallServiceSelector.java
deleted file mode 100644
index 40ff11e..0000000
--- a/src/com/android/telecomm/EmergencyCallServiceSelector.java
+++ /dev/null
@@ -1,73 +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.net.Uri;
-import android.telecomm.CallInfo;
-import android.telecomm.CallServiceDescriptor;
-import android.telecomm.CallServiceSelector;
-import android.telecomm.CallServiceSelectorAdapter;
-import android.telephony.PhoneNumberUtils;
-
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-/**
- * Selects call-services which can place emergency calls. For emergency handles, this selector is
- * always the first selector attempted when placing a call, see
- * {@link Switchboard#processNewOutgoingCall}. If this is ever invoked for a non-emergency handle,
- * this selector returns zero call services so that call-service selection continues to the next
- * selector. For emergency calls, it selects telephony's PSTN call services so that they are the
- * first ones to try to place the call.
- */
-public class EmergencyCallServiceSelector extends CallServiceSelector {
-
-    /**
-     * Returns true if the handle passed in is to a potential emergency number.
-     */
-    static boolean shouldUseSelector(Uri handle) {
-        return PhoneNumberUtils.isPotentialLocalEmergencyNumber(
-                TelecommApp.getInstance(), handle.getSchemeSpecificPart());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
-        List<CallServiceDescriptor> selectedDescriptors = Lists.newArrayList();
-
-        // We check to see if the handle is potentially for an emergency call. *Potentially* means
-        // that we match both the full number and prefix (e.g., "911444" matches 911). After the
-        // call is made, the telephony call services will inform us of the actual number that was
-        // connected, which would be 911. This is why we check *potential* APIs before, but use the
-        // exact {@link PhoneNumberUtils#isLocalEmergencyNumber} once the call is connected.
-        if (shouldUseSelector(callInfo.getHandle())) {
-            // Search for and return the pstn call services if found.
-            for (CallServiceDescriptor descriptor : descriptors) {
-                // TODO(santoscordon): Consider adding some type of CAN_MAKE_EMERGENCY_CALLS
-                // capability for call services and relying on that. Also consider combining this
-                // with a permission so that we can check that instead of relying on hardcoded
-                // paths.
-                if (TelephonyUtil.isPstnCallService(descriptor)) {
-                    selectedDescriptors.add(descriptor);
-                }
-            }
-        }
-
-        getAdapter().setSelectedCallServices(callInfo.getId(), selectedDescriptors);
-    }
-}
diff --git a/src/com/android/telecomm/HeadsetMediaButton.java b/src/com/android/telecomm/HeadsetMediaButton.java
index dab2475..a0d5858 100644
--- a/src/com/android/telecomm/HeadsetMediaButton.java
+++ b/src/com/android/telecomm/HeadsetMediaButton.java
@@ -31,37 +31,6 @@
  */
 final class HeadsetMediaButton extends CallsManagerListenerBase {
 
-    /**
-     * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent.
-     *
-     * This functionality isn't lumped in with the other intents in TelecommBroadcastReceiver
-     * because we instantiate this as a totally separate BroadcastReceiver instance, since we need
-     * to manually adjust its IntentFilter's priority (to make sure we get these intents *before*
-     * the media player.)
-     */
-    private final class MediaButtonBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
-            Log.v(this, "MediaButtonBroadcastReceiver.onReceive()...  event = %s.", event);
-            if ((event != null) && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
-                boolean consumed = handleHeadsetHook(event);
-                Log.v(this, "==> handleHeadsetHook(): consumed = %b.", consumed);
-                if (consumed) {
-                    abortBroadcast();
-                }
-            } else {
-                if (CallsManager.getInstance().hasAnyCalls()) {
-                    // If the phone is anything other than completely idle, then we consume and
-                    // ignore any media key events, otherwise it is too easy to accidentally start
-                    // playing music while a phone call is in progress.
-                    Log.v(this, "MediaButtonBroadcastReceiver: consumed");
-                    abortBroadcast();
-                }
-            }
-        }
-    }
-
     // Types of media button presses
     static final int SHORT_PRESS = 1;
     static final int LONG_PRESS = 2;
@@ -79,9 +48,6 @@
         }
     };
 
-    private final MediaButtonBroadcastReceiver mMediaButtonReceiver =
-            new MediaButtonBroadcastReceiver();
-
     private final CallsManager mCallsManager;
 
     private final MediaSession mSession;
@@ -89,23 +55,6 @@
     HeadsetMediaButton(Context context, CallsManager callsManager) {
         mCallsManager = callsManager;
 
-        // Use a separate receiver (from TelecommBroadcastReceiver) for ACTION_MEDIA_BUTTON
-        // broadcasts, since we need to manually adjust its priority (to make sure we get these
-        // intents *before* the media player.)
-        IntentFilter mediaButtonIntentFilter =
-                new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
-
-        // Make sure we're higher priority than the media player's MediaButtonIntentReceiver (which
-        // currently has the default priority of zero; see apps/Music/AndroidManifest.xml.)
-        mediaButtonIntentFilter.setPriority(1);
-
-        context.registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);
-
-        // register the component so it gets priority for calls
-        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        am.registerMediaButtonEventReceiverForCalls(new ComponentName(context.getPackageName(),
-                MediaButtonBroadcastReceiver.class.getName()));
-
         // Register a MediaSession but don't enable it yet. This is a
         // replacement for MediaButtonReceiver
         MediaSessionManager msm =
diff --git a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
index a0a7c00..c40fde5 100644
--- a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
@@ -132,7 +132,9 @@
             }
 
             GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);
-            mCallsManager.placeOutgoingCall(resultHandleUri, mContactInfo, gatewayInfo);
+            mCallsManager.placeOutgoingCall(resultHandleUri, mContactInfo, gatewayInfo,
+                    mIntent.getBooleanExtra(TelecommConstants.EXTRA_START_CALL_WITH_SPEAKERPHONE,
+                            false));
         }
     }
 
@@ -199,7 +201,9 @@
                     + " OutgoingCallBroadcastReceiver: %s", intent);
             String scheme = isUriNumber ? SCHEME_SIP : SCHEME_TEL;
             mCallsManager.placeOutgoingCall(
-                    Uri.fromParts(scheme, handle, null), mContactInfo, null);
+                    Uri.fromParts(scheme, handle, null), mContactInfo, null,
+                    mIntent.getBooleanExtra(TelecommConstants.EXTRA_START_CALL_WITH_SPEAKERPHONE,
+                            false));
 
             // Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
             // so that third parties can still inspect (but not intercept) the outgoing call. When
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index 366307c..4531455 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -16,15 +16,15 @@
 
 package com.android.telecomm;
 
-import android.content.ComponentName;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
 import android.telecomm.CallServiceDescriptor;
 import android.telephony.DisconnectCause;
+import android.telephony.PhoneNumberUtils;
 
 import com.android.telecomm.BaseRepository.LookupCallback;
 import com.google.android.collect.Sets;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
 
 import java.util.ArrayList;
@@ -70,8 +70,6 @@
 
     private final CallServiceRepository mCallServiceRepository;
 
-    private final CallServiceSelectorRepository mSelectorRepository;
-
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -93,13 +91,6 @@
      */
     private Iterator<CallServiceDescriptor> mCallServiceDescriptorIterator;
 
-    /**
-     * The list of currently-available call-service selector implementations.
-     */
-    private Collection<CallServiceSelectorWrapper> mSelectors;
-
-    private Iterator<CallServiceSelectorWrapper> mSelectorIterator;
-
     private AsyncResultCallback<Boolean> mResultCallback;
 
     private boolean mIsAborted = false;
@@ -109,21 +100,17 @@
     private String mLastErrorMsg = null;
 
     /**
-     * Persists the specified parameters and iterates through the prioritized list of selectors
-     * passing to each selector (read-only versions of) the call object and all available call-
-     * service descriptors.  Stops once a matching selector is found.  Calls with no matching
-     * selectors will eventually be killed by the cleanup/monitor switchboard handler, which will
-     * in turn call the abort method of this processor via {@link OutgoingCallsManager}.
+     * 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.
      *
      * @param call The call to place.
      * @param callServiceRepository
-     * @param selectorRepository
      * @param resultCallback The callback on which to return the result.
      */
     OutgoingCallProcessor(
             Call call,
             CallServiceRepository callServiceRepository,
-            CallServiceSelectorRepository selectorRepository,
             AsyncResultCallback<Boolean> resultCallback) {
 
         ThreadUtil.checkOnMainThread();
@@ -131,7 +118,6 @@
         mCall = call;
         mResultCallback = resultCallback;
         mCallServiceRepository = callServiceRepository;
-        mSelectorRepository = selectorRepository;
     }
 
     /**
@@ -150,20 +136,6 @@
                     setCallServices(services);
                 }
             });
-
-            if (mCall.getCallServiceSelector() == null) {
-                // Lookup selectors
-                mSelectorRepository.lookupServices(
-                        new LookupCallback<CallServiceSelectorWrapper>() {
-                            @Override
-                            public void onComplete(
-                                    Collection<CallServiceSelectorWrapper> selectors) {
-                                setSelectors(selectors);
-                            }
-                        });
-            } else {
-                setSelectors(ImmutableList.of(mCall.getCallServiceSelector()));
-            }
         }
     }
 
@@ -235,23 +207,6 @@
     }
 
     /**
-     * Persists the ordered-list of call-service descriptor as selected by the current selector and
-     * starts iterating through the corresponding call services continuing the attempt to place the
-     * call.
-     *
-     * @param descriptors The (ordered) list of call-service descriptor.
-     */
-    void processSelectedCallServices(List<CallServiceDescriptor> descriptors) {
-        Log.v(this, "processSelectedCallServices");
-        if (descriptors == null || descriptors.isEmpty()) {
-            attemptNextSelector();
-        } else if (mCallServiceDescriptorIterator == null) {
-            mCallServiceDescriptorIterator = descriptors.iterator();
-            attemptNextCallService();
-        }
-    }
-
-    /**
      * Sets the call services to attempt for this outgoing call.
      *
      * @param callServices The call services.
@@ -263,100 +218,26 @@
         // it's being passed down to selectors.
         for (CallServiceWrapper callService : callServices) {
             CallServiceDescriptor descriptor = callService.getDescriptor();
-            mCallServiceDescriptors.add(descriptor);
+            // 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);
+                mCallServiceDescriptors.add(0, descriptor);
+            } else {
+                mCallServiceDescriptors.add(descriptor);
+            }
             mCallServicesById.put(descriptor.getCallServiceId(), callService);
         }
 
-        onLookupComplete();
-    }
+        adjustCallServiceDescriptorsForEmergency();
 
-    /**
-     * Sets the selectors to attemnpt for this outgoing call.
-     *
-     * @param selectors The call-service selectors.
-     */
-    private void setSelectors(Collection<CallServiceSelectorWrapper> selectors) {
-        mSelectors = adjustForEmergencyCalls(selectors);
-        onLookupComplete();
-    }
-
-    private void onLookupComplete() {
-        if (!mIsAborted && mSelectors != null && mCallServiceDescriptors != null) {
-            if (mSelectorIterator == null) {
-                mSelectorIterator = mSelectors.iterator();
-                attemptNextSelector();
-            }
-        }
-    }
-
-    /**
-     * Updates the specified collection of selectors to accomodate for emergency calls and any
-     * preferred selectors specified in the call object.
-     *
-     * @param selectors The selectors found through the selector repository.
-     */
-    private Collection<CallServiceSelectorWrapper> adjustForEmergencyCalls(
-            Collection<CallServiceSelectorWrapper> selectors) {
-        boolean useEmergencySelector =
-                EmergencyCallServiceSelector.shouldUseSelector(mCall.getHandle());
-        Log.d(this, "processNewOutgoingCall, isEmergency=%b", useEmergencySelector);
-
-        if (useEmergencySelector) {
-            // This is potentially an emergency call so add the emergency selector before the
-            // other selectors.
-            ImmutableList.Builder<CallServiceSelectorWrapper> selectorsBuilder =
-                    ImmutableList.builder();
-
-            ComponentName componentName = new ComponentName(
-                    TelecommApp.getInstance(), EmergencyCallServiceSelector.class);
-            CallServiceSelectorWrapper emergencySelector =
-                    new CallServiceSelectorWrapper(
-                            componentName.flattenToShortString(),
-                            componentName,
-                            CallsManager.getInstance());
-
-            selectorsBuilder.add(emergencySelector);
-            selectorsBuilder.addAll(selectors);
-            selectors = selectorsBuilder.build();
-        }
-
-        return selectors;
-    }
-
-    /**
-     * Attempts to place the call using the next selector, no-op if no other selectors
-     * are available.
-     */
-    private void attemptNextSelector() {
-        Log.v(this, "attemptNextSelector, mIsAborted: %b", mIsAborted);
-        if (mIsAborted) {
-            return;
-        }
-
-        if (mSelectorIterator.hasNext()) {
-            CallServiceSelectorWrapper selector = mSelectorIterator.next();
-            mCall.setCallServiceSelector(selector);
-            selector.select(mCall, mCallServiceDescriptors,
-                    new AsyncResultCallback<List<CallServiceDescriptor>>() {
-                        @Override
-                        public void onResult(
-                                List<CallServiceDescriptor> descriptors,
-                                int errorCode, String errorMsg) {
-                            processSelectedCallServices(descriptors);
-                        }
-                    });
-        } else {
-            Log.v(this, "attemptNextSelector, no more selectors, failing");
-            mCall.clearCallServiceSelector();
-            sendResult(false, mLastErrorCode, mLastErrorMsg);
-        }
+        mCallServiceDescriptorIterator = mCallServiceDescriptors.iterator();
+        attemptNextCallService();
     }
 
     /**
      * Attempts to place the call using the call service specified by the next call-service
-     * descriptor of mCallServiceDescriptorIterator.  If there are no more call services to
-     * attempt, the process continues to the next call-service selector via
-     * {@link #attemptNextSelector}.
+     * descriptor of mCallServiceDescriptorIterator.
      */
     private void attemptNextCallService() {
         Log.v(this, "attemptNextCallService, mIsAborted: %b", mIsAborted);
@@ -381,6 +262,7 @@
                 // service from unbinding while we are using it.
                 callService.incrementAssociatedCallCount();
 
+                Log.i(this, "Attempting to call from %s", callService.getDescriptor());
                 callService.call(mCall, new AsyncResultCallback<Boolean>() {
                     @Override
                     public void onResult(Boolean wasCallPlaced, int errorCode, String errorMsg) {
@@ -397,9 +279,10 @@
                 });
             }
         } else {
+            Log.v(this, "attemptNextCallService, no more service descriptors, failing");
             mCallServiceDescriptorIterator = null;
             mCall.clearCallService();
-            attemptNextSelector();
+            sendResult(false, mLastErrorCode, mLastErrorMsg);
         }
     }
 
@@ -413,4 +296,27 @@
             Log.wtf(this, "Attempting to return outgoing result twice for call %s", mCall);
         }
     }
+
+    // If we are possibly attempting to call a local emergency number, ensure that the
+    // plain PSTN call 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))) {
+                    mCallServiceDescriptors.add(0, mCallServiceDescriptors.remove(i));
+                    return;
+                }
+            } else {
+                if (mCallServiceDescriptors.get(i).getServiceComponent().getPackageName().equals(
+                        "com.android.telecomm.tests")) {
+                    mCallServiceDescriptors.add(0, mCallServiceDescriptors.remove(i));
+                }
+            }
+        }
+    }
+
+    private boolean shouldProcessAsEmergency(Uri handle) {
+        return PhoneNumberUtils.isPotentialLocalEmergencyNumber(
+                TelecommApp.getInstance(), handle.getSchemeSpecificPart());
+    }
 }
diff --git a/src/com/android/telecomm/PhoneStateBroadcaster.java b/src/com/android/telecomm/PhoneStateBroadcaster.java
index f929f1f..d6f1a38 100644
--- a/src/com/android/telecomm/PhoneStateBroadcaster.java
+++ b/src/com/android/telecomm/PhoneStateBroadcaster.java
@@ -60,10 +60,12 @@
         intent.putExtra(TelephonyManager.EXTRA_STATE, phoneState);
 
         // Populate both, since the original API was needlessly complicated.
-        String callHandle = call.getHandle().getSchemeSpecificPart();
-        intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, callHandle);
-        // TODO: See if we can add this (the current API only sets this on NEW_OUTGOING_CALL).
-        intent.putExtra(Intent.EXTRA_PHONE_NUMBER, callHandle);
+        if (call.getHandle() != null) {
+            String callHandle = call.getHandle().getSchemeSpecificPart();
+            intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, callHandle);
+            // TODO: See if we can add this (the current API only sets this on NEW_OUTGOING_CALL).
+            intent.putExtra(Intent.EXTRA_PHONE_NUMBER, callHandle);
+        }
 
         // TODO: Replace these with real constants once this API has been vetted.
         CallServiceWrapper callService = call.getCallService();
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 834bf44..7c6d44d 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -34,8 +34,7 @@
 import java.util.Set;
 
 /**
- * Switchboard is responsible for:
- * - gathering the {@link CallServiceWrapper}s and {@link CallServiceSelectorWrapper}s through
+ * Switchboard is responsible for gathering the {@link CallServiceWrapper}s through
  *       which to place outgoing calls
  */
 final class Switchboard {
@@ -46,8 +45,6 @@
 
     private final CallServiceRepository mCallServiceRepository;
 
-    private final CallServiceSelectorRepository mSelectorRepository;
-
     /** Singleton accessor. */
     static Switchboard getInstance() {
         return sInstance;
@@ -60,7 +57,6 @@
         ThreadUtil.checkOnMainThread();
 
         mIncomingCallsManager = new IncomingCallsManager();
-        mSelectorRepository = new CallServiceSelectorRepository();
         mCallServiceRepository =
                 new CallServiceRepository(mIncomingCallsManager);
     }
@@ -69,10 +65,6 @@
         return mCallServiceRepository;
     }
 
-    CallServiceSelectorRepository getSelectorRepository() {
-        return mSelectorRepository;
-    }
-
     /**
      * Retrieves details about the incoming call through the incoming call manager.
      *
diff --git a/src/com/android/telecomm/TelecommServiceImpl.java b/src/com/android/telecomm/TelecommServiceImpl.java
index 1b377b8..9793fda 100644
--- a/src/com/android/telecomm/TelecommServiceImpl.java
+++ b/src/com/android/telecomm/TelecommServiceImpl.java
@@ -16,11 +16,20 @@
 
 package com.android.telecomm;
 
+import com.google.android.collect.Lists;
+
+import com.android.internal.telecomm.ITelecommService;
+
+import android.content.ComponentName;
+import android.content.res.Resources;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
 import android.os.ServiceManager;
+import android.telecomm.Subscription;
+import android.text.TextUtils;
 
-import com.android.internal.telecomm.ITelecommService;
+import java.util.List;
 
 /**
  * Implementation of the ITelecomm interface.
@@ -119,4 +128,68 @@
     private void showCallScreenInternal(boolean showDialpad) {
         CallsManager.getInstance().getInCallController().bringToForeground(showDialpad);
     }
+
+    // TODO (STOPSHIP): Static list of Subscriptions for testing and UX work only.
+
+    private  static final ComponentName sComponentName = new ComponentName(
+            "com.android.telecomm",
+            TelecommServiceImpl.class.getName());  // This field is a no-op
+
+    private static final List<Subscription> sSubscriptions = Lists.newArrayList(
+            new Subscription(
+                    sComponentName,
+                    "subscription0",
+                    Uri.parse("tel:999-555-1212"),
+                    R.string.test_subscription_0_label,
+                    R.string.test_subscription_0_short_description,
+                    R.drawable.q_mobile,
+                    true,
+                    true),
+            new Subscription(
+                    sComponentName,
+                    "subscription1",
+                    Uri.parse("tel:333-111-2222"),
+                    R.string.test_subscription_1_label,
+                    R.string.test_subscription_1_short_description,
+                    R.drawable.market_wireless,
+                    true,
+                    false),
+            new Subscription(
+                    sComponentName,
+                    "subscription2",
+                    Uri.parse("mailto:two@example.com"),
+                    R.string.test_subscription_2_label,
+                    R.string.test_subscription_2_short_description,
+                    R.drawable.talk_to_your_circles,
+                    true,
+                    false),
+            new Subscription(
+                    sComponentName,
+                    "subscription3",
+                    Uri.parse("mailto:three@example.com"),
+                    R.string.test_subscription_3_label,
+                    R.string.test_subscription_3_short_description,
+                    R.drawable.chat_with_others,
+                    true,
+                    false)
+    );
+
+
+
+    @Override
+    public List<Subscription> getSubscriptions() {
+        return sSubscriptions;
+    }
+
+    @Override
+    public void setEnabled(Subscription subscription, boolean enabled) {
+        // Enforce MODIFY_PHONE_STATE ?
+        // TODO
+    }
+
+    @Override
+    public void setSystemDefault(Subscription subscription) {
+        // Enforce MODIFY_PHONE_STATE ?
+        // TODO
+    }
 }
diff --git a/src/com/android/telecomm/TelephonyUtil.java b/src/com/android/telecomm/TelephonyUtil.java
index 4ea46d9..a8cfb3e 100644
--- a/src/com/android/telecomm/TelephonyUtil.java
+++ b/src/com/android/telecomm/TelephonyUtil.java
@@ -31,24 +31,16 @@
     private static final String TELEPHONY_PACKAGE_NAME =
             "com.android.phone";
 
-    private static final String GSM_CALL_SERVICE_CLASS_NAME =
-            "com.android.services.telephony.GsmConnectionService";
-
-    private static final String CDMA_CALL_SERVICE_CLASS_NAME =
-            "com.android.services.telephony.CdmaConnectionService";
+    private static final String PSTN_CALL_SERVICE_CLASS_NAME =
+            "com.android.services.telephony.PstnConnectionService";
 
     private TelephonyUtil() {}
 
-    static boolean isTelephonySelector(CallServiceSelectorWrapper selector) {
-        return selector.getComponentName().getPackageName().equals(TELEPHONY_PACKAGE_NAME);
-    }
-
     static boolean isPstnCallService(CallServiceDescriptor descriptor) {
         ComponentName componentName = descriptor.getServiceComponent();
         if (TELEPHONY_PACKAGE_NAME.equals(componentName.getPackageName())) {
             String className = componentName.getClassName();
-            return GSM_CALL_SERVICE_CLASS_NAME.equals(className) ||
-                    CDMA_CALL_SERVICE_CLASS_NAME.equals(className);
+            return PSTN_CALL_SERVICE_CLASS_NAME.equals(className);
         }
 
         return false;
@@ -60,8 +52,7 @@
      */
     static boolean isCurrentlyPSTNCall(Call call) {
         if (Log.DEBUG) {
-            verifyCallServiceExists(GSM_CALL_SERVICE_CLASS_NAME);
-            verifyCallServiceExists(CDMA_CALL_SERVICE_CLASS_NAME);
+            verifyCallServiceExists(PSTN_CALL_SERVICE_CLASS_NAME);
         }
 
         CallServiceWrapper callService = call.getCallService();
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 807e669..2bcb756 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -29,18 +29,12 @@
             </intent-filter>
         </service>
 
-        <service android:name="com.android.telecomm.testapps.TestCallService">
+        <service android:name="com.android.telecomm.testapps.TestConnectionService">
             <intent-filter>
                 <action android:name="android.telecomm.CallService" />
             </intent-filter>
         </service>
 
-        <service android:name="com.android.telecomm.testapps.DummyCallServiceSelector">
-            <intent-filter>
-                <action android:name="android.telecomm.CallServiceSelector" />
-            </intent-filter>
-        </service>
-
         <activity android:name="com.android.telecomm.testapps.TestCallActivity"
                 android:label="@string/testCallActivityLabel">
             <intent-filter>
diff --git a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
index 336ce56..6364377 100644
--- a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
+++ b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
@@ -27,7 +27,7 @@
 
 /**
  * Class used to create, update and cancel the notification used to display and update call state
- * for {@link TestCallService}.
+ * for {@link TestConnectionService}.
  */
 public class CallServiceNotifier {
     private static final CallServiceNotifier INSTANCE = new CallServiceNotifier();
@@ -86,7 +86,7 @@
 
         builder.setSmallIcon(android.R.drawable.stat_sys_phone_call);
         builder.setContentText("Test calls via CallService API");
-        builder.setContentTitle("TestCallService");
+        builder.setContentTitle("TestConnectionService");
 
         addAddCallAction(builder, context);
         addExitAction(builder, context);
@@ -109,9 +109,9 @@
      */
     private PendingIntent createIncomingCallIntent(Context context) {
         log("Creating incoming call pending intent.");
-        // Build descriptor for TestCallService.
+        // Build descriptor for TestConnectionService.
         CallServiceDescriptor.Builder descriptorBuilder = CallServiceDescriptor.newBuilder(context);
-        descriptorBuilder.setCallService(TestCallService.class);
+        descriptorBuilder.setCallService(TestConnectionService.class);
         descriptorBuilder.setNetworkType(CallServiceDescriptor.FLAG_WIFI);
 
         // Create intent for adding an incoming call.
diff --git a/tests/src/com/android/telecomm/testapps/DummyCallServiceSelector.java b/tests/src/com/android/telecomm/testapps/DummyCallServiceSelector.java
deleted file mode 100644
index 5f0db05..0000000
--- a/tests/src/com/android/telecomm/testapps/DummyCallServiceSelector.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 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.testapps;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.telecomm.CallInfo;
-import android.telecomm.CallServiceDescriptor;
-import android.telecomm.CallServiceSelector;
-import android.telecomm.CallServiceSelectorAdapter;
-import android.util.Log;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-/** Simple selector to exercise Telecomm code. */
-public class DummyCallServiceSelector extends CallServiceSelector {
-    private static DummyCallServiceSelector sInstance;
-    private static final String SCHEME_TEL = "tel";
-    private static final String TELEPHONY_PACKAGE_NAME = "com.android.phone";
-    private static final String CUSTOM_HANDOFF_KEY = "custom_handoff_key";
-    private static final String CUSTOM_HANDOFF_VALUE = "custom_handoff_value";
-
-    public DummyCallServiceSelector() {
-        log("constructor");
-        sInstance = this;
-    }
-
-    static DummyCallServiceSelector getInstance() {
-        Preconditions.checkNotNull(sInstance);
-        return sInstance;
-    }
-
-    @Override
-    protected void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
-        log("select");
-        List<CallServiceDescriptor> orderedList = Lists.newLinkedList();
-
-        boolean shouldHandoffToPstn = false;
-        if (callInfo.getCurrentCallServiceDescriptor() != null) {
-            // If the current call service is TestCallService then handoff to PSTN, otherwise
-            // handoff to TestCallService.
-            shouldHandoffToPstn = isTestCallService(callInfo.getCurrentCallServiceDescriptor());
-            String extraValue = callInfo.getExtras().getString(CUSTOM_HANDOFF_KEY);
-            log("handing off, toPstn: " + shouldHandoffToPstn + ", extraValue: " + extraValue);
-            Preconditions.checkState(CUSTOM_HANDOFF_VALUE.equals(extraValue));
-        }
-
-        for (CallServiceDescriptor descriptor : descriptors) {
-            if (isTestCallService(descriptor) && !shouldHandoffToPstn) {
-                orderedList.add(0, descriptor);
-            } else if (isPstnCallService(descriptor)) {
-                orderedList.add(descriptor);
-            } else {
-                log("skipping call service: " + descriptor.getServiceComponent());
-            }
-        }
-
-        getAdapter().setSelectedCallServices(callInfo.getId(), orderedList);
-    }
-
-    void sendHandoffInfo(Uri remoteHandle, Uri handoffHandle) {
-        log("sendHandoffInfo");
-        String callId = findMatchingCall(remoteHandle);
-        Preconditions.checkNotNull(callId);
-        Bundle extras = new Bundle();
-        extras.putString(CUSTOM_HANDOFF_KEY, CUSTOM_HANDOFF_VALUE);
-        getAdapter().setHandoffInfo(callId, handoffHandle, extras);
-    }
-
-    private String findMatchingCall(Uri remoteHandle) {
-        for (CallInfo callInfo : getCalls()) {
-            if (remoteHandle.equals(callInfo.getOriginalHandle())) {
-                return callInfo.getId();
-            }
-        }
-        return null;
-    }
-
-    private boolean isTestCallService(CallServiceDescriptor descriptor) {
-        if (descriptor == null) {
-            return false;
-        }
-        return getPackageName().equals(descriptor.getServiceComponent().getPackageName());
-    }
-
-    private boolean isPstnCallService(CallServiceDescriptor descriptor) {
-        if (descriptor == null) {
-            return false;
-        }
-        return TELEPHONY_PACKAGE_NAME.equals(descriptor.getServiceComponent().getPackageName());
-    }
-
-    private static void log(String msg) {
-        Log.w("testcallservice", "[DummyCallServiceSelector] " + msg);
-    }
-}
diff --git a/tests/src/com/android/telecomm/testapps/TestCallService.java b/tests/src/com/android/telecomm/testapps/TestCallService.java
deleted file mode 100644
index 67626a2..0000000
--- a/tests/src/com/android/telecomm/testapps/TestCallService.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- Ca* See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.telecomm.testapps;
-
-import android.content.Intent;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.telecomm.CallAudioState;
-import android.telecomm.CallInfo;
-import android.telecomm.CallService;
-import android.telecomm.CallServiceAdapter;
-import android.telecomm.CallState;
-import android.telephony.DisconnectCause;
-import android.util.Log;
-
-import com.android.telecomm.tests.R;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Maps;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Service which provides fake calls to test the ICallService interface.
- * TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyCallService).
- */
-public class TestCallService extends CallService {
-    private static final String SCHEME_TEL = "tel";
-
-    private final Map<String, CallInfo> mCalls = Maps.newHashMap();
-    private final Handler mHandler = new Handler();
-
-    /** Used to play an audio tone during a call. */
-    private MediaPlayer mMediaPlayer;
-
-    /** {@inheritDoc} */
-    @Override
-    public void onAdapterAttached(CallServiceAdapter callServiceAdapter) {
-        log("onAdapterAttached");
-        mMediaPlayer = createMediaPlayer();
-    }
-
-    /**
-     * Responds as compatible for all calls except those starting with the number 7 (arbitrarily
-     * chosen for testing purposes).
-     *
-     * {@inheritDoc}
-     */
-    @Override
-    public void isCompatibleWith(CallInfo callInfo) {
-        log("isCompatibleWith, callInfo: " + callInfo);
-        Preconditions.checkNotNull(callInfo.getHandle());
-
-        // Is compatible if the handle doesn't start with 7.
-        boolean isCompatible = !callInfo.getHandle().getSchemeSpecificPart().startsWith("7");
-
-        // Tell CallsManager whether this call service can place the call.
-        getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
-    }
-
-    /**
-     * Starts a call by calling into the adapter.
-     *
-     * {@inheritDoc}
-     */
-    @Override
-    public void call(final CallInfo callInfo) {
-        String number = callInfo.getHandle().getSchemeSpecificPart();
-        log("call, number: " + number);
-
-        // Crash on 555-DEAD to test call service crashing.
-        if ("5550340".equals(number)) {
-            throw new RuntimeException("Goodbye, cruel world.");
-        }
-
-        mCalls.put(callInfo.getId(), callInfo);
-        getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                activateCall(callInfo.getId());
-            }
-        }, 4000);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void abort(String callId) {
-        log("abort, callId: " + callId);
-        destroyCall(callId);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void setIncomingCallId(String callId, Bundle extras) {
-        log("setIncomingCallId, callId: " + callId + " extras: " + extras);
-
-        // Use dummy number for testing incoming calls.
-        Uri handle = Uri.fromParts(SCHEME_TEL, "5551234", null);
-
-        CallInfo callInfo = new CallInfo(callId, CallState.RINGING, handle);
-        mCalls.put(callInfo.getId(), callInfo);
-        getAdapter().notifyIncomingCall(callInfo);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void answer(String callId) {
-        log("answer, callId: " + callId);
-        activateCall(callId);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void reject(String callId) {
-        log("reject, callId: " + callId);
-        getAdapter().setDisconnected(callId, DisconnectCause.INCOMING_REJECTED, null);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void disconnect(String callId) {
-        log("disconnect, callId: " + callId);
-
-        destroyCall(callId);
-        getAdapter().setDisconnected(callId, DisconnectCause.LOCAL, null);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void hold(String callId) {
-        log("hold, callId: " + callId);
-        getAdapter().setOnHold(callId);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void unhold(String callId) {
-        log("unhold, callId: " + callId);
-        getAdapter().setActive(callId);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void playDtmfTone(String callId, char digit) {
-        log("playDtmfTone, callId: " + callId + " digit: " + digit);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void stopDtmfTone(String callId) {
-        log("stopDtmfTone, callId: " + callId);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onAudioStateChanged(String callId, CallAudioState audioState) {
-        log("onAudioStateChanged, callId: " + callId + " audioState: " + audioState);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onUnbind(Intent intent) {
-        log("onUnbind");
-        mMediaPlayer = null;
-        return super.onUnbind(intent);
-    }
-
-    /** ${inheritDoc} */
-    @Override
-    public void conference(String conferenceCallId, String callId) {
-    }
-
-    /** ${inheritDoc} */
-    @Override
-    public void splitFromConference(String callId) {
-    }
-
-    private void activateCall(String callId) {
-        getAdapter().setActive(callId);
-        if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
-            mMediaPlayer.start();
-        }
-    }
-
-    /**
-     * Removes the specified call ID from the set of live call IDs and stops playing audio if
-     * there exist no more live calls.
-     *
-     * @param callId The identifier of the call to destroy.
-     */
-    private void destroyCall(String callId) {
-        Preconditions.checkState(!Strings.isNullOrEmpty(callId));
-        mCalls.remove(callId);
-
-        // Stops audio if there are no more calls.
-        if (mCalls.isEmpty() && mMediaPlayer.isPlaying()) {
-            mMediaPlayer.stop();
-            mMediaPlayer.release();
-            mMediaPlayer = createMediaPlayer();
-        }
-    }
-
-    private MediaPlayer createMediaPlayer() {
-        // Prepare the media player to play a tone when there is a call.
-        MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.beep_boop);
-        mediaPlayer.setLooping(true);
-        return mediaPlayer;
-    }
-
-    private static void log(String msg) {
-        Log.w("testcallservice", "[TestCallService] " + msg);
-    }
-}
diff --git a/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java b/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java
index a8ccaa1..b1d32a3 100644
--- a/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java
+++ b/tests/src/com/android/telecomm/testapps/TestCallServiceProvider.java
@@ -34,7 +34,7 @@
         log("lookupCallServices");
 
         CallServiceDescriptor.Builder builder = CallServiceDescriptor.newBuilder(this);
-        builder.setCallService(TestCallService.class);
+        builder.setCallService(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
new file mode 100644
index 0000000..1e23916
--- /dev/null
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2013 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.
+ Ca* See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telecomm.testapps;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.telecomm.CallAudioState;
+import android.telecomm.CallInfo;
+import android.telecomm.CallServiceAdapter;
+import android.telecomm.CallState;
+import android.telecomm.Connection;
+import android.telecomm.ConnectionRequest;
+import android.telecomm.ConnectionService;
+import android.telecomm.RemoteConnection;
+import android.telecomm.RemoteConnectionService;
+import android.telecomm.Response;
+
+import android.telecomm.SimpleResponse;
+import android.telecomm.Subscription;
+import android.telephony.DisconnectCause;
+import android.util.Log;
+
+import com.android.telecomm.tests.R;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service which provides fake calls to test the ICallService interface. TODO(santoscordon): Rename
+ * all classes in the directory to Dummy* (e.g., DummyCallService).
+ */
+public class TestConnectionService extends ConnectionService {
+    private final class TestConnection extends Connection {
+        private final RemoteConnection.Listener mProxyListener = new RemoteConnection.Listener() {
+            @Override
+            public void onStateChanged(RemoteConnection connection, int state) {
+                setState(state);
+            }
+
+            @Override
+            public void onAudioStateChanged(RemoteConnection connection, CallAudioState state) {
+                setAudioState(state);
+            }
+
+            @Override
+            public void onDisconnected(RemoteConnection connection, int cause, String message) {
+                setDisconnected(cause, message);
+                destroyCall(TestConnection.this);
+                setDestroyed();
+            }
+
+            @Override
+            public void onRequestingRingback(RemoteConnection connection, boolean ringback) {
+                setRequestingRingback(ringback);
+            }
+
+            @Override
+            public void onPostDialWait(RemoteConnection connection, String remainingDigits) {
+                // TODO(santoscordon): Method needs to be exposed on Connection.java
+            }
+
+            @Override
+            public void onDestroyed(RemoteConnection connection) {
+                setDestroyed();
+            }
+        };
+
+        private final RemoteConnection mRemoteConnection;
+
+        TestConnection(RemoteConnection remoteConnection, int initialState) {
+            mRemoteConnection = remoteConnection;
+            if (mRemoteConnection != null) {
+                mRemoteConnection.addListener(mProxyListener);
+            } else {
+                setState(initialState);
+            }
+        }
+
+        void startOutgoing() {
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    TestConnection.this.setActive();
+                }
+            }, 4000);
+        }
+
+        boolean isProxy() {
+            return mRemoteConnection != null;
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        protected void onAbort() {
+            if (mRemoteConnection != null) {
+                mRemoteConnection.disconnect();
+                mRemoteConnection.removeListener(mProxyListener);
+            } else {
+                destroyCall(this);
+                setDestroyed();
+            }
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        protected void onAnswer() {
+            if (mRemoteConnection != null) {
+                mRemoteConnection.answer();
+            } else {
+                activateCall(this);
+                setActive();
+            }
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        protected void onDisconnect() {
+            if (mRemoteConnection != null) {
+                mRemoteConnection.disconnect();
+            } else {
+                setDisconnected(DisconnectCause.LOCAL, null);
+                destroyCall(this);
+                setDestroyed();
+            }
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        protected void onHold() {
+            if (mRemoteConnection != null) {
+                mRemoteConnection.hold();
+            } else {
+                setOnHold();
+            }
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        protected void onReject() {
+            if (mRemoteConnection != null) {
+                mRemoteConnection.reject();
+            } else {
+                setDisconnected(DisconnectCause.INCOMING_REJECTED, null);
+                destroyCall(this);
+                setDestroyed();
+            }
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        protected void onUnhold() {
+            if (mRemoteConnection != null) {
+                mRemoteConnection.hold();
+            } else {
+                setActive();
+            }
+        }
+
+        private void setState(int state) {
+            switch (state) {
+                case Connection.State.ACTIVE:
+                    setActive();
+                    break;
+                case Connection.State.HOLDING:
+                    setOnHold();
+                    break;
+                case Connection.State.DIALING:
+                    setDialing();
+                    break;
+                case Connection.State.RINGING:
+                    setRinging();
+                    break;
+            }
+        }
+    }
+
+    private class CallAttempter implements SimpleResponse<ConnectionRequest, RemoteConnection> {
+        private final Iterator<Subscription> mSubscriptionIterator;
+        private final Response<ConnectionRequest, Connection> mCallback;
+        private final ConnectionRequest mOriginalRequest;
+
+        CallAttempter(
+                Iterator<Subscription> iterator,
+                Response<ConnectionRequest, Connection> callback,
+                ConnectionRequest originalRequest) {
+            mSubscriptionIterator = iterator;
+            mCallback = callback;
+            mOriginalRequest = originalRequest;
+        }
+
+        @Override
+        public void onResult(
+            ConnectionRequest request, RemoteConnection remoteConnection) {
+
+            if (remoteConnection != null) {
+                TestConnection connection = new TestConnection(
+                        remoteConnection, Connection.State.DIALING);
+                mCalls.add(connection);
+                mCallback.onResult(mOriginalRequest, connection);
+            } else {
+                tryNextSubscription();
+            }
+        }
+
+        @Override
+        public void onError(ConnectionRequest request) {
+            tryNextSubscription();
+        }
+
+        public void tryNextSubscription() {
+            if (mSubscriptionIterator.hasNext()) {
+                ConnectionRequest connectionRequest = new ConnectionRequest(
+                        mSubscriptionIterator.next(),
+                        mOriginalRequest.getCallId(),
+                        mOriginalRequest.getHandle(),
+                        null);
+                createRemoteOutgoingConnection(connectionRequest, this);
+            } else {
+                mCallback.onError(mOriginalRequest, 0, null);
+            }
+        }
+    }
+
+    private static final String SCHEME_TEL = "tel";
+
+    private final List<TestConnection> mCalls = new ArrayList<>();
+    private final Handler mHandler = new Handler();
+
+    /** Used to play an audio tone during a call. */
+    private MediaPlayer mMediaPlayer;
+
+    /** {@inheritDoc} */
+    @Override
+    public void onAdapterAttached(CallServiceAdapter callServiceAdapter) {
+        log("onAdapterAttached");
+        mMediaPlayer = createMediaPlayer();
+        super.onAdapterAttached(callServiceAdapter);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        log("onUnbind");
+        mMediaPlayer = null;
+        return super.onUnbind(intent);
+    }
+
+    private void activateCall(TestConnection connection) {
+        if (!connection.isProxy()) {
+            if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
+                mMediaPlayer.start();
+            }
+        }
+    }
+
+    private void destroyCall(TestConnection connection) {
+        mCalls.remove(connection);
+
+        // Stops audio if there are no more calls.
+        if (mCalls.isEmpty() && mMediaPlayer.isPlaying()) {
+            mMediaPlayer.stop();
+            mMediaPlayer.release();
+            mMediaPlayer = createMediaPlayer();
+        }
+    }
+
+    private MediaPlayer createMediaPlayer() {
+        // Prepare the media player to play a tone when there is a call.
+        MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.beep_boop);
+        mediaPlayer.setLooping(true);
+        return mediaPlayer;
+    }
+
+    private static void log(String msg) {
+        Log.w("telecomtestcallservice", "[TestCallService] " + msg);
+    }
+
+    /** ${inheritDoc} */
+    @Override
+    public void onCreateConnections(
+            final ConnectionRequest originalRequest,
+            final Response<ConnectionRequest, Connection> callback) {
+
+        final Uri handle = originalRequest.getHandle();
+        String number = originalRequest.getHandle().getSchemeSpecificPart();
+        log("call, number: " + number);
+
+        // Crash on 555-DEAD to test call service crashing.
+        if ("5550340".equals(number)) {
+            throw new RuntimeException("Goodbye, cruel world.");
+        }
+
+        // Normally we would use the original request as is, but for testing purposes, we are adding
+        // ".." to the end of the number to follow its path more easily through the logs.
+        final ConnectionRequest request = new ConnectionRequest(
+                originalRequest.getCallId(),
+                Uri.fromParts(handle.getScheme(), handle.getSchemeSpecificPart() + "..", ""),
+                originalRequest.getExtras());
+
+        // If the number starts with 555, then we handle it ourselves. If not, then we
+        // use a remote connection service.
+        // TODO(santoscordon): Have a special phone number to test the subscription-picker dialog
+        // flow.
+        if (number.startsWith("555")) {
+            TestConnection connection = new TestConnection(null, Connection.State.DIALING);
+            mCalls.add(connection);
+            callback.onResult(request, connection);
+            connection.startOutgoing();
+        } else {
+            log("looking up subscriptions");
+            lookupRemoteSubscriptions(handle, new SimpleResponse<Uri, List<Subscription>>() {
+                @Override
+                public void onResult(Uri handle, final List<Subscription> subscriptions) {
+                    log("starting the call attempter with subscriptions: " + subscriptions);
+                    new CallAttempter(subscriptions.iterator(), callback, request)
+                            .tryNextSubscription();
+                }
+
+                @Override
+                public void onError(Uri handle) {
+                    log("remote subscription lookup failed.");
+                    callback.onError(request, 0, null);
+                }
+            });
+        }
+    }
+
+    /** ${inheritDoc} */
+    @Override
+    public void onCreateIncomingConnection(
+            ConnectionRequest request, Response<ConnectionRequest, Connection> callback) {
+
+        // Use dummy number for testing incoming calls.
+        Uri handle = Uri.fromParts(SCHEME_TEL, "5551234", null);
+
+        TestConnection connection = new TestConnection(null, Connection.State.DIALING);
+        mCalls.add(connection);
+        callback.onResult(
+                new ConnectionRequest(handle, request.getExtras()),
+                connection);
+    }
+}