Merge "Rename KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL."
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 39daea8..d75e484 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1447,6 +1447,17 @@
     <string name="alert_dialog_no">No</string>
     <!-- ECM: ECM exit dialog choice -->
     <string name="alert_dialog_dismiss">Dismiss</string>
+    <!-- ECM: Notification body wihout data restriction hint -->
+    <string name="phone_in_ecm_call_notification_text_without_data_restriction_hint">The phone is in emergency callback mode</string>
+    <!-- ECM: Displays the time when ECM will end without data restriction hint, Example: "Until 10:45 AM" -->
+    <string name="phone_in_ecm_notification_complete_time_without_data_restriction_hint">Until <xliff:g id="completeTime">%s</xliff:g></string>
+    <!-- ECM: Dialog box message without data restriction hint for exiting from the notifications screen -->
+    <plurals name="alert_dialog_exit_ecm_without_data_restriction_hint">
+        <!-- number of minutes is one -->
+        <item quantity="one">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minute.\nDo you want to exit now?</item>
+        <!-- number of minutes is not equal to one -->
+        <item quantity="other">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minutes.\nDo you want to exit now?</item>
+    </plurals>
 
     <!-- For incoming calls, this is a string we can get from a CDMA network instead of
          the actual phone number, to indicate there's no number present.  DO NOT TRANSLATE. -->
diff --git a/src/com/android/phone/CallBarringEditPreference.java b/src/com/android/phone/CallBarringEditPreference.java
index 4541926..5d83de1 100644
--- a/src/com/android/phone/CallBarringEditPreference.java
+++ b/src/com/android/phone/CallBarringEditPreference.java
@@ -35,6 +35,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
@@ -108,7 +109,7 @@
         if (!skipReading) {
             // Query call barring status
             mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage(
-                    MyHandler.MESSAGE_GET_CALL_BARRING), 0);
+                    MyHandler.MESSAGE_GET_CALL_BARRING), CommandsInterface.SERVICE_CLASS_VOICE);
             if (mTcpListener != null) {
                 mTcpListener.onStarted(this, true);
             }
@@ -202,7 +203,8 @@
             }
             // Send set call barring message to RIL layer.
             mPhone.setCallBarring(mFacility, !mIsActivated, password,
-                    mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 0);
+                    mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING),
+                    CommandsInterface.SERVICE_CLASS_VOICE);
             if (mTcpListener != null) {
                 mTcpListener.onStarted(this, false);
             }
@@ -326,7 +328,7 @@
                     "",
                     obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING,
                             ar.exception),
-                    0);
+                    CommandsInterface.SERVICE_CLASS_VOICE);
         }
     }
 }
diff --git a/src/com/android/phone/CallForwardEditPreference.java b/src/com/android/phone/CallForwardEditPreference.java
index 76f17b1..c1f219c 100644
--- a/src/com/android/phone/CallForwardEditPreference.java
+++ b/src/com/android/phone/CallForwardEditPreference.java
@@ -159,6 +159,7 @@
                     mPhone.setCallForwardingOption(action,
                             reason,
                             number,
+                            mServiceClass,
                             time,
                             mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
                                     action,
@@ -216,7 +217,7 @@
      */
     void startCallForwardOptionsQuery() {
         if (!mCallForwardByUssd) {
-            mPhone.getCallForwardingOption(reason,
+            mPhone.getCallForwardingOption(reason, mServiceClass,
                     mHandler.obtainMessage(MyHandler.MESSAGE_GET_CF,
                             // unused in this case
                             CommandsInterface.CF_ACTION_DISABLE,
@@ -423,7 +424,7 @@
             }
             Log.d(LOG_TAG, "handleSetCFResponse: re get");
             if (!mCallForwardByUssd) {
-                mPhone.getCallForwardingOption(reason,
+                mPhone.getCallForwardingOption(reason, mServiceClass,
                         obtainMessage(MESSAGE_GET_CF, msg.arg1, MESSAGE_SET_CF, ar.exception));
             } else {
                 mHandler.sendMessage(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index daff69b..ef7f5b8 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -95,6 +95,8 @@
     private PersistableBundle[] mOverrideConfigs;
     // Service connection for binding to config app.
     private CarrierServiceConnection[] mServiceConnection;
+    // Whether we are bound to a service for each phone
+    private boolean[] mServiceBound;
     // Whether we have sent config change bcast for each phone id.
     private boolean[] mHasSentConfigChange;
     // SubscriptionInfoUpdater
@@ -265,7 +267,7 @@
                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
                     // If new service connection has been created, unbind.
                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
-                        unbindIfConnected(mContext, conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break;
                     }
                     final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
@@ -274,7 +276,7 @@
                             new ResultReceiver(this) {
                                 @Override
                                 public void onReceiveResult(int resultCode, Bundle resultData) {
-                                    unbindIfConnected(mContext, conn);
+                                    unbindIfBound(mContext, conn, phoneId);
                                     // If new service connection has been created, this is stale.
                                     if (mServiceConnection[phoneId] != conn) {
                                         loge("Received response for stale request.");
@@ -308,7 +310,7 @@
                     } catch (RemoteException e) {
                         loge("Failed to get carrier config from default app: " +
                                 mPlatformCarrierConfigPackage + " err: " + e.toString());
-                        unbindIfConnected(mContext, conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break; // So we don't set a timeout.
                     }
                     sendMessageDelayed(
@@ -328,7 +330,7 @@
                     if (mServiceConnection[phoneId] != null) {
                         // If a ResponseReceiver callback is in the queue when this happens, we will
                         // unbind twice and throw an exception.
-                        unbindIfConnected(mContext, mServiceConnection[phoneId]);
+                        unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
                         broadcastConfigChangedIntent(phoneId);
                     }
                     notifySubscriptionInfoUpdater(phoneId);
@@ -394,7 +396,7 @@
                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
                     // If new service connection has been created, unbind.
                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
-                        unbindIfConnected(mContext, conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break;
                     }
                     final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
@@ -403,7 +405,7 @@
                             new ResultReceiver(this) {
                                 @Override
                                 public void onReceiveResult(int resultCode, Bundle resultData) {
-                                    unbindIfConnected(mContext, conn);
+                                    unbindIfBound(mContext, conn, phoneId);
                                     // If new service connection has been created, this is stale.
                                     if (mServiceConnection[phoneId] != conn) {
                                         loge("Received response for stale request.");
@@ -438,7 +440,7 @@
                                 + " carrierid: " + carrierId.toString());
                     } catch (RemoteException e) {
                         loge("Failed to get carrier config: " + e.toString());
-                        unbindIfConnected(mContext, conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break; // So we don't set a timeout.
                     }
                     sendMessageDelayed(
@@ -458,7 +460,7 @@
                     if (mServiceConnection[phoneId] != null) {
                         // If a ResponseReceiver callback is in the queue when this happens, we will
                         // unbind twice and throw an exception.
-                        unbindIfConnected(mContext, mServiceConnection[phoneId]);
+                        unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
                         broadcastConfigChangedIntent(phoneId);
                     }
                     notifySubscriptionInfoUpdater(phoneId);
@@ -537,6 +539,7 @@
         mPersistentOverrideConfigs = new PersistableBundle[numPhones];
         mOverrideConfigs = new PersistableBundle[numPhones];
         mServiceConnection = new CarrierServiceConnection[numPhones];
+        mServiceBound = new boolean[numPhones];
         mHasSentConfigChange = new boolean[numPhones];
         // Make this service available through ServiceManager.
         ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
@@ -644,8 +647,13 @@
         carrierService.setPackage(pkgName);
         mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);
         try {
-            return mContext.bindService(carrierService, mServiceConnection[phoneId],
-                    Context.BIND_AUTO_CREATE);
+            if (mContext.bindService(carrierService, mServiceConnection[phoneId],
+                    Context.BIND_AUTO_CREATE)) {
+                mServiceBound[phoneId] = true;
+                return true;
+            } else {
+                return false;
+            }
         } catch (SecurityException ex) {
             return false;
         }
@@ -1127,8 +1135,10 @@
         }
     }
 
-    private static void unbindIfConnected(Context context, CarrierServiceConnection conn) {
-        if (conn.connected) {
+    private void unbindIfBound(Context context, CarrierServiceConnection conn,
+            int phoneId) {
+        if (mServiceBound[phoneId]) {
+            mServiceBound[phoneId] = false;
             context.unbindService(conn);
         }
     }
@@ -1137,7 +1147,6 @@
         int phoneId;
         int eventId;
         IBinder service;
-        boolean connected = false;
 
         public CarrierServiceConnection(int phoneId, int eventId) {
             this.phoneId = phoneId;
@@ -1148,7 +1157,6 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             log("Connected to config app: " + name.flattenToString());
             this.service = service;
-            connected = true;
             mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this));
         }
 
@@ -1156,21 +1164,18 @@
         public void onServiceDisconnected(ComponentName name) {
             log("Disconnected from config app: " + name.flattenToString());
             this.service = null;
-            connected = false;
         }
 
         @Override
         public void onBindingDied(ComponentName name) {
             log("Binding died from config app: " + name.flattenToString());
             this.service = null;
-            connected = false;
         }
 
         @Override
         public void onNullBinding(ComponentName name) {
             log("Null binding from config app: " + name.flattenToString());
             this.service = null;
-            connected = false;
         }
     }
 
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index dcfa024..6edc155 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -300,8 +300,14 @@
             return String.format(getResources().getQuantityText(
                     R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
         case EXIT_ECM_DIALOG:
-            return String.format(getResources().getQuantityText(R.plurals.alert_dialog_exit_ecm,
-                    minutes).toString(), time);
+                boolean shouldRestrictData = mPhone.getImsPhone() != null
+                        && mPhone.getImsPhone().isInImsEcm();
+                return String.format(getResources().getQuantityText(
+                        // During IMS ECM, data restriction hint should be removed.
+                        shouldRestrictData
+                        ? R.plurals.alert_dialog_exit_ecm_without_data_restriction_hint
+                        : R.plurals.alert_dialog_exit_ecm,
+                        minutes).toString(), time);
         }
         return null;
     }
diff --git a/src/com/android/phone/EmergencyCallbackModeService.java b/src/com/android/phone/EmergencyCallbackModeService.java
index 41d83c4..012a670 100644
--- a/src/com/android/phone/EmergencyCallbackModeService.java
+++ b/src/com/android/phone/EmergencyCallbackModeService.java
@@ -194,7 +194,11 @@
         // Format notification string
         String text = null;
         if(mInEmergencyCall) {
-            text = getText(R.string.phone_in_ecm_call_notification_text).toString();
+            text = getText(
+                    // During IMS ECM, data restriction hint should be removed.
+                    (imsPhone != null && imsPhone.isInImsEcm())
+                    ? R.string.phone_in_ecm_call_notification_text_without_data_restriction_hint
+                    : R.string.phone_in_ecm_call_notification_text).toString();
         } else {
             // Calculate the time in ms when the notification will be finished.
             long finishedCountMs = millisUntilFinished + System.currentTimeMillis();
@@ -205,7 +209,11 @@
 
             String completeTime = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(
                     finishedCountMs);
-            text = getResources().getString(R.string.phone_in_ecm_notification_complete_time,
+            text = getResources().getString(
+                    // During IMS ECM, data restriction hint should be removed.
+                    (imsPhone != null && imsPhone.isInImsEcm())
+                    ? R.string.phone_in_ecm_notification_complete_time_without_data_restriction_hint
+                    : R.string.phone_in_ecm_notification_complete_time,
                     completeTime);
         }
         builder.setContentText(text);
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index fe55335..fccceec 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -470,7 +470,7 @@
 
     private Intent getShowVoicemailIntentForDefaultDialer(UserHandle userHandle) {
         String dialerPackage = mContext.getSystemService(TelecomManager.class)
-                .getDefaultDialerPackage(userHandle.getIdentifier());
+                .getDefaultDialerPackage(userHandle);
         return new Intent(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION)
                 .setPackage(dialerPackage);
     }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 4eb1788..8e6e7c8 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -35,7 +35,6 @@
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.net.NetworkStats;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Binder;
@@ -3210,8 +3209,8 @@
     @Override
     public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c)
             throws RemoteException {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "registerImsRegistrationCallback");
 
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
@@ -3236,8 +3235,8 @@
      */
     @Override
     public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "unregisterImsRegistrationCallback");
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
@@ -3293,8 +3292,8 @@
      */
     @Override
     public void getImsMmTelRegistrationTransportType(int subId, IIntegerConsumer consumer) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("getImsMmTelRegistrationTransportType");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "getImsMmTelRegistrationTransportType");
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "IMS not available on device.");
@@ -3333,8 +3332,8 @@
     @Override
     public void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c)
             throws RemoteException {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("registerMmTelCapabilityCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "registerMmTelCapabilityCallback");
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "IMS not available on device.");
@@ -3358,8 +3357,8 @@
      */
     @Override
     public void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "unregisterMmTelCapabilityCallback");
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
@@ -3455,8 +3454,8 @@
      */
     @Override
     public boolean isAdvancedCallingSettingEnabled(int subId) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("isAdvancedCallingSettingEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isAdvancedCallingSettingEnabled");
 
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
@@ -3492,8 +3491,8 @@
      */
     @Override
     public boolean isVtSettingEnabled(int subId) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("isVtSettingEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isVtSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3526,8 +3525,8 @@
      */
     @Override
     public boolean isVoWiFiSettingEnabled(int subId) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("isVoWiFiSettingEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isVoWiFiSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3561,8 +3560,8 @@
      */
     @Override
     public boolean isVoWiFiRoamingSettingEnabled(int subId) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("isVoWiFiRoamingSettingEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isVoWiFiRoamingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3613,8 +3612,8 @@
      */
     @Override
     public int getVoWiFiModeSetting(int subId) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("getVoWiFiModeSetting");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "getVoWiFiModeSetting");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3695,8 +3694,8 @@
      */
     @Override
     public boolean isTtyOverVolteEnabled(int subId) {
-        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
-        enforceReadPrivilegedPermission("isTtyOverVolteEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isTtyOverVolteEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -7158,33 +7157,6 @@
     }
 
     /**
-     * Get aggregated video call data usage since boot.
-     *
-     * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
-     * @return Snapshot of video call data usage
-     * {@hide}
-     */
-    @Override
-    public NetworkStats getVtDataUsage(int subId, boolean perUidStats) {
-        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_NETWORK_USAGE_HISTORY,
-                null);
-
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            // NetworkStatsService keeps tracking the active network interface and identity. It
-            // records the delta with the corresponding network identity.
-            // We just return the total video call data usage snapshot since boot.
-            Phone phone = getPhone(subId);
-            if (phone != null) {
-                return phone.getVtDataUsage(perUidStats);
-            }
-            return null;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    /**
      * Policy control of data connection. Usually used when data limit is passed.
      * @param enabled True if enabling the data, otherwise disabling.
      * @param subId Subscription index
@@ -7701,7 +7673,8 @@
 
     @Override
     public int getCdmaRoamingMode(int subId) {
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
                 mApp, subId, "getCdmaRoamingMode");
 
         final long identity = Binder.clearCallingIdentity();
diff --git a/src/com/android/phone/settings/CallForwardInfoUtil.java b/src/com/android/phone/settings/CallForwardInfoUtil.java
index 1983fab..b963df8 100644
--- a/src/com/android/phone/settings/CallForwardInfoUtil.java
+++ b/src/com/android/phone/settings/CallForwardInfoUtil.java
@@ -82,6 +82,7 @@
         phone.setCallForwardingOption(commandInterfaceCfAction,
                 info.reason,
                 info.number,
+                info.serviceClass,
                 info.timeSeconds,
                 message);
     }
@@ -93,10 +94,12 @@
      */
     public static CallForwardInfo getCallForwardInfo(CallForwardInfo[] infos, int reason) {
         CallForwardInfo info = null;
-        for (int i = 0 ; i < infos.length; i++) {
-            if (isServiceClassVoice(infos[i])) {
-                info = infos[i];
-                break;
+        if (infos != null) {
+            for (int i = 0 ; i < infos.length; i++) {
+                if (isServiceClassVoice(infos[i])) {
+                    info = infos[i];
+                    break;
+                }
             }
         }
 
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index e18dc93..66b1af9 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -43,6 +43,7 @@
 import android.widget.Toast;
 
 import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.util.NotificationChannelController;
@@ -733,6 +734,7 @@
             for (int i = 0; i < mForwardingReadResults.length; i++) {
                 mPhone.getCallForwardingOption(
                         VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[i],
+                        CommandsInterface.SERVICE_CLASS_VOICE,
                         mGetOptionComplete.obtainMessage(EVENT_FORWARDING_GET_COMPLETED, i, 0));
             }
             showDialogIfForeground(VoicemailDialogUtil.VM_FWD_READING_DIALOG);
diff --git a/src/com/android/services/telephony/CdmaConference.java b/src/com/android/services/telephony/CdmaConference.java
index 32badd0..7458195 100644
--- a/src/com/android/services/telephony/CdmaConference.java
+++ b/src/com/android/services/telephony/CdmaConference.java
@@ -17,6 +17,7 @@
 package com.android.services.telephony;
 
 import android.content.Context;
+import android.net.Uri;
 import android.os.PersistableBundle;
 import android.telecom.Connection;
 import android.telecom.PhoneAccountHandle;
@@ -73,6 +74,12 @@
     }
 
     @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+                " for CDMA conference call.");
+    }
+
+    @Override
     public void onAnswer(int videoState) {
         Log.e(this, new Exception(), "Answer not supported for CDMA conference call.");
     }
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index ac3928f..b7ecd48 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -19,13 +19,13 @@
 import android.net.Uri;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
-import com.android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.text.TextUtils;
 
 import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
+import com.android.telephony.Rlog;
 
 /**
  * Represents a participant in a conference call.
@@ -215,7 +215,7 @@
         sb.append(" connectTime:");
         sb.append(getConnectTimeMillis());
         sb.append(" connectElapsedTime:");
-        sb.append(getConnectElapsedTimeMillis());
+        sb.append(getConnectionStartElapsedRealtimeMillis());
         sb.append("]");
 
         return sb.toString();
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index f5f5c66..c11a1ca 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -30,7 +30,6 @@
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import com.android.telephony.Rlog;
 import android.util.Pair;
 
 import com.android.ims.internal.ConferenceParticipant;
@@ -42,6 +41,7 @@
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -313,10 +313,10 @@
         long connectTime = conferenceHost.getOriginalConnection().getConnectTime();
         long connectElapsedTime = conferenceHost.getOriginalConnection().getConnectTimeReal();
         setConnectionTime(connectTime);
-        setConnectionStartElapsedRealTime(connectElapsedTime);
+        setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
         // Set the connectTime in the connection as well.
         conferenceHost.setConnectTimeMillis(connectTime);
-        conferenceHost.setConnectionStartElapsedRealTime(connectElapsedTime);
+        conferenceHost.setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
 
         mTelephonyConnectionService = telephonyConnectionService;
         setConferenceHost(conferenceHost);
@@ -374,6 +374,10 @@
                 Connection.CAPABILITY_CAN_PAUSE_VIDEO,
                 mConferenceHost.getVideoPauseSupported() && isVideoCapable());
 
+        conferenceCapabilities = changeBitmask(conferenceCapabilities,
+                Connection.CAPABILITY_ADD_PARTICIPANT,
+                (capabilities & Connection.CAPABILITY_ADD_PARTICIPANT) != 0);
+
         return conferenceCapabilities;
     }
 
@@ -522,6 +526,19 @@
     }
 
     /**
+     * Supports adding participants to an existing conference call
+     *
+     * @param participants that are pulled to existing conference call
+     */
+    @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        if (mConferenceHost == null) {
+            return;
+        }
+        mConferenceHost.performAddConferenceParticipants(participants);
+    }
+
+    /**
      * Invoked when the conference is answered.
      */
     @Override
@@ -741,7 +758,8 @@
             setAddress(mConferenceHost.getAddress(), mConferenceHost.getAddressPresentation());
             setCallerDisplayName(mConferenceHost.getCallerDisplayName(),
                     mConferenceHost.getCallerDisplayNamePresentation());
-            setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+            setConnectionStartElapsedRealtimeMillis(
+                    mConferenceHost.getConnectionStartElapsedRealtimeMillis());
             setConnectionTime(mConferenceHost.getConnectTimeMillis());
         }
 
@@ -959,7 +977,8 @@
             Log.d(this,
                     "stopEmulatingSinglePartyCall: restored lone participant connect time");
             loneParticipant.setConnectTimeMillis(getConnectionTime());
-            loneParticipant.setConnectionStartElapsedRealTime(getConnectionStartElapsedRealTime());
+            loneParticipant.setConnectionStartElapsedRealtimeMillis(
+                    getConnectionStartElapsedRealtimeMillis());
         }
 
         // Tell Telecom its a conference again.
@@ -999,7 +1018,8 @@
             setAddress(entry.getAddress(), entry.getAddressPresentation());
             setCallerDisplayName(entry.getCallerDisplayName(),
                     entry.getCallerDisplayNamePresentation());
-            setConnectionStartElapsedRealTime(entry.getConnectElapsedTimeMillis());
+            setConnectionStartElapsedRealtimeMillis(
+                    entry.getConnectionStartElapsedRealtimeMillis());
             setConnectionTime(entry.getConnectTimeMillis());
             mLoneParticipantIdentity = new Pair<>(entry.getUserEntity(), entry.getEndpoint());
 
@@ -1043,10 +1063,11 @@
                 !isConferenceHost() /* isRemotelyHosted */);
         if (participant.getConnectTime() == 0) {
             connection.setConnectTimeMillis(parent.getConnectTimeMillis());
-            connection.setConnectionStartElapsedRealTime(parent.getConnectElapsedTimeMillis());
+            connection.setConnectionStartElapsedRealtimeMillis(
+                    parent.getConnectionStartElapsedRealtimeMillis());
         } else {
             connection.setConnectTimeMillis(participant.getConnectTime());
-            connection.setConnectionStartElapsedRealTime(participant.getConnectElapsedTime());
+            connection.setConnectionStartElapsedRealtimeMillis(participant.getConnectElapsedTime());
         }
         // Indicate whether this is an MT or MO call to Telecom; the participant has the cached
         // data from the time of merge.
@@ -1212,7 +1233,8 @@
                 c.updateState();
                 // Copy the connect time from the conferenceHost
                 c.setConnectTimeMillis(mConferenceHost.getConnectTimeMillis());
-                c.setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+                c.setConnectionStartElapsedRealtimeMillis(
+                        mConferenceHost.getConnectionStartElapsedRealtimeMillis());
                 mTelephonyConnectionService.addExistingConnection(phoneAccountHandle, c);
                 mTelephonyConnectionService.addConnectionToConferenceController(c);
             } // CDMA case not applicable for SRVCC
diff --git a/src/com/android/services/telephony/TelephonyConference.java b/src/com/android/services/telephony/TelephonyConference.java
index d720639..7e4693f 100644
--- a/src/com/android/services/telephony/TelephonyConference.java
+++ b/src/com/android/services/telephony/TelephonyConference.java
@@ -16,6 +16,7 @@
 
 package com.android.services.telephony;
 
+import android.net.Uri;
 import android.telecom.Connection;
 import android.telecom.PhoneAccountHandle;
 
@@ -103,6 +104,12 @@
     }
 
     @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+                " for GSM conference call.");
+    }
+
+    @Override
     public void onMerge(Connection connection) {
         try {
             Phone phone = ((TelephonyConnection) connection).getPhone();
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 29b65d0..2f8ac24 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -40,7 +40,6 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import com.android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.ServiceState.RilRadioTechnology;
 import android.telephony.SubscriptionManager;
@@ -51,6 +50,7 @@
 import android.util.Pair;
 
 import com.android.ims.ImsCall;
+import com.android.ims.ImsException;
 import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
@@ -63,12 +63,14 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 import com.android.phone.ImsUtil;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -870,6 +872,11 @@
     }
 
     @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        performAddConferenceParticipants(participants);
+    }
+
+    @Override
     public void onAbort() {
         Log.v(this, "onAbort");
         mHandler.obtainMessage(MSG_HANGUP, android.telephony.DisconnectCause.LOCAL).sendToTarget();
@@ -1120,6 +1127,29 @@
         }
     }
 
+    private String[] getAddConferenceParticipants(List<Uri> participants) {
+        String[] addConfParticipants = new String[participants.size()];
+        int i = 0;
+        for (Uri participant : participants) {
+           addConfParticipants[i] = participant.getSchemeSpecificPart();
+           i++;
+        }
+        return addConfParticipants;
+    }
+
+    public void performAddConferenceParticipants(List<Uri> participants) {
+        Log.v(this, "performAddConferenceParticipants");
+        if (mOriginalConnection.getCall() instanceof ImsPhoneCall) {
+            ImsPhoneCall imsPhoneCall = (ImsPhoneCall)mOriginalConnection.getCall();
+            try {
+                imsPhoneCall.getImsCall().inviteParticipants(
+                        getAddConferenceParticipants(participants));
+            } catch(ImsException e) {
+                Log.e(this, e, "failed to add conference participants");
+            }
+        }
+    }
+
     /**
      * Builds connection capabilities common to all TelephonyConnections. Namely, apply IMS-based
      * capabilities.
@@ -1153,6 +1183,7 @@
         newCapabilities = applyConferenceTerminationCapabilities(newCapabilities);
         newCapabilities = changeBitmask(newCapabilities, CAPABILITY_SUPPORT_DEFLECT,
                 isImsConnection() && canDeflectImsCalls());
+        newCapabilities = applyAddParticipantCapabilities(newCapabilities);
 
         if (getConnectionCapabilities() != newCapabilities) {
             setConnectionCapabilities(newCapabilities);
@@ -1186,7 +1217,7 @@
                 isExternalConnection());
         newProperties = changeBitmask(newProperties, PROPERTY_HAS_CDMA_VOICE_PRIVACY,
                 mIsCdmaVoicePrivacyEnabled);
-        newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING_USED,
+        newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING,
                 mIsUsingAssistedDialing);
         newProperties = changeBitmask(newProperties, PROPERTY_IS_RTT, isRtt());
         newProperties = changeBitmask(newProperties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
@@ -1580,6 +1611,75 @@
                 || !VideoProfile.isVideo(getVideoState()));
     }
 
+    private boolean isConferenceHosted() {
+        boolean isHosted = false;
+        if (getTelephonyConnectionService() != null) {
+            for (Conference current : getTelephonyConnectionService().getAllConferences()) {
+                if (current instanceof ImsConference) {
+                    ImsConference other = (ImsConference) current;
+                    if (getState() == current.getState()) {
+                        continue;
+                    }
+                    if (other.isConferenceHost()) {
+                        isHosted = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return isHosted;
+    }
+
+    private boolean isAddParticipantCapable() {
+        // not add participant capable for non ims phones
+        if (getPhone() == null || getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_IMS) {
+            return false;
+        }
+
+        if (!getCarrierConfig()
+                .getBoolean(CarrierConfigManager.KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL)) {
+            return false;
+        }
+
+        boolean isCapable = !mTreatAsEmergencyCall && (mConnectionState == Call.State.ACTIVE ||
+                mConnectionState == Call.State.HOLDING);
+
+        // add participant capable if current connection is a host connection or
+        // if conference is not hosted on the device
+        isCapable = isCapable && ((mOriginalConnection != null &&
+                mOriginalConnection.isConferenceHost()) ||
+                !isConferenceHosted());
+
+        /**
+          * For individual IMS calls, if the extra for remote conference support is
+          *     - indicated, then consider the same for add participant capability
+          *     - not indicated, then the add participant capability is same as before.
+          */
+        if (isCapable && (mOriginalConnection != null) && !mIsMultiParty) {
+            isCapable = mOriginalConnectionExtras.getBoolean(
+                    ImsCallProfile.EXTRA_CONFERENCE_AVAIL, isCapable);
+        }
+        return isCapable;
+    }
+
+    /**
+     * Applies the add participant capabilities to the {@code CallCapabilities} bit-mask.
+     *
+     * @param callCapabilities The {@code CallCapabilities} bit-mask.
+     * @return The capabilities with the add participant capabilities applied.
+     */
+    private int applyAddParticipantCapabilities(int callCapabilities) {
+        int currentCapabilities = callCapabilities;
+        if (isAddParticipantCapable()) {
+            currentCapabilities = changeBitmask(currentCapabilities,
+                    Connection.CAPABILITY_ADD_PARTICIPANT, true);
+        } else {
+            currentCapabilities = changeBitmask(currentCapabilities,
+                    Connection.CAPABILITY_ADD_PARTICIPANT, false);
+        }
+        return currentCapabilities;
+    }
+
     @VisibleForTesting
     public PersistableBundle getCarrierConfig() {
         Phone phone = getPhone();
@@ -1842,6 +1942,12 @@
 
                     // Ensure extras are propagated to Telecom.
                     putTelephonyExtras(mOriginalConnectionExtras);
+                    // If extras contain Conference support information,
+                    // then ensure capabilities are updated.
+                    if (mOriginalConnectionExtras.containsKey(
+                            ImsCallProfile.EXTRA_CONFERENCE_AVAIL)) {
+                        updateConnectionCapabilities();
+                    }
                 } else {
                     Log.d(this, "Extras update not required");
                 }