Use TelephonyCallServiceSelector as fallback

Also added a CallServiceSelectorWrapper.

Change-Id: I49ff7a372dbee270735f7cc13f3bf7a9766c04f0
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 82bde9e..57074b7 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -20,7 +20,6 @@
 import android.telecomm.CallInfo;
 import android.telecomm.CallState;
 
-import com.android.internal.telecomm.ICallServiceSelector;
 import com.google.android.collect.Sets;
 import com.google.common.base.Preconditions;
 
@@ -65,9 +64,8 @@
 
     /**
      * The call-service selector for this call.
-     * TODO(gilad): Switch to using a wrapper object, see {@link #mCallService}.
      */
-    private ICallServiceSelector mCallServiceSelector;
+    private CallServiceSelectorWrapper mCallServiceSelector;
 
     /** Read-only and parcelable version of this call. */
     private CallInfo mCallInfo;
@@ -188,7 +186,7 @@
         }
     }
 
-    void setCallServiceSelector(ICallServiceSelector selector) {
+    void setCallServiceSelector(CallServiceSelectorWrapper selector) {
         Preconditions.checkNotNull(selector);
         mCallServiceSelector = selector;
     }
diff --git a/src/com/android/telecomm/CallServiceSelectorRepository.java b/src/com/android/telecomm/CallServiceSelectorRepository.java
index 6203ffd..0ec805f 100644
--- a/src/com/android/telecomm/CallServiceSelectorRepository.java
+++ b/src/com/android/telecomm/CallServiceSelectorRepository.java
@@ -19,77 +19,35 @@
 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.Handler;
-import android.os.IBinder;
-import android.os.Looper;
 import android.telecomm.TelecommConstants;
 
 import com.android.internal.telecomm.ICallServiceSelector;
-import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Maps;
 
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 
 /**
  * Helper class to retrieve {@link ICallServiceSelector} implementations on the device and
- * asynchronously bind to them.  Each lookup cycle is time-boxed, hence selectors too slow
- * to bind are effectively omitted from the set that is passed back to {@link Switchboard}.
+ * asynchronously bind to them.
  */
 final class CallServiceSelectorRepository {
 
-    /**
-     * Used to interrupt lookup cycles that didn't terminate naturally within the allowed
-     * period, see {@link Timeouts#getSelectorLookupMs()}.
-     */
-    private final Runnable mLookupTerminator = new Runnable() {
-        @Override
-        public void run() {
-            Log.d(CallServiceSelectorRepository.this, "Timed out processing selectors");
-            terminateLookup();
-        }
-    };
-
-    /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-
     private final Switchboard mSwitchboard;
 
     /** The application context. */
     private final Context mContext;
 
     /**
-     * Determines whether or not a lookup cycle is already running.
+     * The set of call-service selectors. Only populated via initiateLookup scenarios.
      */
-    private boolean mIsLookupInProgress = false;
-
-    /**
-     * The current lookup-cycle ID, unique per invocation of {@link #initiateLookup}.
-     */
-    private int mLookupId = 0;
-
-    /**
-     * The set of bound call-service selectors.  Only populated via initiateLookup scenarios.
-     * Selectors should only be removed upon unbinding.
-     */
-    private final Set<ICallServiceSelector> mSelectorRegistry = Sets.newHashSet();
-
-    /**
-     * Stores the names of the selectors to bind to in one lookup cycle.  The set size represents
-     * the number of call-service selectors this repositories expects to hear back from upon
-     * initiating lookups, see initiateLookup. Whenever all selectors respond before the timeout
-     * occurs, the complete set of available selectors 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
-     * selectors do not require finding and hence are excluded from this set.  Also note that
-     * selectors are removed from this set as they register.
-     */
-    private final Set<ComponentName> mUnregisteredSelectors = Sets.newHashSet();
+    private final Map<ComponentName, CallServiceSelectorWrapper> mCallServiceSelectors =
+            Maps.newHashMap();
 
     /**
      * Persists the specified parameters and initializes the new instance.
@@ -108,47 +66,16 @@
      */
     void initiateLookup(int lookupId) {
         ThreadUtil.checkOnMainThread();
-        if (mIsLookupInProgress) {
-            // At most one active lookup is allowed at any given time, bail out.
-            return;
-        }
 
         List<ComponentName> selectorNames = getSelectorNames();
-        if (selectorNames.isEmpty()) {
-            Log.i(this, "No ICallServiceSelector implementations found.");
-            updateSwitchboard();
-            return;
-        }
-
-        mLookupId = lookupId;
-        mIsLookupInProgress = true;
-        mUnregisteredSelectors.clear();
-
         for (ComponentName name : selectorNames) {
-            if (!mSelectorRegistry.contains(name)) {
-                // The selector is either not yet registered or has been unregistered
-                // due to unbinding etc.
-                mUnregisteredSelectors.add(name);
-                bindSelector(name, lookupId);
+            if (!mCallServiceSelectors.containsKey(name)) {
+                mCallServiceSelectors.put(name, new CallServiceSelectorWrapper(name));
             }
         }
 
-        int selectorCount = selectorNames.size();
-        int unregisteredSelectorCount = mUnregisteredSelectors.size();
-
-        Log.i(this, "Found %d implementations of ICallServiceSelector, %d of which are not " +
-                "currently registered.", selectorCount , unregisteredSelectorCount);
-
-        if (unregisteredSelectorCount == 0) {
-            // All known (selector) implementations are already registered, pass control
-            // back to the switchboard.
-            updateSwitchboard();
-        } else {
-            // Schedule a lookup terminator to run after Timeouts.getSelectorLookupMs()
-            // milliseconds.
-            mHandler.removeCallbacks(mLookupTerminator);
-            mHandler.postDelayed(mLookupTerminator, Timeouts.getSelectorLookupMs());
-        }
+        Log.i(this, "Found %d implementations of ICallServiceSelector", selectorNames.size());
+        updateSwitchboard();
     }
 
     /**
@@ -174,84 +101,22 @@
     }
 
     /**
-     * Attempts to bind the specified selector and have it register upon successful binding.
-     * Also performs the necessary wiring to unregister the selector upon un-binding.
-     *
-     * @param selectorName The component name of the relevant selector.
-     * @param lookupId The lookup-cycle ID.
-     */
-    private void bindSelector(
-            final ComponentName selectorName, final int lookupId) {
-
-        Preconditions.checkNotNull(selectorName);
-
-        Intent serviceIntent = new Intent(
-                TelecommConstants.ACTION_CALL_SERVICE_SELECTOR).setComponent(selectorName);
-        Log.i(this, "Binding to ICallServiceSelector through %s", serviceIntent);
-
-        // Connection object for the service binding.
-        ServiceConnection connection = new ServiceConnection() {
-            @Override
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                ICallServiceSelector selector = ICallServiceSelector.Stub.asInterface(service);
-                registerSelector(lookupId, selectorName, selector);
-            }
-
-            @Override
-            public void onServiceDisconnected(ComponentName className) {
-                unregisterSelector(selectorName);
-            }
-        };
-
-        if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
-            // TODO(gilad): Handle error.
-        }
-    }
-
-    /**
-     * Registers the specified selector.
-     *
-     * @param lookupId The lookup-cycle ID.  Currently unused, consider removing.
-     * @param selectorName The component name of the relevant selector.
-     * @param selector The selector object to register.
-     */
-    private void registerSelector(
-            int lookupId, ComponentName selectorName, ICallServiceSelector selector) {
-
-        ThreadUtil.checkOnMainThread();
-
-        if (mUnregisteredSelectors.remove(selectorName)) {
-            mSelectorRegistry.add(selector);
-            if (mUnregisteredSelectors.size() < 1) {
-                terminateLookup();  // No other selectors to wait for.
-            }
-        }
-    }
-
-    /**
-     * Unregisters the specified selector.
-     *
-     * @param selectorName The component name of the relevant selector.
-     */
-    private void unregisterSelector(ComponentName selectorName) {
-        mSelectorRegistry.remove(selectorName);
-    }
-
-    /**
-     * Timeouts the current lookup cycle, see LookupTerminator.
-     */
-    private void terminateLookup() {
-        mHandler.removeCallbacks(mLookupTerminator);
-        updateSwitchboard();
-    }
-
-    /**
      * Updates the switchboard passing the relevant call services selectors.
      */
     private void updateSwitchboard() {
         ThreadUtil.checkOnMainThread();
 
-        mSwitchboard.setSelectors(mSelectorRegistry);
-        mIsLookupInProgress = false;
+        List<CallServiceSelectorWrapper> selectors = Lists.newLinkedList();
+        for (CallServiceSelectorWrapper selector : mCallServiceSelectors.values()) {
+            if (TelephonyUtil.isTelephonySelector(selector)) {
+                // Add telephony selectors to the end to serve as a fallback.
+                selectors.add(selector);
+            } else {
+                // TODO(sail): Need a way to order selectors.
+                selectors.add(0, selector);
+            }
+        }
+
+        mSwitchboard.setSelectors(ImmutableList.copyOf((selectors)));
     }
 }
diff --git a/src/com/android/telecomm/CallServiceSelectorWrapper.java b/src/com/android/telecomm/CallServiceSelectorWrapper.java
new file mode 100644
index 0000000..a535798
--- /dev/null
+++ b/src/com/android/telecomm/CallServiceSelectorWrapper.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telecomm;
+
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telecomm.CallInfo;
+import android.telecomm.CallServiceDescriptor;
+import android.telecomm.TelecommConstants;
+import android.telecomm.CallServiceSelector.CallServiceSelectionResponse;
+
+import com.google.common.base.Preconditions;
+import com.android.internal.telecomm.ICallServiceSelectionResponse;
+import com.android.internal.telecomm.ICallServiceSelector;
+
+import java.util.List;
+
+/**
+ * Wrapper for {@link ICallServiceSelector}s, handles binding and keeps track of when the object can
+ * safely be unbound.
+ */
+final class CallServiceSelectorWrapper extends ServiceBinder<ICallServiceSelector> {
+    class SelectionResponseImpl extends ICallServiceSelectionResponse.Stub {
+        private final CallServiceSelectionResponse mResponse;
+
+        SelectionResponseImpl(CallServiceSelectionResponse response) {
+            mResponse = response;
+        }
+
+        @Override
+        public void setSelectedCallServiceDescriptors(
+                final List<CallServiceDescriptor> descriptors) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mResponse.setSelectedCallServices(descriptors);
+                }
+            });
+        }
+    }
+
+    private ICallServiceSelector mSelectorInterface;
+
+    private Binder mBinder = new Binder();
+
+    private Handler mHandler = new Handler();
+
+    /**
+     * Creates a call-service selector for the specified component.
+     *
+     * @param componentName The component name of the service.
+     */
+    CallServiceSelectorWrapper(ComponentName componentName) {
+        super(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR, componentName);
+    }
+
+    /**
+     * Retrieves the sorted set of call services that are preferred by this selector. Upon failure,
+     * the error callback is invoked. Can be invoked even when the call service is unbound.
+     *
+     * @param callInfo The details of the call.
+     * @param selectionResponse The selection response callback to invoke upon success.
+     * @param errorCallback The callback to invoke upon failure.
+     */
+    void select(final CallInfo callInfo, final List<CallServiceDescriptor> callServiceDescriptors,
+            final CallServiceSelectionResponse selectionResponse, final Runnable errorCallback) {
+        BindCallback callback = new BindCallback() {
+            @Override
+            public void onSuccess() {
+                if (isServiceValid("select")) {
+                    try {
+                        mSelectorInterface.select(callInfo, callServiceDescriptors,
+                                new SelectionResponseImpl(selectionResponse));
+                    } catch (RemoteException e) {
+                        Log.e(CallServiceSelectorWrapper.this, e, "Failed calling select for selector: %s.",
+                                getComponentName());
+                    }
+                }
+            }
+
+            @Override
+            public void onFailure() {
+                errorCallback.run();
+            }
+        };
+
+        mBinder.bind(callback);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setServiceInterface(IBinder binder) {
+        mSelectorInterface = ICallServiceSelector.Stub.asInterface(binder);
+    }
+}
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index d69aa96..426a019 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -49,7 +49,7 @@
     private Binder mBinder = new Binder();
 
     /**
-     * Creates a call-service provider for the specified component.
+     * Creates a call-service provider for the specified descriptor.
      *
      * @param descriptor The call-service descriptor from
      *         {@link ICallServiceProvider#lookupCallServices}.
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index bbcdb17..3d41fe7 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -21,13 +21,13 @@
 import android.os.RemoteException;
 import android.telecomm.CallState;
 import android.telecomm.CallServiceDescriptor;
+import android.telecomm.CallServiceSelector.CallServiceSelectionResponse;
 
-import com.android.internal.telecomm.ICallServiceSelectionResponse;
-import com.android.internal.telecomm.ICallServiceSelector;
 import com.google.android.collect.Sets;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Lists;
 
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -79,10 +79,7 @@
     /**
      * The list of currently-available call-service selector implementations.
      */
-    private final List<ICallServiceSelector> mSelectors;
-
-    /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Collection<CallServiceSelectorWrapper> mSelectors;
 
     /** Manages all outgoing call processors. */
     private final OutgoingCallsManager mOutgoingCallsManager;
@@ -95,12 +92,18 @@
         }
     };
 
+    private final Runnable mNextSelectorCallback = new Runnable() {
+        @Override public void run() {
+            attemptNextSelector();
+        }
+    };
+
     /**
      * The iterator over the currently-selected ordered list of call-service descriptors.
      */
     private Iterator<CallServiceDescriptor> mCallServiceDescriptorIterator;
 
-    private Iterator<ICallServiceSelector> mSelectorIterator;
+    private Iterator<CallServiceSelectorWrapper> mSelectorIterator;
 
     private boolean mIsAborted = false;
 
@@ -120,7 +123,7 @@
     OutgoingCallProcessor(
             Call call,
             Set<CallServiceWrapper> callServices,
-            List<ICallServiceSelector> selectors,
+            Collection<CallServiceSelectorWrapper> selectors,
             OutgoingCallsManager outgoingCallsManager,
             Switchboard switchboard) {
 
@@ -247,16 +250,17 @@
         }
 
         if (mSelectorIterator.hasNext()) {
-            ICallServiceSelector selector = mSelectorIterator.next();
+            CallServiceSelectorWrapper selector = mSelectorIterator.next();
             mCall.setCallServiceSelector(selector);
 
-            ICallServiceSelectionResponse.Stub response = createSelectionResponse();
-            try {
-                selector.select(mCall.toCallInfo(), mCallServiceDescriptors, response);
-            } catch (RemoteException e) {
-                attemptNextSelector();
-            }
-
+            CallServiceSelectionResponse responseCallback = new CallServiceSelectionResponse() {
+                    @Override
+                    public void setSelectedCallServices(List<CallServiceDescriptor> callServices) {
+                        processSelectedCallServiceDescriptors(callServices);
+                    }
+                };
+            selector.select(mCall.toCallInfo(), mCallServiceDescriptors, responseCallback,
+                    mNextSelectorCallback);
         } else {
             Log.v(this, "attemptNextSelector, no more selectors, failing");
             mOutgoingCallsManager.handleFailedOutgoingCall(mCall, false /* isAborted */);
@@ -264,25 +268,6 @@
     }
 
     /**
-     * @return A new selection-response object that's wired to run on the main (UI) thread.
-     */
-    private ICallServiceSelectionResponse.Stub createSelectionResponse() {
-        return new ICallServiceSelectionResponse.Stub() {
-            @Override public void setSelectedCallServiceDescriptors(
-                    final List<CallServiceDescriptor> selectedCallServiceDescriptors) {
-
-                Runnable runnable = new Runnable() {
-                    @Override public void run() {
-                        processSelectedCallServiceDescriptors(selectedCallServiceDescriptors);
-                    }
-                };
-
-                mHandler.post(runnable);
-            }
-        };
-    }
-
-    /**
      * Persists the ordered-list of call-service descriptor as selected by the current selector and
      * starts iterating through the corresponding call services continuing the attempt to place the
      * call.
diff --git a/src/com/android/telecomm/OutgoingCallsManager.java b/src/com/android/telecomm/OutgoingCallsManager.java
index 37f7eb1..50c24ea 100644
--- a/src/com/android/telecomm/OutgoingCallsManager.java
+++ b/src/com/android/telecomm/OutgoingCallsManager.java
@@ -19,7 +19,7 @@
 import com.android.internal.telecomm.ICallServiceSelector;
 import com.google.common.collect.Maps;
 
-import java.util.List;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
@@ -54,7 +54,9 @@
      * @param selectors The ordered list of selectors used in placing the call.
      */
     void placeCall(
-            Call call, Set<CallServiceWrapper> callServices, List<ICallServiceSelector> selectors) {
+            Call call,
+            Set<CallServiceWrapper> callServices,
+            Collection<CallServiceSelectorWrapper> selectors) {
 
         Log.i(this, "Placing an outgoing call (%s)", call.getId());
 
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 8a3fc81..d8c57fb 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -16,6 +16,9 @@
 
 package com.android.telecomm;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
@@ -26,16 +29,18 @@
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
 
-import com.android.internal.telecomm.ICallServiceSelector;
-
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
 /**
- * Switchboard is responsible for (1) gathering the {@link CallServiceWrapper}s and
- * {@link ICallServiceSelector}s through which to place outgoing calls, (2) starting outgoing calls
- * (via {@link OutgoingCallsManager} and (3) switching active calls between call services.
+ * Switchboard is responsible for:
+ * <ul>
+ * <li> gathering the {@link CallServiceWrapper}s and {@link CallServiceSelectorWrapper}s through which to place
+ * outgoing calls
+ * <li> starting outgoing calls (via {@link OutgoingCallsManager}
+ * <li> switching active calls between call services.
+ * </ul>
  */
 final class Switchboard {
 
@@ -87,7 +92,7 @@
      * see {@link CallServiceSelectorRepository}.
      * TODO(gilad): Clear once the active-call count goes to zero.
      */
-    private final Set<ICallServiceSelector> mSelectors = Sets.newHashSet();
+    private ImmutableCollection<CallServiceSelectorWrapper> mSelectors = ImmutableList.of();
 
     /**
      * The current lookup-cycle ID used with the repositories. Incremented with each invocation
@@ -126,7 +131,7 @@
         // 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.clear();
+        mSelectors = ImmutableList.of();
 
         mNewOutgoingCalls.add(call);
 
@@ -175,22 +180,19 @@
      * Persists the specified list of selectors and attempts to connect any pending outgoing
      * calls.  Intended to be invoked by {@link CallServiceSelectorRepository} exclusively.
      *
-     * @param selectors The potentially-partial set of selectors.  Partial since the lookup
-     *     procedure is time-boxed such that some selectors may be slow to respond and hence
-     *     effectively omitted from the specified set.
+     * @param selectors Collection of selectors. The order of the collection determines the order in
+     *     which the selectors are tried.
      */
-    void setSelectors(Set<ICallServiceSelector> selectors) {
-        // TODO(santoscordon): This should take in CallServiceSelectorWrapper instead of the direct
-        // ICallServiceSelector implementation. Copy what we have for CallServiceWrapper. Also need
-        // to invoke updateBinders(selectors) once this to-do is addressed.
+    void setSelectors(ImmutableCollection<CallServiceSelectorWrapper> selectors) {
+        // TODO(santoscordon):: Need to invoke updateBinders(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.  May want to use a LinkedHashSet for the sorted set.
-        mSelectors.clear();
-        mSelectors.addAll(selectors);
+        // that's probably preferred.
+        mSelectors = selectors;
         processNewOutgoingCalls();
     }
 
@@ -294,12 +296,7 @@
      * @param call The call to place.
      */
     private void processNewOutgoingCall(Call call) {
-        // Convert to (duplicate-free) list to aid index-based iteration, see the comment under
-        // setSelectors regarding using LinkedHashSet instead.
-        List<ICallServiceSelector> selectors = Lists.newArrayList();
-        selectors.addAll(mSelectors);
-
-        mOutgoingCallsManager.placeCall(call, mCallServices, selectors);
+        mOutgoingCallsManager.placeCall(call, mCallServices, mSelectors);
     }
 
     /**
diff --git a/src/com/android/telecomm/TelephonyUtil.java b/src/com/android/telecomm/TelephonyUtil.java
new file mode 100644
index 0000000..7a9ac22
--- /dev/null
+++ b/src/com/android/telecomm/TelephonyUtil.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telecomm;
+
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.telecomm.CallServiceDescriptor;
+
+/**
+ * Utilities to deal with the system telephony services. The system telephony services are treated
+ * differently from 3rd party services in some situations (emergency calls, audio focus, etc...).
+ */
+public final class TelephonyUtil {
+    private static final String TAG = ThreadUtil.class.getSimpleName();
+
+    private static final String TELEPHONY_PACKAGE_NAME =
+            "com.android.phone";
+
+    private static final String GSM_CALL_SERVICE_CLASS_NAME =
+            "com.android.services.telephony.GsmCallService";
+
+    private static final String CDMA_CALL_SERVICE_CLASS_NAME =
+            "com.android.services.telephony.CdmaCallService";
+
+    private TelephonyUtil() {}
+
+    static boolean isTelephonySelector(CallServiceSelectorWrapper selector) {
+        return selector.getComponentName().getPackageName().equals(TELEPHONY_PACKAGE_NAME);
+    }
+
+    /**
+     * Returns whether or not the call is currently connected as a cellular call (through the
+     * device's cellular radio).
+     */
+    static boolean isCurrentlyPSTNCall(Call call) {
+        if (Log.DEBUG) {
+            verifyCallServiceExists(GSM_CALL_SERVICE_CLASS_NAME);
+            verifyCallServiceExists(CDMA_CALL_SERVICE_CLASS_NAME);
+        }
+
+        CallServiceWrapper callService = call.getCallService();
+        if (callService == null) {
+            return false;
+        }
+        CallServiceDescriptor descriptor = callService.getDescriptor();
+        String className = descriptor.getServiceComponent().getClassName();
+        return className.equals(GSM_CALL_SERVICE_CLASS_NAME) ||
+                className.equals(CDMA_CALL_SERVICE_CLASS_NAME);
+    }
+
+    private static void verifyCallServiceExists(String serviceName) {
+        PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
+        try {
+            ServiceInfo info = packageManager.getServiceInfo(
+                    new ComponentName(TELEPHONY_PACKAGE_NAME, serviceName), 0);
+            if (info == null) {
+                Log.wtf(TAG, "Error, unable to find call service: %s", serviceName);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.wtf(TAG, e, "Error, exception while trying to find call service: %s", serviceName);
+        }
+    }
+}
diff --git a/src/com/android/telecomm/Timeouts.java b/src/com/android/telecomm/Timeouts.java
index 0fab3c4..4096c02 100644
--- a/src/com/android/telecomm/Timeouts.java
+++ b/src/com/android/telecomm/Timeouts.java
@@ -54,14 +54,6 @@
     }
 
     /**
-     * @return The longest period in milliseconds each {@link CallServiceSelector} lookup cycle is
-     *     allowed to span over.
-     */
-    public static long getSelectorLookupMs() {
-        return get("selector_lookup_ms", 1000);
-    }
-
-    /**
      * @return How frequently, in milliseconds, to run {@link Switchboard}'s clean-up "tick" cycle.
      */
     public static long getTickMs() {