Merge "Deliver precise disconnect cause"
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/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/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 49a21c8..dacf7e0 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;
@@ -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;
     }