Follow up on c/401744.

Change-Id: I53bdfae84532c9f382d3ebfa8ab7c993898725b7
diff --git a/src/com/android/telecomm/CallServiceFinder.java b/src/com/android/telecomm/CallServiceFinder.java
index aa9f058..360c503 100644
--- a/src/com/android/telecomm/CallServiceFinder.java
+++ b/src/com/android/telecomm/CallServiceFinder.java
@@ -19,17 +19,23 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.os.IBinder;
 import android.telecomm.ICallService;
 import android.telecomm.ICallServiceProvider;
 import android.util.Log;
 
-import com.android.telecomm.CallServiceProviderProxy.CallServiceProviderConnectionCallback;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 
 /**
  * Finds {@link ICallService} and {@link ICallServiceProvider} implementations on the device.
@@ -38,94 +44,282 @@
  * TODO(santoscordon): Add performance timing to async calls.
  */
 final class CallServiceFinder {
+
     /**
-     * Implemented by classes which want to receive the final list of {@link CallService}s found.
+     * Helper class to register/unregister call-service providers.
      */
-    interface CallServiceSearchCallback {
+    private class ProviderRegistrar {
+
         /**
-         * Method called after search has completed.
-         *
-         * @param callServices List of {@link ICallServices} found in the search.
+         * The name of the call-service provider that is expected to register with this finder.
          */
-        public void onSearchComplete(List<ICallService> callServices);
+        private ComponentName mProviderName;
+
+        /**
+         * A unique identifier for a given lookup cycle, see nextLookupId.
+         * TODO(gilad): Potentially unnecessary, consider removing.
+         */
+        int mLookupId;
+
+        /**
+         * Persists the specified parameters.
+         *
+         * @param providerName The component name of the relevant provider.
+         * @param lookupId The lookup-cycle ID.
+         */
+        ProviderRegistrar(ComponentName providerName, int lookupId) {
+            this.mProviderName = providerName;
+            this.mLookupId = lookupId;
+        }
+
+        ComponentName getProviderName() {
+            return mProviderName;
+        }
+
+        /**
+         * Registers the specified call-service provider.
+         *
+         * @param provider The provider object to register.
+         */
+        void register(ICallServiceProvider provider) {
+            registerProvider(mLookupId, mProviderName, provider);
+        }
+
+        /** Unregisters this provider. */
+        void unregister() {
+            unregisterProvider(mProviderName);
+        }
+    }
+
+    /**
+     * Wrapper around ICallServiceProvider, mostly used for binding etc.
+     *
+     * TODO(gilad): Consider making this wrapper unnecessary.
+     */
+    private class ProviderWrapper {
+
+        /**
+         * Persists the specified parameters and attempts to bind the specified provider.
+         *
+         * TODO(gilad): Consider embedding ProviderRegistrar into this class and do away
+         * with the former, or vice versa.
+         *
+         * @param context The relevant application context.
+         * @param registrar The registrar with which to register and unregister this provider.
+         */
+        ProviderWrapper(Context context, final ProviderRegistrar registrar) {
+          ComponentName name = registrar.getProviderName();
+          Preconditions.checkNotNull(name);
+          Preconditions.checkNotNull(context);
+
+          Intent serviceIntent = new Intent(CALL_SERVICE_PROVIDER_CLASS_NAME).setComponent(name);
+          Log.i(TAG, "Binding to ICallServiceProvider through " + serviceIntent);
+
+          // Connection object for the service binding.
+          ServiceConnection connection = new ServiceConnection() {
+              @Override
+              public void onServiceConnected(ComponentName className, IBinder service) {
+                  registrar.register(ICallServiceProvider.Stub.asInterface(service));
+              }
+
+              @Override
+              public void onServiceDisconnected(ComponentName className) {
+                  registrar.unregister();
+              }
+          };
+
+          if (!context.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+              // TODO(santoscordon): Handle error.
+          }
+        }
+    }
+
+    /**
+     * A timer task to ensure each lookup cycle is time-bound, see LOOKUP_TIMEOUT.
+     */
+    private class LookupTerminator extends TimerTask {
+        @Override
+        public void run() {
+          terminateLookup();
+        }
     }
 
     /** Used to identify log entries by this class */
-    static final String TAG = CallServiceFinder.class.getSimpleName();
-
-    /** Private constructor to prevent instances being made. */
-    private CallServiceFinder() {}
+    private static final String TAG = CallServiceFinder.class.getSimpleName();
 
     /**
-     * Asynchronously finds {@link ICallService} implementations and returns them asynchronously
-     * through the callback parameter.
-     *
-     * @param searchCallback The callback executed when the search is complete.
+     * The longest period in milliseconds each lookup cycle is allowed to span over, see mTimer.
+     * TODO(gilad): Likely requires tuning.
      */
-    public static void findCallServices(Context context,
-            final CallServiceSearchCallback searchCallback) {
-        List<ComponentName> components = getAllProviderComponents(context);
+    private static final int LOOKUP_TIMEOUT = 100;
 
-        Log.i(TAG, "Found " + components.size() + " implementations for ICallServiceProvider");
+    /**
+     * Used to retrieve all known ICallServiceProvider implementations from the framework.
+     * TODO(gilad): Move to a more logical place for this to be shared.
+     */
+    static final String CALL_SERVICE_PROVIDER_CLASS_NAME = ICallServiceProvider.class.getName();
 
-        for (ComponentName componentName : components) {
-            CallServiceProviderProxy proxy = new CallServiceProviderProxy(componentName, context);
-            CallServiceProviderConnectionCallback onProviderFoundCallback =
-                    new CallServiceProviderConnectionCallback() {
-                        @Override public void onConnected(ICallServiceProvider serviceProvider) {
-                            onProviderFound(serviceProvider, searchCallback);
-                        }
-                    };
+    /**
+     * Determines whether or not a lookup cycle is already running.
+     */
+    private boolean mIsLookupInProgress = false;
 
-            proxy.connect(onProviderFoundCallback);
+    /**
+     * Used to generate unique lookup-cycle identifiers. Incremented upon initiateLookup calls.
+     */
+    private int mNextLookupId = 0;
+
+    /**
+     * The set of bound call-service providers.  Only populated via initiateLookup scenarios.
+     * Providers should only be removed upon unbinding.
+     */
+    private Set<ICallServiceProvider> mProviderRegistry = Sets.newHashSet();
+
+    /**
+     * Stores the names of the providers to bind to in one lookup cycle.  The set size represents
+     * the number of call-service providers this finder expects to hear back from upon initiating
+     * call-service lookups, see initiateLookup. Whenever all providers respond before the lookup
+     * timeout occurs, the complete set of (available) call services is passed to the switchboard
+     * for further processing of outgoing calls etc.  When the timeout occurs before all responds
+     * are received, the partial (potentially empty) set gets passed (to the switchboard) instead.
+     * Note that cached providers do not require finding and hence are excluded from this count.
+     * Also noteworthy is that providers are dynamically removed from this set as they register.
+     */
+    private Set<ComponentName> mUnregisteredProviders;
+
+    /**
+     * Used to interrupt lookup cycles that didn't terminate naturally within the allowed
+     * period, see LOOKUP_TIMEOUT.
+     */
+    private Timer mTimer;
+
+    /**
+     * Initiates a lookup cycle for call-service providers.
+     * TODO(gilad): Expand this comment to describe the lookup flow in more detail.
+     *
+     * @param context The relevant application context.
+     */
+    public synchronized void initiateLookup(Context context) {
+        if (mIsLookupInProgress) {
+            // At most one active lookup is allowed at any given time, bail out.
+            return;
+        }
+
+        List<ComponentName> providerNames = getProviderNames(context);
+        if (providerNames.isEmpty()) {
+            Log.i(TAG, "No ICallServiceProvider implementations found.");
+            updateSwitchboard();
+            return;
+        }
+
+        mIsLookupInProgress = true;
+        mUnregisteredProviders = Sets.newHashSet();
+
+        int lookupId = mNextLookupId++;
+        for (ComponentName name : providerNames) {
+            if (!mProviderRegistry.contains(name)) {
+                // The provider is either not yet registered or has been unregistered
+                // due to unbinding etc.
+                ProviderRegistrar registrar = new ProviderRegistrar(name, lookupId);
+                new ProviderWrapper(context, registrar);
+                mUnregisteredProviders.add(name);
+            }
+        }
+
+        int providerCount = providerNames.size();
+        int unregisteredProviderCount = mUnregisteredProviders.size();
+
+        Log.i(TAG, "Found " + providerCount + " implementations for ICallServiceProvider, "
+                + unregisteredProviderCount + " of which are not currently registered.");
+
+        if (unregisteredProviderCount == 0) {
+            // All known (provider) implementations are already registered, pass control
+            // back to the switchboard.
+            updateSwitchboard();
+        } else {
+            // Start the timeout for this lookup cycle.
+            // TODO(gilad): Consider reusing the same timer instead of creating new ones.
+            if (mTimer != null) {
+                // Shouldn't be running but better safe than sorry.
+                mTimer.cancel();
+            }
+            mTimer = new Timer();
+            mTimer.schedule(new LookupTerminator(), LOOKUP_TIMEOUT);
         }
     }
 
     /**
-     * Called after a {@link CallServiceProviderProxy} attempts to bind to its
-     * {@link ICallServiceProvider} counterpart. When this method is called, the proxy should
-     * have either made a successful connection or an error occurred.
+     * Returns the all-inclusive list of call-service-provider names.
      *
-     * @param serviceProvider The instance of ICallServiceProvider.
+     * @param context The relevant/application context to query against.
+     * @return The list containing the (component) names of all known ICallServiceProvider
+     *     implementations or the empty list upon no available providers.
      */
-    private static void onProviderFound(ICallServiceProvider serviceProvider,
-            CallServiceSearchCallback searchCallback) {
-        if (serviceProvider == null) {
-            // TODO(santoscordon): Handle error.
-        }
-
-        Log.i(TAG, "Found a service Provider: " + serviceProvider);
-
-        // TODO(santoscordon): asynchronously retrieve ICallService interfaces.
-        // TODO(santoscordon): Filter the list by only those which the user has allowed.
-    }
-
-    private static List<ComponentName> getAllProviderComponents(Context context) {
-        Intent serviceIntent = getICallServiceProviderIntent();
+    private List<ComponentName> getProviderNames(Context context) {
+        // The list of provider names to return to the caller, may be populated below.
+        List<ComponentName> providerNames = Lists.newArrayList();
 
         PackageManager packageManager = context.getPackageManager();
-        List<ResolveInfo> resolveInfos = packageManager.queryIntentServices(serviceIntent, 0);
-
-        List<ComponentName> components = Lists.newArrayList();
-        for (ResolveInfo resolveInfo : resolveInfos) {
-            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-            // Ignore anything that didn't resolve to a proper service.
-            if (serviceInfo == null) {
-                continue;
+        Intent intent = new Intent(CALL_SERVICE_PROVIDER_CLASS_NAME);
+        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));
             }
-
-            ComponentName componentName = new ComponentName(serviceInfo.packageName,
-                    serviceInfo.name);
-            components.add(componentName);
         }
 
-        return components;
+        return providerNames;
     }
 
     /**
-     * Returns the intent used to resolve all registered {@link ICallService}s.
+     * Registers the specified provider and performs the necessary bookkeeping to potentially
+     * return control to the switchboard before the timeout for the current lookup cycle.
+     *
+     * @param lookupId The lookup-cycle ID.
+     * @param providerName The component name of the relevant provider.
+     * @param provider The provider object to register.
      */
-    private static Intent getICallServiceProviderIntent() {
-       return new Intent(ICallServiceProvider.class.getName());
+    private void registerProvider(
+            int lookupId, ComponentName providerName, ICallServiceProvider provider) {
+
+      if (mUnregisteredProviders.remove(providerName)) {
+          mProviderRegistry.add(provider);
+          if (mUnregisteredProviders.size() < 1) {
+              terminateLookup();  // No other providers to wait for.
+          }
+      }
+    }
+
+    /**
+     * Unregisters the specified provider.
+     *
+     * @param providerName The component name of the relevant provider.
+     */
+    private void unregisterProvider(ComponentName providerName) {
+        mProviderRegistry.remove(providerName);
+    }
+
+    /**
+     * Timeouts the current lookup cycle, see LookupTerminator.
+     */
+    private void terminateLookup() {
+        if (mTimer != null) {
+            mTimer.cancel();  // Terminate the timer thread.
+        }
+
+        updateSwitchboard();
+        mIsLookupInProgress = false;
+    }
+
+    /**
+     * Updates the switchboard passing the relevant call services (as opposed
+     * to call-service providers).
+     */
+    private void updateSwitchboard() {
+        synchronized (mProviderRegistry) {
+            // TODO(gilad): More here.
+        }
     }
 }
diff --git a/src/com/android/telecomm/CallServiceProviderProxy.java b/src/com/android/telecomm/CallServiceProviderProxy.java
deleted file mode 100644
index b515850..0000000
--- a/src/com/android/telecomm/CallServiceProviderProxy.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.telecomm;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.telecomm.ICallServiceProvider;
-import android.util.Log;
-
-import com.google.common.base.Preconditions;
-
-/**
- * A proxy to a bound CallServiceProvider implementation. Given a {@link ComponentName}, this class
- * will bind, maintain and unbind a connection with a CallServiceProvider.
- */
-class CallServiceProviderProxy {
-    /**
-     * Interface used for notifying when the {@link ICallServiceProvider} is bound.
-     */
-    public interface CallServiceProviderConnectionCallback {
-        public void onConnected(ICallServiceProvider provider);
-    }
-
-    /** Used to identify log entries by this class */
-    static final String TAG = CallServiceFinder.class.getSimpleName();
-
-    /** Context used to bind with ICallServiceProvider. */
-    private final Context mContext;
-
-    /**
-     * Explicit component name of of the ICallServiceProvider implementation with which to bind.
-     */
-    private final ComponentName mComponentName;
-
-    /**
-     * Persists the specified parameters.
-     */
-    public CallServiceProviderProxy(ComponentName componentName, Context context) {
-        mComponentName = Preconditions.checkNotNull(componentName);
-        mContext = Preconditions.checkNotNull(context);
-    }
-
-    /**
-     * Binds with the {@link ICallServiceProvider} implementation specified by
-     * {@link #mComponentName}.
-     */
-    public void connect(final CallServiceProviderConnectionCallback connectionCallback) {
-        // TODO(santoscordon): Are there cases where we are already connected and should return
-        // early with a saved instance?
-
-        Intent serviceIntent = getServiceIntent();
-        Log.i(TAG, "Binding to ICallService through " + serviceIntent);
-
-        // Connection object for the service binding.
-        ServiceConnection connection = new ServiceConnection() {
-            @Override
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                onConnected(ICallServiceProvider.Stub.asInterface(service), this,
-                        connectionCallback);
-            }
-
-            @Override
-            public void onServiceDisconnected(ComponentName className) {
-                onDisconnected(this);
-            }
-        };
-
-        if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
-            // TODO(santoscordon): Handle error
-        }
-
-        // At this point, we should get called on onServiceConnected asynchronously
-    }
-
-    /**
-     * Returns the service {@link Intent} used to bind to {@link ICallServiceProvider} instances.
-     */
-    private Intent getServiceIntent() {
-        Intent serviceIntent = new Intent(ICallServiceProvider.class.getName());
-        serviceIntent.setComponent(mComponentName);
-        return serviceIntent;
-    }
-
-    /**
-     * Called when an instance of ICallServiceProvider is bound to this process.
-     *
-     * @param serviceProvider The {@link ICallServiceProvider} instance that was bound.
-     * @param connection The service connection used to bind to serviceProvider.
-     */
-    private void onConnected(ICallServiceProvider serviceProvider, ServiceConnection connection,
-            CallServiceProviderConnectionCallback connectionCallback) {
-        // TODO(santoscordon): add some error conditions
-
-        connectionCallback.onConnected(serviceProvider);
-    }
-
-    /**
-     * Called when ICallServiceProvider is disconnected.  This could be for any reason including
-     * the host process dying.
-     *
-     * @param connection The service connection used to bind initially.
-     */
-    private void onDisconnected(ServiceConnection connection) {
-        // TODO(santoscordon): How to handle disconnection?
-    }
-}
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 71c666d..ce8674f 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -22,7 +22,6 @@
 import com.android.telecomm.exceptions.RestrictedCallException;
 import com.google.common.collect.Lists;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 6ee4d22..b33df50 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -23,7 +23,6 @@
 import android.telecomm.ICallService;
 import android.util.Log;
 
-import com.android.telecomm.CallServiceFinder.CallServiceSearchCallback;
 import com.android.telecomm.exceptions.CallServiceUnavailableException;
 import com.android.telecomm.exceptions.OutgoingCallException;
 
@@ -35,98 +34,97 @@
  * considered a different transport type).
  * TODO(santoscordon): Need to add comments on the switchboard optimizer once that it is place.
  */
-class Switchboard {
+final class Switchboard {
     /** Used to identify log entries by this class */
     private static final String TAG = Switchboard.class.getSimpleName();
 
+    private CallServiceFinder callServiceFinder = new CallServiceFinder();
+
     /**
      * Places an outgoing call to the handle passed in. Method asynchronously collects
      * {@link ICallService} implementations and passes them along with the handle and contactInfo
      * to {@link #placeOutgoingCallInternal} to actually place the call.
      *
-     * @param handle The handle to dial.
-     * @param contactInfo Information about the entity being called.
+     * @param handle The handle to dial.  Marked as final so it can be used in the inner class.
+     * @param contactInfo Information about the entity being called. Marked as final so it can
+     *     be used in the inner class.
      * @param context The application context.
      */
-    void placeOutgoingCall(final String handle, final ContactInfo contactInfo,
-            final Context context) {
+    void placeOutgoingCall(String handle, ContactInfo contactInfo, Context context) {
+        callServiceFinder.initiateLookup(context);
 
-        CallServiceFinder.findCallServices(context, new CallServiceSearchCallback() {
-            @Override
-            public void onSearchComplete(List<ICallService> callServices) {
-                try {
-                    placeOutgoingCallInternal(handle, contactInfo, callServices);
-                } catch (CallServiceUnavailableException e) {
-                    // TODO(santoscordon): Handle error
-                }
-            }
-        });
+        // TODO(gilad): Persist the necessary parameters to attempt putting the call through
+        // once the call services become available (likely using some sort of closure).
     }
 
     /**
      * Places an outgoing call to the handle passed in. Given a list of {@link ICallServices},
      * select one and place a call to the handle.
      * TODO(santoscordon): How does the CallService selection process work?
+     * TODO(gilad): Wire this logic from CallServiceFinder.updateSwitchboard.
      *
      * @param handle The handle to dial.
      * @param contactInfo Information about the entity being called.
      * @param callServices The list of available {@link ICallService}s.
      */
-    private void placeOutgoingCallInternal(String handle, ContactInfo contactInfo,
-            List<ICallService> callServices) throws CallServiceUnavailableException {
-        Log.i(TAG, "Placing and outgoing call.");
-
-        if (callServices.isEmpty()) {
-            // No call services, bail out.
-            // TODO(contacts-team): Add logging?
-            // TODO(santoscordon): Does this actually go anywhere considering this method is now
-            // asynchronous?
-            throw new CallServiceUnavailableException("No CallService found.");
-        }
-
-        List<ICallService> compatibleCallServices = Lists.newArrayList();
-        for (ICallService service : callServices) {
-            // TODO(santoscordon): This code needs to be updated to an asynchronous response
-            // callback from isCompatibleWith().
-            /* if (service.isCompatibleWith(handle)) {
-                // NOTE(android-contacts): If we end up taking the liberty to issue
-                // calls not using the explicit user input (in case one is provided)
-                // and instead pull an alternative method of communication from the
-                // specified user-info object, it may be desirable to give precedence
-                // to services that can in fact respect the user's intent.
-                compatibleCallServices.add(service);
-            }
-            */
-        }
-
-        if (compatibleCallServices.isEmpty()) {
-            // None of the available call services is suitable for making this call.
-            // TODO(contacts-team): Same here re logging.
-            throw new CallServiceUnavailableException("No compatible CallService found.");
-        }
-
-        // NOTE(android-team): At this point we can also prompt the user for
-        // preference, i.e. instead of the logic just below.
-        if (compatibleCallServices.size() > 1) {
-            compatibleCallServices = sort(compatibleCallServices);
-        }
-        for (ICallService service : compatibleCallServices) {
-            try {
-                service.call(handle);
-                return;
-            } catch (RemoteException e) {
-                // TODO(santoscordon): Need some proxy for ICallService so that we don't have to
-                // avoid RemoteExceptionHandling everywhere. Take a look at how InputMethodService
-                // handles this.
-            }
-            // catch (OutgoingCallException ignored) {
-            // TODO(santoscordon): Figure out how OutgoingCallException falls into this. Should
-            // RemoteExceptions also be converted to OutgoingCallExceptions thrown by call()?
-        }
-    }
+//    private void placeOutgoingCallInternal(
+//            String handle,
+//            ContactInfo contactInfo,
+//            List<ICallService> callServices) throws CallServiceUnavailableException {
+//
+//        Log.i(TAG, "Placing and outgoing call.");
+//
+//        if (callServices.isEmpty()) {
+//            // No call services, bail out.
+//            // TODO(contacts-team): Add logging?
+//            // TODO(santoscordon): Does this actually go anywhere considering this method is now
+//            // asynchronous?
+//            throw new CallServiceUnavailableException("No CallService found.");
+//        }
+//
+//        List<ICallService> compatibleCallServices = Lists.newArrayList();
+//        for (ICallService service : callServices) {
+//            // TODO(santoscordon): This code needs to be updated to an asynchronous response
+//            // callback from isCompatibleWith().
+//            /* if (service.isCompatibleWith(handle)) {
+//                // NOTE(android-contacts): If we end up taking the liberty to issue
+//                // calls not using the explicit user input (in case one is provided)
+//                // and instead pull an alternative method of communication from the
+//                // specified user-info object, it may be desirable to give precedence
+//                // to services that can in fact respect the user's intent.
+//                compatibleCallServices.add(service);
+//            }
+//            */
+//        }
+//
+//        if (compatibleCallServices.isEmpty()) {
+//            // None of the available call services is suitable for making this call.
+//            // TODO(contacts-team): Same here re logging.
+//            throw new CallServiceUnavailableException("No compatible CallService found.");
+//        }
+//
+//        // NOTE(android-team): At this point we can also prompt the user for
+//        // preference, i.e. instead of the logic just below.
+//        if (compatibleCallServices.size() > 1) {
+//            compatibleCallServices = sort(compatibleCallServices);
+//        }
+//        for (ICallService service : compatibleCallServices) {
+//            try {
+//                service.call(handle);
+//                return;
+//            } catch (RemoteException e) {
+//                // TODO(santoscordon): Need some proxy for ICallService so that we don't have to
+//                // avoid RemoteExceptionHandling everywhere. Take a look at how InputMethodService
+//                // handles this.
+//            }
+//            // catch (OutgoingCallException ignored) {
+//            // TODO(santoscordon): Figure out how OutgoingCallException falls into this. Should
+//            // RemoteExceptions also be converted to OutgoingCallExceptions thrown by call()?
+//        }
+//    }
 
     /**
-     * Sorts a list of {@link ICallService} ordered by the prefered service for dialing the call.
+     * Sorts a list of {@link ICallService} ordered by the preferred service for dialing the call.
      *
      * @param callServices The list to order.
      */