Replace CallServiceSelectors with Subscriptions (3/3)

Remove CallServiceSelectors and replace them with comprehensive
support for Subscriptions as the means of selecting ways of making
phone calls. After this change, a ConnectionService is not a
semantically meaningful "way of making a call" -- it's more like the
mechanism whereby the Android system communicates with a 3rd party
process to ask for phone services. We anticipate each process having
only one ConnectionService.

Change-Id: I251c0b6f4106104d945b3723fa4da1081a06b8cd
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eaa09fe..a2da689 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -553,24 +553,10 @@
                 <action android:name="android.telecomm.CallServiceProvider" />
             </intent-filter>
         </service>
-        <service android:name="com.android.services.telephony.TelephonyCallServiceSelector"
-                android:singleUser="true">
-            <intent-filter>
-                <action android:name="android.telecomm.CallServiceSelector" />
-            </intent-filter>
-        </service>
         <service
                 android:singleUser="true"
-                android:name="com.android.services.telephony.GsmConnectionService"
-                android:label="@string/gsm_connection_service_label">
-            <intent-filter>
-                <action android:name="android.telecomm.CallService" />
-            </intent-filter>
-        </service>
-        <service
-                android:singleUser="true"
-                android:name="com.android.services.telephony.CdmaConnectionService"
-                android:label="@string/cdma_connection_service_label">
+                android:name="com.android.services.telephony.PstnConnectionService"
+                android:label="@string/pstn_connection_service_label">
             <intent-filter>
                 <action android:name="android.telecomm.CallService" />
             </intent-filter>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bfb10b5..f9ff5b8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1511,11 +1511,8 @@
     <!-- Title for button to not use WiFi calling. -->
     <string name ="choose_wifi_for_call_no">No</string>
 
-    <!-- Label for GSM connection service. -->
-    <string name="gsm_connection_service_label">Built-in GSM SIM card</string>
-
-    <!-- Label for CDMA connection service. -->
-    <string name="cdma_connection_service_label">Built-in CDMA SIM card</string>
+    <!-- Label for PSTN connection service. -->
+    <string name="pstn_connection_service_label">Built-in SIM cards</string>
 
     <!-- Label for SIP connection service. -->
     <string name="sip_connection_service_label">Built-in Internet calling</string>
diff --git a/src/com/android/services/telephony/CdmaConnectionService.java b/src/com/android/services/telephony/CdmaConnectionService.java
deleted file mode 100644
index 75bd12b..0000000
--- a/src/com/android/services/telephony/CdmaConnectionService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.services.telephony;
-
-import android.content.Context;
-import android.net.Uri;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneFactory;
-import com.android.phone.Constants;
-import android.telecomm.ConnectionRequest;
-
-/**
- * Connection service that uses CDMA.
- */
-public class CdmaConnectionService extends PstnConnectionService {
-
-    /** {@inheritDoc} */
-    @Override
-    protected Phone getPhone() {
-        return PhoneFactory.getDefaultPhone();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected boolean canCall(Uri handle) {
-        return canCall(this, handle);
-    }
-
-    // TODO: Refactor this out when CallServiceSelector is deprecated
-    /* package */ static boolean canCall(Context context, Uri handle) {
-        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        return telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA
-                && Constants.SCHEME_TEL.equals(handle.getScheme());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected TelephonyConnection onCreateTelephonyConnection(
-            ConnectionRequest request, Connection connection) {
-        return new CdmaConnection(getPhone(), connection);
-    }
-}
diff --git a/src/com/android/services/telephony/GsmConferenceController.java b/src/com/android/services/telephony/GsmConferenceController.java
new file mode 100644
index 0000000..35b81d2
--- /dev/null
+++ b/src/com/android/services/telephony/GsmConferenceController.java
@@ -0,0 +1,122 @@
+/*
+ * 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.services.telephony;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.PhoneFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.telecomm.Connection;
+
+/**
+ * Maintains a list of all the known GSM connections and implements GSM-specific conference
+ * call functionality.
+ */
+public class GsmConferenceController {
+
+    private final Connection.Listener mConnectionListener =
+            new Connection.ListenerBase() {
+                @Override
+                public void onStateChanged(Connection c, int state) {
+                    // No need to recalculate for conference calls, just traditional calls.
+                    if (c != mGsmConferenceConnection) {
+                        recalculate();
+                    }
+                }
+
+                /** ${inheritDoc} */
+                @Override
+                public void onDisconnected(
+                        Connection c, int cause, String message) {
+                    // When a connection disconnects, make sure to release its parent reference
+                    // so that the parent can move to disconnected as well.
+                    c.setParentConnection(null);
+                }
+
+            };
+
+    /** The known GSM connections. */
+    private final List<GsmConnection> mGsmConnections = new ArrayList<>();
+
+    /** The GSM conference connection object. */
+    private ConferenceConnection mGsmConferenceConnection;
+
+    public void add(GsmConnection connection) {
+        connection.addConnectionListener(mConnectionListener);
+        mGsmConnections.add(connection);
+        recalculate();
+    }
+
+    public void remove(GsmConnection connection) {
+        connection.removeConnectionListener(mConnectionListener);
+        mGsmConnections.remove(connection);
+        recalculate();
+    }
+
+    public ConferenceConnection createConferenceConnection(Connection rootConnection) {
+        if (mGsmConferenceConnection == null) {
+            mGsmConferenceConnection = new ConferenceConnection();
+            Log.d(this, "creating the conference connection: %s", mGsmConferenceConnection);
+        }
+        rootConnection.conference();
+        return mGsmConferenceConnection;
+    }
+
+    /**
+     * Calculates the conference-capable state of all GSM connections in this connection service.
+     */
+    private void recalculate() {
+        Log.v(this, "recalculateGsmConferenceState");
+        for (GsmConnection connection : mGsmConnections) {
+            Log.d(this, "recalc - %s", connection);
+            boolean isConferenceCapable = false;
+            com.android.internal.telephony.Connection radioConnection =
+                    connection.getOriginalConnection();
+            if (radioConnection != null) {
+
+                // First calculate to see if we are in the conference call. We only support a
+                // single active conference call on PSTN, which makes things a little easier.
+                if (mGsmConferenceConnection != null) {
+                    if (radioConnection.getCall().isMultiparty()) {
+                        connection.setParentConnection(mGsmConferenceConnection);
+                    } else {
+                        connection.setParentConnection(null);
+                    }
+                }
+
+                boolean callIsActive = radioConnection.getState() == Call.State.ACTIVE;
+                boolean isConferenced =
+                        callIsActive && radioConnection.getCall().isMultiparty();
+                // TODO: The below does not work when we use PhoneFactory.getGsmPhone() -- the
+                // phone from getGsmPhone() erroneously reports it has no background calls.
+                boolean hasBackgroundCall =
+                        radioConnection.getCall().getPhone().getBackgroundCall().hasConnections();
+                Log.d(this, "recalc: active: %b, is_conf: %b, has_bkgd: %b",
+                        callIsActive, isConferenced, hasBackgroundCall);
+                // We only set conference capable on:
+                // 1) Active calls,
+                // 2) which are not already part of a conference call
+                // 3) and there exists a call on HOLD
+                isConferenceCapable = callIsActive && !isConferenced && hasBackgroundCall;
+            }
+
+            connection.setIsConferenceCapable(isConferenceCapable);
+        }
+    }
+}
diff --git a/src/com/android/services/telephony/GsmConnectionService.java b/src/com/android/services/telephony/GsmConnectionService.java
deleted file mode 100644
index ae5dc22..0000000
--- a/src/com/android/services/telephony/GsmConnectionService.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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.services.telephony;
-
-import android.content.Context;
-import android.net.Uri;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneFactory;
-import com.android.phone.Constants;
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import android.telecomm.CallState;
-import android.telecomm.ConnectionRequest;
-import android.telecomm.Response;
-
-/**
- * Connnection service that uses GSM.
- */
-public class GsmConnectionService extends PstnConnectionService {
-
-    private final android.telecomm.Connection.Listener mConnectionListener =
-            new android.telecomm.Connection.ListenerBase() {
-                @Override
-                public void onStateChanged(android.telecomm.Connection c, int state) {
-                    // No need to recalculate for conference calls, just traditional calls.
-                    if (c != mConferenceConnection) {
-                        recalculateConferenceState();
-                    }
-                }
-
-                /** ${inheritDoc} */
-                @Override
-                public void onDisconnected(
-                        android.telecomm.Connection c, int cause, String message) {
-                    // When a connection disconnects, make sure to release its parent reference
-                    // so that the parent can move to disconnected as well.
-                    c.setParentConnection(null);
-                }
-
-            };
-
-    /** The conferenc connection object. */
-    private ConferenceConnection mConferenceConnection;
-
-    /** {@inheritDoc} */
-    @Override
-    protected Phone getPhone() {
-        return PhoneFactory.getDefaultPhone();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected boolean canCall(Uri handle) {
-        return canCall(this, handle);
-    }
-
-    // TODO: Refactor this out when CallServiceSelector is deprecated
-    /* package */ static boolean canCall(Context context, Uri handle) {
-        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        return telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM
-                && Constants.SCHEME_TEL.equals(handle.getScheme());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected TelephonyConnection onCreateTelephonyConnection(
-            ConnectionRequest request, Connection connection) {
-        return new GsmConnection(getPhone(), connection);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onConnectionAdded(android.telecomm.Connection connection) {
-        connection.addConnectionListener(mConnectionListener);
-        recalculateConferenceState();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onConnectionRemoved(android.telecomm.Connection connection) {
-        connection.removeConnectionListener(mConnectionListener);
-        recalculateConferenceState();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onCreateConferenceConnection(
-            String token,
-            android.telecomm.Connection telecommConnection,
-            Response<String, android.telecomm.Connection> callback) {
-        if (mConferenceConnection == null) {
-            mConferenceConnection = new ConferenceConnection();
-            Log.d(this, "creating the conference connection: %s", mConferenceConnection);
-        }
-        callback.onResult(token, mConferenceConnection);
-        telecommConnection.conference();
-    }
-
-    /**
-     * Calculates the conference-capable state of all connections in this connection service.
-     */
-    private void recalculateConferenceState() {
-        Log.v(this, "recalculateConferenceState");
-        Collection<android.telecomm.Connection> allConnections = this.getAllConnections();
-        for (android.telecomm.Connection connection : new HashSet<>(allConnections)) {
-            Log.d(this, "recalc - %s", connection);
-            if (connection instanceof GsmConnection) {
-                boolean isConferenceCapable = false;
-                Connection radioConnection = ((GsmConnection) connection).getOriginalConnection();
-                if (radioConnection != null) {
-
-                    // First calculate to see if we are in the conference call. We only support a
-                    // single active conference call on PSTN, which makes things a little easier.
-                    if (mConferenceConnection != null) {
-                        if (radioConnection.getCall().isMultiparty()) {
-                            connection.setParentConnection(mConferenceConnection);
-                        } else {
-                            connection.setParentConnection(null);
-                        }
-                    }
-
-                    boolean callIsActive = radioConnection.getState() == Call.State.ACTIVE;
-                    boolean isConferenced =
-                            callIsActive && radioConnection.getCall().isMultiparty();
-                    boolean hasBackgroundCall = getPhone().getBackgroundCall().hasConnections();
-                    Log.d(this, "recalc: active: %b, is_conf: %b, has_bkgd: %b",
-                            callIsActive, isConferenced, hasBackgroundCall);
-                    // We only set conference capable on:
-                    // 1) Active calls,
-                    // 2) which are not already part of a conference call
-                    // 3) and there exists a call on HOLD
-                    isConferenceCapable = callIsActive && !isConferenced && hasBackgroundCall;
-                }
-
-                ((GsmConnection) connection).setIsConferenceCapable(isConferenceCapable);
-            }
-        }
-    }
-}
diff --git a/src/com/android/services/telephony/PstnConnectionService.java b/src/com/android/services/telephony/PstnConnectionService.java
index 21ee41c..a654c69 100644
--- a/src/com/android/services/telephony/PstnConnectionService.java
+++ b/src/com/android/services/telephony/PstnConnectionService.java
@@ -23,22 +23,27 @@
 import android.telecomm.ConnectionRequest;
 import android.telecomm.Response;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.phone.Constants;
 
 import java.util.HashSet;
 import java.util.Set;
 
 /**
- * The parent class for PSTN-based call services. Handles shared functionality between all PSTN
- * call services.
+ * The connection service for making PSTN connections using built-in SIM cards.
  */
-public abstract class PstnConnectionService extends TelephonyConnectionService {
+public final class PstnConnectionService extends TelephonyConnectionService {
+
     private EmergencyCallHelper mEmergencyCallHelper;
+
     private final Set<ConnectionRequest> mPendingOutgoingEmergencyCalls = new HashSet<>();
 
+    private final GsmConferenceController mGsmConferenceController = new GsmConferenceController();
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -64,7 +69,7 @@
         // TODO: Consider passing call emergency information as part of ConnectionRequest so
         // that we do not have to make the check here once again.
         String handle = request.getHandle().getSchemeSpecificPart();
-        final Phone phone = getPhone();
+        final Phone phone = PhoneFactory.getDefaultPhone();
         if (PhoneNumberUtils.isPotentialEmergencyNumber(handle)) {
             EmergencyCallHelper.Callback callback = new EmergencyCallHelper.Callback() {
                 @Override
@@ -102,7 +107,7 @@
             ConnectionRequest request,
             Response<ConnectionRequest, Connection> response) {
         Log.d(this, "onCreateIncomingConnection");
-        Call call = getPhone().getRingingCall();
+        Call call = PhoneFactory.getDefaultPhone().getRingingCall();
 
         // The ringing call is always not-null, check if it is truly ringing by checking its state.
         if (call.getState().isRinging()) {
@@ -125,7 +130,10 @@
 
                 TelephonyConnection telephonyConnection;
                 try {
-                    telephonyConnection = createTelephonyConnection(request, connection);
+                    telephonyConnection = createTelephonyConnection(
+                            request,
+                            PhoneFactory.getDefaultPhone(),
+                            connection);
                 } catch (Exception e) {
                     respondWithError(
                             request,
@@ -150,8 +158,51 @@
         super.onCreateIncomingConnection(request, response);
     }
 
-    /**
-     * @return The current phone object behind this call service.
-     */
-    protected abstract Phone getPhone();
+    /** {@inheritDoc} */
+    @Override
+    protected boolean canCall(Uri handle) {
+        return Constants.SCHEME_TEL.equals(handle.getScheme());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected TelephonyConnection onCreateTelephonyConnection(
+            ConnectionRequest request,
+            Phone phone,
+            com.android.internal.telephony.Connection connection) {
+        switch (phone.getPhoneType()) {
+            case TelephonyManager.PHONE_TYPE_GSM: {
+                final GsmConnection gsmConn = new GsmConnection(phone, connection);
+                mGsmConferenceController.add(gsmConn);
+                gsmConn.addConnectionListener(new Connection.ListenerBase() {
+                    @Override
+                    public void onDestroyed(Connection c) {
+                        mGsmConferenceController.remove(gsmConn);
+                    }
+                });
+                return gsmConn;
+            }
+            case TelephonyManager.PHONE_TYPE_CDMA:
+                return new CdmaConnection(phone, connection);
+            default:
+                Log.d(this, "Inappropriate phone type for PSTN: %d", phone.getPhoneType());
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void onCreateConferenceConnection(
+            String token,
+            Connection connection,
+            Response<String, Connection> callback) {
+        // TODO: Create a more general framework for conferencing. At the moment, our goal is
+        // simply not to break the previous GSM-specific conferencing functionality.
+        if (connection instanceof GsmConnection || connection instanceof ConferenceConnection) {
+            if (connection.isConferenceCapable()) {
+                callback.onResult(token,
+                        mGsmConferenceController.createConferenceConnection(connection));
+            }
+        }
+    }
 }
diff --git a/src/com/android/services/telephony/IncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
similarity index 89%
rename from src/com/android/services/telephony/IncomingCallNotifier.java
rename to src/com/android/services/telephony/PstnIncomingCallNotifier.java
index 04aac0b..9dffe50 100644
--- a/src/com/android/services/telephony/IncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -40,16 +40,13 @@
  * Listens to incoming-call events from the associated phone object and notifies Telecomm upon each
  * occurence. One instance of these exists for each of the telephony-based call services.
  */
-final class IncomingCallNotifier {
+final class PstnIncomingCallNotifier {
     /** New ringing connection event code. */
     private static final int EVENT_NEW_RINGING_CONNECTION = 100;
 
     /** The phone proxy object to listen to. */
     private final PhoneProxy mPhoneProxy;
 
-    /** The phone type for this incoming call notifier. */
-    private final int mPhoneType;
-
     /**
      * The base phone implementation behind phone proxy. The underlying phone implementation can
      * change underneath when the radio technology changes. We listen for these events and update
@@ -58,9 +55,6 @@
      */
     private Phone mPhoneBase;
 
-    /** The class for the associated call service. */
-    private final Class<? extends CallService> mCallServiceClass;
-
     /**
      * Used to listen to events from {@link #mPhoneBase}.
      */
@@ -96,17 +90,11 @@
     /**
      * Persists the specified parameters and starts listening to phone events.
      *
-     * @param callServiceClass The call service class.
-     * @param phoneType The type of phone this class should be listening to.
      * @param phoneProxy The phone object for listening to incoming calls.
      */
-    IncomingCallNotifier(
-            Class<? extends CallService> callServiceClass, int phoneType, PhoneProxy phoneProxy) {
-        Preconditions.checkNotNull(callServiceClass);
+    PstnIncomingCallNotifier(PhoneProxy phoneProxy) {
         Preconditions.checkNotNull(phoneProxy);
 
-        mCallServiceClass = callServiceClass;
-        mPhoneType = phoneType;
         mPhoneProxy = phoneProxy;
 
         registerForNotifications();
@@ -134,7 +122,7 @@
                 mPhoneBase.unregisterForNewRingingConnection(mHandler);
             }
 
-            if (newPhone != null && newPhone.getPhoneType() == mPhoneType) {
+            if (newPhone != null) {
                 Log.i(this, "Registering: %s", newPhone);
                 mPhoneBase = newPhone;
                 mPhoneBase.registerForNewRingingConnection(
@@ -168,7 +156,7 @@
         Context context = mPhoneProxy.getContext();
 
         CallServiceDescriptor.Builder builder = CallServiceDescriptor.newBuilder(context);
-        builder.setCallService(mCallServiceClass);
+        builder.setCallService(PstnConnectionService.class);
         builder.setNetworkType(CallServiceDescriptor.FLAG_PSTN);
 
         Intent intent = new Intent(TelecommConstants.ACTION_INCOMING_CALL);
diff --git a/src/com/android/services/telephony/SipConnectionService.java b/src/com/android/services/telephony/SipConnectionService.java
index 7824274..3faf787 100644
--- a/src/com/android/services/telephony/SipConnectionService.java
+++ b/src/com/android/services/telephony/SipConnectionService.java
@@ -25,6 +25,7 @@
 import android.provider.Settings;
 import android.telephony.PhoneNumberUtils;
 
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.sip.SipPhone;
 import com.android.phone.Constants;
@@ -64,23 +65,19 @@
     /** {@inheritDoc} */
     @Override
     protected boolean canCall(Uri handle) {
-        return canCall(this, handle);
-    }
-
-    // TODO: Refactor this out when CallServiceSelector is deprecated
-    /* package */ static boolean canCall(Context context, Uri handle) {
-        return shouldUseSipPhone(context, handle.getScheme(), handle.getSchemeSpecificPart());
+        return shouldUseSipPhone(handle.getScheme(), handle.getSchemeSpecificPart());
     }
 
     /** {@inheritDoc} */
     @Override
     protected TelephonyConnection onCreateTelephonyConnection(
             ConnectionRequest request,
+            Phone phone,
             com.android.internal.telephony.Connection connection) {
         return new SipConnection(connection);
     }
 
-    private static boolean shouldUseSipPhone(Context context, String scheme, String number) {
+    private boolean shouldUseSipPhone(String scheme, String number) {
         // Scheme must be "sip" or "tel".
         boolean isKnownCallScheme = Constants.SCHEME_TEL.equals(scheme)
                 || Constants.SCHEME_SIP.equals(scheme);
@@ -95,7 +92,7 @@
         }
 
         // Check SIP address only
-        SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
+        SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(this);
         String callOption = sipSharedPreferences.getSipCallOption();
         boolean isRegularNumber = Constants.SCHEME_TEL.equals(scheme)
                 && !PhoneNumberUtils.isUriNumber(number);
@@ -104,7 +101,7 @@
         }
 
         // Check if no SIP profiles.
-        SipProfileDb sipProfileDb = new SipProfileDb(context);
+        SipProfileDb sipProfileDb = new SipProfileDb(this);
         if (sipProfileDb.getProfilesCount() == 0 && isRegularNumber) {
             return false;
         }
diff --git a/src/com/android/services/telephony/TelephonyCallServiceProvider.java b/src/com/android/services/telephony/TelephonyCallServiceProvider.java
index a299913..cc89c0e 100644
--- a/src/com/android/services/telephony/TelephonyCallServiceProvider.java
+++ b/src/com/android/services/telephony/TelephonyCallServiceProvider.java
@@ -31,11 +31,7 @@
     public void lookupCallServices(CallServiceLookupResponse response) {
         ArrayList<CallServiceDescriptor> descriptors = new ArrayList<CallServiceDescriptor>();
         descriptors.add(CallServiceDescriptor.newBuilder(this)
-                   .setCallService(GsmConnectionService.class)
-                   .setNetworkType(CallServiceDescriptor.FLAG_PSTN)
-                   .build());
-        descriptors.add(CallServiceDescriptor.newBuilder(this)
-                   .setCallService(CdmaConnectionService.class)
+                   .setCallService(PstnConnectionService.class)
                    .setNetworkType(CallServiceDescriptor.FLAG_PSTN)
                    .build());
         descriptors.add(CallServiceDescriptor.newBuilder(this)
diff --git a/src/com/android/services/telephony/TelephonyCallServiceSelector.java b/src/com/android/services/telephony/TelephonyCallServiceSelector.java
deleted file mode 100644
index ef5d361..0000000
--- a/src/com/android/services/telephony/TelephonyCallServiceSelector.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.services.telephony;
-
-import android.telecomm.CallInfo;
-import android.telecomm.CallServiceDescriptor;
-import android.telecomm.CallServiceSelector;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Decides which call service should be used to place outgoing calls or to switch the call to.
- */
-public class TelephonyCallServiceSelector extends CallServiceSelector {
-
-    /** {@inheritDoc} */
-    @Override
-    protected void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
-        ArrayList<CallServiceDescriptor> selectedDescriptors =
-                new ArrayList<CallServiceDescriptor>();
-
-        CallServiceDescriptor descriptor = getDescriptor(descriptors, CdmaConnectionService.class);
-        if (descriptor != null) {
-            if (CdmaConnectionService.canCall(this, callInfo.getHandle())) {
-                selectedDescriptors.add(descriptor);
-            }
-        }
-        descriptor = getDescriptor(descriptors, GsmConnectionService.class);
-        if (descriptor != null) {
-            if (GsmConnectionService.canCall(this, callInfo.getHandle())) {
-                selectedDescriptors.add(descriptor);
-            }
-        }
-        descriptor = getDescriptor(descriptors, SipConnectionService.class);
-        if (descriptor != null) {
-            if (SipConnectionService.canCall(this, callInfo.getHandle())) {
-                selectedDescriptors.add(descriptor);
-            }
-        }
-
-        getAdapter().setSelectedCallServices(callInfo.getId(), selectedDescriptors);
-    }
-
-    private CallServiceDescriptor getDescriptor(
-            List<CallServiceDescriptor> descriptors, Class<?> clazz) {
-
-        for (CallServiceDescriptor descriptor : descriptors) {
-            if (!getPackageName().equals(descriptor.getServiceComponent().getPackageName())) {
-                continue;
-            }
-
-            if (clazz.getName().equals(descriptor.getServiceComponent().getClassName())) {
-                return descriptor;
-            }
-        }
-
-        return null;
-    }
-}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 9758118..db4720b 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -16,7 +16,6 @@
 
 package com.android.services.telephony;
 
-import android.content.ComponentName;
 import android.net.Uri;
 import android.telephony.DisconnectCause;
 import android.telephony.ServiceState;
@@ -36,37 +35,17 @@
 import java.util.Set;
 
 /**
- * The parent class for telephony-based call services. Subclasses provide the specific phone (GSM,
- * CDMA, etc...) to use.
+ * The parent class for Android's built-in connection services.
  */
 public abstract class TelephonyConnectionService extends ConnectionService {
     private static final Set<com.android.internal.telephony.Connection> sKnownConnections
             = new HashSet<>();
 
-    private static final Subscription sStaticSubscription = new Subscription(
-            null, "Telephony", null, 0, 0, 0, true, false);
-
-    /** {@inheritDoc} */
-    @Override
-    public void onFindSubscriptions(
-            Uri handle,
-            Response<Uri, Subscription> response) {
-        try {
-            respondWithResult(handle, response, canCall(handle) ? sStaticSubscription : null);
-        } catch (Exception e) {
-            respondWithError(
-                    handle,
-                    response,
-                    DisconnectCause.ERROR_UNSPECIFIED,  // Internal error
-                    "onFindSubscriptions error: " + e.toString());
-        }
-    }
-
     /**
      * Initiates the underlying Telephony call, then creates a {@link TelephonyConnection}
      * by calling
-     * {@link #createTelephonyConnection(ConnectionRequest,
-     *         com.android.internal.telephony.Connection)}
+     * {@link #createTelephonyConnection(
+     *         ConnectionRequest,Phone,com.android.internal.telephony.Connection)}
      * at the appropriate time. Should be called by the subclass.
      */
     protected void startCallWithPhone(
@@ -131,15 +110,15 @@
 
         try {
             final TelephonyConnection telephonyConnection =
-                    createTelephonyConnection(request, connection);
+                    createTelephonyConnection(request, phone, connection);
             respondWithResult(request, response, telephonyConnection);
 
-            final com.android.internal.telephony.Connection connectionCopy = connection;
+            final com.android.internal.telephony.Connection connectionFinal = connection;
             PostDialListener postDialListener = new PostDialListener() {
                 @Override
                 public void onPostDialWait() {
                     TelephonyConnectionService.this.onPostDialWait(telephonyConnection,
-                            connectionCopy.getRemainingPostDialString());
+                            connectionFinal.getRemainingPostDialString());
                 }
             };
             connection.addPostDialListener(postDialListener);
@@ -222,9 +201,10 @@
 
     protected final TelephonyConnection createTelephonyConnection(
             ConnectionRequest request,
+            Phone phone,
             final com.android.internal.telephony.Connection connection) {
         final TelephonyConnection telephonyConnection =
-                onCreateTelephonyConnection(request, connection);
+                onCreateTelephonyConnection(request, phone, connection);
         sKnownConnections.add(connection);
         telephonyConnection.addConnectionListener(new Connection.ListenerBase() {
             @Override
@@ -255,11 +235,13 @@
      * Create a Telephony-specific {@link Connection} object.
      *
      * @param request A request for creating a {@link Connection}.
+     * @param phone A {@code Phone} object to use.
      * @param connection An underlying Telephony {@link com.android.internal.telephony.Connection}
      *         to use.
      * @return A new {@link TelephonyConnection}.
      */
     protected abstract TelephonyConnection onCreateTelephonyConnection(
             ConnectionRequest request,
+            Phone phone,
             com.android.internal.telephony.Connection connection);
 }
diff --git a/src/com/android/services/telephony/TelephonyGlobals.java b/src/com/android/services/telephony/TelephonyGlobals.java
index 60389bf..22346b7 100644
--- a/src/com/android/services/telephony/TelephonyGlobals.java
+++ b/src/com/android/services/telephony/TelephonyGlobals.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.PhoneProxy;
 
@@ -35,11 +34,8 @@
     /** The application context. */
     private final Context mContext;
 
-    /** Handles incoming calls for GSM. */
-    private IncomingCallNotifier mGsmIncomingCallNotifier;
-
-    /** Handles incoming calls for CDMA. */
-    private IncomingCallNotifier mCdmaIncomingCallNotifier;
+    /** Handles incoming calls for PSTN calls. */
+    private PstnIncomingCallNotifier mPtsnIncomingCallNotifier;
 
     /**
      * Persists the specified parameters.
@@ -61,13 +57,8 @@
         PhoneProxy defaultPhone = (PhoneProxy) PhoneFactory.getDefaultPhone();
         Log.i(this, "Default phone: %s.", defaultPhone);
 
-        Log.i(this, "Registering the GSM listener.");
-        mGsmIncomingCallNotifier = new IncomingCallNotifier(
-                GsmConnectionService.class, PhoneConstants.PHONE_TYPE_GSM, defaultPhone);
-
-        Log.i(this, "Registering the CDMA listener.");
-        mCdmaIncomingCallNotifier = new IncomingCallNotifier(
-                CdmaConnectionService.class, PhoneConstants.PHONE_TYPE_CDMA, defaultPhone);
+        Log.i(this, "Registering the PSTN listener.");
+        mPtsnIncomingCallNotifier = new PstnIncomingCallNotifier(defaultPhone);
 
         // TODO(santoscordon): Do SIP.  SIP will require a slightly different solution since it
         // doesn't have a phone object in the same way as PSTN calls. Additionally, the user can