Add emergency call service selector.

Change-Id: I85b8c0a6c6d2db668caaf27abe6b022e8e06cc8c
diff --git a/src/com/android/telecomm/CallServiceAdapter.java b/src/com/android/telecomm/CallServiceAdapter.java
index 2db6255..195ac17 100644
--- a/src/com/android/telecomm/CallServiceAdapter.java
+++ b/src/com/android/telecomm/CallServiceAdapter.java
@@ -174,7 +174,7 @@
     /** {@inheritDoc} */
     @Override
     public void setIsCompatibleWith(String callId, boolean isCompatible) {
-        Log.v(this, "setIsCompatibleWith id: %d, isCompatible: %b", callId, isCompatible);
+        Log.v(this, "setIsCompatibleWith id: %s, isCompatible: %b", callId, isCompatible);
         mCallIdMapper.checkValidCallId(callId);
         mHandler.obtainMessage(MSG_SET_IS_COMPATIBLE_WITH, isCompatible ? 1 : 0, 0, callId).
                 sendToTarget();
diff --git a/src/com/android/telecomm/CallServiceSelectorRepository.java b/src/com/android/telecomm/CallServiceSelectorRepository.java
index 50d26e8..709d440 100644
--- a/src/com/android/telecomm/CallServiceSelectorRepository.java
+++ b/src/com/android/telecomm/CallServiceSelectorRepository.java
@@ -93,8 +93,9 @@
             ServiceInfo serviceInfo = entry.serviceInfo;
             if (serviceInfo != null) {
                 // The entry resolves to a proper service, add it to the list of selector names.
-                selectorNames.add(
-                        new ComponentName(serviceInfo.packageName, serviceInfo.name));
+                ComponentName componentName =
+                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
+                selectorNames.add(componentName);
             }
         }
 
diff --git a/src/com/android/telecomm/CallServiceSelectorWrapper.java b/src/com/android/telecomm/CallServiceSelectorWrapper.java
index f4ddf19..75aab41 100644
--- a/src/com/android/telecomm/CallServiceSelectorWrapper.java
+++ b/src/com/android/telecomm/CallServiceSelectorWrapper.java
@@ -25,9 +25,10 @@
 import android.telecomm.CallServiceSelector;
 import android.telecomm.TelecommConstants;
 
-import com.google.common.base.Preconditions;
+import com.android.internal.telecomm.ICallServiceSelectionResponse;
 import com.android.internal.telecomm.ICallServiceSelector;
 import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+import com.google.common.base.Preconditions;
 
 import java.util.List;
 
@@ -43,15 +44,42 @@
     private final CallServiceSelectorAdapter mAdapter;
 
     /**
-     * Creates a call-service selector for the specified component.
+     * Creates a call-service selector for the specified component using the specified action to
+     * bind to it.
+     *
+     * @param action The action used to bind to the selector.
+     * @param componentName The component name of the service.
+     * @param callsManager The calls manager.
+     * @param outgoingCallsManager The outgoing calls manager.
+     */
+    CallServiceSelectorWrapper(
+            String action,
+            ComponentName componentName,
+            CallsManager callsManager,
+            OutgoingCallsManager outgoingCallsManager) {
+
+        super(action, componentName);
+        mAdapter =
+                new CallServiceSelectorAdapter(callsManager, outgoingCallsManager, mCallIdMapper);
+    }
+
+    /**
+     * Creates a call-service selector for specified component and uses
+     * {@link TelecommConstants#ACTION_CALL_SERVICE_SELECTOR} as the action to bind.
      *
      * @param componentName The component name of the service.
+     * @param callsManager The calls manager.
+     * @param outgoingCallsManager The outgoing calls manager.
      */
-    CallServiceSelectorWrapper(ComponentName componentName, CallsManager callsManager,
+    CallServiceSelectorWrapper(
+            ComponentName componentName,
+            CallsManager callsManager,
             OutgoingCallsManager outgoingCallsManager) {
-        super(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR, componentName);
-        mAdapter = new CallServiceSelectorAdapter(callsManager, outgoingCallsManager,
-                mCallIdMapper);
+
+        this(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR,
+                componentName,
+                callsManager,
+                outgoingCallsManager);
     }
 
     /** See {@link CallServiceSelector#setCallServiceSelectorAdapter}. */
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 3e8a42e..c82b04d 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -188,7 +188,7 @@
      * @param handle Handle to connect the call with.
      * @param contactInfo Information about the entity being called.
      * @param gatewayInfo Optional gateway information that can be used to route the call to the
-     *     actual dialed handle via a gateway provider. May be null.
+     *         actual dialed handle via a gateway provider. May be null.
      */
     void placeOutgoingCall(Uri handle, ContactInfo contactInfo, GatewayInfo gatewayInfo) {
         for (OutgoingCallValidator validator : mOutgoingCallValidators) {
@@ -207,7 +207,7 @@
             Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s",
                     Log.pii(uriHandle), Log.pii(handle));
         }
-        Call call = new Call(uriHandle, contactInfo, gatewayInfo, false /*isIncoming*/);
+        Call call = new Call(uriHandle, contactInfo, gatewayInfo, false /* isIncoming */);
         setCallState(call, CallState.DIALING);
         addCall(call);
         mSwitchboard.placeOutgoingCall(call);
diff --git a/src/com/android/telecomm/EmergencyCallServiceSelector.java b/src/com/android/telecomm/EmergencyCallServiceSelector.java
new file mode 100644
index 0000000..d5f2774
--- /dev/null
+++ b/src/com/android/telecomm/EmergencyCallServiceSelector.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telecomm;
+
+import android.net.Uri;
+import android.telecomm.CallInfo;
+import android.telecomm.CallServiceDescriptor;
+import android.telecomm.CallServiceSelector;
+import android.telecomm.CallServiceSelectorAdapter;
+import android.telephony.PhoneNumberUtils;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Selects call-services which can place emergency calls. For emergency handles, this selector is
+ * always the first selector attempted when placing a call, see
+ * {@link Switchboard#processNewOutgoingCall}. If this is ever invoked for a non-emergency handle,
+ * this selector returns zero call services so that call-service selection continues to the next
+ * selector. For emergency calls, it selects telephony's PSTN call services so that they are the
+ * first ones to try to place the call.
+ */
+public class EmergencyCallServiceSelector extends CallServiceSelector {
+    CallServiceSelectorAdapter mAdapter = null;
+
+    /**
+     * Returns true if the handle passed in is to a potential emergency number.
+     */
+    static boolean shouldUseSelector(Uri handle) {
+        return PhoneNumberUtils.isPotentialLocalEmergencyNumber(
+                handle.getSchemeSpecificPart(), TelecommApp.getInstance());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setCallServiceSelectorAdapter(CallServiceSelectorAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
+        List<CallServiceDescriptor> selectedDescriptors = Lists.newArrayList();
+
+        // We check to see if the handle is potentially for an emergency call. *Potentially* means
+        // that we match both the full number and prefix (e.g., "911444" matches 911). After the
+        // call is made, the telephony call services will inform us of the actual number that was
+        // connected, which would be 911. This is why we check *potential* APIs before, but use the
+        // exact {@link PhoneNumberUtils#isLocalEmergencyNumber} once the call is connected.
+        if (shouldUseSelector(callInfo.getHandle())) {
+            // Search for and return the pstn call services if found.
+            for (CallServiceDescriptor descriptor : descriptors) {
+                // TODO(santoscordon): Consider adding some type of CAN_MAKE_EMERGENCY_CALLS
+                // capability for call services and relying on that. Also consider combining this
+                // with a permission so that we can check that instead of relying on hardcoded
+                // paths.
+                if (TelephonyUtil.isPstnCallService(descriptor)) {
+                    selectedDescriptors.add(descriptor);
+                }
+            }
+        }
+
+        if (mAdapter != null) {
+            mAdapter.setSelectedCallServices(callInfo.getId(), selectedDescriptors);
+        }
+    }
+}
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 77c3c16..ccb6b80 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -16,12 +16,7 @@
 
 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;
-
+import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -29,18 +24,21 @@
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+
+import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Set;
 
 /**
  * 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>
+ * - 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 {
 
@@ -149,7 +147,7 @@
      * @param call The call object.
      * @param descriptor The relevant call-service descriptor.
      * @param extras The optional extras passed via
-     *     {@link TelecommConstants#EXTRA_INCOMING_CALL_EXTRAS}
+     *         {@link TelecommConstants#EXTRA_INCOMING_CALL_EXTRAS}
      */
     void retrieveIncomingCall(Call call, CallServiceDescriptor descriptor, Bundle extras) {
         Log.d(this, "retrieveIncomingCall");
@@ -295,7 +293,33 @@
      * @param call The call to place.
      */
     private void processNewOutgoingCall(Call call) {
-        mOutgoingCallsManager.placeCall(call, mCallServices, mSelectors);
+        Collection<CallServiceSelectorWrapper> selectors = mSelectors;
+
+        boolean useEmergencySelector =
+                EmergencyCallServiceSelector.shouldUseSelector(call.getHandle());
+        Log.d(this, "processNewOutgoingCall, isEmergency=%b", useEmergencySelector);
+
+        if (useEmergencySelector) {
+            // This is potentially an emergency call so add the emergency selector before the
+            // other selectors.
+            ImmutableList.Builder<CallServiceSelectorWrapper> selectorsBuilder =
+                    ImmutableList.builder();
+
+            ComponentName componentName = new ComponentName(
+                    TelecommApp.getInstance(), EmergencyCallServiceSelector.class);
+            CallServiceSelectorWrapper emergencySelector =
+                    new CallServiceSelectorWrapper(
+                            componentName.flattenToShortString(),
+                            componentName,
+                            mCallsManager,
+                            mOutgoingCallsManager);
+
+            selectorsBuilder.add(emergencySelector);
+            selectorsBuilder.addAll(mSelectors);
+            selectors = selectorsBuilder.build();
+        }
+
+        mOutgoingCallsManager.placeCall(call, mCallServices, selectors);
     }
 
     /**
diff --git a/src/com/android/telecomm/TelephonyUtil.java b/src/com/android/telecomm/TelephonyUtil.java
index 7a9ac22..be501f0 100644
--- a/src/com/android/telecomm/TelephonyUtil.java
+++ b/src/com/android/telecomm/TelephonyUtil.java
@@ -43,6 +43,17 @@
         return selector.getComponentName().getPackageName().equals(TELEPHONY_PACKAGE_NAME);
     }
 
+    static boolean isPstnCallService(CallServiceDescriptor descriptor) {
+        ComponentName componentName = descriptor.getServiceComponent();
+        if (TELEPHONY_PACKAGE_NAME.equals(componentName.getPackageName())) {
+            String className = componentName.getClassName();
+            return GSM_CALL_SERVICE_CLASS_NAME.equals(className) ||
+                    CDMA_CALL_SERVICE_CLASS_NAME.equals(className);
+        }
+
+        return false;
+    }
+
     /**
      * Returns whether or not the call is currently connected as a cellular call (through the
      * device's cellular radio).
@@ -57,10 +68,7 @@
         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);
+        return isPstnCallService(callService.getDescriptor());
     }
 
     private static void verifyCallServiceExists(String serviceName) {