Simplify Respositories, Switchboard and Switchboard-indirection.

This is a step into separating Call into Call + Connection.

Changes:
1. Update Repositories to:
  A. Share code via the new BaseRepository
  B. Perform a lookup per call instead of attempting to have 1 lookup
     work for concurrent calls. This allowed removal of extra state
     out of the repositories (mIsLookupInProgress) and out of
     Switchboard (mNewOutgoingCalls, mPendingOutgoingCalls, etc).
2. Add a OutgoingCallEntry class to Switchboard to support 1 service
   lookup per outgoing call. The new class maintains the necessary
   state (CS collection & selector collection).
3. Outgoing/IncomingCallsManager now reports success/failure directly
   to the Call class instead of indirecting through the switchboard.
4. Switchboard, for the time being, kept the outgoing call timeout and
   triggers it through OutgoingCallEntry.

Change-Id: I01196dd5384ad256cf09035018a76abaadb2c04d
diff --git a/src/com/android/telecomm/BaseRepository.java b/src/com/android/telecomm/BaseRepository.java
new file mode 100644
index 0000000..4b913ee
--- /dev/null
+++ b/src/com/android/telecomm/BaseRepository.java
@@ -0,0 +1,94 @@
+/*
+ * 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;
+
+import android.content.ComponentName;
+
+import com.google.common.collect.Maps;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Looks up, caches and returns binder services. Ensures that there is only one instance of a
+ * service per component.
+ */
+abstract class BaseRepository<ServiceClass extends ServiceBinder<?>>
+        implements ServiceBinder.Listener<ServiceClass> {
+
+    /**
+     * Callback interface for notifying when a lookup has completed.
+     */
+    interface LookupCallback<ServiceClass> {
+        void onComplete(Collection<ServiceClass> services);
+    }
+
+    /** Map of cached services. */
+    private final Map<ComponentName, ServiceClass> mServiceCache = Maps.newHashMap();
+
+    /**
+     * Removes the specified service from the cache when the service unbinds.
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    public void onUnbind(ServiceClass service) {
+        mServiceCache.remove(service.getComponentName());
+    }
+
+    /**
+     * Looks up service implementations.
+     *
+     * @param callback The callback on which to return execution when complete.
+     */
+    final void lookupServices(final LookupCallback<ServiceClass> callback) {
+        onLookupServices(callback);
+    }
+
+    /**
+     * Performs the grunt work of the lookup, to be implemented by the subclass.
+     *
+     * @param callback The callback on which to return execution when complete.
+     */
+    protected abstract void onLookupServices(LookupCallback<ServiceClass> callback);
+
+    /**
+     * Creates a new service implementation for the specified component.
+     *
+     * @param componentName The component name for the service.
+     * @param param Sub-class-provided parameter, see {@link #getService}.
+     */
+    protected abstract ServiceClass onCreateNewServiceWrapper(
+            ComponentName componentName, Object param);
+
+    /**
+     * Returns a cached implementation of the service. If no cached version exists, makes a
+     * request to the subclass for a new implementation which will then be cached and returned.
+     *
+     * @param componentName The component name for the service.
+     * @param param Sub-class-provided parameter.
+     */
+    protected final ServiceClass getService(ComponentName componentName, Object param) {
+        ServiceClass service = mServiceCache.get(componentName);
+        if (service == null) {
+            service = onCreateNewServiceWrapper(componentName, param);
+            service.addListener(this);
+            mServiceCache.put(componentName, service);
+        }
+        return service;
+    }
+}
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index fe984cd..d86a8f9 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -394,6 +394,10 @@
     }
 
     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);
@@ -479,7 +483,7 @@
             // objects and remove any multi-class shared state of incoming and outgoing call
             // processing.
             Switchboard.getInstance().abortCall(this);
-        } else {
+        } else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) {
             Preconditions.checkNotNull(mCallService);
 
             Log.i(this, "Send disconnect to call service for call: %s", this);
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index c58a332..0589358 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -22,308 +22,176 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Handler;
-import android.os.Looper;
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
 
 import com.android.internal.telecomm.ICallServiceLookupResponse;
-import com.android.internal.telecomm.ICallServiceProvider;
-import com.google.common.base.Preconditions;
-
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 /**
- * Uses package manager to find all implementations of {@link ICallServiceProvider} and uses them to
- * get the corresponding list of call-service descriptor. Ultimately provides the up-to-date list of
- * call services as {@link CallServiceWrapper}s. The resulting call services may or may not be bound
- * at the time {@link Switchboard#setCallServices} is invoked.
- * TODO(santoscordon): Add performance timing to async calls.
- * TODO(santoscordon): Need to unbind/remove unused call services stored in the cache.
+ * Searches for and returns call services.
  */
-final class CallServiceRepository {
+class CallServiceRepository extends BaseRepository<CallServiceWrapper> {
+    /**
+     * The representation of a single lookup. Maintains lookup state and invokes the "complete"
+     * callback when finished.
+     */
+    private final class CallServiceLookup {
+        final Set<ComponentName> mOutstandingProviders = Sets.newHashSet();
+        final Set<CallServiceWrapper> mServices = Sets.newHashSet();
+        final LookupCallback<CallServiceWrapper> mCallback;
 
-    private final Switchboard mSwitchboard;
+        CallServiceLookup(LookupCallback<CallServiceWrapper> callback) {
+            mCallback = callback;
+        }
+
+        /** Starts the lookup. */
+        void start() {
+            List<ComponentName> providerNames = getProviderNames();
+            if (providerNames.isEmpty()) {
+                finishLookup();
+                return;
+            }
+
+            for (ComponentName name : providerNames) {
+                mOutstandingProviders.add(name);
+                queryProviderForCallServices(name);
+            }
+
+            Log.i(this, "Found %d implementations of ICallServiceProvider.",
+                    mOutstandingProviders.size());
+        }
+
+        /**
+         * Returns the all-inclusive list of call-service-provider names.
+         *
+         * @return The list containing the (component) names of all known ICallServiceProvider
+         *         implementations or the empty list upon no available providers.
+         */
+        private List<ComponentName> getProviderNames() {
+            // The list of provider names to return to the caller, may be populated below.
+            List<ComponentName> providerNames = Lists.newArrayList();
+
+            PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
+            Intent intent = new Intent(TelecommConstants.ACTION_CALL_SERVICE_PROVIDER);
+            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 provider names.
+                    providerNames.add(
+                            new ComponentName(serviceInfo.packageName, serviceInfo.name));
+                }
+            }
+
+            return providerNames;
+        }
+
+        /**
+         * Attempts to obtain call-service descriptors from the specified provider (asynchronously)
+         * and passes the list through to {@link #processCallServices}, which then relinquishes
+         * control back to the switchboard.
+         *
+         * @param providerName The component name of the relevant provider.
+         */
+        private void queryProviderForCallServices(final ComponentName providerName) {
+            final CallServiceProviderWrapper provider = new CallServiceProviderWrapper(
+                    providerName);
+
+            ICallServiceLookupResponse response = new ICallServiceLookupResponse.Stub() {
+                    @Override
+                public void setCallServiceDescriptors(
+                        final List<CallServiceDescriptor> callServiceDescriptors) {
+
+                    mHandler.post(new Runnable() {
+                            @Override
+                        public void run() {
+                            processCallServices(provider, Sets.newHashSet(callServiceDescriptors));
+                        }
+                    });
+                }
+            };
+
+            Runnable errorCallback = new Runnable() {
+                    @Override
+                public void run() {
+                    processCallServices(provider, null);
+                }
+            };
+
+            provider.lookupCallServices(response, errorCallback);
+        }
+
+        /**
+         * Processes the call-service descriptors provided by the specified provider.
+         *
+         * @param provider The call-service provider.
+         * @param callServiceDescriptors The set of descriptors to process.
+         */
+        private void processCallServices(
+                CallServiceProviderWrapper provider,
+                Set<CallServiceDescriptor> callServiceDescriptors) {
+
+            // Descriptor lookup finished, we no longer need the provider.
+            provider.unbind();
+
+            ComponentName providerName = provider.getComponentName();
+            if (mOutstandingProviders.remove(providerName)) {
+                if (callServiceDescriptors != null) {
+                    // Add all the call services from this provider to the call-service cache.
+                    for (CallServiceDescriptor descriptor : callServiceDescriptors) {
+                        mServices.add(getService(descriptor.getServiceComponent(), descriptor));
+                    }
+                }
+
+                if (mOutstandingProviders.isEmpty()) {
+                    finishLookup();
+                }
+            } else {
+                Log.i(this, "Unexpected call services from %s in lookup.", providerName);
+            }
+        }
+
+        void finishLookup() {
+            mCallback.onComplete(mServices);
+        }
+    }
 
     private final OutgoingCallsManager mOutgoingCallsManager;
-
     private final IncomingCallsManager mIncomingCallsManager;
+    private final Handler mHandler = new Handler();
 
-    /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-
-    private final Runnable mTimeoutLookupTerminator = new Runnable() {
-        @Override
-        public void run() {
-            Log.d(CallServiceRepository.this, "Timed out processing providers");
-            terminateLookup();
-        }
-    };
-
-    /**
-     * The current lookup-cycle ID, unique per invocation of {@link #initiateLookup}.
-     */
-    private int mLookupId = -1;
-
-    /**
-     * Determines whether or not a lookup cycle is already running.
-     */
-    private boolean mIsLookupInProgress = false;
-
-    /**
-     * Stores the names of the providers to bind to in one lookup cycle. During lookup two things
-     * can happen:
-     *    - lookup can succeed, in this case this set will be empty at the end of the lookup.
-     *    - lookup can timeout, in this case any outstanding providers will be discarded.
-     */
-    private final Set<ComponentName> mOutstandingProviders = Sets.newHashSet();
-
-    /**
-     * The map of call-service wrappers keyed by their ComponentName. This is passed back to the
-     * switchboard once lookup is complete.
-     */
-    private final Map<ComponentName, CallServiceWrapper> mCallServices = Maps.newHashMap();
-
-    /**
-     * The set of call-service components found during a single lookup.
-     */
-    private final Set<ComponentName> mFoundCallServices = Sets.newHashSet();
-
-    /**
-     * Persists the specified parameters.
-     *
-     * @param switchboard The switchboard.
-     * @param outgoingCallsManager Manages the placing of outgoing calls.
-     * @param incomingCallsManager Manages the incoming call initialization flow.
-     */
+    /** Persists specified parameters. */
     CallServiceRepository(
-            Switchboard switchboard,
             OutgoingCallsManager outgoingCallsManager,
             IncomingCallsManager incomingCallsManager) {
 
-        mSwitchboard = switchboard;
         mOutgoingCallsManager = outgoingCallsManager;
         mIncomingCallsManager = incomingCallsManager;
     }
 
     /**
-     * Initiates a lookup cycle for call-service providers. Must be called from the UI thread.
-     * TODO(gilad): Expand this comment to describe the lookup flow in more detail.
-     *
-     * @param lookupId The switchboard-supplied lookup ID.
-     */
-    void initiateLookup(int lookupId) {
-        ThreadUtil.checkOnMainThread();
-
-        if (mIsLookupInProgress) {
-            // At most one active lookup is allowed at any given time, bail out.
-            return;
-        }
-
-        mFoundCallServices.clear();
-        List<ComponentName> providerNames = getProviderNames();
-        if (providerNames.isEmpty()) {
-            Log.i(this, "No ICallServiceProvider implementations found, bailing out.");
-            return;
-        }
-
-        mLookupId = lookupId;
-        mIsLookupInProgress = true;
-
-        mOutstandingProviders.clear();
-        for (ComponentName name : providerNames) {
-            mOutstandingProviders.add(name);
-            lookupCallServices(name);
-        }
-
-        Log.i(this, "Found %d implementations of ICallServiceProvider.",
-                mOutstandingProviders.size());
-
-        // Schedule a timeout.
-        mHandler.postDelayed(mTimeoutLookupTerminator, Timeouts.getProviderLookupMillis());
-    }
-
-    /**
-     * Creates the requested call service or pulls the previously-created entry from memory.
-     *
-     * @param descriptor The call service descriptor.
-     * @return The corresponding call-service wrapper or null upon failure to retrieve it.
-     */
-    CallServiceWrapper getCallService(CallServiceDescriptor descriptor) {
-        // Create the new call-service wrapper and update {@link #mCallServices}.
-        registerCallService(descriptor);
-
-        return mCallServices.get(descriptor.getServiceComponent());
-    }
-
-    /**
-     * Returns the all-inclusive list of call-service-provider names.
-     *
-     * @return The list containing the (component) names of all known ICallServiceProvider
-     *     implementations or the empty list upon no available providers.
-     */
-    private List<ComponentName> getProviderNames() {
-        // The list of provider names to return to the caller, may be populated below.
-        List<ComponentName> providerNames = Lists.newArrayList();
-
-        PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
-        Intent intent = new Intent(TelecommConstants.ACTION_CALL_SERVICE_PROVIDER);
-        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 provider names.
-                providerNames.add(
-                        new ComponentName(serviceInfo.packageName, serviceInfo.name));
-            }
-        }
-
-        return providerNames;
-    }
-
-    /**
-     * Attempts to obtain call-service descriptors from the specified provider (asynchronously) and
-     * passes the list through to {@link #processCallServices}, which then relinquishes control back
-     * to the switchboard.
-     *
-     * @param providerName The component name of the relevant provider.
-     */
-    private void lookupCallServices(final ComponentName providerName) {
-        final CallServiceProviderWrapper provider = new CallServiceProviderWrapper(providerName);
-
-        ICallServiceLookupResponse response = new ICallServiceLookupResponse.Stub() {
-            @Override
-            public void setCallServiceDescriptors(
-                    final List<CallServiceDescriptor> callServiceDescriptors) {
-
-                // TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity()?
-                mHandler.post(new Runnable() {
-                    @Override public void run() {
-                        if (mIsLookupInProgress) {
-                            processCallServices(provider, Sets.newHashSet(callServiceDescriptors));
-                        }
-                    }
-                });
-            }
-        };
-
-        Runnable errorCallback = new Runnable() {
-            @Override public void run() {
-                removeOutstandingProvider(providerName);
-            }
-        };
-
-        provider.lookupCallServices(response, errorCallback);
-    }
-
-    /**
-     * Creates {@link CallServiceWrapper}s from the given {@link CallServiceDescriptor}s.
-     *
-     * @param provider The provider associated with call services.
-     * @param callServiceDescriptors The set of call service descriptors to process.
-     */
-    private void processCallServices(
-            CallServiceProviderWrapper provider,
-            Set<CallServiceDescriptor> callServiceDescriptors) {
-
-        ThreadUtil.checkOnMainThread();
-
-        Preconditions.checkNotNull(provider);
-        Preconditions.checkNotNull(callServiceDescriptors);
-
-        // The set of call-service descriptors is available, unbind the provider.
-        provider.unbind();
-
-        ComponentName providerName = provider.getComponentName();
-        if (mOutstandingProviders.contains(providerName)) {
-            // Add all the call services from this provider to the call-service cache.
-            for (CallServiceDescriptor descriptor : callServiceDescriptors) {
-                mFoundCallServices.add(descriptor.getServiceComponent());
-                registerCallService(descriptor);
-            }
-
-            removeOutstandingProvider(providerName);
-        } else {
-            Log.i(this, "Unexpected call services from %s in lookup %s", providerName, mLookupId);
-        }
-    }
-
-    /**
-     * Creates a call-service wrapper from the given call-service descriptor if no cached instance
-     * exists.
+     * Returns the call service implementation specified by the descriptor.
      *
      * @param descriptor The call-service descriptor.
      */
-    private void registerCallService(CallServiceDescriptor descriptor) {
-        Preconditions.checkNotNull(descriptor);
-
-        // TODO(santoscordon): Rename getServiceComponent to getComponentName.
-        ComponentName callServiceName = descriptor.getServiceComponent();
-
-        CallServiceWrapper callService = mCallServices.get(callServiceName);
-        if (callService == null) {
-            mCallServices.put(callServiceName, new CallServiceWrapper(descriptor,
-                    mOutgoingCallsManager, mIncomingCallsManager));
-        }
+    CallServiceWrapper getService(CallServiceDescriptor descriptor) {
+        return getService(descriptor.getServiceComponent(), descriptor);
     }
 
-    /**
-     * Removes an entry from the set of outstanding providers. When the final outstanding
-     * provider is removed, terminates the lookup.
-     *
-     * @param providerName The component name of the relevant provider.
-     */
-    private void removeOutstandingProvider(ComponentName providerName) {
-        ThreadUtil.checkOnMainThread();
-
-        if (mIsLookupInProgress) {
-            mOutstandingProviders.remove(providerName);
-            if (mOutstandingProviders.size() < 1) {
-                terminateLookup();  // No other providers to wait for.
-            }
-        }
+    /** {@inheritDoc} */
+    @Override
+    protected void onLookupServices(LookupCallback<CallServiceWrapper> callback) {
+        new CallServiceLookup(callback).start();
     }
 
-    /**
-     * Terminates the current lookup cycle, either due to a timeout or completed lookup.
-     */
-    private void terminateLookup() {
-        mHandler.removeCallbacks(mTimeoutLookupTerminator);
-        mOutstandingProviders.clear();
-
-        // Clean out any old call services. Since the set of call services can change (app installs,
-        // uninstalls, etc.) between lookups, we need to make sure that we purge our registry
-        // of any old call services (call services which were not found in this lookup). However,
-        // we dont purge any call services that might still have calls associated with them.
-        for (ComponentName component : ImmutableSet.copyOf(mCallServices.keySet().iterator())) {
-            if (!mFoundCallServices.contains(component)) {
-                // This component is registered, but was not found in the latest lookup...so try
-                // to remove it.
-                CallServiceWrapper callService = mCallServices.get(component);
-                if (callService.getAssociatedCallCount() < 1) {
-                    mCallServices.remove(component);
-                }
-            }
-        }
-        mFoundCallServices.clear();
-
-        updateSwitchboard();
-        mIsLookupInProgress = false;
-    }
-
-    /**
-     * Updates the switchboard with the call services from the latest lookup.
-     */
-    private void updateSwitchboard() {
-        ThreadUtil.checkOnMainThread();
-
-        Set<CallServiceWrapper> callServices = Sets.newHashSet(mCallServices.values());
-        mSwitchboard.setCallServices(callServices);
+    @Override
+    protected CallServiceWrapper onCreateNewServiceWrapper(ComponentName componentName,
+            Object param) {
+        return new CallServiceWrapper(
+                (CallServiceDescriptor) param, mOutgoingCallsManager, mIncomingCallsManager);
     }
 }
diff --git a/src/com/android/telecomm/CallServiceSelectorRepository.java b/src/com/android/telecomm/CallServiceSelectorRepository.java
index 90e2d55..99a2f52 100644
--- a/src/com/android/telecomm/CallServiceSelectorRepository.java
+++ b/src/com/android/telecomm/CallServiceSelectorRepository.java
@@ -36,9 +36,8 @@
  * Helper class to retrieve {@link ICallServiceSelector} implementations on the device and
  * asynchronously bind to them.
  */
-final class CallServiceSelectorRepository implements ServiceBinder.Listener {
+final class CallServiceSelectorRepository extends BaseRepository<CallServiceSelectorWrapper> {
 
-    private final Switchboard mSwitchboard;
     private final OutgoingCallsManager mOutgoingCallsManager;
 
     /**
@@ -50,21 +49,15 @@
     /**
      * Persists the specified parameters and initializes the new instance.
      *
-     * @param switchboard The switchboard for this finer to work against.
+     * @param outgoingCallsManager The outgoing calls manager.
      */
-    CallServiceSelectorRepository(
-            Switchboard switchboard,
-            OutgoingCallsManager outgoingCallsManager) {
-        mSwitchboard = switchboard;
+    CallServiceSelectorRepository(OutgoingCallsManager outgoingCallsManager) {
         mOutgoingCallsManager = outgoingCallsManager;
     }
 
-    /**
-     * Initiates a lookup cycle for call-service selectors. Must be called from the UI thread.
-     *
-     * @param lookupId The switchboard-supplied lookup ID.
-     */
-    void initiateLookup(int lookupId) {
+    /** {@inheritDoc} */
+    @Override
+    protected void onLookupServices(LookupCallback<CallServiceSelectorWrapper> callback) {
         ThreadUtil.checkOnMainThread();
 
         List<ComponentName> selectorNames = getSelectorNames();
@@ -72,11 +65,7 @@
 
         // Register any new selectors.
         for (ComponentName name : selectorNames) {
-            CallServiceSelectorWrapper selector = mCallServiceSelectors.get(name);
-            if (selector == null) {
-                selector = createWrapper(name);
-                mCallServiceSelectors.put(name, selector);
-            }
+            CallServiceSelectorWrapper selector = getService(name, null);
 
             if (TelephonyUtil.isTelephonySelector(selector)) {
                 // Add telephony selectors to the end to serve as a fallback.
@@ -86,26 +75,17 @@
                 foundSelectors.add(0, selector);
             }
         }
-
         Log.i(this, "Found %d implementations of ICallServiceSelector", selectorNames.size());
-        updateSwitchboard(foundSelectors);
+        callback.onComplete(foundSelectors);
     }
 
-    /**
-     * Removes the specified selector (as a ServiceBinder) from the map of registered selectors.
-     *
-     * {@inheritDoc}
-     */
-    @SuppressWarnings("rawtypes")
+    /** {@inheritDoc} */
     @Override
-    public void onUnbind(ServiceBinder serviceBinder) {
-        if (serviceBinder instanceof CallServiceSelectorWrapper) {
-            CallServiceSelectorWrapper selector = (CallServiceSelectorWrapper) serviceBinder;
-            mCallServiceSelectors.remove(selector.getComponentName());
-        } else {
-            Log.wtf(this, "Received unbind notice from non-selector: %s.",
-                    serviceBinder.getComponentName().flattenToShortString());
-        }
+    protected CallServiceSelectorWrapper onCreateNewServiceWrapper(
+            ComponentName componentName, Object param) {
+
+        return new CallServiceSelectorWrapper(
+                componentName, CallsManager.getInstance(), mOutgoingCallsManager);
     }
 
     /**
@@ -117,13 +97,12 @@
     private CallServiceSelectorWrapper createWrapper(ComponentName componentName) {
         CallServiceSelectorWrapper selector = new CallServiceSelectorWrapper(
                 componentName, CallsManager.getInstance(), mOutgoingCallsManager);
-        selector.addListener(this);
         return selector;
     }
 
     /**
-     * @return The list containing the (component) names of all known ICallServiceSelector
-     *     implementations or the empty list upon no available selectors.
+     * 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.
@@ -143,13 +122,4 @@
 
         return selectorNames;
     }
-
-    /**
-     * Updates the switchboard passing the relevant call services selectors.
-     *
-     * @param selectors The selectors found during lookup.
-     */
-    private void updateSwitchboard(List<CallServiceSelectorWrapper> selectors) {
-        mSwitchboard.setSelectors(ImmutableList.copyOf(selectors));
-    }
 }
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index bef1dfa..85b9340 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -41,7 +41,7 @@
  */
 public final class CallsManager implements Call.Listener {
 
- // TODO(santoscordon): Consider renaming this CallsManagerPlugin.
+    // TODO(santoscordon): Consider renaming this CallsManagerPlugin.
     interface CallsManagerListener {
         void onCallAdded(Call call);
         void onCallRemoved(Call call);
diff --git a/src/com/android/telecomm/IncomingCallsManager.java b/src/com/android/telecomm/IncomingCallsManager.java
index 41b98f2..13ffb64 100644
--- a/src/com/android/telecomm/IncomingCallsManager.java
+++ b/src/com/android/telecomm/IncomingCallsManager.java
@@ -31,19 +31,9 @@
  */
 final class IncomingCallsManager {
 
-    private final Switchboard mSwitchboard;
     private final Set<Call> mPendingIncomingCalls = Sets.newLinkedHashSet();
 
     /**
-     * Persists the specified parameters.
-     *
-     * @param switchboard The switchboard.
-     */
-    IncomingCallsManager(Switchboard switchboard) {
-        mSwitchboard = switchboard;
-    }
-
-    /**
      * Retrieves details of an incoming call through its associated call service.
      *
      * @param call The call object.
@@ -69,7 +59,7 @@
     }
 
     /**
-     * Notifies the switchboard of a successful incoming call after removing it from the pending
+     * Notifies the incoming call of success after removing it from the pending
      * list.
      *
      * @param callInfo The details of the call.
@@ -80,12 +70,12 @@
         if (mPendingIncomingCalls.contains(call)) {
             Log.d(this, "Incoming call %s found.", call);
             mPendingIncomingCalls.remove(call);
-            mSwitchboard.handleSuccessfulIncomingCall(call, callInfo);
+            call.handleSuccessfulIncoming(callInfo);
         }
     }
 
     /**
-     * Notifies switchboard of the failed incoming call after removing it from the pending list.
+     * Notifies  incoming call of failure after removing it from the pending list.
      */
     void handleFailedIncomingCall(Call call) {
         ThreadUtil.checkOnMainThread();
@@ -94,7 +84,7 @@
             Log.i(this, "Failed to get details for incoming call %s", call);
             mPendingIncomingCalls.remove(call);
             // The call was found still waiting for details. Consider it failed.
-            mSwitchboard.handleFailedIncomingCall(call);
+            call.handleFailedIncoming();
         }
     }
 }
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index 5c8d5f5..3874bd5 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -33,10 +33,9 @@
  * Iterates through the selectors and gets a sorted list of supported call-service descriptors
  * for each selector. Upon receiving each sorted list (one list per selector), each of the
  * corresponding call services is then attempted until either the outgoing call is placed, the
- * attempted call is aborted (by the switchboard), or the list is exhausted -- whichever occurs
- * first.
+ * attempted call is aborted, or the list is exhausted -- whichever occurs first.
  *
- * Except for the abort case, all other scenarios should terminate with the switchboard notified
+ * Except for the abort case, all other scenarios should terminate with the call notified
  * of the result.
  *
  * NOTE(gilad): Currently operating under the assumption that we'll have one timeout per (outgoing)
@@ -79,8 +78,6 @@
     /** Manages all outgoing call processors. */
     private final OutgoingCallsManager mOutgoingCallsManager;
 
-    private final Switchboard mSwitchboard;
-
     private final Runnable mNextCallServiceCallback = new Runnable() {
         @Override public void run() {
             attemptNextCallService();
@@ -113,21 +110,18 @@
      * @param callServices The available call-service implementations.
      * @param selectors The available call-service selector implementations.
      * @param outgoingCallsManager Manager of all outgoing call processors.
-     * @param switchboard The switchboard.
      */
     OutgoingCallProcessor(
             Call call,
-            Set<CallServiceWrapper> callServices,
+            Collection<CallServiceWrapper> callServices,
             Collection<CallServiceSelectorWrapper> selectors,
-            OutgoingCallsManager outgoingCallsManager,
-            Switchboard switchboard) {
+            OutgoingCallsManager outgoingCallsManager) {
 
         ThreadUtil.checkOnMainThread();
 
         mCall = call;
         mSelectors = selectors;
         mOutgoingCallsManager = outgoingCallsManager;
-        mSwitchboard = switchboard;
 
         // Populate the list and map of call-service descriptors.  The list is needed since
         // it's being passed down to selectors.
@@ -214,7 +208,7 @@
         for (CallServiceWrapper callService : mIncompatibleCallServices) {
             mCall.addIncompatibleCallService(callService);
         }
-        mSwitchboard.handleSuccessfulOutgoingCall(mCall);
+        mCall.handleSuccessfulOutgoing();
     }
 
     /**
diff --git a/src/com/android/telecomm/OutgoingCallsManager.java b/src/com/android/telecomm/OutgoingCallsManager.java
index 7bbfd04..05bdad0 100644
--- a/src/com/android/telecomm/OutgoingCallsManager.java
+++ b/src/com/android/telecomm/OutgoingCallsManager.java
@@ -30,22 +30,16 @@
  * 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 (Switchboard, CallServiceAdapter, etc),
+ * to {@link OutgoingCallProcessor} so that other classes (CallServiceAdapter, etc),
  * can simply call into this class instead of individual OutgoingCallProcessors.
  */
 final class OutgoingCallsManager {
-    private final Switchboard mSwitchboard;
 
     /**
      * Maps call to {@link OutgoingCallProcessor}s.
      */
     private Map<Call, OutgoingCallProcessor> mOutgoingCallProcessors = Maps.newHashMap();
 
-    /** Persists specified parameters. */
-    OutgoingCallsManager(Switchboard switchboard) {
-        mSwitchboard = switchboard;
-    }
-
     /**
      * 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})
@@ -53,12 +47,12 @@
      * {@link #handleFailedCallAttempt}.
      *
      * @param call The call to place.
-     * @param callServices The set of call services which can potentially place the call.
+     * @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,
-            Set<CallServiceWrapper> callServices,
+            Collection<CallServiceWrapper> callServices,
             Collection<CallServiceSelectorWrapper> selectors) {
 
         Log.i(this, "Placing an outgoing call: %s", call);
@@ -67,7 +61,7 @@
         // attempts can be aborted etc.
         // TODO(gilad): Consider passing mSelector as an immutable set.
         OutgoingCallProcessor processor =
-                new OutgoingCallProcessor(call, callServices, selectors, this, mSwitchboard);
+                new OutgoingCallProcessor(call, callServices, selectors, this);
 
         mOutgoingCallProcessors.put(call, processor);
         processor.process();
@@ -92,7 +86,7 @@
 
     /**
      * Removes the outgoing call processor mapping for the successful call and returns execution to
-     * the switchboard. This method is invoked from {@link CallServiceAdapter} after a call service
+     * 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) {
@@ -129,10 +123,10 @@
 
     /**
      * Removes the outgoing call processor mapping for the failed call and returns execution to the
-     * switchboard. In contrast to handleFailedCallAttempt which comes from the call-service and
+     * 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 Switchboard.
+     * should cleanup and notify the call.
      *
      * @param call The failed outgoing call.
      * @param isAborted True if the call timedout and is aborted.
@@ -140,7 +134,7 @@
     void handleFailedOutgoingCall(Call call, boolean isAborted) {
         Log.v(this, "handleFailedOutgoingCall, call: %s", call);
         mOutgoingCallProcessors.remove(call);
-        mSwitchboard.handleFailedOutgoingCall(call, isAborted);
+        call.handleFailedOutgoing(isAborted);
     }
 
     /**
@@ -166,9 +160,9 @@
      *         successful.
      */
     boolean abort(Call call) {
-        Log.v(this, "abort, call: %s", call);
         OutgoingCallProcessor processor = mOutgoingCallProcessors.remove(call);
         if (processor != null) {
+            Log.v(this, "abort, call: %s", call);
             processor.abort();
             return true;
         }
diff --git a/src/com/android/telecomm/ServiceBinder.java b/src/com/android/telecomm/ServiceBinder.java
index 3dc86be..ed84bcf 100644
--- a/src/com/android/telecomm/ServiceBinder.java
+++ b/src/com/android/telecomm/ServiceBinder.java
@@ -49,9 +49,8 @@
     /**
      * Listener for bind events on ServiceBinder.
      */
-    interface Listener {
-        @SuppressWarnings("rawtypes")
-        void onUnbind(ServiceBinder serviceBinder);
+    interface Listener<ServiceBinderClass extends ServiceBinder<?>> {
+        void onUnbind(ServiceBinderClass serviceBinder);
     }
 
     /**
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 81ab172..5b8d25d 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -24,6 +24,7 @@
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
 
+import com.android.telecomm.BaseRepository.LookupCallback;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
@@ -37,9 +38,81 @@
  * - gathering the {@link CallServiceWrapper}s and {@link CallServiceSelectorWrapper}s through
  *       which to place outgoing calls
  * - starting outgoing calls (via {@link OutgoingCallsManager}
- * - switching active calls between call services.
  */
 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();
@@ -60,7 +133,7 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_EXPIRE_STALE_CALL:
-                    expireStaleCall((Call) msg.obj);
+                    ((OutgoingCallEntry) msg.obj).expire();
                     break;
                 default:
                     Log.wtf(Switchboard.this, "Unexpected message %d.", msg.what);
@@ -68,30 +141,6 @@
         }
     };
 
-    private final Set<Call> mNewOutgoingCalls = Sets.newLinkedHashSet();
-
-    private final Set<Call> mPendingOutgoingCalls = Sets.newLinkedHashSet();
-
-    /**
-     * The set of currently available call-service implementations, see
-     * {@link CallServiceRepository}.  Populated during call-service lookup cycles as part of the
-     * {@link #placeOutgoingCall} flow and cleared upon zero-remaining new/pending outgoing calls.
-     */
-    private final Set<CallServiceWrapper> mCallServices = Sets.newHashSet();
-
-    /**
-     * The set of currently available call-service-selector implementations,
-     * see {@link CallServiceSelectorRepository}.
-     * TODO(gilad): Clear once the active-call count goes to zero.
-     */
-    private ImmutableCollection<CallServiceSelectorWrapper> mSelectors = ImmutableList.of();
-
-    /**
-     * The current lookup-cycle ID used with the repositories. Incremented with each invocation
-     * of {@link #placeOutgoingCall} and passed to the repositories via initiateLookup().
-     */
-    private int mLookupId = 0;
-
     /** Singleton accessor. */
     static Switchboard getInstance() {
         return sInstance;
@@ -103,11 +152,11 @@
     private Switchboard() {
         ThreadUtil.checkOnMainThread();
 
-        mOutgoingCallsManager = new OutgoingCallsManager(this);
-        mIncomingCallsManager = new IncomingCallsManager(this);
-        mSelectorRepository = new CallServiceSelectorRepository(this, mOutgoingCallsManager);
+        mOutgoingCallsManager = new OutgoingCallsManager();
+        mIncomingCallsManager = new IncomingCallsManager();
+        mSelectorRepository = new CallServiceSelectorRepository(mOutgoingCallsManager);
         mCallServiceRepository =
-                new CallServiceRepository(this, mOutgoingCallsManager, mIncomingCallsManager);
+                new CallServiceRepository(mOutgoingCallsManager, mIncomingCallsManager);
     }
 
     /**
@@ -118,30 +167,30 @@
      * @param call The yet-to-be-connected outgoing-call object.
      */
     void placeOutgoingCall(Call call) {
-        // Reset prior to initiating the next lookup. One case to consider is (1) placeOutgoingCall
-        // is invoked with call A, (2) the call-service lookup completes, but the one for selectors
-        // does not, (3) placeOutgoingCall is invoked again with call B, (4) mCallServices below is
-        // reset, (5) the selector lookup completes but the call-services are missing.  This should
-        // be okay since the call-service lookup completed. Specifically the already-available call
-        // services are cached and will be provided in response to the second lookup cycle.
-        mCallServices.clear();
-        mSelectors = ImmutableList.of();
+        final OutgoingCallEntry callEntry = new OutgoingCallEntry(call);
 
-        mNewOutgoingCalls.add(call);
+        // Lookup call services
+        mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
+            @Override
+            public void onComplete(Collection<CallServiceWrapper> services) {
+                callEntry.setCallServices(services);
+            }
+        });
 
-        // Initiate a lookup every time to account for newly-installed apps and/or updated settings.
-        mLookupId++;
-        mCallServiceRepository.initiateLookup(mLookupId);
-        mSelectorRepository.initiateLookup(mLookupId);
+        // 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, call);
+        Message msg = mHandler.obtainMessage(MSG_EXPIRE_STALE_CALL, callEntry);
         mHandler.sendMessageDelayed(msg, Timeouts.getNewOutgoingCallMillis());
     }
 
     /**
-     * Retrieves details about the incoming call through the incoming call manager. The incoming
-     * call manager will invoke either {@link #handleSuccessfulIncomingCall} or
-     * {@link #handleFailedIncomingCall} depending on the result of the retrieval.
+     * Retrieves details about the incoming call through the incoming call manager.
      *
      * @param call The call object.
      * @param descriptor The relevant call-service descriptor.
@@ -150,96 +199,12 @@
      */
     void retrieveIncomingCall(Call call, CallServiceDescriptor descriptor, Bundle extras) {
         Log.d(this, "retrieveIncomingCall");
-        CallServiceWrapper callService = mCallServiceRepository.getCallService(descriptor);
+        CallServiceWrapper callService = mCallServiceRepository.getService(descriptor);
         call.setCallService(callService);
         mIncomingCallsManager.retrieveIncomingCall(call, extras);
     }
 
     /**
-     * Persists the specified set of call services and attempts to place any pending outgoing
-     * calls.  Intended to be invoked by {@link CallServiceRepository} exclusively.
-     *
-     * @param callServices The potentially-partial set of call services.  Partial since the lookup
-     *     process is time-boxed, such that some providers/call-services may be slow to respond and
-     *     hence effectively omitted from the specified list.
-     */
-    void setCallServices(Set<CallServiceWrapper> callServices) {
-        mCallServices.clear();
-        mCallServices.addAll(callServices);
-        processNewOutgoingCalls();
-    }
-
-    /**
-     * Persists the specified list of selectors and attempts to connect any pending outgoing
-     * calls.  Intended to be invoked by {@link CallServiceSelectorRepository} exclusively.
-     *
-     * @param selectors Collection of selectors. The order of the collection determines the order in
-     *     which the selectors are tried.
-     */
-    void setSelectors(ImmutableCollection<CallServiceSelectorWrapper> selectors) {
-        ThreadUtil.checkOnMainThread();
-        Preconditions.checkNotNull(selectors);
-
-        // TODO(gilad): Add logic to include the built-in selectors (e.g. for dealing with
-        // emergency calls) and order the entire set prior to the assignment below. If the
-        // built-in selectors can be implemented in a manner that does not require binding,
-        // that's probably preferred.
-        mSelectors = selectors;
-        processNewOutgoingCalls();
-    }
-
-    /**
-     * Handles the case where an outgoing call has been successfully placed,
-     * see {@link OutgoingCallProcessor}.
-     */
-    void handleSuccessfulOutgoingCall(Call call) {
-        Log.d(this, "handleSuccessfulOutgoingCall");
-
-        finalizeOutgoingCall(call);
-        call.handleSuccessfulOutgoing();
-    }
-
-    /**
-     * Handles the case where an outgoing call could not be proceed by any of the
-     * selector/call-service implementations, see {@link OutgoingCallProcessor}.
-     */
-    void handleFailedOutgoingCall(Call call, boolean isAborted) {
-        Log.d(this, "handleFailedOutgoingCall");
-
-        finalizeOutgoingCall(call);
-        call.handleFailedOutgoing(isAborted);
-    }
-
-    /**
-     * Handles the case where we successfully receive details of an incoming call. Hands the
-     * resulting call to {@link CallsManager} as the final step in the incoming sequence. At that
-     * point, {@link CallsManager} should bring up the incoming-call UI.
-     */
-    void handleSuccessfulIncomingCall(Call call, CallInfo callInfo) {
-        Log.d(this, "handleSuccessfulIncomingCall");
-        call.handleSuccessfulIncoming(callInfo);
-    }
-
-    /**
-     * Handles the case where we failed to retrieve an incoming call after receiving an incoming-call
-     * intent via {@link CallActivity}.
-     *
-     * @param call The call.
-     */
-    void handleFailedIncomingCall(Call call) {
-        Log.d(this, "handleFailedIncomingCall");
-
-        // Since we set the call service before calling into incoming-calls manager, we clear it for
-        // good measure if an error is reported.
-        call.handleFailedIncoming();
-
-        // At the moment there is nothing more to do if an incoming call is not retrieved. We may at
-        // a future date bind to the in-call app optimistically during the incoming-call sequence
-        // and this method could tell {@link CallsManager} to unbind from the in-call app if the
-        // incoming call was not retrieved.
-    }
-
-    /**
      * Ensures any state regarding a call is cleaned up.
      *
      * @param call The call.
@@ -250,38 +215,19 @@
     }
 
     /**
-     * Attempts to process the next new outgoing calls that have not yet been expired.
-     */
-    private void processNewOutgoingCalls() {
-        if (mCallServices.isEmpty() || mSelectors.isEmpty()) {
-            // At least one call service and one selector are required to process outgoing calls.
-            return;
-        }
-
-        if (!mNewOutgoingCalls.isEmpty()) {
-            Call call = mNewOutgoingCalls.iterator().next();
-            mNewOutgoingCalls.remove(call);
-            mPendingOutgoingCalls.add(call);
-
-            // Specifically only attempt to place one call at a time such that call services
-            // can be freed from needing to deal with concurrent requests.
-            processNewOutgoingCall(call);
-        }
-    }
-
-    /**
      * Attempts to place the specified call.
      *
-     * @param call The call to place.
+     * @param callEntry The call entry to place.
      */
-    private void processNewOutgoingCall(Call call) {
+    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 = mSelectors;
+            selectors = callEntry.getSelectors();
         }
 
         boolean useEmergencySelector =
@@ -308,39 +254,6 @@
             selectors = selectorsBuilder.build();
         }
 
-        mOutgoingCallsManager.placeCall(call, mCallServices, selectors);
-    }
-
-    /**
-     * Finalizes the outgoing-call sequence, regardless if it succeeded or failed.
-     */
-    private void finalizeOutgoingCall(Call call) {
-        mPendingOutgoingCalls.remove(call);
-
-        processNewOutgoingCalls();  // Process additional (new) calls, if any.
-    }
-
-    /**
-     * Expires calls which are taking too long to connect.
-     *
-     * @param call The call to expire.
-     */
-    private void expireStaleCall(Call call) {
-        final long newCallTimeoutMillis = Timeouts.getNewOutgoingCallMillis();
-
-        if (call.getAgeMillis() < newCallTimeoutMillis) {
-            Log.wtf(this, "Expiring a call early. Age: %d, Time since attempt: %d",
-                    call.getAgeMillis(), newCallTimeoutMillis);
-        }
-
-        if (mNewOutgoingCalls.remove(call)) {
-            // The call had not yet been processed so all we have to do is report the
-            // failure.
-            handleFailedOutgoingCall(call, true /* isAborted */);
-        } else if (mPendingOutgoingCalls.remove(call)) {
-            if (!mOutgoingCallsManager.abort(call)) {
-                Log.wtf(this, "Pending call failed to abort, call: %s.", call);
-            }
-        }
+        mOutgoingCallsManager.placeCall(call, callEntry.getCallServices(), selectors);
     }
 }