Merge "Add IMS Registration Integration"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 69620cd..53384d9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -79,6 +79,7 @@
     <protected-broadcast android:name= "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT" />
     <protected-broadcast android:name= "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" />
     <protected-broadcast android:name= "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO" />
+    <protected-broadcast android:name= "android.intent.action.CURRENT_CARRIER_IDENTITY_CHANGED" />
 
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
diff --git a/res/values/config.xml b/res/values/config.xml
index b3fc30a..1b612c9 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -237,7 +237,7 @@
 
     <!-- Flag indicating whether a system app can use video calling fallback if carrier video
          calling is not available. -->
-    <bool name="config_support_video_calling_fallback">false</bool>
+    <bool name="config_support_video_calling_fallback">true</bool>
 
     <!-- Whether the cellular radio is allowed to be power down when the Bluetooth can provide the data/call capabilities -->
     <bool name="config_allowRadioPowerDownOnBluetooth">false</bool>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7ab8d36..e5dd9b6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1489,4 +1489,114 @@
     <string name="mobile_data_activate_button">ADD DATA</string>
     <!-- activate data plan dialogue button for cancel further actions-->
     <string name="mobile_data_activate_cancel_button">CANCEL</string>
+
+    <!-- Call failed messages -->
+    <!-- In-call screen: status label displayed briefly after a call ends -->
+    <string name="clh_card_title_call_ended_txt">Call ended</string>
+    <!-- In-call screen: call failure reason (radio is off) -->
+    <string name="clh_callFailed_powerOff_txt">Radio off</string>
+    <!-- In-call screen: call failure reason (SIM error) -->
+    <string name="clh_callFailed_simError_txt">No SIM card or SIM card error</string>
+    <!-- In-call screen: call failure message displayed in an error dialog -->
+    <string name="clh_incall_error_out_of_service_txt">Mobile network not available</string>
+
+    <!-- See CallFailCause for details on what causes each message -->
+    <!-- In-call screen: call failure reason (Cause Number 1) -->
+    <string name="clh_callFailed_unassigned_number_txt">Unassigned (unallocated) number</string>
+    <!-- In-call screen: call failure reason (Cause Number 3) -->
+    <string name="clh_callFailed_no_route_to_destination_txt">No route to destination</string>
+    <!-- In-call screen: call failure reason (Cause Number 6) -->
+    <string name="clh_callFailed_channel_unacceptable_txt">Channel unacceptable</string>
+    <!-- In-call screen: call failure reason (Cause Number 8) -->
+    <string name="clh_callFailed_operator_determined_barring_txt">Operator determined barring</string>
+    <!-- In-call screen: call failure reason (Cause Number 16) -->
+    <string name="clh_callFailed_normal_call_clearing_txt">Normal call clearing</string>
+    <!-- In-call screen: call failure reason (Cause Number 17) -->
+    <string name="clh_callFailed_user_busy_txt">User busy</string>
+    <!-- In-call screen: call failure reason (Cause Number 18) -->
+    <string name="clh_callFailed_no_user_responding_txt">No user responding</string>
+    <!-- In-call screen: call failure reason (Cause Number 19) -->
+    <string name="clh_callFailed_user_alerting_txt">User alerting, no answer</string>
+    <!-- In-call screen: call failure reason (Cause Number 21) -->
+    <string name="clh_callFailed_call_rejected_txt">Call rejected</string>
+    <!-- In-call screen: call failure reason (Cause Number 22) -->
+    <string name="clh_callFailed_number_changed_txt">Number changed</string>
+    <!-- In-call screen: call failure reason (Cause Number 25) -->
+    <string name="clh_callFailed_pre_emption_txt">Pre-emption</string>
+    <!-- In-call screen: call failure reason (Cause Number 26) -->
+    <string name="clh_callFailed_non_selected_user_clearing_txt">Non selected user clearing</string>
+    <!-- In-call screen: call failure reason (Cause Number 27) -->
+    <string name="clh_callFailed_destination_out_of_order_txt">Destination out of order</string>
+    <!-- In-call screen: call failure reason (Cause Number 28) -->
+    <string name="clh_callFailed_invalid_number_format_txt">Invalid number format (incomplete number)</string>
+    <!-- In-call screen: call failure reason (Cause Number 29) -->
+    <string name="clh_callFailed_facility_rejected_txt">Facility rejected</string>
+    <!-- In-call screen: call failure reason (Cause Number 30) -->
+    <string name="clh_callFailed_response_to_STATUS_ENQUIRY_txt">Response to STATUS ENQUIRY</string>
+    <!-- In-call screen: call failure reason (Cause Number 31) -->
+    <string name="clh_callFailed_normal_unspecified_txt">Normal, unspecified</string>
+    <!-- In-call screen: call failure reason (Cause Number 34) -->
+    <string name="clh_callFailed_no_circuit_available_txt">No circuit/channel available</string>
+    <!-- In-call screen: call failure reason (Cause Number 38) -->
+    <string name="clh_callFailed_network_out_of_order_txt">Network out of order</string>
+    <!-- In-call screen: call failure reason (Cause Number 41) -->
+    <string name="clh_callFailed_temporary_failure_txt">Temporary failure</string>
+    <!-- In-call screen: call failure reason (Cause Number 42) -->
+    <string name="clh_callFailed_switching_equipment_congestion_txt">Switching equipment congestion</string>
+    <!-- In-call screen: call failure reason (Cause Number 43) -->
+    <string name="clh_callFailed_access_information_discarded_txt">Access information discarded</string>
+    <!-- In-call screen: call failure reason (Cause Number 44) -->
+    <string name="clh_callFailed_requested_circuit_txt">Requested circuit/channel not available</string>
+    <!-- In-call screen: call failure reason (Cause Number 47) -->
+    <string name="clh_callFailed_resources_unavailable_unspecified_txt">Resources unavailable, unspecified</string>
+    <!-- In-call screen: call failure reason (Cause Number 49) -->
+    <string name="clh_callFailed_quality_of_service_unavailable_txt">Quality of service unavailable</string>
+    <!-- In-call screen: call failure reason (Cause Number 50) -->
+    <string name="clh_callFailed_requested_facility_not_subscribed_txt">Requested facility not subscribed</string>
+    <!-- In-call screen: call failure reason (Cause Number 55) -->
+    <string name="clh_callFailed_incoming_calls_barred_within_the_CUG_txt">Incoming calls barred within the CUG</string>
+    <!-- In-call screen: call failure reason (Cause Number 57) -->
+    <string name="clh_callFailed_bearer_capability_not_authorized_txt">Bearer capability not authorized</string>
+    <!-- In-call screen: call failure reason (Cause Number 58) -->
+    <string name="clh_callFailed_bearer_capability_not_presently_available_txt">Bearer capability not presently available</string>
+    <!-- In-call screen: call failure reason (Cause Number 63) -->
+    <string name="clh_callFailed_service_or_option_not_available_unspecified_txt">Service or option not available, unspecified</string>
+    <!-- In-call screen: call failure reason (Cause Number 65) -->
+    <string name="clh_callFailed_bearer_service_not_implemented_txt">Bearer service not implemented</string>
+    <!-- In-call screen: call failure reason (Cause Number 68) -->
+    <string name="clh_callFailed_ACM_equal_to_or_greater_than_ACMmax_txt">ACM equal to or greater than ACMmax</string>
+    <!-- In-call screen: call failure reason (Cause Number 69) -->
+    <string name="clh_callFailed_requested_facility_not_implemented_txt">Requested facility not implemented</string>
+    <!-- In-call screen: call failure reason (Cause Number 70) -->
+    <string name="clh_callFailed_only_restricted_digital_information_bearer_capability_is_available_txt">Only restricted digital information bearer capability is available</string>
+    <!-- In-call screen: call failure reason (Cause Number 79) -->
+    <string name="clh_callFailed_service_or_option_not_implemented_unspecified_txt">Service or option not implemented, unspecified</string>
+    <!-- In-call screen: call failure reason (Cause Number 81) -->
+    <string name="clh_callFailed_invalid_transaction_identifier_value_txt">Invalid transaction identifier value</string>
+    <!-- In-call screen: call failure reason (Cause Number 87) -->
+    <string name="clh_callFailed_user_not_member_of_CUG_txt">User not member of CUG</string>
+    <!-- In-call screen: call failure reason (Cause Number 88) -->
+    <string name="clh_callFailed_incompatible_destination_txt">Incompatible destination</string>
+    <!-- In-call screen: call failure reason (Cause Number 91) -->
+    <string name="clh_callFailed_invalid_transit_network_selection_txt">Invalid transit network selection</string>
+    <!-- In-call screen: call failure reason (Cause Number 95) -->
+    <string name="clh_callFailed_semantically_incorrect_message_txt">Semantically incorrect message</string>
+    <!-- In-call screen: call failure reason (Cause Number 96) -->
+    <string name="clh_callFailed_invalid_mandatory_information_txt">Invalid mandatory information</string>
+    <!-- In-call screen: call failure reason (Cause Number 97) -->
+    <string name="clh_callFailed_message_type_non_existent_or_not_implemented_txt">Message type non-existent or not implemented</string>
+    <!-- In-call screen: call failure reason (Cause Number 98) -->
+    <string name="clh_callFailed_message_type_not_compatible_with_protocol_state_txt">Message type not compatible with protocol state</string>
+    <!-- In-call screen: call failure reason (Cause Number 99) -->
+    <string name="clh_callFailed_information_element_non_existent_or_not_implemented_txt">Information element non-existent or not implemented</string>
+    <!-- In-call screen: call failure reason (Cause Number 100) -->
+    <string name="clh_callFailed_conditional_IE_error_txt">Conditional IE error</string>
+    <!-- In-call screen: call failure reason (Cause Number 101) -->
+    <string name="clh_callFailed_message_not_compatible_with_protocol_state_txt">Message not compatible with protocol state</string>
+    <!-- In-call screen: call failure reason (Cause Number 102) -->
+    <string name="clh_callFailed_recovery_on_timer_expiry_txt">Recovery on timer expiry</string>
+    <!-- In-call screen: call failure reason (Cause Number 111) -->
+    <string name="clh_callFailed_protocol_Error_unspecified_txt">Protocol error, unspecified</string>
+    <!-- In-call screen: call failure reason (Cause Number 127) -->
+    <string name="clh_callFailed_interworking_unspecified_txt">Interworking, unspecified</string>
 </resources>
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index e5527bc..a3b0892 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -16,24 +16,18 @@
 
 package com.android.phone;
 
-import android.app.ActionBar;
 import android.app.Activity;
-import android.app.ActivityOptions;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.os.UserHandle;
 import android.os.UserManager;
-import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
@@ -42,10 +36,9 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
-import android.telephony.ims.feature.ImsFeature;
 import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
-import android.text.TextUtils;
+import android.telephony.ims.feature.ImsFeature;
 import android.util.Log;
 import android.view.MenuItem;
 import android.widget.Toast;
@@ -53,18 +46,12 @@
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsException;
 import com.android.ims.ImsManager;
-import com.android.internal.telephony.CallForwardInfo;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.phone.common.util.SettingsUtil;
-import com.android.phone.settings.AccountSelectionPreference;
 import com.android.phone.settings.PhoneAccountSettingsFragment;
 import com.android.phone.settings.VoicemailSettingsActivity;
 import com.android.phone.settings.fdn.FdnSetting;
-import com.android.services.telephony.sip.SipUtil;
 
-import java.lang.String;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -144,7 +131,7 @@
         if (DBG) log("onPreferenceChange: \"" + preference + "\" changed to \"" + objValue + "\"");
 
         if (preference == mEnableVideoCalling) {
-            if (ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())) {
+            if (mImsMgr.isEnhanced4gLteModeSettingEnabledByUser()) {
                 PhoneGlobals.getInstance().phoneMgr.enableVideoCalling((boolean) objValue);
             } else {
                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
@@ -296,13 +283,12 @@
             }
         }
 
-        if (ImsManager.isVtEnabledByPlatform(mPhone.getContext()) &&
-                ImsManager.isVtProvisionedOnDevice(mPhone.getContext()) &&
-                (carrierConfig.getBoolean(
+        if (mImsMgr.isVtEnabledByPlatform() && mImsMgr.isVtProvisionedOnDevice()
+                && (carrierConfig.getBoolean(
                         CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)
-                        || mPhone.mDcTracker.isDataEnabled())) {
+                || mPhone.mDcTracker.isDataEnabled())) {
             boolean currentValue =
-                    ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
+                    mImsMgr.isEnhanced4gLteModeSettingEnabledByUser()
                     ? PhoneGlobals.getInstance().phoneMgr.isVideoCallingEnabled(
                             getOpPackageName()) : false;
             mEnableVideoCalling.setChecked(currentValue);
@@ -311,8 +297,8 @@
             prefSet.removePreference(mEnableVideoCalling);
         }
 
-        if (ImsManager.isVolteEnabledByPlatform(this) &&
-                !carrierConfig.getBoolean(
+        if (mImsMgr.isVolteEnabledByPlatform()
+                && !carrierConfig.getBoolean(
                         CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
             TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
             /* tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); */
@@ -338,14 +324,13 @@
             } else {
                 prefSet.removePreference(wifiCallingSettings);
             }
-        } else if (!ImsManager.isWfcEnabledByPlatform(mPhone.getContext()) ||
-                !ImsManager.isWfcProvisionedOnDevice(mPhone.getContext())) {
+        } else if (!mImsMgr.isWfcEnabledByPlatform() || !mImsMgr.isWfcProvisionedOnDevice()) {
             prefSet.removePreference(wifiCallingSettings);
         } else {
             int resId = com.android.internal.R.string.wifi_calling_off_summary;
-            if (ImsManager.isWfcEnabledByUser(mPhone.getContext())) {
+            if (mImsMgr.isWfcEnabledByUser()) {
                 boolean isRoaming = telephonyManager.isNetworkRoaming();
-                int wfcMode = ImsManager.getWfcMode(mPhone.getContext(), isRoaming);
+                int wfcMode = mImsMgr.getWfcMode(isRoaming);
                 switch (wfcMode) {
                     case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
                         resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
diff --git a/src/com/android/phone/ImsUtil.java b/src/com/android/phone/ImsUtil.java
index b6c88ae..4d8ff80 100644
--- a/src/com/android/phone/ImsUtil.java
+++ b/src/com/android/phone/ImsUtil.java
@@ -20,6 +20,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
 import android.util.Log;
 
 import com.android.ims.ImsConfig;
@@ -52,8 +53,9 @@
      * @return {@code true} if WFC is supported by the platform and has been enabled by the user.
      */
     public static boolean isWfcEnabled(Context context) {
-        boolean isEnabledByPlatform = ImsManager.isWfcEnabledByPlatform(context);
-        boolean isEnabledByUser = ImsManager.isWfcEnabledByUser(context);
+        ImsManager imsManager = getDefaultImsManagerInstance(context);
+        boolean isEnabledByPlatform = imsManager.isWfcEnabledByPlatform();
+        boolean isEnabledByUser = imsManager.isWfcEnabledByUser();
         if (DBG) Log.d(LOG_TAG, "isWfcEnabled :: isEnabledByPlatform=" + isEnabledByPlatform);
         if (DBG) Log.d(LOG_TAG, "isWfcEnabled :: isEnabledByUser=" + isEnabledByUser);
         return isEnabledByPlatform && isEnabledByUser;
@@ -64,8 +66,8 @@
      * enabled, this will return {@code false}.
      */
     public static boolean isWfcModeWifiOnly(Context context) {
-        boolean isWifiOnlyMode =
-                ImsManager.getWfcMode(context) == ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY;
+        boolean isWifiOnlyMode = getDefaultImsManagerInstance(context).getWfcMode()
+                == ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY;
         if (DBG) Log.d(LOG_TAG, "isWfcModeWifiOnly :: isWifiOnlyMode" + isWifiOnlyMode);
         return isWfcEnabled(context) && isWifiOnlyMode;
     }
@@ -86,7 +88,7 @@
             return false;
         }
 
-        if (!ImsManager.isWfcProvisionedOnDevice(context)) {
+        if (!getDefaultImsManagerInstance(context).isWfcProvisionedOnDevice()) {
             return false;
         }
 
@@ -100,4 +102,8 @@
         }
         return false;
     }
+
+    private static ImsManager getDefaultImsManagerInstance(Context context) {
+        return ImsManager.getInstance(context, SubscriptionManager.getDefaultVoicePhoneId());
+    }
 }
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 4f449cf..5b9e638 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -145,18 +145,29 @@
     }
 
     /**
-     * Whether to show the Enhanced 4G LTE settings.
+     * Whether to show the Enhanced 4G LTE settings in search result.
      *
      * <p>We show this settings if the VoLTE can be enabled by this device and the carrier app
-     * doesn't set {@link CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL} to false.
+     * doesn't set {@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL} to false.
      */
-    public static boolean hideEnhanced4gLteSettings(Context context,
-                PersistableBundle carrierConfig) {
-        return !(ImsManager.isVolteEnabledByPlatform(context)
-            && ImsManager.isVolteProvisionedOnDevice(context))
-            || carrierConfig.getBoolean(
-            CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL);
+    public static boolean hideEnhanced4gLteSettings(Context context) {
+        List<SubscriptionInfo> sil =
+                SubscriptionManager.from(context).getActiveSubscriptionInfoList();
+        // Check all active subscriptions. We only hide the button if it's disabled for all
+        // active subscriptions.
+        for (SubscriptionInfo subInfo : sil) {
+            ImsManager imsManager = ImsManager.getInstance(context, subInfo.getSimSlotIndex());
+            PersistableBundle carrierConfig = PhoneGlobals.getInstance()
+                    .getCarrierConfigForSubId(subInfo.getSubscriptionId());
+            if ((imsManager.isVolteEnabledByPlatform()
+                    && imsManager.isVolteProvisionedOnDevice())
+                    || carrierConfig.getBoolean(
+                    CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL)) {
+                return false;
+            }
+        }
 
+        return true;
     }
 
     public static class MobileNetworkFragment extends PreferenceFragment implements
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index af57f32..64f6214 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -1541,7 +1541,7 @@
         int subId = mSubscriptionController.getDefaultDataSubId();
         final Phone phone = getPhone(subId);
         if (phone != null) {
-            phone.setDataEnabled(true);
+            phone.setUserDataEnabled(true);
             return true;
         } else {
             return false;
@@ -1555,7 +1555,7 @@
         int subId = mSubscriptionController.getDefaultDataSubId();
         final Phone phone = getPhone(subId);
         if (phone != null) {
-            phone.setDataEnabled(false);
+            phone.setUserDataEnabled(false);
             return true;
         } else {
             return false;
@@ -1770,6 +1770,18 @@
       return phone == null ? null : phone.getDeviceSvn();
     }
 
+    @Override
+    public int getSubscriptionCarrierId(int subId) {
+        final Phone phone = getPhone(subId);
+        return phone == null ? TelephonyManager.UNKNOWN_CARRIER_ID : phone.getCarrierId();
+    }
+
+    @Override
+    public String getSubscriptionCarrierName(int subId) {
+        final Phone phone = getPhone(subId);
+        return phone == null ? null : phone.getCarrierName();
+    }
+
     //
     // Internal helper methods.
     //
@@ -2759,28 +2771,46 @@
      * @param enable {@code true} turn turn data on, else {@code false}
      */
     @Override
-    public void setDataEnabled(int subId, boolean enable) {
+    public void setUserDataEnabled(int subId, boolean enable) {
         enforceModifyPermissionOrCarrierPrivilege(subId);
         int phoneId = mSubscriptionController.getPhoneId(subId);
-        if (DBG) log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
+        if (DBG) log("setUserDataEnabled: subId=" + subId + " phoneId=" + phoneId);
         Phone phone = PhoneFactory.getPhone(phoneId);
         if (phone != null) {
-            if (DBG) log("setDataEnabled: subId=" + subId + " enable=" + enable);
-            phone.setDataEnabled(enable);
+            if (DBG) log("setUserDataEnabled: subId=" + subId + " enable=" + enable);
+            phone.setUserDataEnabled(enable);
         } else {
-            loge("setDataEnabled: no phone for subId=" + subId);
+            loge("setUserDataEnabled: no phone for subId=" + subId);
         }
     }
 
     /**
-     * Get whether mobile data is enabled.
+     * Get the user enabled state of Mobile Data.
+     *
+     * TODO: remove and use isUserDataEnabled.
+     * This can't be removed now because some vendor codes
+     * calls through ITelephony directly while they should
+     * use TelephonyManager.
+     *
+     * @return true on enabled
+     */
+    @Override
+    public boolean getDataEnabled(int subId) {
+        return isUserDataEnabled(subId);
+    }
+
+    /**
+     * Get whether mobile data is enabled per user setting.
+     *
+     * There are other factors deciding whether mobile data is actually enabled, but they are
+     * not considered here. See {@link #isDataEnabled(int)} for more details.
      *
      * Accepts either ACCESS_NETWORK_STATE, MODIFY_PHONE_STATE or carrier privileges.
      *
      * @return {@code true} if data is enabled else {@code false}
      */
     @Override
-    public boolean getDataEnabled(int subId) {
+    public boolean isUserDataEnabled(int subId) {
         try {
             mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
                     null);
@@ -2788,14 +2818,45 @@
             enforceModifyPermissionOrCarrierPrivilege(subId);
         }
         int phoneId = mSubscriptionController.getPhoneId(subId);
-        if (DBG) log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
+        if (DBG) log("isUserDataEnabled: subId=" + subId + " phoneId=" + phoneId);
         Phone phone = PhoneFactory.getPhone(phoneId);
         if (phone != null) {
-            boolean retVal = phone.getDataEnabled();
-            if (DBG) log("getDataEnabled: subId=" + subId + " retVal=" + retVal);
+            boolean retVal = phone.isUserDataEnabled();
+            if (DBG) log("isUserDataEnabled: subId=" + subId + " retVal=" + retVal);
             return retVal;
         } else {
-            if (DBG) loge("getDataEnabled: no phone subId=" + subId + " retVal=false");
+            if (DBG) loge("isUserDataEnabled: no phone subId=" + subId + " retVal=false");
+            return false;
+        }
+    }
+
+    /**
+     * Get whether mobile data is enabled.
+     *
+     * Comparable to {@link #isUserDataEnabled(int)}, this considers all factors deciding
+     * whether mobile data is actually enabled.
+     *
+     * Accepts either ACCESS_NETWORK_STATE, MODIFY_PHONE_STATE or carrier privileges.
+     *
+     * @return {@code true} if data is enabled else {@code false}
+     */
+    @Override
+    public boolean isDataEnabled(int subId) {
+        try {
+            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
+                    null);
+        } catch (Exception e) {
+            enforceModifyPermissionOrCarrierPrivilege(subId);
+        }
+        int phoneId = mSubscriptionController.getPhoneId(subId);
+        if (DBG) log("isDataEnabled: subId=" + subId + " phoneId=" + phoneId);
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        if (phone != null) {
+            boolean retVal = phone.isDataEnabled();
+            if (DBG) log("isDataEnabled: subId=" + subId + " retVal=" + retVal);
+            return retVal;
+        } else {
+            if (DBG) loge("isDataEnabled: no phone subId=" + subId + " retVal=false");
             return false;
         }
     }
@@ -3107,7 +3168,7 @@
     @Override
     public void enableVideoCalling(boolean enable) {
         enforceModifyPermission();
-        ImsManager.setVtSetting(mPhone.getContext(), enable);
+        ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()).setVtSetting(enable);
     }
 
     @Override
@@ -3120,9 +3181,10 @@
         // enabled video calling, if IMS is disabled we aren't able to support video calling.
         // In the long run, we may instead need to check if there exists a connection service
         // which can support video calling.
-        return ImsManager.isVtEnabledByPlatform(mPhone.getContext())
-                && ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
-                && ImsManager.isVtEnabledByUser(mPhone.getContext());
+        ImsManager imsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());
+        return imsManager.isVtEnabledByPlatform()
+                && imsManager.isEnhanced4gLteModeSettingEnabledByUser()
+                && imsManager.isVtEnabledByUser();
     }
 
     @Override
@@ -3299,7 +3361,7 @@
             if (SubscriptionManager.isUsableSubIdValue(subId) && !mUserManager.hasUserRestriction(
                     UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
                 // Enable data
-                setDataEnabled(subId, true);
+                setUserDataEnabled(subId, true);
                 // Set network selection mode to automatic
                 setNetworkSelectionModeAutomatic(subId);
                 // Set preferred mobile network type to the best available
diff --git a/src/com/android/phone/PhoneSearchIndexablesProvider.java b/src/com/android/phone/PhoneSearchIndexablesProvider.java
index b0491ec..9c5f354 100644
--- a/src/com/android/phone/PhoneSearchIndexablesProvider.java
+++ b/src/com/android/phone/PhoneSearchIndexablesProvider.java
@@ -36,7 +36,6 @@
 import android.provider.SearchIndexablesContract.RawData;
 import android.provider.SearchIndexablesProvider;
 import android.support.annotation.VisibleForTesting;
-import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 
 public class PhoneSearchIndexablesProvider extends SearchIndexablesProvider {
@@ -126,10 +125,7 @@
     }
 
     @VisibleForTesting boolean isEnhanced4gLteHidden() {
-        TelephonyManager telephonyManager =
-                (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
-        return MobileNetworkSettings
-                .hideEnhanced4gLteSettings(getContext(), telephonyManager.getCarrierConfig());
+        return MobileNetworkSettings.hideEnhanced4gLteSettings(getContext());
     }
 
     private Object[] createNonIndexableRow(String key) {
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 01ccf79..361e5dc 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -20,6 +20,7 @@
 import android.media.ToneGenerator;
 import android.telecom.DisconnectCause;
 
+import com.android.internal.telephony.CallFailCause;
 import com.android.phone.ImsUtil;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.common.R;
@@ -34,7 +35,8 @@
     * @param telephonyDisconnectCause The code for the reason for the disconnect.
     */
     public static DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause) {
-        return toTelecomDisconnectCause(telephonyDisconnectCause, null /* reason */);
+        return toTelecomDisconnectCause(telephonyDisconnectCause,
+                CallFailCause.NOT_VALID, null /* reason */);
     }
 
    /**
@@ -47,10 +49,25 @@
     */
     public static DisconnectCause toTelecomDisconnectCause(
             int telephonyDisconnectCause, String reason) {
+        return toTelecomDisconnectCause(telephonyDisconnectCause, CallFailCause.NOT_VALID, reason);
+    }
+
+   /**
+    * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more
+    * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized
+    * message and tone.
+    *
+    * @param telephonyDisconnectCause The code for the reason for the disconnect.
+    * @param telephonyPerciseDisconnectCause The code for the percise reason for the disconnect.
+    * @param reason Description of the reason for the disconnect, not intended for the user to see..
+    */
+    public static DisconnectCause toTelecomDisconnectCause(
+            int telephonyDisconnectCause, int telephonyPerciseDisconnectCause, String reason) {
         Context context = PhoneGlobals.getInstance();
         return new DisconnectCause(
                 toTelecomDisconnectCauseCode(telephonyDisconnectCause),
-                toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause),
+                toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause,
+                        telephonyPerciseDisconnectCause),
                 toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause),
                 toTelecomDisconnectReason(context,telephonyDisconnectCause, reason),
                 toTelecomDisconnectCauseTone(telephonyDisconnectCause));
@@ -168,8 +185,23 @@
      * Returns a label for to the disconnect cause to be shown to the user.
      */
     private static CharSequence toTelecomDisconnectCauseLabel(
+            Context context, int telephonyDisconnectCause, int telephonyPerciseDisconnectCause) {
+        CharSequence label;
+        if (telephonyPerciseDisconnectCause != CallFailCause.NOT_VALID) {
+            label = getLabelFromPreciseDisconnectCause(context, telephonyPerciseDisconnectCause,
+                    telephonyDisconnectCause);
+        } else {
+            label = getLabelFromDisconnectCause(context, telephonyDisconnectCause);
+        }
+        return label;
+    }
+
+    /**
+     * Returns a label for to the generic disconnect cause to be shown to the user.
+     */
+    private static CharSequence getLabelFromDisconnectCause(
             Context context, int telephonyDisconnectCause) {
-        if (context == null ) {
+        if (context == null) {
             return "";
         }
 
@@ -264,6 +296,190 @@
     }
 
     /**
+     * Returns a label for to the precise disconnect cause to be shown to the user.
+     */
+    private static CharSequence getLabelFromPreciseDisconnectCause(
+            Context context, int telephonyPreciseDisconnectCause, int telephonyDisconnectCause) {
+        if (context == null) {
+            return "";
+        }
+
+        Integer resourceId = null;
+        switch (telephonyPreciseDisconnectCause) {
+            case CallFailCause.UNOBTAINABLE_NUMBER:
+                resourceId = R.string.clh_callFailed_unassigned_number_txt;
+                break;
+            case CallFailCause.NO_ROUTE_TO_DEST:
+                resourceId = R.string.clh_callFailed_no_route_to_destination_txt;
+                break;
+            case CallFailCause.CHANNEL_UNACCEPTABLE:
+                resourceId = R.string.clh_callFailed_channel_unacceptable_txt;
+                break;
+            case CallFailCause.OPERATOR_DETERMINED_BARRING:
+                resourceId = R.string.clh_callFailed_operator_determined_barring_txt;
+                break;
+            case CallFailCause.NORMAL_CLEARING:
+                resourceId = R.string.clh_callFailed_normal_call_clearing_txt;
+                break;
+            case CallFailCause.USER_BUSY:
+                resourceId = R.string.clh_callFailed_user_busy_txt;
+                break;
+            case CallFailCause.NO_USER_RESPONDING:
+                resourceId = R.string.clh_callFailed_no_user_responding_txt;
+                break;
+            case CallFailCause.USER_ALERTING_NO_ANSWER:
+                resourceId = R.string.clh_callFailed_user_alerting_txt;
+                break;
+            case CallFailCause.CALL_REJECTED:
+                resourceId = R.string.clh_callFailed_call_rejected_txt;
+                break;
+            case CallFailCause.NUMBER_CHANGED:
+                resourceId = R.string.clh_callFailed_number_changed_txt;
+                break;
+            case CallFailCause.PRE_EMPTION:
+                resourceId = R.string.clh_callFailed_pre_emption_txt;
+                break;
+            case CallFailCause.NON_SELECTED_USER_CLEARING:
+                resourceId = R.string.clh_callFailed_non_selected_user_clearing_txt;
+                break;
+            case CallFailCause.DESTINATION_OUT_OF_ORDER:
+                resourceId = R.string.clh_callFailed_destination_out_of_order_txt;
+                break;
+            case CallFailCause.INVALID_NUMBER_FORMAT:
+                resourceId = R.string.clh_callFailed_invalid_number_format_txt;
+                break;
+            case CallFailCause.FACILITY_REJECTED:
+                resourceId = R.string.clh_callFailed_facility_rejected_txt;
+                break;
+            case CallFailCause.STATUS_ENQUIRY:
+                resourceId = R.string.clh_callFailed_response_to_STATUS_ENQUIRY_txt;
+                break;
+            case CallFailCause.NORMAL_UNSPECIFIED:
+                resourceId = R.string.clh_callFailed_normal_unspecified_txt;
+                break;
+            case CallFailCause.NO_CIRCUIT_AVAIL:
+                resourceId = R.string.clh_callFailed_no_circuit_available_txt;
+                break;
+            case CallFailCause.NETWORK_OUT_OF_ORDER:
+                resourceId = R.string.clh_callFailed_network_out_of_order_txt;
+                break;
+            case CallFailCause.TEMPORARY_FAILURE:
+                resourceId = R.string.clh_callFailed_temporary_failure_txt;
+                break;
+            case CallFailCause.SWITCHING_CONGESTION:
+                resourceId = R.string.clh_callFailed_switching_equipment_congestion_txt;
+                break;
+            case CallFailCause.ACCESS_INFORMATION_DISCARDED:
+                resourceId = R.string.clh_callFailed_access_information_discarded_txt;
+                break;
+            case CallFailCause.CHANNEL_NOT_AVAIL:
+                resourceId = R.string.clh_callFailed_requested_circuit_txt;
+                break;
+            case CallFailCause.RESOURCES_UNAVAILABLE_UNSPECIFIED:
+                resourceId = R.string.clh_callFailed_resources_unavailable_unspecified_txt;
+                break;
+            case CallFailCause.QOS_NOT_AVAIL:
+                resourceId = R.string.clh_callFailed_quality_of_service_unavailable_txt;
+                break;
+            case CallFailCause.REQUESTED_FACILITY_NOT_SUBSCRIBED:
+                resourceId = R.string.clh_callFailed_requested_facility_not_subscribed_txt;
+                break;
+            case CallFailCause.INCOMING_CALL_BARRED_WITHIN_CUG:
+                resourceId = R.string.clh_callFailed_incoming_calls_barred_within_the_CUG_txt;
+                break;
+            case CallFailCause.BEARER_CAPABILITY_NOT_AUTHORISED:
+                resourceId = R.string.clh_callFailed_bearer_capability_not_authorized_txt;
+                break;
+            case CallFailCause.BEARER_NOT_AVAIL:
+                resourceId = R.string.clh_callFailed_bearer_capability_not_presently_available_txt;
+                break;
+            case CallFailCause.SERVICE_OR_OPTION_NOT_AVAILABLE:
+                resourceId =
+                        R.string.clh_callFailed_service_or_option_not_available_unspecified_txt;
+                break;
+            case CallFailCause.BEARER_SERVICE_NOT_IMPLEMENTED:
+                resourceId = R.string.clh_callFailed_bearer_service_not_implemented_txt;
+                break;
+            case CallFailCause.ACM_LIMIT_EXCEEDED:
+                resourceId = R.string.clh_callFailed_ACM_equal_to_or_greater_than_ACMmax_txt;
+                break;
+            case CallFailCause.REQUESTED_FACILITY_NOT_IMPLEMENTED:
+                resourceId = R.string.clh_callFailed_requested_facility_not_implemented_txt;
+                break;
+            case CallFailCause.ONLY_RESTRICTED_DIGITAL_INFO_BC_AVAILABLE:
+                resourceId = R.string
+                        .clh_callFailed_only_restricted_digital_information_bearer_capability_is_available_txt;
+                break;
+            case CallFailCause.SERVICE_OR_OPTION_NOT_IMPLEMENTED:
+                resourceId =
+                        R.string.clh_callFailed_service_or_option_not_implemented_unspecified_txt;
+                break;
+            case CallFailCause.INVALID_TRANSACTION_ID_VALUE:
+                resourceId = R.string.clh_callFailed_invalid_transaction_identifier_value_txt;
+                break;
+            case CallFailCause.USER_NOT_MEMBER_OF_CUG:
+                resourceId = R.string.clh_callFailed_user_not_member_of_CUG_txt;
+                break;
+            case CallFailCause.INCOMPATIBLE_DESTINATION:
+                resourceId = R.string.clh_callFailed_incompatible_destination_txt;
+                break;
+            case CallFailCause.INVALID_TRANSIT_NETWORK_SELECTION:
+                resourceId = R.string.clh_callFailed_invalid_transit_network_selection_txt;
+                break;
+            case CallFailCause.SEMANTICALLY_INCORRECT_MESSAGE:
+                resourceId = R.string.clh_callFailed_semantically_incorrect_message_txt;
+                break;
+            case CallFailCause.INVALID_MANDATORY_INFORMATION:
+                resourceId = R.string.clh_callFailed_invalid_mandatory_information_txt;
+                break;
+            case CallFailCause.MESSAGE_TYPE_NON_EXISTENT:
+                resourceId =
+                        R.string.clh_callFailed_message_type_non_existent_or_not_implemented_txt;
+                break;
+            case CallFailCause.MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROT_STATE:
+                resourceId = R.string
+                        .clh_callFailed_message_type_not_compatible_with_protocol_state_txt;
+                break;
+            case CallFailCause.IE_NON_EXISTENT_OR_NOT_IMPLEMENTED:
+                resourceId = R.string
+                        .clh_callFailed_information_element_non_existent_or_not_implemented_txt;
+                break;
+            case CallFailCause.CONDITIONAL_IE_ERROR:
+                resourceId = R.string.clh_callFailed_conditional_IE_error_txt;
+                break;
+            case CallFailCause.MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE:
+                resourceId = R.string.clh_callFailed_message_not_compatible_with_protocol_state_txt;
+                break;
+            case CallFailCause.RECOVERY_ON_TIMER_EXPIRY:
+                resourceId = R.string.clh_callFailed_recovery_on_timer_expiry_txt;
+                break;
+            case CallFailCause.PROTOCOL_ERROR_UNSPECIFIED:
+                resourceId = R.string.clh_callFailed_protocol_Error_unspecified_txt;
+                break;
+            case CallFailCause.INTERWORKING_UNSPECIFIED:
+                resourceId = R.string.clh_callFailed_interworking_unspecified_txt;
+                break;
+            default:
+                switch (telephonyDisconnectCause) {
+                    case android.telephony.DisconnectCause.POWER_OFF:
+                        resourceId = R.string.clh_callFailed_powerOff_txt;
+                        break;
+                    case android.telephony.DisconnectCause.ICC_ERROR:
+                        resourceId = R.string.clh_callFailed_simError_txt;
+                        break;
+                    case android.telephony.DisconnectCause.OUT_OF_SERVICE:
+                        resourceId = R.string.clh_incall_error_out_of_service_txt;
+                        break;
+                    default:
+                        resourceId = R.string.clh_card_title_call_ended_txt;
+                        break;
+                }
+                break;
+        }
+        return context.getResources().getString(resourceId);
+    }
+
+    /**
      * Returns a description of the disconnect cause to be shown to the user.
      */
     private static CharSequence toTelecomDisconnectCauseDescription(
diff --git a/src/com/android/services/telephony/Log.java b/src/com/android/services/telephony/Log.java
index a56e8b1..9941a59 100644
--- a/src/com/android/services/telephony/Log.java
+++ b/src/com/android/services/telephony/Log.java
@@ -43,7 +43,6 @@
         // Register Telephony with the Telecom Logger.
         android.telecom.Log.setTag(TAG);
         android.telecom.Log.setSessionContext(context);
-        android.telecom.Log.initMd5Sum();
     }
 
     // Relay log messages to Telecom
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 49a21c8..3f21d17 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -83,6 +83,7 @@
         private boolean mIsVideoConferencingSupported;
         private boolean mIsMergeOfWifiCallsAllowedWhenVoWifiOff;
         private boolean mIsManageImsConferenceCallSupported;
+        private boolean mIsShowPreciseFailedCause;
 
         AccountEntry(Phone phone, boolean isEmergency, boolean isDummy) {
             mPhone = phone;
@@ -184,8 +185,8 @@
             }
 
             mIsVideoCapable = mPhone.isVideoEnabled();
-            boolean isVideoEnabledByPlatform =
-                    ImsManager.isVtEnabledByPlatform(mPhone.getContext());
+            boolean isVideoEnabledByPlatform = ImsManager.getInstance(mPhone.getContext(),
+                    mPhone.getPhoneId()).isVtEnabledByPlatform();
 
             if (!mIsPrimaryUser) {
                 Log.i(this, "Disabling video calling for secondary user.");
@@ -247,6 +248,7 @@
             mIsMergeOfWifiCallsAllowedWhenVoWifiOff =
                     isCarrierMergeOfWifiCallsAllowedWhenVoWifiOff();
             mIsManageImsConferenceCallSupported = isCarrierManageImsConferenceCallSupported();
+            mIsShowPreciseFailedCause = isCarrierShowPreciseFailedCause();
 
             if (isEmergency && mContext.getResources().getBoolean(
                     R.bool.config_emergency_account_emergency_calls_only)) {
@@ -429,6 +431,19 @@
         }
 
         /**
+         * Determines from carrier config whether showing percise call diconnect cause to user
+         * is supported.
+         *
+         * @return {@code true} if showing percise call diconnect cause to user is supported,
+         *         {@code false} otherwise.
+         */
+        private boolean isCarrierShowPreciseFailedCause() {
+            PersistableBundle b =
+                    PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            return b.getBoolean(CarrierConfigManager.KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL);
+        }
+
+        /**
          * Where a device supports instant lettering and call subjects, retrieves the necessary
          * PhoneAccount extras for those features.
          * @return The {@link PhoneAccount} extras associated with the current subscription.
@@ -519,6 +534,16 @@
         public boolean isManageImsConferenceCallSupported() {
             return mIsManageImsConferenceCallSupported;
         }
+
+        /**
+         * Indicates whether this account supports showing the precise call disconnect cause
+         * to user (i.e. conferencing).
+         * @return {@code true} if the account supports showing the precise call disconnect cause,
+         *         {@code false} otherwise.
+         */
+        public boolean isShowPreciseFailedCause() {
+            return mIsShowPreciseFailedCause;
+        }
     }
 
     private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
@@ -706,6 +731,23 @@
     }
 
     /**
+     * showing precise call disconnect cause to the user.
+     *
+     * @param handle The {@link PhoneAccountHandle}.
+     * @return {@code True} if showing precise call disconnect cause to the user is supported.
+     */
+    boolean isShowPreciseFailedCause(PhoneAccountHandle handle) {
+        synchronized (mAccountsLock) {
+            for (AccountEntry entry : mAccounts) {
+                if (entry.getPhoneAccountHandle().equals(handle)) {
+                    return entry.isShowPreciseFailedCause();
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * @return Reference to the {@code TelecomAccountRegistry}'s subscription manager.
      */
     SubscriptionManager getSubscriptionManager() {
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index bd8fb71..2358160 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -40,6 +40,7 @@
 import com.android.ims.ImsCall;
 import com.android.ims.ImsCallProfile;
 import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallFailCause;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection.Capability;
 import com.android.internal.telephony.Connection.PostDialListener;
@@ -525,6 +526,11 @@
     private boolean mIsUsingAssistedDialing;
 
     /**
+     * Indicates whether this connection supports showing preciese call failed cause.
+     */
+    private boolean mShowPreciseFailedCause;
+
+    /**
      * Listeners to our TelephonyConnection specific callbacks
      */
     private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
@@ -1362,8 +1368,14 @@
                         fireOnOriginalConnectionRetryDial(cause
                                 == android.telephony.DisconnectCause.EMERGENCY_PERM_FAILURE);
                     } else {
+                        int preciseDisconnectCause = CallFailCause.NOT_VALID;
+                        if (mShowPreciseFailedCause) {
+                            preciseDisconnectCause =
+                                    mOriginalConnection.getPreciseDisconnectCause();
+                        }
                         setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
                                 mOriginalConnection.getDisconnectCause(),
+                                preciseDisconnectCause,
                                 mOriginalConnection.getVendorDisconnectCause()));
                         close();
                     }
@@ -1680,6 +1692,15 @@
     }
 
     /**
+     * Sets whether this connection supports showing precise call disconnect cause.
+     * @param showPreciseFailedCause  {@code true} if showing precise call
+     * disconnect cause is supported by this connection, {@code false} otherwise.
+     */
+    public void setShowPreciseFailedCause(boolean showPreciseFailedCause) {
+        mShowPreciseFailedCause = showPreciseFailedCause;
+    }
+
+    /**
      * Whether the original connection is an IMS connection.
      * @return {@code True} if the original connection is an IMS connection, {@code false}
      *     otherwise.
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index ea460cf..8584d42 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1053,6 +1053,9 @@
             returnConnection.setManageImsConferenceCallSupported(
                     TelecomAccountRegistry.getInstance(this).isManageImsConferenceCallSupported(
                             phoneAccountHandle));
+            returnConnection.setShowPreciseFailedCause(
+                    TelecomAccountRegistry.getInstance(this).isShowPreciseFailedCause(
+                            phoneAccountHandle));
         }
         return returnConnection;
     }