Merge "Merge tag 'AU_LINUX_ANDROID_LA.BF64.1.2.1_RB2.05.00.02.081.002' into HEAD"
diff --git a/src/java/com/android/ims/ImsCall.java b/src/java/com/android/ims/ImsCall.java
old mode 100644
new mode 100755
index be722c7..0a98d8e
--- a/src/java/com/android/ims/ImsCall.java
+++ b/src/java/com/android/ims/ImsCall.java
@@ -28,9 +28,13 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Message;
+import android.provider.Settings;
 import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
+import android.telecom.TelecomManager;
 import android.telephony.Rlog;
+import android.util.Log;
+import android.widget.Toast;
 
 import com.android.ims.internal.CallGroup;
 import com.android.ims.internal.CallGroupManager;
@@ -54,7 +58,9 @@
     public static final int USSD_MODE_REQUEST = 1;
 
     private static final String TAG = "ImsCall";
-    private static final boolean DBG = true;
+    private static final boolean FORCE_DEBUG = false; /* STOPSHIP if true */
+    private static final boolean DBG = FORCE_DEBUG || Rlog.isLoggable(TAG, Log.DEBUG);
+    private static final boolean VDBG = FORCE_DEBUG || Rlog.isLoggable(TAG, Log.VERBOSE);
 
     private List<ConferenceParticipant> mConferenceParticipants;
     private boolean mIsCEPPresent = false;
@@ -2935,6 +2941,40 @@
                 }
             }
         }
+
+        @Override
+        public void callSessionTtyModeReceived(ImsCallSession session, int mode) {
+            if (DBG) {
+                log("callSessionTtyModeReceived :: session=" + session
+                        + ", mode=" + mode);
+            }
+
+            int settingsTtyMode = Settings.Secure.getInt(
+                    mContext.getContentResolver(),
+                    Settings.Secure.PREFERRED_TTY_MODE,
+                    TelecomManager.TTY_MODE_OFF);
+            if (settingsTtyMode == TelecomManager.TTY_MODE_OFF) {
+                // Notify the user that TTY mode changed in the far device
+                int resId = 0;
+                switch (mode) {
+                    case TelecomManager.TTY_MODE_FULL:
+                        resId = com.android.internal.R.string.peerTtyModeFull;
+                        break;
+                    case TelecomManager.TTY_MODE_HCO:
+                        resId = com.android.internal.R.string.peerTtyModeHco;
+                        break;
+                    case TelecomManager.TTY_MODE_VCO:
+                        resId = com.android.internal.R.string.peerTtyModeVco;
+                        break;
+                    case TelecomManager.TTY_MODE_OFF:
+                        resId = com.android.internal.R.string.peerTtyModeOff;
+                        break;
+                }
+                if (resId != 0) {
+                    Toast.makeText(mContext, resId, Toast.LENGTH_SHORT).show();
+                }
+            }
+        }
     }
 
     /**
@@ -2962,4 +3002,54 @@
             }
         }
     }
+
+    /**
+     * Provides a human-readable string representation of an update request.
+     *
+     * @param updateRequest The update request.
+     * @return The string representation.
+     */
+    private String updateRequestToString(int updateRequest) {
+        switch (updateRequest) {
+            case UPDATE_NONE:
+                return "NONE";
+            case UPDATE_HOLD:
+                return "HOLD";
+            case UPDATE_HOLD_MERGE:
+                return "HOLD_MERGE";
+            case UPDATE_RESUME:
+                return "RESUME";
+            case UPDATE_MERGE:
+                return "MERGE";
+            case UPDATE_EXTEND_TO_CONFERENCE:
+                return "EXTEND_TO_CONFERENCE";
+            case UPDATE_UNSPECIFIED:
+                return "UNSPECIFIED";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Provides a string representation of the {@link ImsCall}.  Primarily intended for use in log
+     * statements.
+     *
+     * @return String representation of call.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[ImsCall objId:");
+        sb.append(System.identityHashCode(this));
+        sb.append(" multiParty:");
+        sb.append(isMultiparty()?"Y":"N");
+        sb.append(" session:");
+        sb.append(mSession);
+        sb.append(" updateRequest:");
+        sb.append(updateRequestToString(mUpdateRequest));
+        sb.append(" transientSession:");
+        sb.append(mTransientConferenceSession);
+        sb.append("]");
+        return sb.toString();
+    }
 }
diff --git a/src/java/com/android/ims/ImsConfig.java b/src/java/com/android/ims/ImsConfig.java
index 32f2e4b..94f4e73 100644
--- a/src/java/com/android/ims/ImsConfig.java
+++ b/src/java/com/android/ims/ImsConfig.java
@@ -16,6 +16,7 @@
 
 package com.android.ims;
 
+import android.content.Context;
 import android.os.RemoteException;
 import android.telephony.Rlog;
 
@@ -34,6 +35,8 @@
     private static final String TAG = "ImsConfig";
     private boolean DBG = true;
     private final IImsConfig miConfig;
+    private Context mContext;
+    private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE;
 
     /**
     * Defines IMS service/capability feature constants.
@@ -114,7 +117,7 @@
         public static final int MIN_SE = 3;
 
         /**
-         * SIP_INVITE cancellation time out value. Integer format.
+         * SIP_INVITE cancellation time out value (in milliseconds). Integer format.
          * Value is in Integer format.
          */
         public static final int CANCELLATION_TIMER = 4;
@@ -132,19 +135,19 @@
         public static final int SILENT_REDIAL_ENABLE = 6;
 
         /**
-         * SIP T1 timer value in seconds. See RFC 3261 for define.
+         * SIP T1 timer value in milliseconds. See RFC 3261 for define.
          * Value is in Integer format.
          */
         public static final int SIP_T1_TIMER = 7;
 
         /**
-         * SIP T2 timer value in seconds.  See RFC 3261 for define.
+         * SIP T2 timer value in milliseconds.  See RFC 3261 for define.
          * Value is in Integer format.
          */
         public static final int SIP_T2_TIMER  = 8;
 
          /**
-         * SIP TF timer value in seconds.  See RFC 3261 for define.
+         * SIP TF timer value in milliseconds.  See RFC 3261 for define.
          * Value is in Integer format.
          */
         public static final int SIP_TF_TIMER = 9;
@@ -160,10 +163,74 @@
          * Value is in Integer format.
          */
         public static final int LVC_SETTING_ENABLED = 11;
-
+        /**
+         * Domain Name for the device to populate the request URI for REGISTRATION.
+         * Value is in String format.
+         */
+        public static final int DOMAIN_NAME = 12;
+         /**
+         * Device Outgoing SMS based on either 3GPP or 3GPP2 standards.
+         * Value is in Integer format. 3GPP2(0), 3GPP(1)
+         */
+        public static final int SMS_FORMAT = 13;
+         /**
+         * Turns IMS ON/OFF on the device.
+         * Value is in Integer format. ON (1), OFF(0).
+         */
+        public static final int SMS_OVER_IP = 14;
+        /**
+         * Requested expiration for Published Online availability.
+         * Value is in Integer format.
+         */
+        public static final int PUBLISH_TIMER = 15;
+        /**
+         * Requested expiration for Published Offline availability.
+         * Value is in Integer format.
+         */
+        public static final int PUBLISH_TIMER_EXTENDED = 16;
+        /**
+         * Period of time the capability information of the  contact is cached on handset.
+         * Value is in Integer format.
+         */
+        public static final int CAPABILITIES_CACHE_EXPIRATION = 17;
+        /**
+         * Peiod of time the availability information of a contact is cached on device.
+         * Value is in Integer format.
+         */
+        public static final int AVAILABILITY_CACHE_EXPIRATION = 18;
+        /**
+         * Interval between successive capabilities polling.
+         * Value is in Integer format.
+         */
+        public static final int CAPABILITIES_POLL_INTERVAL = 19;
+        /**
+         * Minimum time between two published messages from the device.
+         * Value is in Integer format.
+         */
+        public static final int SOURCE_THROTTLE_PUBLISH = 20;
+        /**
+         * The Maximum number of MDNs contained in one Request Contained List.
+         * Value is in Integer format.
+         */
+        public static final int MAX_NUMENTRIES_IN_RCL = 21;
+        /**
+         * Expiration timer for subscription of a Request Contained List, used in capability polling.
+         * Value is in Integer format.
+         */
+        public static final int CAPAB_POLL_LIST_SUB_EXP = 22;
+        /**
+         * Applies compression to LIST Subscription.
+         * Value is in Integer format. Enable (1), Disable(0).
+         */
+        public static final int GZIP_FLAG = 23;
+        /**
+         * VOLTE Status for EAB/s status of Enabled (1), or Disabled (0).
+         * Value is in Integer format.
+         */
+        public static final int EAB_SETTING_ENABLED = 24;
         // Expand the operator config items as needed here, need to change
         // PROVISIONED_CONFIG_END after that.
-        public static final int PROVISIONED_CONFIG_END = LVC_SETTING_ENABLED;
+        public static final int PROVISIONED_CONFIG_END = EAB_SETTING_ENABLED;
 
         // Expand the operator config items as needed here.
     }
@@ -200,9 +267,10 @@
         public static final int ON = 1;
     }
 
-    public ImsConfig(IImsConfig iconfig) {
+    public ImsConfig(IImsConfig iconfig, Context context) {
         if (DBG) Rlog.d(TAG, "ImsConfig creates");
         miConfig = iconfig;
+        mContext = context;
     }
 
     /**
@@ -243,7 +311,7 @@
         try {
             ret = miConfig.getMasterStringValue(item);
         }  catch (RemoteException e) {
-            throw new ImsException("getStringValue()", e,
+            throw new ImsException("getMasterStringValue()", e,
                     ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
         }
         if (DBG) Rlog.d(TAG, "getMasterStringValue(): item = " + item + ", ret =" + ret);
@@ -252,55 +320,115 @@
     }
 
     /**
-     * Sets the value for IMS service/capabilities parameters by
-     * the operator device management entity.
-     * This function should not be called from main thread as it could block
-     * mainthread to cause ANR.
+     * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+     * This function should not be called from the mainthread as it could block the
+     * mainthread.
      *
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
-     * @param value in Integer format.
-     * @return void
+     * @return the value in Integer format.
      *
      * @throws ImsException if calling the IMS service results in an error.
      */
-    public void setProvisionedValue(int item, int value)
-            throws ImsException {
-        // TODO: ADD PERMISSION CHECK
-        if (DBG) {
-            Rlog.d(TAG, "setProvisionedValue(): item = " + item +
-                    "value = " + value);
-        }
+    public int getProvisionedValue(int item) throws ImsException {
+        int ret = 0;
+        /*
         try {
-            miConfig.setProvisionedValue(item, value);
+            ret = miConfig.getProvisionedValue(item);
         }  catch (RemoteException e) {
-            throw new ImsException("setProvisionedValue()", e,
+            throw new ImsException("getValue()", e,
                     ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
         }
+        */
+        if (DBG) Rlog.d(TAG, "getProvisionedValue(): item = " + item + ", ret =" + ret);
+
+        return ret;
+    }
+
+    /**
+     * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+     * This function should not be called from the mainthread as it could block the
+     * mainthread.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @return value in String format.
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public String getProvisionedStringValue(int item) throws ImsException {
+        String ret = "Unknown";
+        /*
+        try {
+            ret = miConfig.getProvisionedStringValue(item);
+        }  catch (RemoteException e) {
+            throw new ImsException("getProvisionedStringValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+        */
+        if (DBG) Rlog.d(TAG, "getProvisionedStringValue(): item = " + item + ", ret =" + ret);
+
+        return ret;
     }
 
     /**
      * Sets the value for IMS service/capabilities parameters by
      * the operator device management entity.
+     * This function should not be called from main thread as it could block
+     * mainthread.
      *
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
-     * @param value in String format.
-     * @return void.
+     * @param value in Integer format.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
      *
      * @throws ImsException if calling the IMS service results in an error.
      */
-    public void setProvisionedStringValue(int item, String value)
+    public int setProvisionedValue(int item, int value)
             throws ImsException {
-        // TODO: ADD PERMISSION CHECK
+        mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+        int ret = ImsConfig.OperationStatusConstants.UNKNOWN;
         if (DBG) {
-            Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
-                    ", value =" + value);
+            Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+                    "value = " + value);
         }
         try {
-            miConfig.setProvisionedStringValue(item, value);
+            ret = miConfig.setProvisionedValue(item, value);
+        }  catch (RemoteException e) {
+            throw new ImsException("setProvisionedValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+        if (DBG) {
+            Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+                    " value = " + value + " ret = " + ret);
+        }
+        return ret;
+    }
+
+    /**
+     * Sets the value for IMS service/capabilities parameters by
+     * the operator device management entity.
+     * This function should not be called from main thread as it could block
+     * mainthread.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in String format.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public int setProvisionedStringValue(int item, String value)
+            throws ImsException {
+        mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+        int ret = ImsConfig.OperationStatusConstants.UNKNOWN;
+        try {
+            ret = miConfig.setProvisionedStringValue(item, value);
         }  catch (RemoteException e) {
             throw new ImsException("setProvisionedStringValue()", e,
                     ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
         }
+        if (DBG) {
+            Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
+                    ", value =" + value);
+        }
+        return ret;
     }
 
     /**
@@ -340,7 +468,7 @@
      */
     public void setFeatureValue(int feature, int network, int value,
             ImsConfigListener listener) throws ImsException {
-        // TODO: ADD PERMISSION CHECK (should there be permission, same as provisioning?)
+        mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
         if (DBG) {
             Rlog.d(TAG, "setFeatureValue: feature = " + feature + ", network =" + network +
                     ", value =" + value + ", listener =" + listener);
@@ -387,4 +515,25 @@
                     ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
         }
      }
+
+    /**
+     * Gets the value for IMS Volte provisioned.
+     * It should be the same as operator provisioned value if applies.
+     *
+     * @return boolean
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public boolean getVolteProvisioned() throws ImsException {
+        Rlog.d(TAG, "getVolteProvisioned() forced to return true!");
+        /*
+        try {
+           return miConfig.getVolteProvisioned();
+        } catch (RemoteException e) {
+            throw new ImsException("getVolteProvisioned()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+        */
+        return true;
+    }
 }
diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java
index 27a9924..5aaf68f 100644
--- a/src/java/com/android/ims/ImsManager.java
+++ b/src/java/com/android/ims/ImsManager.java
@@ -27,7 +27,9 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.provider.Settings;
+import android.telecom.TelecomManager;
 import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import com.android.ims.internal.IImsCallSession;
@@ -52,18 +54,14 @@
  * @hide
  */
 public class ImsManager {
-    /*
-     * Shared preference constants storing the "Enhanced 4G LTE Mode" configuration
-     */
-    public static final String IMS_SHARED_PREFERENCES = "IMS_PREFERENCES";
-    public static final String KEY_IMS_ON = "IMS";
-    public static final boolean IMS_DEFAULT_SETTING = true;
 
     /*
      * Debug flag to override configuration flag
      */
-    public static final String PROPERTY_DBG_VOLTE_VT_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
-    public static final int PROPERTY_DBG_VOLTE_VT_AVAIL_OVERRIDE_DEFAULT = 0;
+    public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
+    public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0;
+    public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr";
+    public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0;
 
     /**
      * For accessing the IMS related service.
@@ -102,19 +100,11 @@
 
     /**
      * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
-     * A long value; the subId corresponding to the IMS service coming up or down.
+     * A long value; the phone ID corresponding to the IMS service coming up or down.
      * Internal use only.
      * @hide
      */
-    public static final String EXTRA_SUBID = "android:subid";
-
-    /**
-     * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
-     * A int value; the phoneId corresponding to the IMS service coming up or down.
-     * Internal use only.
-     * @hide
-     */
-    public static final String EXTRA_PHONEID = "android:phoneid";
+    public static final String EXTRA_PHONE_ID = "android:phone_id";
 
     /**
      * Action for the incoming call intent for the Phone app.
@@ -207,11 +197,11 @@
     private static final String TAG = "ImsManager";
     private static final boolean DBG = true;
 
-    private static HashMap<Long, ImsManager> sImsManagerInstances =
-            new HashMap<Long, ImsManager>();
+    private static HashMap<Integer, ImsManager> sImsManagerInstances =
+            new HashMap<Integer, ImsManager>();
 
     private Context mContext;
-    private long mSubId;
+    private int mPhoneId;
     private IImsService mImsService = null;
     private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
     // Ut interface for the supplementary service configuration
@@ -226,16 +216,16 @@
      * Gets a manager instance.
      *
      * @param context application context for creating the manager object
-     * @param subId the subscription ID for the IMS Service
-     * @return the manager instance corresponding to the subId
+     * @param phoneId the phone ID for the IMS Service
+     * @return the manager instance corresponding to the phoneId
      */
-    public static ImsManager getInstance(Context context, long subId) {
+    public static ImsManager getInstance(Context context, int phoneId) {
         synchronized (sImsManagerInstances) {
-            if (sImsManagerInstances.containsKey(subId))
-                return sImsManagerInstances.get(subId);
+            if (sImsManagerInstances.containsKey(phoneId))
+                return sImsManagerInstances.get(phoneId);
 
-            ImsManager mgr = new ImsManager(context, subId);
-            sImsManagerInstances.put(subId, mgr);
+            ImsManager mgr = new ImsManager(context, phoneId);
+            sImsManagerInstances.put(phoneId, mgr);
 
             return mgr;
         }
@@ -245,34 +235,115 @@
      * Returns the user configuration of Enhanced 4G LTE Mode setting
      */
     public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
-        boolean imsEnabled = IMS_DEFAULT_SETTING;
-        try {
-            imsEnabled = (Settings.System.getInt(context.getContentResolver(),
-                    KEY_IMS_ON)) == 1 ? true : false;
-        } catch(Exception e) {
-        }
-        return imsEnabled;
+        int enabled = android.provider.Settings.Global.getInt(
+                    context.getContentResolver(),
+                    android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+        return (enabled == 1)? true:false;
     }
 
     /**
-     * Returns a platform configuration which may override the user setting.
+     * Change persistent Enhanced 4G LTE Mode setting
      */
-    public static boolean isEnhanced4gLteModeSettingEnabledByPlatform(Context context) {
-        if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_VT_AVAIL_OVERRIDE,
-                PROPERTY_DBG_VOLTE_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
+    public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
+        int value = enabled ? 1 : 0;
+        android.provider.Settings.Global.putInt(
+                context.getContentResolver(),
+                android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);
+
+        if (isNonTtyOrTtyOnVolteEnabled(context)) {
+            ImsManager imsManager = ImsManager.getInstance(context,
+                    SubscriptionManager.getDefaultVoicePhoneId());
+            if (imsManager != null) {
+                try {
+                    imsManager.setAdvanced4GMode(enabled);
+                } catch (ImsException ie) {
+                    // do nothing
+                }
+            }
+        }
+    }
+
+    /**
+     * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
+     * supported.
+     */
+    public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
+        if (context.getResources().getBoolean(
+                com.android.internal.R.bool.config_carrier_volte_tty_supported)) {
+            return true;
+        }
+
+        return Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
+                == TelecomManager.TTY_MODE_OFF;
+    }
+
+    /**
+     * Returns a platform configuration for VoLTE which may override the user setting.
+     */
+    public static boolean isVolteEnabledByPlatform(Context context) {
+        if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
+                PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
+            return true;
+        }
+
+        boolean disabledByGlobalSetting = android.provider.Settings.Global.getInt(
+                context.getContentResolver(),
+                android.provider.Settings.Global.VOLTE_FEATURE_DISABLED, 0) == 1;
+
+        return context.getResources().getBoolean(
+                com.android.internal.R.bool.config_device_volte_available) && context.getResources()
+                .getBoolean(com.android.internal.R.bool.config_carrier_volte_available)
+                && !disabledByGlobalSetting;
+    }
+
+    /*
+     * Indicates whether VoLTE is provisioned on device
+     */
+    public static boolean isVolteProvisionedOnDevice(Context context) {
+        boolean isProvisioned = true;
+        if (context.getResources().getBoolean(
+                        com.android.internal.R.bool.config_carrier_volte_provisioned)) {
+            isProvisioned = false; // disable on any error
+            ImsManager mgr = ImsManager.getInstance(context,
+                    SubscriptionManager.getDefaultVoiceSubId());
+            if (mgr != null) {
+                try {
+                    ImsConfig config = mgr.getConfigInterface();
+                    if (config != null) {
+                        isProvisioned = config.getVolteProvisioned();
+                    }
+                } catch (ImsException ie) {
+                    // do nothing
+                }
+            }
+        }
+
+        return isProvisioned;
+    }
+
+    /**
+     * Returns a platform configuration for VT which may override the user setting.
+     *
+     * Note: VT presumes that VoLTE is enabled (these are configuration settings
+     * which must be done correctly).
+     */
+    public static boolean isVtEnabledByPlatform(Context context) {
+        if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
+                PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
             return true;
         }
 
         return
                 context.getResources().getBoolean(
-                        com.android.internal.R.bool.config_device_volte_vt_available) &&
+                        com.android.internal.R.bool.config_device_vt_available) &&
                 context.getResources().getBoolean(
-                        com.android.internal.R.bool.config_carrier_volte_vt_available);
+                        com.android.internal.R.bool.config_carrier_vt_available);
     }
 
-    private ImsManager(Context context, long subId) {
+    private ImsManager(Context context, int phoneId) {
         mContext = context;
-        mSubId = subId;
+        mPhoneId = phoneId;
         createImsService(true);
     }
 
@@ -314,7 +385,7 @@
         int result = 0;
 
         try {
-            result = mImsService.open(serviceClass, incomingCallPendingIntent,
+            result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
                     createRegistrationListenerProxy(serviceClass, listener));
         } catch (RemoteException e) {
             throw new ImsException("open()", e,
@@ -566,12 +637,12 @@
             checkAndThrowExceptionIfServiceUnavailable();
 
             try {
-                IImsConfig config = mImsService.getConfigInterface();
+                IImsConfig config = mImsService.getConfigInterface(mPhoneId);
                 if (config == null) {
                     throw new ImsException("getConfigInterface()",
                             ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
                 }
-                mConfig = new ImsConfig(config);
+                mConfig = new ImsConfig(config, mContext);
             } catch (RemoteException e) {
                 throw new ImsException("getConfigInterface()", e,
                         ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
@@ -581,17 +652,31 @@
         return mConfig;
     }
 
-    public void setUiTTYMode(int serviceId, int uiTtyMode, Message onComplete)
+    public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete)
             throws ImsException {
 
-       checkAndThrowExceptionIfServiceUnavailable();
+        checkAndThrowExceptionIfServiceUnavailable();
 
-       try {
-           mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
-       } catch (RemoteException e) {
-           throw new ImsException("setTTYMode()", e,
-                   ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
-       }
+        try {
+            mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
+        } catch (RemoteException e) {
+            throw new ImsException("setTTYMode()", e,
+                    ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
+        }
+
+        /* TODO: config_carrier_volte_tty_supported needs to be enabled for
+                 carriers that support it in their respective MCC-MNC config.xml
+                 Example: values-mcc310-mnc230
+                 Uncomment the code below after the change is done. Leaving this
+                 commented so that TTY over VoLTE call is not blocked from apps.
+        */
+        /*
+        if (!context.getResources().getBoolean(
+                com.android.internal.R.bool.config_carrier_volte_tty_supported)) {
+            setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) &&
+                    isEnhanced4gLteModeSettingEnabledByUser(context));
+        }
+        */
     }
 
     /**
@@ -637,9 +722,8 @@
         }
     }
 
-    private static String getImsServiceName(long subId) {
-        // TODO: MSIM implementation needs to decide on service name as a function of subId
-        // or value derived from subId (slot ID?)
+    private static String getImsServiceName(int phoneId) {
+        // TODO: MSIM implementation needs to decide on service name as a function of phoneId
         return IMS_SERVICE;
     }
 
@@ -648,14 +732,14 @@
      */
     private void createImsService(boolean checkService) {
         if (checkService) {
-            IBinder binder = ServiceManager.checkService(getImsServiceName(mSubId));
+            IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
 
             if (binder == null) {
                 return;
             }
         }
 
-        IBinder b = ServiceManager.getService(getImsServiceName(mSubId));
+        IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
 
         if (b != null) {
             try {
@@ -710,7 +794,7 @@
         checkAndThrowExceptionIfServiceUnavailable();
 
         try {
-            mImsService.turnOnIms();
+            mImsService.turnOnIms(mPhoneId);
         } catch (RemoteException e) {
             throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
         }
@@ -719,16 +803,16 @@
     public void setAdvanced4GMode(boolean turnOn) throws ImsException {
         checkAndThrowExceptionIfServiceUnavailable();
 
-        try {
-            ImsConfig config = getConfigInterface();
-            if (config != null) {
-                config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
-                        TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
+        ImsConfig config = getConfigInterface();
+        if (config != null) {
+            config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
+                    TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
+            if (isVtEnabledByPlatform(mContext)) {
+                // TODO: once VT is available on platform replace the '1' with the current
+                // user configuration of VT.
                 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
                         TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
             }
-        } catch (ImsException e) {
-            log("setAdvanced4GMode() : " + e);
         }
         if (turnOn) {
             turnOnIms();
@@ -747,7 +831,7 @@
         checkAndThrowExceptionIfServiceUnavailable();
 
         try {
-            mImsService.turnOffIms();
+            mImsService.turnOffIms(mPhoneId);
         } catch (RemoteException e) {
             throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
         }
@@ -766,7 +850,7 @@
 
             if (mContext != null) {
                 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-                intent.putExtra(EXTRA_SUBID, mSubId);
+                intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
                 mContext.sendBroadcast(new Intent(intent));
             }
         }
diff --git a/src/java/com/android/ims/internal/ImsCallSession.java b/src/java/com/android/ims/internal/ImsCallSession.java
index 69dcd7e..6075d70 100644
--- a/src/java/com/android/ims/internal/ImsCallSession.java
+++ b/src/java/com/android/ims/internal/ImsCallSession.java
@@ -377,6 +377,16 @@
                 ImsSuppServiceNotification suppServiceInfo) {
         }
 
+        /**
+         * Called when TTY mode of remote party changed
+         *
+         * @param session IMS session object
+         * @param mode TTY mode of remote party
+         */
+        public void callSessionTtyModeReceived(ImsCallSession session,
+                                       int mode) {
+            // no-op
+        }
     }
 
     private final IImsCallSession miSession;
@@ -1206,8 +1216,7 @@
         public void callSessionTtyModeReceived(IImsCallSession session,
                 int mode) {
             if (mListener != null) {
-                //TODO: UI specific implementation.
-                //Vendor UI can listen to this callback to take action on received TTY mode.
+                mListener.callSessionTtyModeReceived(ImsCallSession.this, mode);
             }
         }
 
@@ -1240,4 +1249,23 @@
         }
 
     }
+
+    /**
+     * Provides a string representation of the {@link ImsCallSession}.  Primarily intended for
+     * use in log statements.
+     *
+     * @return String representation of session.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[ImsCallSession objId:");
+        sb.append(System.identityHashCode(this));
+        sb.append(" state:");
+        sb.append(State.toString(getState()));
+        sb.append(" callId:");
+        sb.append(getCallId());
+        sb.append("]");
+        return sb.toString();
+    }
 }
diff --git a/src/java/com/android/ims/internal/ImsVideoCallProvider.java b/src/java/com/android/ims/internal/ImsVideoCallProvider.java
index ae70e92..416a4e2 100644
--- a/src/java/com/android/ims/internal/ImsVideoCallProvider.java
+++ b/src/java/com/android/ims/internal/ImsVideoCallProvider.java
@@ -222,7 +222,7 @@
     }
 
     /** @see Connection.VideoProvider#changeCallDataUsage */
-    public void changeCallDataUsage(long dataUsage) {
+    public void changeCallDataUsage(int dataUsage) {
         if (mCallback != null) {
             try {
                 mCallback.changeCallDataUsage(dataUsage);
diff --git a/src/java/com/android/ims/internal/ImsVideoCallProviderWrapper.java b/src/java/com/android/ims/internal/ImsVideoCallProviderWrapper.java
index f562707..86211a2 100644
--- a/src/java/com/android/ims/internal/ImsVideoCallProviderWrapper.java
+++ b/src/java/com/android/ims/internal/ImsVideoCallProviderWrapper.java
@@ -97,7 +97,7 @@
         }
 
         @Override
-        public void changeCallDataUsage(long dataUsage) {
+        public void changeCallDataUsage(int dataUsage) {
             mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, dataUsage).sendToTarget();
         }
 
@@ -143,7 +143,7 @@
                     }
                     break;
                 case MSG_CHANGE_CALL_DATA_USAGE:
-                    changeCallDataUsage((long) msg.obj);
+                    changeCallDataUsage(msg.arg1);
                     break;
                 case MSG_CHANGE_CAMERA_CAPABILITIES:
                     changeCameraCapabilities((CameraCapabilities) msg.obj);
@@ -237,7 +237,7 @@
     }
 
     /** @inheritDoc */
-    public void onRequestCallDataUsage() {
+    public void onRequestConnectionDataUsage() {
         try {
             mVideoCallProvider.requestCallDataUsage();
         } catch (RemoteException e) {