Merge "[DO NOT MERGE] Add BIND permission"
diff --git a/ecc/conversion_toolset_v1/gen_eccdata.sh b/ecc/conversion_toolset_v1/gen_eccdata.sh
index 1efac37..803f39b 100644
--- a/ecc/conversion_toolset_v1/gen_eccdata.sh
+++ b/ecc/conversion_toolset_v1/gen_eccdata.sh
@@ -19,7 +19,7 @@
 source "${LOCAL_TOOLSET_DIR}/env.sh"
 
 echo "Converting eccdata..."
-${ANDROID_BUILD_TOP}/prebuilts/tools/linux-x86_64/protoc/bin/protoc \
+${ANDROID_BUILD_TOP}/prebuilts/misc/${KERNEL}-x86/protobuf/aprotoc \
   --encode=ecc.AllInfo proto/protobuf_ecc_data.proto \
   < "${INPUT_DATA}" > "${RAW_DATA}"
 
diff --git a/ecc/gen_eccdata.sh b/ecc/gen_eccdata.sh
index e4dd745..4c1f616 100755
--- a/ecc/gen_eccdata.sh
+++ b/ecc/gen_eccdata.sh
@@ -34,7 +34,7 @@
 esac
 
 read -d "" PROTOC_COMMAND << END || :
-${ANDROID_BUILD_TOP}/prebuilts/tools/${KERNEL}-x86_64/protoc/bin/protoc
+${ANDROID_BUILD_TOP}/prebuilts/misc/${KERNEL}-x86/protobuf/aprotoc
 END
 if ! [ -x "${PROTOC_COMMAND}" ] ; then
   echo "Missing ${PROTOC_COMMAND}." 1>&2
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c68deb2..dd8abe7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1547,6 +1547,15 @@
          message is shown when an in-progress call is ended due to the battery being low. -->
     <string name="callFailed_low_battery">Video call ended due to low battery.</string>
 
+    <!-- In-call screen: error message shown when the user attempts to place an emergency call
+         over wifi calling (WFC), but emergency services are not available in the current
+         location. -->
+    <string name="callFailed_emergency_call_over_wfc_not_available">Emergency calls over Wi-Fi calling not available in this location.</string>
+
+    <!-- In-call screen: error message shown when the user attempts to place a call over wifi
+         calling (WFC), but wifi calling is not available in the current location. -->
+    <string name="callFailed_wfc_service_not_available_in_this_location">Wi-Fi calling is not available in this location.</string>
+
     <!-- The title for the change voicemail PIN activity -->
     <string name="change_pin_title">Change Voicemail PIN</string>
     <!-- The label for the continue button in change voicemail PIN activity -->
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 48047ca..d1eb3dc 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -194,7 +194,7 @@
 
                 case EVENT_SYSTEM_UNLOCKED:
                 {
-                    for (int i = 0; i < TelephonyManager.from(mContext).getPhoneCount(); ++i) {
+                    for (int i = 0; i < TelephonyManager.from(mContext).getMaxPhoneCount(); ++i) {
                         // When user unlock device, we should only try to send broadcast again if we
                         // have sent it before unlock. This will avoid we try to load carrier config
                         // when SIM is still loading when unlock happens.
@@ -211,7 +211,7 @@
                     // Only update if there are cached config removed to avoid updating config for
                     // unrelated packages.
                     if (clearCachedConfigForPackage(carrierPackageName)) {
-                        int numPhones = TelephonyManager.from(mContext).getPhoneCount();
+                        int numPhones = TelephonyManager.from(mContext).getMaxPhoneCount();
                         for (int i = 0; i < numPhones; ++i) {
                             updateConfigForPhoneId(i);
                         }
@@ -523,7 +523,7 @@
         pkgFilter.addDataScheme("package");
         context.registerReceiver(mPackageReceiver, pkgFilter);
 
-        int numPhones = TelephonyManager.from(context).getPhoneCount();
+        int numPhones = TelephonyManager.from(context).getMaxPhoneCount();
         mConfigFromDefaultApp = new PersistableBundle[numPhones];
         mConfigFromCarrierApp = new PersistableBundle[numPhones];
         mOverrideConfigs = new PersistableBundle[numPhones];
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 17a887d..e5e9fe7 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_IMS;
 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 
 import android.Manifest.permission;
@@ -149,7 +150,10 @@
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.euicc.EuiccConnector;
 import com.android.internal.telephony.ims.ImsResolver;
+import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.uicc.SIMRecords;
@@ -158,7 +162,6 @@
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UiccProfile;
 import com.android.internal.telephony.uicc.UiccSlot;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.util.VoicemailNotificationSettingsUtil;
 import com.android.internal.util.HexDump;
 import com.android.phone.settings.PickSmsSubscriptionActivity;
@@ -2718,7 +2721,7 @@
             if (phone != null) {
                 phone.setDataActivationState(activationState);
             } else {
-                loge("setVoiceActivationState fails with invalid subId: " + subId);
+                loge("setDataActivationState fails with invalid subId: " + subId);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -4809,13 +4812,13 @@
     public int getCarrierPrivilegeStatusForUid(int subId, int uid) {
         final Phone phone = getPhone(subId);
         if (phone == null) {
-            loge("getCarrierPrivilegeStatus: Invalid subId");
+            loge("getCarrierPrivilegeStatusForUid: Invalid subId");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
         }
         UiccProfile profile =
                 UiccController.getInstance().getUiccProfileForPhone(phone.getPhoneId());
         if (profile == null) {
-            loge("getCarrierPrivilegeStatus: No UICC");
+            loge("getCarrierPrivilegeStatusForUid: No UICC");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
         return profile.getCarrierPrivilegeStatusForUid(phone.getContext().getPackageManager(), uid);
@@ -4866,7 +4869,7 @@
         }
         UiccCard card = UiccController.getInstance().getUiccCard(phoneId);
         if (card == null) {
-            loge("getCarrierPackageNamesForIntent: No UICC");
+            loge("getCarrierPackageNamesForIntentAndPhone: No UICC");
             return null ;
         }
         return card.getCarrierPackageNamesForIntent(mApp.getPackageManager(), intent);
@@ -6456,7 +6459,10 @@
                 if (card != null) {
                     cardId = card.getCardId();
                 } else {
-                    cardId = slot.getIccId();
+                    cardId = slot.getEid();
+                    if (TextUtils.isEmpty(cardId)) {
+                        cardId = slot.getIccId();
+                    }
                 }
 
                 if (cardId != null) {
@@ -7216,4 +7222,32 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
+
+    /**
+     * Updates whether conference event pacakge handling is enabled.
+     * @param isCepEnabled {@code true} if CEP handling is enabled (default), or {@code false}
+     *                                 otherwise.
+     */
+    @Override
+    public void setCepEnabled(boolean isCepEnabled) {
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "setCepEnabled");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Rlog.i(LOG_TAG, "setCepEnabled isCepEnabled=" + isCepEnabled);
+            for (Phone phone : PhoneFactory.getPhones()) {
+                Phone defaultPhone = phone.getImsPhone();
+                if (defaultPhone != null && defaultPhone.getPhoneType() == PHONE_TYPE_IMS) {
+                    ImsPhone imsPhone = (ImsPhone) defaultPhone;
+                    ImsPhoneCallTracker imsPhoneCallTracker =
+                            (ImsPhoneCallTracker) imsPhone.getCallTracker();
+                    imsPhoneCallTracker.setConferenceEventPackageEnabled(isCepEnabled);
+                    Rlog.i(LOG_TAG, "setCepEnabled isCepEnabled=" + isCepEnabled + ", for imsPhone "
+                            + imsPhone.getMsisdn());
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
 }
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index a59c9c4..a34abc0 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -53,6 +53,10 @@
     private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
     private static final String IMS_ENABLE = "enable";
     private static final String IMS_DISABLE = "disable";
+    // Used to disable or enable processing of conference event package data from the network.
+    // This is handy for testing scenarios where CEP data does not exist on a network which does
+    // support CEP data.
+    private static final String IMS_CEP = "conference-event-package";
 
     private static final String SMS_GET_APPS = "get-apps";
     private static final String SMS_GET_DEFAULT_APP = "get-default-app";
@@ -131,6 +135,8 @@
         pw.println("  ims disable [-s SLOT_ID]");
         pw.println("    disables IMS for the SIM slot specified, or for the default voice SIM");
         pw.println("    slot if none is specified.");
+        pw.println("  ims conference-event-package [enable/disable]");
+        pw.println("    enables or disables handling or network conference event package data.");
     }
 
     private void onHelpSms() {
@@ -190,6 +196,9 @@
             case IMS_DISABLE: {
                 return handleDisableIms();
             }
+            case IMS_CEP: {
+                return handleCepChange();
+            }
         }
 
         return -1;
@@ -466,6 +475,22 @@
         return 0;
     }
 
+    private int handleCepChange() {
+        Log.i(LOG_TAG, "handleCepChange");
+        String opt = getNextArg();
+        if (opt == null) {
+            return -1;
+        }
+        boolean isCepEnabled = opt.equals("enable");
+
+        try {
+            mInterface.setCepEnabled(isCepEnabled);
+        } catch (RemoteException e) {
+            return -1;
+        }
+        return 0;
+    }
+
     private int getDefaultSlot() {
         int slotId = SubscriptionManager.getDefaultVoicePhoneId();
         if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index cf3f913..4a5fb4a 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -18,10 +18,14 @@
 
 import android.content.Context;
 import android.media.ToneGenerator;
+import android.os.PersistableBundle;
 import android.telecom.DisconnectCause;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 
 import com.android.internal.telephony.CallFailCause;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.phone.ImsUtil;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.common.R;
@@ -102,7 +106,7 @@
                         telephonyPerciseDisconnectCause),
                 toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause, phoneId),
                 toTelecomDisconnectReason(context,telephonyDisconnectCause, reason, phoneId),
-                toTelecomDisconnectCauseTone(telephonyDisconnectCause));
+                toTelecomDisconnectCauseTone(telephonyDisconnectCause, phoneId));
     }
 
     /**
@@ -166,6 +170,8 @@
             case android.telephony.DisconnectCause.POWER_OFF:
             case android.telephony.DisconnectCause.LOW_BATTERY:
             case android.telephony.DisconnectCause.DIAL_LOW_BATTERY:
+            case android.telephony.DisconnectCause.EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+            case android.telephony.DisconnectCause.WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
             case android.telephony.DisconnectCause.SERVER_ERROR:
             case android.telephony.DisconnectCause.SERVER_UNREACHABLE:
             case android.telephony.DisconnectCause.TIMED_OUT:
@@ -357,6 +363,12 @@
             case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS:
                 resourceId = R.string.callFailed_otasp_provisioning_in_process;
                 break;
+            case android.telephony.DisconnectCause.EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+                resourceId = R.string.callFailed_emergency_call_over_wfc_not_available;
+                break;
+            case android.telephony.DisconnectCause.WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
+                resourceId = R.string.callFailed_wfc_service_not_available_in_this_location;
+                break;
             default:
                 break;
         }
@@ -744,6 +756,12 @@
             case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS:
                 resourceId = R.string.callFailed_otasp_provisioning_in_process;
                 break;
+            case android.telephony.DisconnectCause.EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+                resourceId = R.string.callFailed_emergency_call_over_wfc_not_available;
+                break;
+            case android.telephony.DisconnectCause.WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
+                resourceId = R.string.callFailed_wfc_service_not_available_in_this_location;
+                break;
             default:
                 break;
         }
@@ -793,11 +811,22 @@
     /**
      * Returns the tone to play for the disconnect cause, or UNKNOWN if none should be played.
      */
-    private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause) {
-        switch (telephonyDisconnectCause) {
-            case android.telephony.DisconnectCause.BUSY:
+    private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause, int phoneId) {
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        PersistableBundle config;
+        if (phone != null) {
+            config = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+        } else {
+            config = PhoneGlobals.getInstance().getCarrierConfig();
+        }
+        int[] busyToneArray = config.getIntArray(
+                CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY);
+        for (int busyTone : busyToneArray) {
+            if (busyTone == telephonyDisconnectCause) {
                 return ToneGenerator.TONE_SUP_BUSY;
-
+            }
+        }
+        switch (telephonyDisconnectCause) {
             case android.telephony.DisconnectCause.CONGESTION:
                 return ToneGenerator.TONE_SUP_CONGESTION;
 
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 4da92e2..5617334 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -110,6 +110,25 @@
                handleOriginalConnectionChange();
             }
         }
+
+        /**
+         * Handles changes to conference participant data as reported by the conference host
+         * connection.
+         *
+         * @param c The connection.
+         * @param participants The participant information.
+         */
+        @Override
+        public void onConferenceParticipantsChanged(android.telecom.Connection c,
+                List<ConferenceParticipant> participants) {
+
+            if (c == null || participants == null) {
+                return;
+            }
+            Log.v(this, "onConferenceParticipantsChanged: %d participants", participants.size());
+            TelephonyConnection telephonyConnection = (TelephonyConnection) c;
+            handleConferenceParticipantsUpdate(telephonyConnection, participants);
+        }
     };
 
     /**
@@ -140,25 +159,6 @@
             setDisconnected(disconnectCause);
         }
 
-        /**
-         * Handles changes to conference participant data as reported by the conference host
-         * connection.
-         *
-         * @param c The connection.
-         * @param participants The participant information.
-         */
-        @Override
-        public void onConferenceParticipantsChanged(android.telecom.Connection c,
-                List<ConferenceParticipant> participants) {
-
-            if (c == null || participants == null) {
-                return;
-            }
-            Log.v(this, "onConferenceParticipantsChanged: %d participants", participants.size());
-            TelephonyConnection telephonyConnection = (TelephonyConnection) c;
-            handleConferenceParticipantsUpdate(telephonyConnection, participants);
-        }
-
         @Override
         public void onVideoStateChanged(android.telecom.Connection c, int videoState) {
             Log.d(this, "onVideoStateChanged video state %d", videoState);
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 9902700..b193c7f 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -53,6 +53,21 @@
         }
     };
 
+    private final TelephonyConnection.TelephonyConnectionListener mTelephonyConnectionListener =
+            new TelephonyConnection.TelephonyConnectionListener() {
+        @Override
+        public void onConferenceStarted() {
+            Log.v(this, "onConferenceStarted");
+            recalculate();
+        }
+
+        @Override
+        public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {
+            Log.v(this, "onConferenceSupportedChanged");
+            recalculate();
+        }
+    };
+
     /**
      * Ims conference controller connection listener.  Used to respond to changes in state of the
      * Telephony connections the controller is aware of.
@@ -74,18 +89,6 @@
         public void onDestroyed(Connection connection) {
             remove(connection);
         }
-
-        @Override
-        public void onConferenceStarted() {
-            Log.v(this, "onConferenceStarted");
-            recalculate();
-        }
-
-        @Override
-        public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {
-            Log.v(this, "onConferenceSupportedChanged");
-            recalculate();
-        }
     };
 
     /**
@@ -149,6 +152,7 @@
 
         mTelephonyConnections.add(connection);
         connection.addConnectionListener(mConnectionListener);
+        connection.addTelephonyConnectionListener(mTelephonyConnectionListener);
         recalculateConference();
     }
 
@@ -176,6 +180,10 @@
         }
 
         connection.removeConnectionListener(mConnectionListener);
+        if (connection instanceof TelephonyConnection) {
+            TelephonyConnection telephonyConnection = (TelephonyConnection) connection;
+            telephonyConnection.removeTelephonyConnectionListener(mTelephonyConnectionListener);
+        }
         mTelephonyConnections.remove(connection);
         recalculateConferenceable();
     }
@@ -388,6 +396,7 @@
         // Use the "Other" disconnect cause to ensure the call is logged to the call log but the
         // disconnect tone is not played.
         connection.removeConnectionListener(mConnectionListener);
+        connection.removeTelephonyConnectionListener(mTelephonyConnectionListener);
         connection.clearOriginalConnection();
         connection.setDisconnected(new DisconnectCause(DisconnectCause.OTHER,
                 android.telephony.DisconnectCause.toString(
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 288c72c..85f94ab 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -53,7 +53,7 @@
             return;
         }
         mListeners = new ArrayList<>(2);
-        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+        for (int i = 0; i < TelephonyManager.getDefault().getMaxPhoneCount(); i++) {
             mListeners.add(new RadioOnStateListener());
         }
     }
@@ -76,7 +76,7 @@
         mCallback = callback;
         mInProgressListeners.clear();
         mIsRadioOnCallingEnabled = false;
-        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+        for (int i = 0; i < TelephonyManager.getDefault().getMaxPhoneCount(); i++) {
             Phone phone = PhoneFactory.getPhone(i);
             if (phone == null) {
                 continue;
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 84fa40c..1601f00 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -26,8 +26,10 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.telecom.CallAudioState;
+import android.telecom.Conference;
 import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
+import android.telecom.ConnectionService;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.StatusHints;
@@ -406,6 +408,10 @@
     public abstract static class TelephonyConnectionListener {
         public void onOriginalConnectionConfigured(TelephonyConnection c) {}
         public void onOriginalConnectionRetry(TelephonyConnection c, boolean isPermanentFailure) {}
+        public void onConferenceParticipantsChanged(Connection c,
+                List<ConferenceParticipant> participants) {}
+        public void onConferenceStarted() {}
+        public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
     }
 
     private final PostDialListener mPostDialListener = new PostDialListener() {
@@ -623,6 +629,7 @@
         }
     };
 
+    private TelephonyConnectionService mTelephonyConnectionService;
     protected com.android.internal.telephony.Connection mOriginalConnection;
     private Call.State mConnectionState = Call.State.IDLE;
     private Bundle mOriginalConnectionExtras = new Bundle();
@@ -1265,13 +1272,23 @@
      */
     private void setTechnologyTypeExtra() {
         if (getPhone() != null) {
-            putExtra(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE, getPhone().getPhoneType());
+            Bundle newExtras = getExtras();
+            if (newExtras == null) {
+                newExtras = new Bundle();
+            }
+            newExtras.putInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE, getPhone().getPhoneType());
+            putExtras(newExtras);
         }
     }
 
     private void refreshDisableAddCall() {
         if (shouldSetDisableAddCallExtra()) {
-            putExtra(Connection.EXTRA_DISABLE_ADD_CALL, true);
+            Bundle newExtras = getExtras();
+            if (newExtras == null) {
+                newExtras = new Bundle();
+            }
+            newExtras.putBoolean(Connection.EXTRA_DISABLE_ADD_CALL, true);
+            putExtras(newExtras);
         } else {
             removeExtras(Connection.EXTRA_DISABLE_ADD_CALL);
         }
@@ -1759,8 +1776,8 @@
         // To "optimize", we check here to see if there already exists any active calls.  If so,
         // we issue an update for those calls first to make sure we only have one top-level
         // active call.
-        if (getConnectionService() != null) {
-            for (Connection current : getConnectionService().getAllConnections()) {
+        if (getTelephonyConnectionService() != null) {
+            for (Connection current : getTelephonyConnectionService().getAllConnections()) {
                 if (current != this && current instanceof TelephonyConnection) {
                     TelephonyConnection other = (TelephonyConnection) current;
                     if (other.getState() == STATE_ACTIVE) {
@@ -1787,9 +1804,10 @@
      * @return {@code true} if the connection is video capable, {@code false} otherwise.
      */
     private boolean isVideoCapable() {
-        return can(mOriginalConnectionCapabilities, Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
-                && can(mOriginalConnectionCapabilities,
-                Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
+        return (mOriginalConnectionCapabilities & Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
+                == Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL
+                && (mOriginalConnectionCapabilities & Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL)
+                == Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL;
     }
 
     /**
@@ -1801,7 +1819,8 @@
      * @return {@code true} if the connection is external, {@code false} otherwise.
      */
     private boolean isExternalConnection() {
-        return can(mOriginalConnectionCapabilities, Capability.IS_EXTERNAL_CONNECTION);
+        return (mOriginalConnectionCapabilities
+                & Capability.IS_EXTERNAL_CONNECTION) == Capability.IS_EXTERNAL_CONNECTION;
     }
 
     /**
@@ -1823,8 +1842,10 @@
      * @return {@code true} if the connection is pullable, {@code false} otherwise.
      */
     private boolean isPullable() {
-        return can(mOriginalConnectionCapabilities, Capability.IS_EXTERNAL_CONNECTION)
-                && can(mOriginalConnectionCapabilities, Capability.IS_PULLABLE);
+        return (mOriginalConnectionCapabilities & Capability.IS_EXTERNAL_CONNECTION)
+                == Capability.IS_EXTERNAL_CONNECTION
+                && (mOriginalConnectionCapabilities & Capability.IS_PULLABLE)
+                == Capability.IS_PULLABLE;
     }
 
     /**
@@ -1882,17 +1903,20 @@
     public int applyOriginalConnectionCapabilities(int capabilities) {
         // We only support downgrading to audio if both the remote and local side support
         // downgrading to audio.
-        boolean supportsDowngradeToAudio = can(mOriginalConnectionCapabilities,
-                Capability.SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL |
-                        Capability.SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE);
+        int supportsDowngrade = Capability.SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL
+                | Capability.SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE;
+        boolean supportsDowngradeToAudio =
+                (mOriginalConnectionCapabilities & supportsDowngrade) == supportsDowngrade;
         capabilities = changeBitmask(capabilities,
                 CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO, !supportsDowngradeToAudio);
 
         capabilities = changeBitmask(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
-                can(mOriginalConnectionCapabilities, Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL));
+                (mOriginalConnectionCapabilities & Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL)
+                        == Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
 
-        boolean isLocalVideoSupported = can(mOriginalConnectionCapabilities,
-                Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL) && !mIsTtyEnabled;
+        boolean isLocalVideoSupported = (mOriginalConnectionCapabilities
+                & Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
+                == Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL && !mIsTtyEnabled;
         capabilities = changeBitmask(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
                 isLocalVideoSupported);
 
@@ -2343,4 +2367,47 @@
         sb.append("]");
         return sb.toString();
     }
+
+    public final void setTelephonyConnectionService(TelephonyConnectionService connectionService) {
+        mTelephonyConnectionService = connectionService;
+    }
+
+    public final TelephonyConnectionService getTelephonyConnectionService() {
+        return mTelephonyConnectionService;
+    }
+
+    /**
+     * Notifies listeners of a change to conference participant(s).
+     *
+     * @param conferenceParticipants The participants.
+     */
+    protected final void updateConferenceParticipants(
+            List<ConferenceParticipant> conferenceParticipants) {
+        for (TelephonyConnectionListener l : mTelephonyListeners) {
+            l.onConferenceParticipantsChanged(this, conferenceParticipants);
+        }
+    }
+
+    /**
+     * Called by a {@link ConnectionService} to notify Telecom that a {@link Conference#onMerge()}
+     * operation has started.
+     * <p>
+     */
+    protected void notifyConferenceStarted() {
+        for (TelephonyConnectionListener l : mTelephonyListeners) {
+            l.onConferenceStarted();
+        }
+    }
+
+    /**
+     * Notifies listeners when a change has occurred to the Connection which impacts its ability to
+     * be a part of a conference call.
+     * @param isConferenceSupported {@code true} if the connection supports being part of a
+     *      conference call, {@code false} otherwise.
+     */
+    protected void notifyConferenceSupportedChanged(boolean isConferenceSupported) {
+        for (TelephonyConnectionListener l : mTelephonyListeners) {
+            l.onConferenceSupportedChanged(this, isConferenceSupported);
+        }
+    }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 0e5a612..5e3a899 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1344,6 +1344,7 @@
             returnConnection.setShowPreciseFailedCause(
                     TelecomAccountRegistry.getInstance(this).isShowPreciseFailedCause(
                             phoneAccountHandle));
+            returnConnection.setTelephonyConnectionService(this);
         }
         return returnConnection;
     }
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 1329a77..ab4c067 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -46,6 +46,7 @@
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 
 import org.junit.After;
@@ -72,6 +73,7 @@
     @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
     @Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
     @Mock TelephonyConnectionService.PhoneFactoryProxy mPhoneFactoryProxy;
+    @Mock EmergencyNumberTracker mEmergencyNumberTracker;
 
     TelephonyConnectionService mTestConnectionService;
 
@@ -818,6 +820,8 @@
         when(phone.getServiceState()).thenReturn(testServiceState);
         when(phone.getPhoneId()).thenReturn(phoneId);
         when(phone.getDefaultPhone()).thenReturn(phone);
+        when(phone.getEmergencyNumberTracker()).thenReturn(mEmergencyNumberTracker);
+        when(mEmergencyNumberTracker.getEmergencyNumber(anyString())).thenReturn(null);
         return phone;
     }
 
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index b6e4bf3..f77fd30 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -23,6 +23,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -31,6 +32,7 @@
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -56,6 +58,9 @@
     @Mock
     Resources mMockResources;
 
+    @Mock
+    EmergencyNumberTracker mEmergencyNumberTracker;
+
     private Phone mMockPhone;
     private int mNotifyPhoneAccountChangedCount = 0;
     private List<String> mLastConnectionEvents = new ArrayList<>();
@@ -80,6 +85,8 @@
         doNothing().when(mMockRadioConnection).addListener(any(Connection.Listener.class));
         doNothing().when(mMockRadioConnection).addPostDialListener(
                 any(Connection.PostDialListener.class));
+        when(mEmergencyNumberTracker.getEmergencyNumber(anyString())).thenReturn(null);
+        when(mMockPhone.getEmergencyNumberTracker()).thenReturn(mEmergencyNumberTracker);
         when(mMockPhone.getRingingCall()).thenReturn(mMockCall);
         when(mMockPhone.getContext()).thenReturn(mMockContext);
         when(mMockPhone.getCurrentSubscriberUris()).thenReturn(null);