Updating the outgoing call sequence.

- Removes OutgoingCallsManager
- Call now invokes it's own OutgoingCallProcessor (OCP) directly.
- Results for select(), call(), and OCP.process() now happen through
  new AsyncResultCallback closure objects specified at the time
  the methods are invoked.
- Move remaining outgoing call responsibilities in Switchboard to
  OCP including expiration and CS/selector discovery.
- Remove isCompatibleWith sequence

Change-Id: Ie63c7900dc7a324d0c56e0767ed19b2ef0868528
diff --git a/src/com/android/telecomm/AsyncResultCallback.java b/src/com/android/telecomm/AsyncResultCallback.java
new file mode 100644
index 0000000..d059c6c
--- /dev/null
+++ b/src/com/android/telecomm/AsyncResultCallback.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * Generic result interface for use with async method callback.
+ */
+interface AsyncResultCallback<T> {
+    void onResult(T param1);
+}
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index d86a8f9..995957c 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -127,6 +127,12 @@
     /** Set of listeners on this call. */
     private Set<Listener> mListeners = Sets.newHashSet();
 
+    private OutgoingCallProcessor mOutgoingCallProcessor;
+
+    // TODO(santoscordon): The repositories should be changed into singleton types.
+    private CallServiceRepository mCallServiceRepository;
+    private CallServiceSelectorRepository mSelectorRepository;
+
     /**
      * Creates an empty call object.
      *
@@ -379,14 +385,33 @@
     }
 
     /**
-     * Starts the outgoing call flow through the switchboard. When switchboard completes, it will
-     * invoke handleSuccessful/FailedOutgoingCall.
+     * Starts the outgoing call sequence.  Upon completion, there should exist an active connection
+     * through a call service (or the call will have failed).
      */
     void startOutgoing() {
-        Switchboard.getInstance().placeOutgoingCall(this);
+        Preconditions.checkState(mOutgoingCallProcessor == null);
+
+        mOutgoingCallProcessor = new OutgoingCallProcessor(
+                this,
+                Switchboard.getInstance().getCallServiceRepository(),
+                Switchboard.getInstance().getSelectorRepository(),
+                new AsyncResultCallback<Boolean>() {
+                    @Override
+                    public void onResult(Boolean wasCallPlaced) {
+                        if (wasCallPlaced) {
+                            handleSuccessfulOutgoing();
+                        } else {
+                            handleFailedOutgoing(mOutgoingCallProcessor.isAborted());
+                        }
+                        mOutgoingCallProcessor = null;
+                    }
+                });
+        mOutgoingCallProcessor.process();
     }
 
     void handleSuccessfulOutgoing() {
+        setState(CallState.DIALING);
+
         // TODO(santoscordon): Replace this with state transitions related to "connecting".
         for (Listener l : mListeners) {
             l.onSuccessfulOutgoingCall(this);
@@ -394,14 +419,13 @@
     }
 
     void handleFailedOutgoing(boolean isAborted) {
-        if (isAborted) {
-            finalizeAbort();
-        }
-
         // TODO(santoscordon): Replace this with state transitions related to "connecting".
         for (Listener l : mListeners) {
             l.onFailedOutgoingCall(this, isAborted);
         }
+
+        clearCallService();
+        clearCallServiceSelector();
     }
 
     /**
@@ -431,20 +455,6 @@
     }
 
     /**
-     * Issues an abort signal to the associated call service and clears the current call service
-     * and call-service selector.
-     */
-    void finalizeAbort() {
-        Preconditions.checkState(mState == CallState.NEW);
-
-        if (mCallService != null) {
-            mCallService.abort(this);
-        }
-        clearCallService();
-        clearCallServiceSelector();
-    }
-
-    /**
      * Plays the specified DTMF tone.
      */
     void playDtmfTone(char digit) {
@@ -473,16 +483,8 @@
      */
     void disconnect() {
         if (mState == CallState.NEW) {
-            // There is a very strange indirection here. When we are told to disconnect, we issue
-            // an 'abort' to the switchboard if we are still in the NEW (or "connecting") state.
-            // The switchboard will then cancel the outgoing call process and ask this class to
-            // finalize the abort procedure via {@link #finalizeAbort}. The issue is that
-            // Switchboard edits the state of the call as part of the process and then this class
-            // is responsible for undoing it, and that is all kinds of backwards.
-            // TODO(santoscordon): Remove Switchboard's requirement to edit the state of the Call
-            // objects and remove any multi-class shared state of incoming and outgoing call
-            // processing.
-            Switchboard.getInstance().abortCall(this);
+            Log.v(this, "Aborting call %s", this);
+            abort();
         } else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) {
             Preconditions.checkNotNull(mCallService);
 
@@ -494,6 +496,12 @@
         }
     }
 
+    void abort() {
+        if (mOutgoingCallProcessor != null) {
+            mOutgoingCallProcessor.abort();
+        }
+    }
+
     /**
      * Answers the call if it is ringing.
      */
diff --git a/src/com/android/telecomm/CallIdMapper.java b/src/com/android/telecomm/CallIdMapper.java
index 7044d89..7f92067 100644
--- a/src/com/android/telecomm/CallIdMapper.java
+++ b/src/com/android/telecomm/CallIdMapper.java
@@ -52,6 +52,11 @@
         mCalls.inverse().remove(call);
     }
 
+    void removeCall(String callId) {
+        ThreadUtil.checkOnMainThread();
+        mCalls.remove(callId);
+    }
+
     String getCallId(Call call) {
         ThreadUtil.checkOnMainThread();
         Preconditions.checkNotNull(call);
@@ -70,6 +75,10 @@
         return mCalls.get(callId);
     }
 
+    void clear() {
+        mCalls.clear();
+    }
+
     void checkValidCallId(String callId) {
         // Note, no need for thread check, this method is thread safe.
         if (!isValidCallId(callId)) {
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index 0589358..f6e1164 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -160,16 +160,11 @@
         }
     }
 
-    private final OutgoingCallsManager mOutgoingCallsManager;
     private final IncomingCallsManager mIncomingCallsManager;
     private final Handler mHandler = new Handler();
 
     /** Persists specified parameters. */
-    CallServiceRepository(
-            OutgoingCallsManager outgoingCallsManager,
-            IncomingCallsManager incomingCallsManager) {
-
-        mOutgoingCallsManager = outgoingCallsManager;
+    CallServiceRepository(IncomingCallsManager incomingCallsManager) {
         mIncomingCallsManager = incomingCallsManager;
     }
 
@@ -191,7 +186,6 @@
     @Override
     protected CallServiceWrapper onCreateNewServiceWrapper(ComponentName componentName,
             Object param) {
-        return new CallServiceWrapper(
-                (CallServiceDescriptor) param, mOutgoingCallsManager, mIncomingCallsManager);
+        return new CallServiceWrapper((CallServiceDescriptor) param, mIncomingCallsManager);
     }
 }
diff --git a/src/com/android/telecomm/CallServiceSelectorRepository.java b/src/com/android/telecomm/CallServiceSelectorRepository.java
index 99a2f52..0a8deb6 100644
--- a/src/com/android/telecomm/CallServiceSelectorRepository.java
+++ b/src/com/android/telecomm/CallServiceSelectorRepository.java
@@ -38,23 +38,6 @@
  */
 final class CallServiceSelectorRepository extends BaseRepository<CallServiceSelectorWrapper> {
 
-    private final OutgoingCallsManager mOutgoingCallsManager;
-
-    /**
-     * The set of call-service selectors. Only populated via initiateLookup scenarios.
-     */
-    private final Map<ComponentName, CallServiceSelectorWrapper> mCallServiceSelectors =
-            Maps.newHashMap();
-
-    /**
-     * Persists the specified parameters and initializes the new instance.
-     *
-     * @param outgoingCallsManager The outgoing calls manager.
-     */
-    CallServiceSelectorRepository(OutgoingCallsManager outgoingCallsManager) {
-        mOutgoingCallsManager = outgoingCallsManager;
-    }
-
     /** {@inheritDoc} */
     @Override
     protected void onLookupServices(LookupCallback<CallServiceSelectorWrapper> callback) {
@@ -84,20 +67,7 @@
     protected CallServiceSelectorWrapper onCreateNewServiceWrapper(
             ComponentName componentName, Object param) {
 
-        return new CallServiceSelectorWrapper(
-                componentName, CallsManager.getInstance(), mOutgoingCallsManager);
-    }
-
-    /**
-     * Creates a wrapper for the specified component name and starts listening to it's unbind event.
-     *
-     * @param componentName The component name of the call-service selector.
-     * @return The wrapper for the selector.
-     */
-    private CallServiceSelectorWrapper createWrapper(ComponentName componentName) {
-        CallServiceSelectorWrapper selector = new CallServiceSelectorWrapper(
-                componentName, CallsManager.getInstance(), mOutgoingCallsManager);
-        return selector;
+        return new CallServiceSelectorWrapper(componentName, CallsManager.getInstance());
     }
 
     /**
diff --git a/src/com/android/telecomm/CallServiceSelectorWrapper.java b/src/com/android/telecomm/CallServiceSelectorWrapper.java
index 74073df..7cc01a2 100644
--- a/src/com/android/telecomm/CallServiceSelectorWrapper.java
+++ b/src/com/android/telecomm/CallServiceSelectorWrapper.java
@@ -32,7 +32,9 @@
 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
@@ -52,15 +54,17 @@
                     case MSG_SET_SELECTED_CALL_SERVICES: {
                         SomeArgs args = (SomeArgs) msg.obj;
                         try {
-                            Call call = mCallIdMapper.getCall(args.arg1);
-                            List<CallServiceDescriptor> descriptors =
-                                    (List<CallServiceDescriptor>) args.arg2;
-                            if (call != null) {
-                                mOutgoingCallsManager.processSelectedCallServices(call,
-                                        descriptors);
+                            String callId = (String) args.arg1;
+                            if (mPendingSelects.containsKey(callId)) {
+                                @SuppressWarnings("unchecked")
+                                List<CallServiceDescriptor> descriptors =
+                                        (List<CallServiceDescriptor>) args.arg2;
+
+                                mCallIdMapper.removeCall(callId);
+                                mPendingSelects.remove(callId).onResult(descriptors);
                             } else {
                                 Log.w(this, "setSelectedCallServices: unknown call: %s, id: %s",
-                                        call, args.arg1);
+                                        callId, args.arg1);
                             }
                         } finally {
                             args.recycle();
@@ -70,7 +74,7 @@
                     case MSG_CANCEL_OUTGOING_CALL: {
                         Call call = mCallIdMapper.getCall(msg.obj);
                         if (call != null) {
-                            mOutgoingCallsManager.abort(call);
+                            call.abort();
                         } else {
                             Log.w(this, "cancelOutgoingCall: unknown call: %s, id: %s", call,
                                     msg.obj);
@@ -128,9 +132,9 @@
     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 OutgoingCallsManager mOutgoingCallsManager;
+    private final Map<String, AsyncResultCallback<List<CallServiceDescriptor>>> mPendingSelects =
+            new HashMap<>();
 
     private ICallServiceSelector mSelectorInterface;
 
@@ -141,17 +145,12 @@
      * @param action The action used to bind to the selector.
      * @param componentName The component name of the service.
      * @param callsManager The calls manager.
-     * @param outgoingCallsManager The outgoing calls manager.
      */
     CallServiceSelectorWrapper(
-            String action,
-            ComponentName componentName,
-            CallsManager callsManager,
-            OutgoingCallsManager outgoingCallsManager) {
+            String action, ComponentName componentName, CallsManager callsManager) {
 
         super(action, componentName);
         mCallsManager = callsManager;
-        mOutgoingCallsManager = outgoingCallsManager;
     }
 
     /**
@@ -160,17 +159,9 @@
      *
      * @param componentName The component name of the service.
      * @param callsManager The calls manager.
-     * @param outgoingCallsManager The outgoing calls manager.
      */
-    CallServiceSelectorWrapper(
-            ComponentName componentName,
-            CallsManager callsManager,
-            OutgoingCallsManager outgoingCallsManager) {
-
-        this(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR,
-                componentName,
-                callsManager,
-                outgoingCallsManager);
+    CallServiceSelectorWrapper(ComponentName componentName, CallsManager callsManager) {
+        this(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR, componentName, callsManager);
     }
 
     /**
@@ -180,25 +171,31 @@
      * @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 errorCallback The callback to invoke upon failure.
+     * @param resultCallback The callback on which to return the result.
      */
-    void select(final Call call, final List<CallServiceDescriptor> descriptors,
-            final Runnable errorCallback) {
+    void select(
+            final Call call,
+            final List<CallServiceDescriptor> descriptors,
+            final AsyncResultCallback<List<CallServiceDescriptor>> resultCallback) {
+
         BindCallback callback = new BindCallback() {
             @Override
             public void onSuccess() {
-                if (isServiceValid("select")) {
-                    try {
-                        CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
-                        mSelectorInterface.select(callInfo, descriptors);
-                    } catch (RemoteException e) {
-                    }
+                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);
                 }
             }
 
             @Override
             public void onFailure() {
-                errorCallback.run();
+                resultCallback.onResult(null);
             }
         };
 
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index a4e3d24..4040e33 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -36,6 +36,8 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -46,7 +48,6 @@
 final class CallServiceWrapper extends ServiceBinder<ICallService> {
 
     private final class Adapter extends ICallServiceAdapter.Stub {
-        private static final int MSG_SET_IS_COMPATIBLE_WITH = 0;
         private static final int MSG_NOTIFY_INCOMING_CALL = 1;
         private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
         private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
@@ -61,20 +62,11 @@
             public void handleMessage(Message msg) {
                 Call call;
                 switch (msg.what) {
-                    case MSG_SET_IS_COMPATIBLE_WITH:
-                        call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null && !call.isIncoming()) {
-                            mOutgoingCallsManager.setIsCompatibleWith(call,
-                                    msg.arg1 == 1 ? true : false);
-                        } else {
-                            Log.w(this, "setIsCompatibleWith, unknown call: %s, id: %s", call,
-                                    msg.obj);
-                        }
-                        break;
                     case MSG_NOTIFY_INCOMING_CALL:
                         CallInfo clientCallInfo = (CallInfo) msg.obj;
                         call = mCallIdMapper.getCall(clientCallInfo.getId());
-                        if (call != null && mPendingCalls.remove(call) && call.isIncoming()) {
+                        if (call != null && mPendingIncomingCalls.remove(call) &&
+                                call.isIncoming()) {
                             CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
                                     clientCallInfo.getHandle());
                             mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
@@ -84,28 +76,27 @@
                                     clientCallInfo.getId());
                         }
                         break;
-                    case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL:
-                        call = mCallIdMapper.getCall(msg.obj);
-                        if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
-                            mOutgoingCallsManager.handleSuccessfulCallAttempt(call);
+                    case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
+                        String callId = (String) msg.obj;
+                        if (mPendingOutgoingCalls.containsKey(callId)) {
+                            mPendingOutgoingCalls.remove(callId).onResult(true);
                         } else {
-                            // TODO(gilad): Figure out how to wire up the callService.abort() call.
-                            Log.w(this,
-                                    "handleSuccessfulOutgoingCall, unknown call: %s, id: %s",
-                                    call, msg.obj);
+                            Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
                         }
                         break;
+                    }
                     case MSG_HANDLE_FAILED_OUTGOING_CALL: {
                         SomeArgs args = (SomeArgs) msg.obj;
                         try {
-                            call = mCallIdMapper.getCall(args.arg1);
+                            String callId = (String) args.arg1;
                             String reason = (String) args.arg2;
-                            if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
-                                mOutgoingCallsManager.handleFailedCallAttempt(call, reason);
+                            // TODO(santoscordon): Do something with 'reason' or get rid of it.
+
+                            if (mPendingOutgoingCalls.containsKey(callId)) {
+                                mPendingOutgoingCalls.remove(callId).onResult(false);
+                                mCallIdMapper.removeCall(callId);
                             } else {
-                                Log.w(this,
-                                        "handleFailedOutgoingCall, unknown call: %s, id: %s",
-                                        call, args.arg1);
+                                Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
                             }
                         } finally {
                             args.recycle();
@@ -168,10 +159,7 @@
         /** {@inheritDoc} */
         @Override
         public void setIsCompatibleWith(String callId, boolean isCompatible) {
-            Log.v(this, "setIsCompatibleWith id: %s, isCompatible: %b", callId, isCompatible);
-            mCallIdMapper.checkValidCallId(callId);
-            mHandler.obtainMessage(MSG_SET_IS_COMPATIBLE_WITH, isCompatible ? 1 : 0, 0, callId).
-                    sendToTarget();
+            Log.wtf(this, "Not expected.");
         }
 
         /** {@inheritDoc} */
@@ -184,6 +172,7 @@
         /** {@inheritDoc} */
         @Override
         public void handleSuccessfulOutgoingCall(String callId) {
+            Log.d(this, "handleSuccessfulOutgoingCall %s", callId);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
         }
@@ -192,6 +181,7 @@
         @Override
         public void handleFailedOutgoingCall(String callId, String reason) {
             mCallIdMapper.checkValidCallId(callId);
+            Log.d(this, "handleFailedOutgoingCall %d", callId);
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = callId;
             args.arg2 = reason;
@@ -241,11 +231,11 @@
 
     private final Adapter mAdapter = new Adapter();
     private final CallsManager mCallsManager = CallsManager.getInstance();
-    private final Set<Call> mPendingCalls = Sets.newHashSet();
+    private final Set<Call> mPendingIncomingCalls = Sets.newHashSet();
     private final CallServiceDescriptor mDescriptor;
     private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
-    private final OutgoingCallsManager mOutgoingCallsManager;
     private final IncomingCallsManager mIncomingCallsManager;
+    private final Map<String, AsyncResultCallback<Boolean>> mPendingOutgoingCalls = new HashMap<>();
 
     private Binder mBinder = new Binder();
     private ICallService mServiceInterface;
@@ -255,17 +245,14 @@
      *
      * @param descriptor The call-service descriptor from
      *            {@link ICallServiceProvider#lookupCallServices}.
-     * @param outgoingCallsManager Manages the placing of outgoing calls.
      * @param incomingCallsManager Manages the incoming call initialization flow.
      */
     CallServiceWrapper(
             CallServiceDescriptor descriptor,
-            OutgoingCallsManager outgoingCallsManager,
             IncomingCallsManager incomingCallsManager) {
         super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
         mDescriptor = descriptor;
         mIncomingCallsManager = incomingCallsManager;
-        mOutgoingCallsManager = outgoingCallsManager;
     }
 
     CallServiceDescriptor getDescriptor() {
@@ -283,60 +270,48 @@
     }
 
     /**
-     * Checks whether or not the specified call is compatible with this call-service implementation,
-     * see {@link ICallService#isCompatibleWith}. Upon failure, the specified error callback is
-     * invoked. Can be invoked even when the call service is unbound.
-     *
-     * @param errorCallback The callback to invoke upon failure.
+     * Attempts to place the specified call, see {@link ICallService#call}. Returns the result
+     * asynchronously through the specified callback.
      */
-    void isCompatibleWith(final Call call, final Runnable errorCallback) {
-        Log.d(this, "isCompatibleWith(%s) via %s.", call, getComponentName());
+    void call(final Call call, final AsyncResultCallback<Boolean> resultCallback) {
+        Log.d(this, "call(%s) via %s.", call, getComponentName());
         BindCallback callback = new BindCallback() {
             @Override
             public void onSuccess() {
-                if (isServiceValid("isCompatibleWith")) {
-                    try {
-                        mPendingCalls.add(call);
-                        CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
-                        mServiceInterface.isCompatibleWith(callInfo);
-                    } catch (RemoteException e) {
-                    }
+                String callId = mCallIdMapper.getCallId(call);
+                mPendingOutgoingCalls.put(callId, resultCallback);
+
+                try {
+                    CallInfo callInfo = call.toCallInfo(callId);
+                    mServiceInterface.call(callInfo);
+                } catch (RemoteException e) {
+                    mPendingOutgoingCalls.remove(callId).onResult(false);
                 }
             }
 
             @Override
             public void onFailure() {
-                errorCallback.run();
+                resultCallback.onResult(false);
             }
         };
 
         mBinder.bind(callback);
     }
 
-    /**
-     * Attempts to place the specified call, see {@link ICallService#call}. Upon failure, the
-     * specified error callback is invoked. Can be invoked even when the call service is unbound.
-     */
-    void call(Call call) {
-        Log.d(this, "call(%s) via %s.", call, getComponentName());
-        if (isServiceValid("call")) {
-            try {
-                CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
-                mServiceInterface.call(callInfo);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
     /** @see CallService#abort(String) */
     void abort(Call call) {
-        mPendingCalls.remove(call);
+        // Clear out any pending outgoing call data
+        String callId = mCallIdMapper.getCallId(call);
+
+        // If still bound, tell the call service to abort.
         if (isServiceValid("abort")) {
             try {
-                mServiceInterface.abort(mCallIdMapper.getCallId(call));
+                mServiceInterface.abort(callId);
             } catch (RemoteException e) {
             }
         }
+
+        removeCall(call);
     }
 
     /** @see CallService#hold(String) */
@@ -386,7 +361,7 @@
             @Override
             public void onSuccess() {
                 if (isServiceValid("setIncomingCallId")) {
-                    mPendingCalls.add(call);
+                    mPendingIncomingCalls.add(call);
                     try {
                         mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
                                 extras);
@@ -467,7 +442,14 @@
     }
 
     void removeCall(Call call) {
-        mPendingCalls.remove(call);
+        mPendingIncomingCalls.remove(call);
+
+        AsyncResultCallback<Boolean> outgoingResultCallback =
+            mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
+        if (outgoingResultCallback != null) {
+            outgoingResultCallback.onResult(false);
+        }
+
         mCallIdMapper.removeCall(call);
     }
 
@@ -492,22 +474,27 @@
      * Called when the associated call service dies.
      */
     private void handleCallServiceDeath() {
-        if (!mPendingCalls.isEmpty()) {
+        if (!mPendingOutgoingCalls.isEmpty()) {
+            for (AsyncResultCallback<Boolean> callback : mPendingOutgoingCalls.values()) {
+                callback.onResult(false);
+            }
+            mPendingOutgoingCalls.clear();
+        }
+
+        if (!mPendingIncomingCalls.isEmpty()) {
             // Iterate through a copy because the code inside the loop will modify the original
             // list.
-            for (Call call : ImmutableList.copyOf(mPendingCalls)) {
-                if (call.isIncoming()) {
-                    mIncomingCallsManager.handleFailedIncomingCall(call);
-                } else {
-                    mOutgoingCallsManager.handleFailedCallAttempt(call,
-                            "Call service disconnected.");
-                }
+            for (Call call : ImmutableList.copyOf(mPendingIncomingCalls)) {
+                Preconditions.checkState(call.isIncoming());
+                mIncomingCallsManager.handleFailedIncomingCall(call);
             }
 
-            if (!mPendingCalls.isEmpty()) {
+            if (!mPendingIncomingCalls.isEmpty()) {
                 Log.wtf(this, "Pending calls did not get cleared.");
-                mPendingCalls.clear();
+                mPendingIncomingCalls.clear();
             }
         }
+
+        mCallIdMapper.clear();
     }
 }
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 85b9340..a4b2086 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -311,6 +311,8 @@
      * the user hitting the end-call button.
      */
     void disconnectCall(Call call) {
+        Log.v(this, "disconnectCall %s", call);
+
         if (!mCalls.contains(call)) {
             Log.w(this, "Unknown call (%s) asked to disconnect", call);
         } else {
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index 3874bd5..0f77567 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -16,12 +16,17 @@
 
 package com.android.telecomm;
 
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.Message;
 import android.telecomm.CallServiceDescriptor;
 
+import com.android.telecomm.BaseRepository.LookupCallback;
 import com.google.android.collect.Sets;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -44,17 +49,14 @@
  */
 final class OutgoingCallProcessor {
 
+    private final static int MSG_EXPIRE = 1;
+
     /**
      * The outgoing call this processor is tasked with placing.
      */
     private final Call mCall;
 
     /**
-     * The duplicate-free list of currently-available call-service descriptors.
-     */
-    private final List<CallServiceDescriptor> mCallServiceDescriptors = Lists.newArrayList();
-
-    /**
      * The map of currently-available call-service implementations keyed by call-service ID.
      */
     private final Map<String, CallServiceWrapper> mCallServicesById = Maps.newHashMap();
@@ -65,38 +67,40 @@
      */
     private final Set<CallServiceWrapper> mAttemptedCallServices = Sets.newHashSet();
 
-    /**
-     * The set of incompatible call services, used to suppress unnecessary call switching attempts.
-     */
-    private final Set<CallServiceWrapper> mIncompatibleCallServices = Sets.newHashSet();
+    private final CallServiceRepository mCallServiceRepository;
 
-    /**
-     * The list of currently-available call-service selector implementations.
-     */
-    private final Collection<CallServiceSelectorWrapper> mSelectors;
+    private final CallServiceSelectorRepository mSelectorRepository;
 
-    /** Manages all outgoing call processors. */
-    private final OutgoingCallsManager mOutgoingCallsManager;
-
-    private final Runnable mNextCallServiceCallback = new Runnable() {
-        @Override public void run() {
-            attemptNextCallService();
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_EXPIRE:
+                    abort();
+                    break;
+            }
         }
     };
 
-    private final Runnable mNextSelectorCallback = new Runnable() {
-        @Override public void run() {
-            attemptNextSelector();
-        }
-    };
+    /**
+     * The duplicate-free list of currently-available call-service descriptors.
+     */
+    private List<CallServiceDescriptor> mCallServiceDescriptors;
 
     /**
      * The iterator over the currently-selected ordered list of call-service descriptors.
      */
     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;
 
     /**
@@ -107,29 +111,22 @@
      * in turn call the abort method of this processor via {@link OutgoingCallsManager}.
      *
      * @param call The call to place.
-     * @param callServices The available call-service implementations.
-     * @param selectors The available call-service selector implementations.
-     * @param outgoingCallsManager Manager of all outgoing call processors.
+     * @param callServiceRepository
+     * @param selectorRepository
+     * @param resultCallback The callback on which to return the result.
      */
     OutgoingCallProcessor(
             Call call,
-            Collection<CallServiceWrapper> callServices,
-            Collection<CallServiceSelectorWrapper> selectors,
-            OutgoingCallsManager outgoingCallsManager) {
+            CallServiceRepository callServiceRepository,
+            CallServiceSelectorRepository selectorRepository,
+            AsyncResultCallback<Boolean> resultCallback) {
 
         ThreadUtil.checkOnMainThread();
 
         mCall = call;
-        mSelectors = selectors;
-        mOutgoingCallsManager = outgoingCallsManager;
-
-        // Populate the list and map of call-service descriptors.  The list is needed since
-        // it's being passed down to selectors.
-        for (CallServiceWrapper callService : callServices) {
-            CallServiceDescriptor descriptor = callService.getDescriptor();
-            mCallServiceDescriptors.add(descriptor);
-            mCallServicesById.put(descriptor.getCallServiceId(), callService);
-        }
+        mResultCallback = resultCallback;
+        mCallServiceRepository = callServiceRepository;
+        mSelectorRepository = selectorRepository;
     }
 
     /**
@@ -138,42 +135,30 @@
     void process() {
         Log.v(this, "process, mIsAborted: %b", mIsAborted);
         if (!mIsAborted) {
-            // Only process un-aborted calls.
-            ThreadUtil.checkOnMainThread();
+            // Start the expiration timeout.
+            mHandler.sendEmptyMessageDelayed(MSG_EXPIRE, Timeouts.getNewOutgoingCallMillis());
 
-            if (mSelectorIterator == null) {
-                mSelectorIterator = mSelectors.iterator();
-                attemptNextSelector();
-            }
-        }
-    }
-
-    /**
-     * Handles the specified compatibility status from the call-service implementation.
-     * TODO(gilad): Consider making this class stateful, potentially rejecting out-of-order/
-     * unexpected invocations (i.e. beyond checking for unexpected call IDs).
-     *
-     * @param isCompatible True if the call-service is compatible with the corresponding call and
-     *     false otherwise.
-     */
-    void setIsCompatibleWith(Call call, boolean isCompatible) {
-        Log.v(this, "setIsCompatibleWith, call: %s, isCompatible: %b", call, isCompatible);
-        if (call != mCall) {
-            Log.wtf(this, "setIsCompatibleWith invoked with unexpected call: %s, expected call: %s",
-                    call, mCall);
-            return;
-        }
-
-        if (!mIsAborted) {
-            CallServiceWrapper callService = mCall.getCallService();
-            if (callService != null) {
-                if (isCompatible) {
-                    callService.call(mCall);
-                    return;
+            // Lookup call services
+            mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
+                @Override
+                public void onComplete(Collection<CallServiceWrapper> services) {
+                    setCallServices(services);
                 }
-                mIncompatibleCallServices.add(callService);
+            });
+
+            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()));
             }
-            attemptNextCallService();
         }
     }
 
@@ -184,31 +169,43 @@
     void abort() {
         Log.v(this, "abort");
         ThreadUtil.checkOnMainThread();
-        if (!mIsAborted) {
+        if (!mIsAborted && mResultCallback != null) {
             mIsAborted = true;
-            // This will also clear the call's call service and selector.
-            mOutgoingCallsManager.handleFailedOutgoingCall(mCall, true /* isAborted */);
+
+            // On an abort, we need to check if we already told the call service to place the
+            // call. If so, we need to tell it to abort.
+            // TODO(santoscordon): The call service is saved with the call and so we have to query
+            // the call to get it, which is a bit backwards.  Ideally, the call service would be
+            // saved inside this class until the whole thing is complete and then set on the call.
+            CallServiceWrapper callService = mCall.getCallService();
+            if (callService != null) {
+                callService.abort(mCall);
+            }
+
+            sendResult(false);
         }
     }
 
+    boolean isAborted() {
+        return mIsAborted;
+    }
+
     /**
      * Completes the outgoing call sequence by setting the call service on the call object. This is
      * invoked when the call service adapter receives positive confirmation that the call service
      * placed the call.
      */
-    void handleSuccessfulCallAttempt() {
+    void handleSuccessfulCallAttempt(CallServiceWrapper callService) {
         Log.v(this, "handleSuccessfulCallAttempt");
         ThreadUtil.checkOnMainThread();
 
         if (mIsAborted) {
             // TODO(gilad): Ask the call service to drop the call?
+            callService.abort(mCall);
             return;
         }
 
-        for (CallServiceWrapper callService : mIncompatibleCallServices) {
-            mCall.addIncompatibleCallService(callService);
-        }
-        mCall.handleSuccessfulOutgoing();
+        sendResult(true);
     }
 
     /**
@@ -243,6 +240,78 @@
     }
 
     /**
+     * Sets the call services to attempt for this outgoing call.
+     *
+     * @param callServices The call services.
+     */
+    private void setCallServices(Collection<CallServiceWrapper> callServices) {
+        mCallServiceDescriptors = new ArrayList<>();
+
+        // Populate the list and map of call-service descriptors.  The list is needed since
+        // it's being passed down to selectors.
+        for (CallServiceWrapper callService : callServices) {
+            CallServiceDescriptor descriptor = callService.getDescriptor();
+            mCallServiceDescriptors.add(descriptor);
+            mCallServicesById.put(descriptor.getCallServiceId(), callService);
+        }
+
+        onLookupComplete();
+    }
+
+    /**
+     * 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.
      */
@@ -255,11 +324,17 @@
         if (mSelectorIterator.hasNext()) {
             CallServiceSelectorWrapper selector = mSelectorIterator.next();
             mCall.setCallServiceSelector(selector);
-            selector.select(mCall, mCallServiceDescriptors, mNextSelectorCallback);
+            selector.select(mCall, mCallServiceDescriptors,
+                    new AsyncResultCallback<List<CallServiceDescriptor>>() {
+                        @Override
+                        public void onResult(List<CallServiceDescriptor> descriptors) {
+                            processSelectedCallServices(descriptors);
+                        }
+                    });
         } else {
             Log.v(this, "attemptNextSelector, no more selectors, failing");
             mCall.clearCallServiceSelector();
-            mOutgoingCallsManager.handleFailedOutgoingCall(mCall, false /* isAborted */);
+            sendResult(false);
         }
     }
 
@@ -287,7 +362,25 @@
             } else {
                 mAttemptedCallServices.add(callService);
                 mCall.setCallService(callService);
-                callService.isCompatibleWith(mCall, mNextCallServiceCallback);
+
+                // Increment the associated call count until we get a result. This prevents the call
+                // service from unbinding while we are using it.
+                callService.incrementAssociatedCallCount();
+
+                callService.call(mCall, new AsyncResultCallback<Boolean>() {
+                    @Override
+                    public void onResult(Boolean wasCallPlaced) {
+                        if (wasCallPlaced) {
+                            handleSuccessfulCallAttempt(callService);
+                        } else {
+                            handleFailedCallAttempt("call failed.");
+                        }
+
+                        // If successful, the call should not have it's own association to keep
+                        // the call service bound.
+                        callService.decrementAssociatedCallCount();
+                    }
+                });
             }
         } else {
             mCallServiceDescriptorIterator = null;
@@ -295,4 +388,15 @@
             attemptNextSelector();
         }
     }
+
+    private void sendResult(boolean wasCallPlaced) {
+        if (mResultCallback != null) {
+            mResultCallback.onResult(wasCallPlaced);
+            mResultCallback = null;
+
+            mHandler.removeMessages(MSG_EXPIRE);
+        } else {
+            Log.wtf(this, "Attempting to return outgoing result twice for call %s", mCall);
+        }
+    }
 }
diff --git a/src/com/android/telecomm/OutgoingCallsManager.java b/src/com/android/telecomm/OutgoingCallsManager.java
deleted file mode 100644
index 05bdad0..0000000
--- a/src/com/android/telecomm/OutgoingCallsManager.java
+++ /dev/null
@@ -1,172 +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.telecomm.CallServiceDescriptor;
-
-import com.android.internal.telecomm.ICallServiceSelector;
-import com.google.common.collect.Maps;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Responsible for placing all outgoing calls. For each outgoing call, this class creates an
- * instance of {@link OutgoingCallProcessor} which handles the details of connecting to the
- * appropriate call service and placing the call. This class maintains a mapping from call
- * to {@link OutgoingCallProcessor} so that other classes (CallServiceAdapter, etc),
- * can simply call into this class instead of individual OutgoingCallProcessors.
- */
-final class OutgoingCallsManager {
-
-    /**
-     * Maps call to {@link OutgoingCallProcessor}s.
-     */
-    private Map<Call, OutgoingCallProcessor> mOutgoingCallProcessors = Maps.newHashMap();
-
-    /**
-     * Starts the process of placing a call by constructing an outgoing call processor and asking
-     * it to place the call. Upon success, execution will continue (via {@link CallServiceAdapter})
-     * to {@link #handleSuccessfulCallAttempt}. Upon failure, execution will return to
-     * {@link #handleFailedCallAttempt}.
-     *
-     * @param call The call to place.
-     * @param callServices The collection of call services which can potentially place the call.
-     * @param selectors The ordered list of selectors used in placing the call.
-     */
-    void placeCall(
-            Call call,
-            Collection<CallServiceWrapper> callServices,
-            Collection<CallServiceSelectorWrapper> selectors) {
-
-        Log.i(this, "Placing an outgoing call: %s", call);
-
-        // Create the processor for this (outgoing) call and store it in a map such that call
-        // attempts can be aborted etc.
-        // TODO(gilad): Consider passing mSelector as an immutable set.
-        OutgoingCallProcessor processor =
-                new OutgoingCallProcessor(call, callServices, selectors, this);
-
-        mOutgoingCallProcessors.put(call, processor);
-        processor.process();
-    }
-
-    /**
-     * Forwards the compatibility status from the call-service to the corresponding outgoing-call
-     * processor.
-     *
-     * @param isCompatible True if the call-service is compatible with the call.
-     */
-    void setIsCompatibleWith(Call call, boolean isCompatible) {
-        Log.v(this, "setIsCompatibleWith, call %s, isCompatible: %b", call, isCompatible);
-        OutgoingCallProcessor processor = mOutgoingCallProcessors.get(call);
-        if (processor == null) {
-            // Shouldn't happen, so log a wtf if it does.
-            Log.wtf(this, "Received unexpected setCompatibleWith notification.");
-        } else {
-            processor.setIsCompatibleWith(call, isCompatible);
-        }
-    }
-
-    /**
-     * Removes the outgoing call processor mapping for the successful call and returns execution to
-     * the call. This method is invoked from {@link CallServiceAdapter} after a call service
-     * has notified Telecomm that it successfully placed the call.
-     */
-    void handleSuccessfulCallAttempt(Call call) {
-        Log.v(this, "handleSuccessfulCallAttempt, call: %s", call);
-        OutgoingCallProcessor processor = mOutgoingCallProcessors.remove(call);
-
-        if (processor == null) {
-            // Shouldn't happen, so log a wtf if it does.
-            Log.wtf(this, "Received an unexpected placed-call notification.");
-        } else {
-            processor.handleSuccessfulCallAttempt();
-        }
-    }
-
-    /**
-     * Notifies the appropriate outgoing call processor that a call attempt to place the call has
-     * failed and the processor should continue attempting to place the call with the next call
-     * service. This method is called from {@link CallServiceAdapter} after a call service has
-     * notified Telecomm that it could not place the call.
-     *
-     * @param reason The call-service supplied reason for the failed call attempt.
-     */
-    void handleFailedCallAttempt(Call call, String reason) {
-        Log.v(this, "handleFailedCallAttempt, call: %s, reason: %s", call, reason);
-        OutgoingCallProcessor processor = mOutgoingCallProcessors.get(call);
-
-        if (processor == null) {
-            // Shouldn't happen, so log a wtf if it does.
-            Log.wtf(this, "Received an unexpected failed-call notification.");
-        } else {
-            processor.handleFailedCallAttempt(reason);
-        }
-    }
-
-    /**
-     * Removes the outgoing call processor mapping for the failed call and returns execution to the
-     * call. In contrast to handleFailedCallAttempt which comes from the call-service and
-     * goes to the outgoing-call processor indicating a single failed call attempt, this method is
-     * invoked by the outgoing-call processor to indicate that the entire process has failed and we
-     * should cleanup and notify the call.
-     *
-     * @param call The failed outgoing call.
-     * @param isAborted True if the call timedout and is aborted.
-     */
-    void handleFailedOutgoingCall(Call call, boolean isAborted) {
-        Log.v(this, "handleFailedOutgoingCall, call: %s", call);
-        mOutgoingCallProcessors.remove(call);
-        call.handleFailedOutgoing(isAborted);
-    }
-
-    /**
-     * Forwards the selected call service from the selector to the corresponding outgoing-call
-     * processor.
-     */
-    void processSelectedCallServices(Call call, List<CallServiceDescriptor> descriptors) {
-        Log.v(this, "processSelectedCallServices, call %s,  descriptors: %s", call, descriptors);
-        OutgoingCallProcessor processor = mOutgoingCallProcessors.get(call);
-        if (processor == null) {
-            // Shouldn't happen, so log a wtf if it does.
-            Log.wtf(this, "Received unexpected setSelectedCallServices notification.");
-        } else {
-            processor.processSelectedCallServices(descriptors);
-        }
-    }
-
-    /**
-     * Aborts any ongoing attempts to connect the specified (outgoing) call.
-     *
-     * @param call The call to be aborted.
-     * @return False if the call was not found; True otherwise, indicating that the abort was
-     *         successful.
-     */
-    boolean abort(Call call) {
-        OutgoingCallProcessor processor = mOutgoingCallProcessors.remove(call);
-        if (processor != null) {
-            Log.v(this, "abort, call: %s", call);
-            processor.abort();
-            return true;
-        }
-
-        return false;
-    }
-}
diff --git a/src/com/android/telecomm/ServiceBinder.java b/src/com/android/telecomm/ServiceBinder.java
index ed84bcf..55e39f0 100644
--- a/src/com/android/telecomm/ServiceBinder.java
+++ b/src/com/android/telecomm/ServiceBinder.java
@@ -219,7 +219,7 @@
 
     final boolean isServiceValid(String actionName) {
         if (mBinder == null) {
-            Log.wtf(this, "%s invoked while service is unbound", actionName);
+            Log.w(this, "%s invoked while service is unbound", actionName);
             return false;
         }
 
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 5b8d25d..834bf44 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -37,89 +37,10 @@
  * Switchboard is responsible for:
  * - gathering the {@link CallServiceWrapper}s and {@link CallServiceSelectorWrapper}s through
  *       which to place outgoing calls
- * - starting outgoing calls (via {@link OutgoingCallsManager}
  */
 final class Switchboard {
-    /**
-     * Encapsulates a request to place an outgoing call.
-     * TODO(santoscordon): Move this state into Call and remove this class.
-     */
-    private final class OutgoingCallEntry {
-        final Call call;
-
-        private Collection<CallServiceWrapper> mCallServices;
-        private Collection<CallServiceSelectorWrapper> mSelectors;
-        private boolean mIsCallPending = true;
-
-        OutgoingCallEntry(Call call) {
-            this.call = call;
-        }
-
-        /**
-         * Sets the call services to attempt for this outgoing call.
-         *
-         * @param callServices The call services.
-         */
-        void setCallServices(Collection<CallServiceWrapper> callServices) {
-            mCallServices = callServices;
-            onLookupComplete();
-        }
-
-        Collection<CallServiceWrapper> getCallServices() {
-            return mCallServices;
-        }
-
-        /**
-         * Sets the selectors to attemnpt for this outgoing call.
-         *
-         * @param selectors The call-service selectors.
-         */
-        void setSelectors(Collection<CallServiceSelectorWrapper> selectors) {
-            mSelectors = selectors;
-            onLookupComplete();
-        }
-
-        Collection<CallServiceSelectorWrapper> getSelectors() {
-            return mSelectors;
-        }
-
-        /** Expires the pending outgoing call and stops it from being made. */
-        void expire() {
-            // This can be executed in three states:
-            // 1) We are still waiting for the list of CSs (Call Services)
-            // 2) We told outgoing calls manager to place the call using the CSs
-            // 3) Outgoing calls manager already successfully placed the call.
-            if (mIsCallPending) {
-                // Handle state (1), tell the call to clean itself up and shut everything down.
-                mIsCallPending = false;
-                call.handleFailedOutgoing(true /* isAborted */);
-            } else {
-                // Handle states (2) & (3). We can safely call abort() in either case. If the call
-                // is not yet successful, then it will abort.  If the call was already placed, then
-                // outgoing calls manager will do nothing (and return false which we ignore).
-                boolean isAborted = mOutgoingCallsManager.abort(call);
-                Log.v(this, "expire() caused abort: %b", isAborted);
-            }
-        }
-
-        /** Initiates processing of the call once call-services and selectors are set. */
-        private void onLookupComplete() {
-            if (mIsCallPending) {
-                if (mSelectors != null && mCallServices != null) {
-                    mIsCallPending = false;
-                    processNewOutgoingCall(this);
-                }
-            }
-        }
-    }
-
-    private final static int MSG_EXPIRE_STALE_CALL = 1;
-
     private final static Switchboard sInstance = new Switchboard();
 
-    /** Used to place outgoing calls. */
-    private final OutgoingCallsManager mOutgoingCallsManager;
-
     /** Used to retrieve incoming call details. */
     private final IncomingCallsManager mIncomingCallsManager;
 
@@ -127,20 +48,6 @@
 
     private final CallServiceSelectorRepository mSelectorRepository;
 
-    /** Used to schedule tasks on the main (UI) thread. */
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case MSG_EXPIRE_STALE_CALL:
-                    ((OutgoingCallEntry) msg.obj).expire();
-                    break;
-                default:
-                    Log.wtf(Switchboard.this, "Unexpected message %d.", msg.what);
-            }
-        }
-    };
-
     /** Singleton accessor. */
     static Switchboard getInstance() {
         return sInstance;
@@ -152,41 +59,18 @@
     private Switchboard() {
         ThreadUtil.checkOnMainThread();
 
-        mOutgoingCallsManager = new OutgoingCallsManager();
         mIncomingCallsManager = new IncomingCallsManager();
-        mSelectorRepository = new CallServiceSelectorRepository(mOutgoingCallsManager);
+        mSelectorRepository = new CallServiceSelectorRepository();
         mCallServiceRepository =
-                new CallServiceRepository(mOutgoingCallsManager, mIncomingCallsManager);
+                new CallServiceRepository(mIncomingCallsManager);
     }
 
-    /**
-     * Starts the process of placing an outgoing call by searching for available call services
-     * through which the call can be placed. After a lookup for those services completes, execution
-     * returns to {@link #setCallServices} where the process of placing the call continues.
-     *
-     * @param call The yet-to-be-connected outgoing-call object.
-     */
-    void placeOutgoingCall(Call call) {
-        final OutgoingCallEntry callEntry = new OutgoingCallEntry(call);
+    CallServiceRepository getCallServiceRepository() {
+        return mCallServiceRepository;
+    }
 
-        // Lookup call services
-        mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
-            @Override
-            public void onComplete(Collection<CallServiceWrapper> services) {
-                callEntry.setCallServices(services);
-            }
-        });
-
-        // Lookup selectors
-        mSelectorRepository.lookupServices(new LookupCallback<CallServiceSelectorWrapper>() {
-            @Override
-            public void onComplete(Collection<CallServiceSelectorWrapper> selectors) {
-                callEntry.setSelectors(selectors);
-            }
-        });
-
-        Message msg = mHandler.obtainMessage(MSG_EXPIRE_STALE_CALL, callEntry);
-        mHandler.sendMessageDelayed(msg, Timeouts.getNewOutgoingCallMillis());
+    CallServiceSelectorRepository getSelectorRepository() {
+        return mSelectorRepository;
     }
 
     /**
@@ -203,57 +87,4 @@
         call.setCallService(callService);
         mIncomingCallsManager.retrieveIncomingCall(call, extras);
     }
-
-    /**
-     * Ensures any state regarding a call is cleaned up.
-     *
-     * @param call The call.
-     */
-    void abortCall(Call call) {
-        Log.d(this, "abortCall");
-        mOutgoingCallsManager.abort(call);
-    }
-
-    /**
-     * Attempts to place the specified call.
-     *
-     * @param callEntry The call entry to place.
-     */
-    private void processNewOutgoingCall(OutgoingCallEntry callEntry) {
-        Collection<CallServiceSelectorWrapper> selectors;
-        Call call = callEntry.call;
-
-        // Use the call's selector if it's already tied to one. This is the case for handoff calls.
-        if (call.getCallServiceSelector() != null) {
-            selectors = ImmutableList.of(call.getCallServiceSelector());
-        } else {
-            selectors = callEntry.getSelectors();
-        }
-
-        boolean useEmergencySelector =
-                EmergencyCallServiceSelector.shouldUseSelector(call.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(),
-                            mOutgoingCallsManager);
-
-            selectorsBuilder.add(emergencySelector);
-            selectorsBuilder.addAll(selectors);
-            selectors = selectorsBuilder.build();
-        }
-
-        mOutgoingCallsManager.placeCall(call, callEntry.getCallServices(), selectors);
-    }
 }