Merge kwd to master

Add initial IMS and MSIM support from klp-wireless-dev-mirror

Change-Id: Idb607c0aa32f80fe4fe1539aedea7a221e9e7f04
diff --git a/Android.mk b/Android.mk
index c889fa1..7a46a1f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -341,6 +341,7 @@
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
+	telephony/java/com/android/internal/telephony/ISub.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
 	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 5b027b3..5d92792 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -193,6 +193,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3fe0fb8..2a5e9fd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6547,6 +6547,53 @@
         public static boolean putFloat(ContentResolver cr, String name, float value) {
             return putString(cr, name, Float.toString(value));
         }
+
+
+        /**
+          * Subscription to be used for voice call on a multi sim device. The supported values
+          * are 0 = SUB1, 1 = SUB2 and etc.
+          * @hide
+          */
+        public static final String MULTI_SIM_VOICE_CALL_SUBSCRIPTION = "multi_sim_voice_call";
+
+        /**
+          * Used to provide option to user to select subscription during dial.
+          * The supported values are 0 = disable or 1 = enable prompt.
+          * @hide
+          */
+        public static final String MULTI_SIM_VOICE_PROMPT = "multi_sim_voice_prompt";
+
+        /**
+          * Subscription to be used for data call on a multi sim device. The supported values
+          * are 0 = SUB1, 1 = SUB2 and etc.
+          * @hide
+          */
+        public static final String MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call";
+
+        /**
+          * Subscription to be used for SMS on a multi sim device. The supported values
+          * are 0 = SUB1, 1 = SUB2 and etc.
+          * @hide
+          */
+        public static final String MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms";
+
+       /**
+          * Used to provide option to user to select subscription during send SMS.
+          * The value 1 - enable, 0 - disable
+          * @hide
+          */
+        public static final String MULTI_SIM_SMS_PROMPT = "multi_sim_sms_prompt";
+
+
+
+        /** User preferred subscriptions setting.
+          * This holds the details of the user selected subscription from the card and
+          * the activation status. Each settings string have the coma separated values
+          * iccId,appType,appId,activationStatus,3gppIndex,3gpp2Index
+          * @hide
+         */
+        public static final String[] MULTI_SIM_USER_PREFERRED_SUBS = {"user_preferred_sub1",
+                "user_preferred_sub2","user_preferred_sub3"};
     }
 
     /**
diff --git a/core/res/res/drawable-hdpi/sim_dark_blue.9.png b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..b991535
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_green.9.png b/core/res/res/drawable-hdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..c8de61d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_orange.9.png b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..10347e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_purple.9.png b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..ac4ee01
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_blue.9.png b/core/res/res/drawable-hdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..b2c5581
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_green.9.png b/core/res/res/drawable-hdpi/sim_light_green.9.png
new file mode 100755
index 0000000..4d29c81
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_orange.9.png b/core/res/res/drawable-hdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..68c6c2f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_purple.9.png b/core/res/res/drawable-hdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..4deb8dc5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_blue.9.png b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..d646a7f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_green.9.png b/core/res/res/drawable-mdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..ee4ea0d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_orange.9.png b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..b394999
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_purple.9.png b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..459b5d69
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_blue.9.png b/core/res/res/drawable-mdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..396ad70
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_green.9.png b/core/res/res/drawable-mdpi/sim_light_green.9.png
new file mode 100755
index 0000000..a063174
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_orange.9.png b/core/res/res/drawable-mdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..95ea88e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_purple.9.png b/core/res/res/drawable-mdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..b1bd35f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/layout/subscription_item_layout.xml b/core/res/res/layout/subscription_item_layout.xml
new file mode 100755
index 0000000..9f8f2b3
--- /dev/null
+++ b/core/res/res/layout/subscription_item_layout.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright (C) 2014 MediaTek Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" >
+    <RelativeLayout
+        android:layout_width="48dip"
+        android:layout_height="32dip"
+        android:id="@+id/sub_color"
+        android:layout_marginEnd="6dip"
+        android:layout_centerVertical="true">
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/sub_short_number"
+            android:layout_marginBottom="2dip"
+            android:layout_marginEnd="4dip"
+            android:layout_alignParentEnd="true" 
+            android:layout_alignParentBottom="true"
+            android:textSize="12sp"
+            android:singleLine="true"
+            android:textColor="@android:color/white"
+            android:includeFontPadding="false"/>
+    </RelativeLayout>
+    <RelativeLayout
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:layout_centerVertical="true">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/sub_name"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:requiresFadingEdge="horizontal"
+            android:scrollHorizontally="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/sub_number"
+            android:layout_below="@+id/sub_name"
+            android:layout_alignStart="@+id/sub_name"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:requiresFadingEdge="horizontal"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"/>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 830c64c..a4f78bd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1574,4 +1574,28 @@
         <item>users</item>
     </string-array>
 
+    <!-- default telephony hardware configuration for this platform.
+    -->
+    <!-- this string array should be overridden by the device to present a list
+         telephony hardware resource.  this is used by the telephony device controller
+         (TDC) to offer the basic capabilities of the hardware to the telephony
+         framework
+    -->
+    <!-- an array of "[hardware type],[hardware-uuid],[state],[[hardware-type specific]]"
+         with, [[hardware-type specific]] in:
+            - "[[ril-model],[rat],[max-active-voice],[max-active-data],[max-active-standby]]"
+              for 'modem' hardware
+            - "[[associated-modem-uuid]]"
+              for 'sim' hardware.
+         refer to HardwareConfig in com.android.internal.telephony for specific details/values
+         those elements can carry.
+    -->
+    <string-array translatable="false" name="config_telephonyHardware">
+        <!-- modem -->
+        <item>"0,modem,0,0,0,1,1,1"</item>
+        <!-- sim -->
+        <item>"1,sim,0,modem"</item>
+    </string-array>
+
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8fad07a..d69f60a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -999,6 +999,7 @@
   <java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
   <java-symbol type="array" name="config_callBarringMMI" />
   <java-symbol type="array" name="config_globalActionsList" />
+  <java-symbol type="array" name="config_telephonyHardware" />
 
   <java-symbol type="drawable" name="default_wallpaper" />
   <java-symbol type="drawable" name="indicator_input_error" />
@@ -1122,6 +1123,15 @@
   <java-symbol type="drawable" name="ic_corp_badge" />
   <java-symbol type="drawable" name="ic_corp_icon_badge" />
 
+  <java-symbol type="drawable" name="sim_light_blue" />
+  <java-symbol type="drawable" name="sim_light_green" />
+  <java-symbol type="drawable" name="sim_light_orange" />
+  <java-symbol type="drawable" name="sim_light_purple" />
+  <java-symbol type="drawable" name="sim_dark_blue" />
+  <java-symbol type="drawable" name="sim_dark_green" />
+  <java-symbol type="drawable" name="sim_dark_orange" />
+  <java-symbol type="drawable" name="sim_dark_purple" />
+
   <java-symbol type="layout" name="action_bar_home" />
   <java-symbol type="layout" name="action_bar_title_item" />
   <java-symbol type="layout" name="action_menu_item_layout" />
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 362061e..d26f3fc 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -61,6 +61,7 @@
 import android.os.SystemProperties;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -237,7 +238,9 @@
         mThread = new Thread(mConnector, NETD_TAG);
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
-        mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) {
+        mPhoneStateListener = new PhoneStateListener(
+                SubscriptionManager.DEFAULT_SUB_ID, // FIXME: What Subscription should be used??
+                mDaemonHandler.getLooper()) {
             public void onDataConnectionRealTimeInfoChanged(
                     DataConnectionRealTimeInfo dcRtInfo) {
                 notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index cfaf016..9d92421 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -33,10 +33,13 @@
 import android.os.UserHandle;
 import android.telephony.CellLocation;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseCallState;
@@ -65,8 +68,9 @@
  */
 class TelephonyRegistry extends ITelephonyRegistry.Stub {
     private static final String TAG = "TelephonyRegistry";
-    private static final boolean DBG = false;
-    private static final boolean DBG_LOC = false;
+    private static final boolean DBG = false; // STOPSHIP if true
+    private static final boolean DBG_LOC = false; // STOPSHIP if true
+    private static final boolean VDBG = false; // STOPSHIP if true
 
     private static class Record {
         String pkgForDebug;
@@ -79,6 +83,10 @@
 
         int events;
 
+        long subId;
+
+        boolean isLegacyApp;
+
         @Override
         public String toString() {
             return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
@@ -94,41 +102,47 @@
 
     private final IBatteryStats mBatteryStats;
 
-    private int mCallState = TelephonyManager.CALL_STATE_IDLE;
+    private int mNumPhones;
 
-    private String mCallIncomingNumber = "";
+    private int[] mCallState;
 
-    private ServiceState mServiceState = new ServiceState();
+    private String[] mCallIncomingNumber;
 
-    private SignalStrength mSignalStrength = new SignalStrength();
+    private ServiceState[] mServiceState;
 
-    private boolean mMessageWaiting = false;
+    private SignalStrength[] mSignalStrength;
 
-    private boolean mCallForwarding = false;
+    private boolean[] mMessageWaiting;
 
-    private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    private boolean[] mCallForwarding;
 
-    private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
+    private int[] mDataActivity;
 
-    private boolean mDataConnectionPossible = false;
+    private int[] mDataConnectionState;
 
-    private String mDataConnectionReason = "";
+    private boolean[] mDataConnectionPossible;
 
-    private String mDataConnectionApn = "";
+    private String[] mDataConnectionReason;
+
+    private String[] mDataConnectionApn;
 
     private ArrayList<String> mConnectedApns;
 
-    private LinkProperties mDataConnectionLinkProperties;
+    private LinkProperties[] mDataConnectionLinkProperties;
 
-    private NetworkCapabilities mDataConnectionNetworkCapabilities;
+    private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
 
-    private Bundle mCellLocation = new Bundle();
+    private Bundle[] mCellLocation;
 
-    private int mDataConnectionNetworkType;
+    private int[] mDataConnectionNetworkType;
 
     private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
 
-    private List<CellInfo> mCellInfo = null;
+    private ArrayList<List<CellInfo>> mCellInfo = null;
+
+    private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
+
+    private long mDefaultSubId;
 
     private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
 
@@ -148,21 +162,40 @@
                 PhoneStateListener.LISTEN_CALL_STATE |
                 PhoneStateListener.LISTEN_DATA_ACTIVITY |
                 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
-                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
+                PhoneStateListener.LISTEN_VOLTE_STATE;;
 
     static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
                 PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
 
     private static final int MSG_USER_SWITCHED = 1;
+    private static final int MSG_UPDATE_DEFAULT_SUB = 2;
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_USER_SWITCHED: {
-                    if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
-                    TelephonyRegistry.this.notifyCellLocation(mCellLocation);
+                    Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+                    int numPhones = TelephonyManager.getDefault().getPhoneCount();
+                    for (int sub = 0; sub < numPhones; sub++) {
+                        TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]);
+                    }
+                    break;
+                }
+                case MSG_UPDATE_DEFAULT_SUB: {
+                    Slog.d(TAG, "MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId);
+                    // Default subscription id changed, update the changed default subscription
+                    // id in  all the legacy application listener records.
+                    synchronized (mRecords) {
+                        for (Record r : mRecords) {
+                            // FIXME: Be sure we're using isLegacyApp correctly!
+                            if (r.isLegacyApp == true) {
+                                r.subId = mDefaultSubId;
+                            }
+                        }
+                    }
                     break;
                 }
             }
@@ -173,9 +206,14 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            Slog.d(TAG, "mBroadcastReceiver: action=" + action);
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+            } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
+                mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                        SubscriptionManager.getDefaultSubId());
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
             }
         }
     };
@@ -190,13 +228,55 @@
     TelephonyRegistry(Context context) {
         CellLocation  location = CellLocation.getEmpty();
 
+        mContext = context;
+        mBatteryStats = BatteryStatsService.getService();
+        mConnectedApns = new ArrayList<String>();
+
+        // Initialize default subscription to be used for single standby.
+        mDefaultSubId = SubscriptionManager.getDefaultSubId();
+
+        int numPhones = TelephonyManager.getDefault().getPhoneCount();
+        if (DBG) Slog.d(TAG, "TelephonyRegistor: ctor numPhones=" + numPhones);
+        mNumPhones = numPhones;
+        mCallState = new int[numPhones];
+        mDataActivity = new int[numPhones];
+        mDataConnectionState = new int[numPhones];
+        mDataConnectionNetworkType = new int[numPhones];
+        mCallIncomingNumber = new String[numPhones];
+        mServiceState = new ServiceState[numPhones];
+        mSignalStrength = new SignalStrength[numPhones];
+        mMessageWaiting = new boolean[numPhones];
+        mDataConnectionPossible = new boolean[numPhones];
+        mDataConnectionReason = new String[numPhones];
+        mDataConnectionApn = new String[numPhones];
+        mCallForwarding = new boolean[numPhones];
+        mCellLocation = new Bundle[numPhones];
+        mDataConnectionLinkProperties = new LinkProperties[numPhones];
+        mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
+        mCellInfo = new ArrayList<List<CellInfo>>();
+        for (int i = 0; i < numPhones; i++) {
+            mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
+            mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
+            mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+            mCallIncomingNumber[i] =  "";
+            mServiceState[i] =  new ServiceState();
+            mSignalStrength[i] =  new SignalStrength();
+            mMessageWaiting[i] =  false;
+            mCallForwarding[i] =  false;
+            mDataConnectionPossible[i] = false;
+            mDataConnectionReason[i] =  "";
+            mDataConnectionApn[i] =  "";
+            mCellLocation[i] = new Bundle();
+            mCellInfo.add(i, null);
+        }
+
         // Note that location can be null for non-phone builds like
         // like the generic one.
         if (location != null) {
-            location.fillInNotifierBundle(mCellLocation);
+            for (int i = 0; i < numPhones; i++) {
+                location.fillInNotifierBundle(mCellLocation[i]);
+            }
         }
-        mContext = context;
-        mBatteryStats = BatteryStatsService.getService();
         mConnectedApns = new ArrayList<String>();
     }
 
@@ -205,16 +285,31 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
+        Slog.d(TAG, "systemRunning register for intents");
         mContext.registerReceiver(mBroadcastReceiver, filter);
     }
 
     @Override
     public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
             boolean notifyNow) {
+        listen(pkgForDebug, callback, events, notifyNow, mDefaultSubId, true);
+    }
+
+    @Override
+    public void listenUsingSubId(long subId, String pkgForDebug, IPhoneStateListener callback,
+            int events, boolean notifyNow) {
+        listen(pkgForDebug, callback, events, notifyNow, subId, false);
+    }
+
+    private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
+            boolean notifyNow, long subId, boolean isLegacyApp) {
         int callerUid = UserHandle.getCallingUserId();
         int myUid = UserHandle.myUserId();
-        if (DBG) {
+        if (VDBG) {
             Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+                + " notifyNow=" + notifyNow + " subId=" + subId
+                + " isLegacyApp=" + isLegacyApp
                 + " myUid=" + myUid
                 + " callerUid=" + callerUid);
         }
@@ -239,22 +334,37 @@
                     r.callback = callback;
                     r.pkgForDebug = pkgForDebug;
                     r.callerUid = callerUid;
+                    r.subId = subId;
+                    r.isLegacyApp = isLegacyApp;
+                    // Legacy applications pass invalid subId(-1), based on
+                    // the received subId value update the isLegacyApp field
+                    if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) {
+                        r.subId = mDefaultSubId;
+                        r.isLegacyApp = true; // FIXME: is this needed ??
+                    }
+                    if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+                        r.subId = mDefaultSubId;
+                        if (DBG) Slog.i(TAG, "listen: DEFAULT_SUB_ID");
+                    }
                     mRecords.add(r);
                     if (DBG) Slog.i(TAG, "listen: add new record=" + r);
                 }
+                int phoneId = SubscriptionManager.getPhoneId(subId);
                 int send = events & (events ^ r.events);
                 r.events = events;
-                if (notifyNow) {
+                if (notifyNow && validatePhoneId(phoneId)) {
                     if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
                         try {
-                            r.callback.onServiceStateChanged(new ServiceState(mServiceState));
+                            r.callback.onServiceStateChanged(
+                                    new ServiceState(mServiceState[phoneId]));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
                         try {
-                            int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
+                            int gsmSignalStrength = mSignalStrength[phoneId]
+                                    .getGsmSignalStrength();
                             r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
                                     : gsmSignalStrength));
                         } catch (RemoteException ex) {
@@ -263,51 +373,56 @@
                     }
                     if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
                         try {
-                            r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
+                            r.callback.onMessageWaitingIndicatorChanged(
+                                    mMessageWaiting[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
                         try {
-                            r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
+                            r.callback.onCallForwardingIndicatorChanged(
+                                    mCallForwarding[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
                         try {
-                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
-                            r.callback.onCellLocationChanged(new Bundle(mCellLocation));
+                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation = "
+                                    + mCellLocation[phoneId]);
+                            r.callback.onCellLocationChanged(
+                                    new Bundle(mCellLocation[phoneId]));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
                         try {
-                            r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
+                            r.callback.onCallStateChanged(mCallState[phoneId],
+                                     mCallIncomingNumber[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
                         try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
-                                mDataConnectionNetworkType);
+                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                mDataConnectionNetworkType[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
                         try {
-                            r.callback.onDataActivity(mDataActivity);
+                            r.callback.onDataActivity(mDataActivity[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
                         try {
-                            r.callback.onSignalStrengthsChanged(mSignalStrength);
+                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -321,8 +436,9 @@
                     }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
                         try {
-                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
-                            r.callback.onCellInfoChanged(mCellInfo);
+                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo[" + phoneId + "] = "
+                                    + mCellInfo.get(phoneId));
+                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -373,10 +489,10 @@
             return;
         }
         synchronized (mRecords) {
-            mCallState = state;
-            mCallIncomingNumber = incomingNumber;
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+                if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                    (r.isLegacyApp == true)) {
+                    // FIXME: why does isLegacyApp need to be true?
                     try {
                         r.callback.onCallStateChanged(state, incomingNumber);
                     } catch (RemoteException ex) {
@@ -386,82 +502,148 @@
             }
             handleRemoveListLocked();
         }
-        broadcastCallStateChanged(state, incomingNumber);
+        broadcastCallStateChanged(state, incomingNumber, mDefaultSubId);
     }
 
-    public void notifyServiceState(ServiceState state) {
+    public void notifyCallStateUsingSubId(long subId, int state, String incomingNumber) {
+        if (!checkNotifyPermission("notifyCallState()")) {
+            return;
+        }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCallStateUsingSubId: subId=" + subId
+                + " state=" + state + " incomingNumber=" + incomingNumber);
+        }
+        synchronized (mRecords) {
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCallState[phoneId] = state;
+                mCallIncomingNumber[phoneId] = incomingNumber;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                        (r.subId == subId) && (r.isLegacyApp == false)) {
+                        // FIXME: why isLegacyApp false?
+                        try {
+                            r.callback.onCallStateChanged(state, incomingNumber);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+        broadcastCallStateChanged(state, incomingNumber, subId);
+    }
+
+     public void notifyServiceState(ServiceState state) {
+         notifyServiceStateUsingSubId(mDefaultSubId, state);
+     }
+
+    public void notifyServiceStateUsingSubId(long subId, ServiceState state) {
         if (!checkNotifyPermission("notifyServiceState()")){
             return;
         }
-        long ident = Binder.clearCallingIdentity();
-        try {
-            mBatteryStats.notePhoneState(state.getState());
-        } catch (RemoteException re) {
-            // Can't do much
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+        if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
+            subId = mDefaultSubId;
+            Slog.d(TAG, "notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
+        }
+        if (VDBG) {
+            Slog.d(TAG, "notifyServiceStateUsingSubId: subId=" + subId
+                + " state=" + state);
         }
         synchronized (mRecords) {
-            mServiceState = state;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
-                    try {
-                        r.callback.onServiceStateChanged(new ServiceState(state));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mServiceState[phoneId] = state;
+                for (Record r : mRecords) {
+                    // FIXME: use DEFAULT_SUB_ID instead??
+                    if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
+                            (r.subId == subId)) {
+                        try {
+                            r.callback.onServiceStateChanged(new ServiceState(state));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
+            } else {
+                Slog.d(TAG, "notifyServiceStateUsingSubId: INVALID phoneId=" + phoneId);
             }
             handleRemoveListLocked();
         }
-        broadcastServiceStateChanged(state);
+        broadcastServiceStateChanged(state, subId);
     }
 
     public void notifySignalStrength(SignalStrength signalStrength) {
+        notifySignalStrengthUsingSubId(mDefaultSubId, signalStrength);
+    }
+
+    public void notifySignalStrengthUsingSubId(long subId, SignalStrength signalStrength) {
         if (!checkNotifyPermission("notifySignalStrength()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifySignalStrengthUsingSubId: subId=" + subId
+                + " signalStrength=" + signalStrength);
+        }
         synchronized (mRecords) {
-            mSignalStrength = signalStrength;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
-                    try {
-                        r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mSignalStrength[phoneId] = signalStrength;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
+                        (r.subId == subId)){
+                        try {
+                            r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
-                }
-                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
-                    try {
-                        int gsmSignalStrength = signalStrength.getGsmSignalStrength();
-                        r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
-                                : gsmSignalStrength));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            int gsmSignalStrength = signalStrength.getGsmSignalStrength();
+                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+                                    : gsmSignalStrength));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
             handleRemoveListLocked();
         }
-        broadcastSignalStrengthChanged(signalStrength);
+        broadcastSignalStrengthChanged(signalStrength, subId);
     }
 
     public void notifyCellInfo(List<CellInfo> cellInfo) {
+         notifyCellInfoUsingSubId(mDefaultSubId, cellInfo);
+    }
+
+    public void notifyCellInfoUsingSubId(long subId, List<CellInfo> cellInfo) {
         if (!checkNotifyPermission("notifyCellInfo()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCellInfoUsingSubId: subId=" + subId
+                + " cellInfo=" + cellInfo);
+        }
 
         synchronized (mRecords) {
-            mCellInfo = cellInfo;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
-                    try {
-                        if (DBG_LOC) {
-                            Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCellInfo.set(phoneId, cellInfo);
+                for (Record r : mRecords) {
+                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)
+                            && r.subId == subId) {
+                        try {
+                            if (DBG_LOC) {
+                                Slog.d(TAG, "notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
+                            }
+                            r.callback.onCellInfoChanged(cellInfo);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
                         }
-                        r.callback.onCellInfoChanged(cellInfo);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
                     }
                 }
             }
@@ -495,17 +677,29 @@
     }
 
     public void notifyMessageWaitingChanged(boolean mwi) {
+        notifyMessageWaitingChangedUsingSubId(mDefaultSubId, mwi);
+    }
+
+    public void notifyMessageWaitingChangedUsingSubId(long subId, boolean mwi) {
         if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyMessageWaitingChangedUsingSubId: subId=" + subId
+                + " mwi=" + mwi);
+        }
         synchronized (mRecords) {
-            mMessageWaiting = mwi;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
-                    try {
-                        r.callback.onMessageWaitingIndicatorChanged(mwi);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mMessageWaiting[phoneId] = mwi;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            r.callback.onMessageWaitingIndicatorChanged(mwi);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -514,17 +708,29 @@
     }
 
     public void notifyCallForwardingChanged(boolean cfi) {
+        notifyCallForwardingChangedUsingSubId(mDefaultSubId, cfi);
+    }
+
+    public void notifyCallForwardingChangedUsingSubId(long subId, boolean cfi) {
         if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCallForwardingChangedUsingSubId: subId=" + subId
+                + " cfi=" + cfi);
+        }
         synchronized (mRecords) {
-            mCallForwarding = cfi;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
-                    try {
-                        r.callback.onCallForwardingIndicatorChanged(cfi);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCallForwarding[phoneId] = cfi;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            r.callback.onCallForwardingIndicatorChanged(cfi);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -533,11 +739,16 @@
     }
 
     public void notifyDataActivity(int state) {
+        notifyDataActivityUsingSubId(mDefaultSubId, state);
+    }
+
+    public void notifyDataActivityUsingSubId(long subId, int state) {
         if (!checkNotifyPermission("notifyDataActivity()" )) {
             return;
         }
         synchronized (mRecords) {
-            mDataActivity = state;
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            mDataActivity[phoneId] = state;
             for (Record r : mRecords) {
                 if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
                     try {
@@ -554,29 +765,40 @@
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+        notifyDataConnectionUsingSubId(mDefaultSubId, state, isDataConnectivityPossible,
+            reason, apn, apnType, linkProperties,
+            networkCapabilities, networkType, roaming);
+    }
+
+    public void notifyDataConnectionUsingSubId(long subId, int state,
+            boolean isDataConnectivityPossible, String reason, String apn, String apnType,
+            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+            int networkType, boolean roaming) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
-        if (DBG) {
-            Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
-                + isDataConnectivityPossible + " reason='" + reason
+        if (VDBG) {
+            Slog.i(TAG, "notifyDataConnectionUsingSubId: subId=" + subId
+                + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible
+                + " reason='" + reason
                 + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
                 + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
         }
         synchronized (mRecords) {
+            int phoneId = SubscriptionManager.getPhoneId(subId);
             boolean modified = false;
             if (state == TelephonyManager.DATA_CONNECTED) {
                 if (!mConnectedApns.contains(apnType)) {
                     mConnectedApns.add(apnType);
-                    if (mDataConnectionState != state) {
-                        mDataConnectionState = state;
+                    if (mDataConnectionState[phoneId] != state) {
+                        mDataConnectionState[phoneId] = state;
                         modified = true;
                     }
                 }
             } else {
                 if (mConnectedApns.remove(apnType)) {
                     if (mConnectedApns.isEmpty()) {
-                        mDataConnectionState = state;
+                        mDataConnectionState[phoneId] = state;
                         modified = true;
                     } else {
                         // leave mDataConnectionState as is and
@@ -584,25 +806,28 @@
                     }
                 }
             }
-            mDataConnectionPossible = isDataConnectivityPossible;
-            mDataConnectionReason = reason;
-            mDataConnectionLinkProperties = linkProperties;
-            mDataConnectionNetworkCapabilities = networkCapabilities;
-            if (mDataConnectionNetworkType != networkType) {
-                mDataConnectionNetworkType = networkType;
+            mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
+            mDataConnectionReason[phoneId] = reason;
+            mDataConnectionLinkProperties[phoneId] = linkProperties;
+            mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
+            if (mDataConnectionNetworkType[phoneId] != networkType) {
+                mDataConnectionNetworkType[phoneId] = networkType;
                 // need to tell registered listeners about the new network type
                 modified = true;
             }
             if (modified) {
                 if (DBG) {
-                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState
-                        + ", " + mDataConnectionNetworkType + ")");
+                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+                        + ", " + mDataConnectionNetworkType[phoneId] + ")");
                 }
                 for (Record r : mRecords) {
-                    if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+                    if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
+                            (r.subId == subId)) {
                         try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
-                                    mDataConnectionNetworkType);
+                            Slog.d(TAG,"Notify data connection state changed on sub: " +
+                                    subId);
+                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                    mDataConnectionNetworkType[phoneId]);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -624,15 +849,24 @@
             handleRemoveListLocked();
         }
         broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
-                apnType, linkProperties, networkCapabilities, roaming);
+                apnType, linkProperties, networkCapabilities, roaming, subId);
         broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
                 linkProperties, "");
     }
 
     public void notifyDataConnectionFailed(String reason, String apnType) {
+         notifyDataConnectionFailedUsingSubId(mDefaultSubId, reason, apnType);
+    }
+
+    public void notifyDataConnectionFailedUsingSubId(long subId,
+            String reason, String apnType) {
         if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyDataConnectionFailedUsingSubId: subId=" + subId
+                + " reason=" + reason + " apnType=" + apnType);
+        }
         synchronized (mRecords) {
             mPreciseDataConnectionState = new PreciseDataConnectionState(
                     TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -648,29 +882,42 @@
             }
             handleRemoveListLocked();
         }
-        broadcastDataConnectionFailed(reason, apnType);
+        broadcastDataConnectionFailed(reason, apnType, subId);
         broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
     }
 
     public void notifyCellLocation(Bundle cellLocation) {
+         notifyCellLocationUsingSubId(mDefaultSubId, cellLocation);
+    }
+
+    public void notifyCellLocationUsingSubId(long subId, Bundle cellLocation) {
+        Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+                + " cellLocation=" + cellLocation);
         if (!checkNotifyPermission("notifyCellLocation()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+                + " cellLocation=" + cellLocation);
+        }
         synchronized (mRecords) {
-            mCellLocation = cellLocation;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
-                    try {
-                        if (DBG_LOC) {
-                            Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
-                                    + " r=" + r);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCellLocation[phoneId] = cellLocation;
+                for (Record r : mRecords) {
+                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)
+                            && r.subId == subId) {
+                        try {
+                            if (DBG_LOC) {
+                                Slog.d(TAG, "notifyCellLocation: cellLocation=" + cellLocation
+                                        + " r=" + r);
+                            }
+                            r.callback.onCellLocationChanged(new Bundle(cellLocation));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
                         }
-                        r.callback.onCellLocationChanged(new Bundle(cellLocation));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
                     }
-
                 }
             }
             handleRemoveListLocked();
@@ -771,6 +1018,26 @@
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
     }
 
+    public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
+        if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            mVoLteServiceState = lteState;
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
+                    try {
+                        r.callback.onVoLteServiceStateChanged(
+                                new VoLteServiceState(mVoLteServiceState));
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -810,15 +1077,26 @@
     // the legacy intent broadcasting
     //
 
-    private void broadcastServiceStateChanged(ServiceState state) {
+    private void broadcastServiceStateChanged(ServiceState state, long subId) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.notePhoneState(state.getState());
+        } catch (RemoteException re) {
+            // Can't do much
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
         Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
         Bundle data = new Bundle();
         state.fillInNotifierBundle(data);
         intent.putExtras(data);
+        // Pass the subscription along with the intent.
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
+    private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) {
         long ident = Binder.clearCallingIdentity();
         try {
             mBatteryStats.notePhoneSignalStrength(signalStrength);
@@ -833,10 +1111,11 @@
         Bundle data = new Bundle();
         signalStrength.fillInNotifierBundle(data);
         intent.putExtras(data);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastCallStateChanged(int state, String incomingNumber) {
+    private void broadcastCallStateChanged(int state, String incomingNumber, long subId) {
         long ident = Binder.clearCallingIdentity();
         try {
             if (state == TelephonyManager.CALL_STATE_IDLE) {
@@ -856,6 +1135,7 @@
         if (!TextUtils.isEmpty(incomingNumber)) {
             intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
         }
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                 android.Manifest.permission.READ_PHONE_STATE);
     }
@@ -863,7 +1143,7 @@
     private void broadcastDataConnectionStateChanged(int state,
             boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, boolean roaming) {
+            NetworkCapabilities networkCapabilities, boolean roaming, long subId) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
@@ -890,13 +1170,16 @@
 
         intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
         intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastDataConnectionFailed(String reason, String apnType) {
+    private void broadcastDataConnectionFailed(String reason, String apnType,
+            long subId) {
         Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
         intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
         intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
@@ -989,4 +1272,10 @@
         }
         return valid;
     }
+
+    private boolean validatePhoneId(int phoneId) {
+        boolean valid = (phoneId >= 0) && (phoneId < mNumPhones);
+        if (VDBG) Slog.d(TAG, "validatePhoneId: " + valid);
+        return valid;
+    }
 }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index ed7f6b8..b935d2a 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -36,6 +36,7 @@
 import android.telephony.Rlog;
 import android.util.SparseIntArray;
 
+import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
@@ -166,7 +167,9 @@
         // TODO: We don't check for SecurityException here (requires
         // CALL_PRIVILEGED permission).
         if (scheme.equals("voicemail")) {
-            return TelephonyManager.getDefault().getCompleteVoiceMailNumber();
+            long subId = intent.getLongExtra(SUBSCRIPTION_KEY,
+                    SubscriptionManager.getDefaultVoiceSubId());
+            return TelephonyManager.getDefault().getCompleteVoiceMailNumber(subId);
         }
 
         if (context == null) {
@@ -1144,7 +1147,7 @@
      * @return A locally acceptable formatting of the input, or the raw input if
      *  formatting rules aren't known for the number
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static String formatNumber(String source) {
         SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1162,7 +1165,7 @@
      * @return The phone number formatted with the given formatting type.
      *
      * @hide
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static String formatNumber(String source, int defaultFormattingType) {
         SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1177,7 +1180,7 @@
      * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
      * rules are not known for the given locale
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static int getFormatTypeForLocale(Locale locale) {
         String country = locale.getCountry();
@@ -1193,7 +1196,7 @@
      * @param defaultFormattingType The default formatting rules to apply if the number does
      * not begin with +[country_code]
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static void formatNumber(Editable text, int defaultFormattingType) {
         int formatType = defaultFormattingType;
@@ -1241,7 +1244,7 @@
      *
      * @param text the number to be formatted, will be modified with the formatting
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static void formatNanpNumber(Editable text) {
         int length = text.length();
@@ -1356,7 +1359,7 @@
      * @param text the number to be formatted, will be modified with
      * the formatting
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static void formatJapaneseNumber(Editable text) {
         JapanesePhoneNumberFormatter.format(text);
@@ -1560,9 +1563,23 @@
      *         listed in the RIL / SIM, otherwise return false.
      */
     public static boolean isEmergencyNumber(String number) {
+        return isEmergencyNumber(getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks a given number against the list of
+     * emergency numbers provided by the RIL and SIM card.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @return true if the number is in the list of emergency numbers
+     *         listed in the RIL / SIM, otherwise return false.
+     * @hide
+     */
+    public static boolean isEmergencyNumber(long subId, String number) {
         // Return true only if the specified number *exactly* matches
         // one of the emergency numbers listed by the RIL / SIM.
-        return isEmergencyNumberInternal(number, true /* useExactMatch */);
+        return isEmergencyNumberInternal(subId, number, true /* useExactMatch */);
     }
 
     /**
@@ -1586,9 +1603,33 @@
      * @hide
      */
     public static boolean isPotentialEmergencyNumber(String number) {
+        return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks if given number might *potentially* result in
+     * a call to an emergency service on the current network.
+     *
+     * Specifically, this method will return true if the specified number
+     * is an emergency number according to the list managed by the RIL or
+     * SIM, *or* if the specified number simply starts with the same
+     * digits as any of the emergency numbers listed in the RIL / SIM.
+     *
+     * This method is intended for internal use by the phone app when
+     * deciding whether to allow ACTION_CALL intents from 3rd party apps
+     * (where we're required to *not* allow emergency calls to be placed.)
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @return true if the number is in the list of emergency numbers
+     *         listed in the RIL / SIM, *or* if the number starts with the
+     *         same digits as any of those emergency numbers.
+     * @hide
+     */
+    public static boolean isPotentialEmergencyNumber(long subId, String number) {
         // Check against the emergency numbers listed by the RIL / SIM,
         // and *don't* require an exact match.
-        return isEmergencyNumberInternal(number, false /* useExactMatch */);
+        return isEmergencyNumberInternal(subId, number, false /* useExactMatch */);
     }
 
     /**
@@ -1611,7 +1652,32 @@
      *         listed in the RIL / sim, otherwise return false.
      */
     private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) {
-        return isEmergencyNumberInternal(number, null, useExactMatch);
+        return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, useExactMatch);
+    }
+
+    /**
+     * Helper function for isEmergencyNumber(String) and
+     * isPotentialEmergencyNumber(String).
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     *
+     * @param useExactMatch if true, consider a number to be an emergency
+     *           number only if it *exactly* matches a number listed in
+     *           the RIL / SIM.  If false, a number is considered to be an
+     *           emergency number if it simply starts with the same digits
+     *           as any of the emergency numbers listed in the RIL / SIM.
+     *           (Setting useExactMatch to false allows you to identify
+     *           number that could *potentially* result in emergency calls
+     *           since many networks will actually ignore trailing digits
+     *           after a valid emergency number.)
+     *
+     * @return true if the number is in the list of emergency numbers
+     *         listed in the RIL / sim, otherwise return false.
+     */
+    private static boolean isEmergencyNumberInternal(long subId, String number,
+            boolean useExactMatch) {
+        return isEmergencyNumberInternal(subId, number, null, useExactMatch);
     }
 
     /**
@@ -1625,7 +1691,21 @@
      * @hide
      */
     public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
-        return isEmergencyNumberInternal(number,
+            return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+    }
+
+    /**
+     * Checks if a given number is an emergency number for a specific country.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param defaultCountryIso the specific country which the number should be checked against
+     * @return if the number is an emergency number for the specific country, then return true,
+     * otherwise false
+     * @hide
+     */
+    public static boolean isEmergencyNumber(long subId, String number, String defaultCountryIso) {
+        return isEmergencyNumberInternal(subId, number,
                                          defaultCountryIso,
                                          true /* useExactMatch */);
     }
@@ -1652,7 +1732,33 @@
      * @hide
      */
     public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
-        return isEmergencyNumberInternal(number,
+        return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+    }
+
+    /**
+     * Checks if a given number might *potentially* result in a call to an
+     * emergency service, for a specific country.
+     *
+     * Specifically, this method will return true if the specified number
+     * is an emergency number in the specified country, *or* if the number
+     * simply starts with the same digits as any emergency number for that
+     * country.
+     *
+     * This method is intended for internal use by the phone app when
+     * deciding whether to allow ACTION_CALL intents from 3rd party apps
+     * (where we're required to *not* allow emergency calls to be placed.)
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param defaultCountryIso the specific country which the number should be checked against
+     * @return true if the number is an emergency number for the specific
+     *         country, *or* if the number starts with the same digits as
+     *         any of those emergency numbers.
+     * @hide
+     */
+    public static boolean isPotentialEmergencyNumber(long subId, String number,
+            String defaultCountryIso) {
+        return isEmergencyNumberInternal(subId, number,
                                          defaultCountryIso,
                                          false /* useExactMatch */);
     }
@@ -1674,6 +1780,29 @@
     private static boolean isEmergencyNumberInternal(String number,
                                                      String defaultCountryIso,
                                                      boolean useExactMatch) {
+        return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, defaultCountryIso,
+                useExactMatch);
+    }
+
+    /**
+     * Helper function for isEmergencyNumber(String, String) and
+     * isPotentialEmergencyNumber(String, String).
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param defaultCountryIso the specific country which the number should be checked against
+     * @param useExactMatch if true, consider a number to be an emergency
+     *           number only if it *exactly* matches a number listed in
+     *           the RIL / SIM.  If false, a number is considered to be an
+     *           emergency number if it simply starts with the same digits
+     *           as any of the emergency numbers listed in the RIL / SIM.
+     *
+     * @return true if the number is an emergency number for the specified country.
+     * @hide
+     */
+    private static boolean isEmergencyNumberInternal(long subId, String number,
+                                                     String defaultCountryIso,
+                                                     boolean useExactMatch) {
         // If the number passed in is null, just return false:
         if (number == null) return false;
 
@@ -1692,9 +1821,14 @@
         // to the list.
         number = extractNetworkPortionAlt(number);
 
+        String numbers = "";
+        int slotId = SubscriptionManager.getSlotId(subId);
         // retrieve the list of emergency numbers
         // check read-write ecclist property first
-        String numbers = SystemProperties.get("ril.ecclist");
+        String ecclist = (slotId == 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
+
+        numbers = SystemProperties.get(ecclist);
+
         if (TextUtils.isEmpty(numbers)) {
             // then read-only ecclist property since old RIL only uses this
             numbers = SystemProperties.get("ro.ril.ecclist");
@@ -1742,15 +1876,29 @@
 
     /**
      * Checks if a given number is an emergency number for the country that the user is in.
-     * @param context the specific context which the number should be checked against
-     * @param number the number to look up.
      *
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
      * @return true if the specified number is an emergency number for the country the user
      * is currently in.
      */
     public static boolean isLocalEmergencyNumber(Context context, String number) {
-        return isLocalEmergencyNumberInternal(context,
-                                              number,
+        return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks if a given number is an emergency number for the country that the user is in.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
+     * @return true if the specified number is an emergency number for the country the user
+     * is currently in.
+     * @hide
+     */
+    public static boolean isLocalEmergencyNumber(Context context, long subId, String number) {
+        return isLocalEmergencyNumberInternal(subId, number,
+                                              context,
                                               true /* useExactMatch */);
     }
 
@@ -1767,9 +1915,9 @@
      * This method is intended for internal use by the phone app when
      * deciding whether to allow ACTION_CALL intents from 3rd party apps
      * (where we're required to *not* allow emergency calls to be placed.)
-     * @param context the specific context which the number should be checked against
-     * @param number the number to look up.
      *
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
      * @return true if the specified number is an emergency number for a local country, based on the
      *              CountryDetector.
      *
@@ -1777,16 +1925,44 @@
      * @hide
      */
     public static boolean isPotentialLocalEmergencyNumber(Context context, String number) {
-        return isLocalEmergencyNumberInternal(context,
-                                              number,
+        return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks if a given number might *potentially* result in a call to an
+     * emergency service, for the country that the user is in. The current
+     * country is determined using the CountryDetector.
+     *
+     * Specifically, this method will return true if the specified number
+     * is an emergency number in the current country, *or* if the number
+     * simply starts with the same digits as any emergency number for the
+     * current country.
+     *
+     * This method is intended for internal use by the phone app when
+     * deciding whether to allow ACTION_CALL intents from 3rd party apps
+     * (where we're required to *not* allow emergency calls to be placed.)
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
+     * @return true if the specified number is an emergency number for a local country, based on the
+     *              CountryDetector.
+     *
+     * @hide
+     */
+    public static boolean isPotentialLocalEmergencyNumber(Context context, long subId,
+            String number) {
+        return isLocalEmergencyNumberInternal(subId, number,
+                                              context,
                                               false /* useExactMatch */);
     }
 
     /**
      * Helper function for isLocalEmergencyNumber() and
      * isPotentialLocalEmergencyNumber().
-     * @param context the specific context which the number should be checked against
+     *
      * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
      * @param useExactMatch if true, consider a number to be an emergency
      *           number only if it *exactly* matches a number listed in
      *           the RIL / SIM.  If false, a number is considered to be an
@@ -1797,9 +1973,34 @@
      *              local country, based on the CountryDetector.
      *
      * @see android.location.CountryDetector
+     * @hide
      */
-    private static boolean isLocalEmergencyNumberInternal(Context context,
-                                                          String number,
+    private static boolean isLocalEmergencyNumberInternal(String number,
+                                                          Context context,
+                                                          boolean useExactMatch) {
+        return isLocalEmergencyNumberInternal(getDefaultVoiceSubId(), number, context,
+                useExactMatch);
+    }
+
+    /**
+     * Helper function for isLocalEmergencyNumber() and
+     * isPotentialLocalEmergencyNumber().
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
+     * @param useExactMatch if true, consider a number to be an emergency
+     *           number only if it *exactly* matches a number listed in
+     *           the RIL / SIM.  If false, a number is considered to be an
+     *           emergency number if it simply starts with the same digits
+     *           as any of the emergency numbers listed in the RIL / SIM.
+     *
+     * @return true if the specified number is an emergency number for a
+     *              local country, based on the CountryDetector.
+     * @hide
+     */
+    private static boolean isLocalEmergencyNumberInternal(long subId, String number,
+                                                          Context context,
                                                           boolean useExactMatch) {
         String countryIso;
         CountryDetector detector = (CountryDetector) context.getSystemService(
@@ -1812,7 +2013,7 @@
             Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
                     + countryIso);
         }
-        return isEmergencyNumberInternal(number, countryIso, useExactMatch);
+        return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
     }
 
     /**
@@ -1826,10 +2027,26 @@
      * to read the VM number.
      */
     public static boolean isVoiceMailNumber(String number) {
+        return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number);
+    }
+
+    /**
+     * isVoiceMailNumber: checks a given number against the voicemail
+     *   number provided by the RIL and SIM card. The caller must have
+     *   the READ_PHONE_STATE credential.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @return true if the number is in the list of voicemail. False
+     * otherwise, including if the caller does not have the permission
+     * to read the VM number.
+     * @hide
+     */
+    public static boolean isVoiceMailNumber(long subId, String number) {
         String vmNumber;
 
         try {
-            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(subId);
         } catch (SecurityException ex) {
             return false;
         }
@@ -2561,5 +2778,11 @@
         return true;
     }
 
+    /**
+     * Returns Default voice subscription Id.
+     */
+    private static long getDefaultVoiceSubId() {
+        return SubscriptionManager.getDefaultVoiceSubId();
+    }
     //==== End of utility methods used only in compareStrictly() =====
 }
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 59ec6f5..c8c3063 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,11 +20,13 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
 import android.telephony.CellLocation;
 import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
 import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 
@@ -48,6 +50,7 @@
  * appropriate LISTEN_ flags.
  */
 public class PhoneStateListener {
+    private static final String TAG = "PhoneStateListener";
 
     /**
      * Stop listening for updates.
@@ -200,18 +203,42 @@
      */
     public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO           = 0x00002000;
 
+    /**
+     * Listen for changes to LTE network state
+     *
+     * @see #onLteNetworkStateChanged
+     * @hide
+     */
+    public static final int LISTEN_VOLTE_STATE                              = 0x00004000;
+
+     /*
+     * Subscription used to listen to the phone state changes
+     * @hide
+     */
+    /** @hide */
+    protected long mSubId = 0;
+
     private final Handler mHandler;
 
     public PhoneStateListener() {
-        this(Looper.myLooper());
+        this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
+    }
+
+    /**
+     * @hide
+     */
+    public PhoneStateListener(long subId) {
+        this(subId, Looper.myLooper());
     }
 
     /** @hide */
-    public PhoneStateListener(Looper looper) {
+    public PhoneStateListener(long subId, Looper looper) {
+        Rlog.d(TAG, "ctor: subId=" + subId + " looper=" + looper);
+        mSubId = subId;
         mHandler = new Handler(looper) {
             public void handleMessage(Message msg) {
-                //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what)
-                // + " msg=" + msg);
+                Rlog.d(TAG, "mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what)
+                 + " msg=" + msg);
                 switch (msg.what) {
                     case LISTEN_SERVICE_STATE:
                         PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
@@ -258,6 +285,9 @@
                         PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
                                 (DataConnectionRealTimeInfo)msg.obj);
                         break;
+                    case LISTEN_VOLTE_STATE:
+                        PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
+                        break;
                 }
             }
         };
@@ -417,6 +447,15 @@
     }
 
     /**
+     * Callback invoked when the service state of LTE network
+     * related to the VoLTE service has changed.
+     * @param stateInfo is the current LTE network information
+     * @hide
+     */
+    public void onVoLteServiceStateChanged(VoLteServiceState stateInfo) {
+    }
+
+    /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
      */
@@ -484,5 +523,9 @@
             Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0,
                     dcRtInfo).sendToTarget();
         }
+
+        public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
+            Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
+        }
     };
 }
diff --git a/telephony/java/android/telephony/SubInfoRecord.aidl b/telephony/java/android/telephony/SubInfoRecord.aidl
new file mode 100755
index 0000000..a2de676
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.aidl
@@ -0,0 +1,19 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable SubInfoRecord;
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
new file mode 100644
index 0000000..670def7
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -0,0 +1,108 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ *  A parcelable holder class of byte[] for ISms aidl implementation
+ *  @hide
+ */
+
+public class SubInfoRecord implements Parcelable {
+
+    public long mSubId;
+    public String mIccId;
+    public int mSlotId;
+    public String mDisplayName;
+    public int mNameSource;
+    public int mColor;
+    public String mNumber;
+    public int mDispalyNumberFormat;
+    public int mDataRoaming;
+    public int[] mSimIconRes;
+
+    public SubInfoRecord() {
+        this.mSubId = -1;
+        this.mIccId = "";
+        this.mSlotId = -1;
+        this.mDisplayName = "";
+        this.mNameSource = 0;
+        this.mColor = 0;
+        this.mNumber = "";
+        this.mDispalyNumberFormat = 0;
+        this.mDataRoaming = 0;
+        this.mSimIconRes = new int[2];
+    }
+
+
+    public SubInfoRecord(long subId, String iccId, int slotId, String displayname, int nameSource,
+            int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) {
+        this.mSubId = subId;
+        this.mIccId = iccId;
+        this.mSlotId = slotId;
+        this.mDisplayName = displayname;
+        this.mNameSource = nameSource;
+        this.mColor = mColor;
+        this.mNumber = mNumber;
+        this.mDispalyNumberFormat = displayFormat;
+        this.mDataRoaming = roaming;
+        this.mSimIconRes = iconRes;
+    }
+
+    public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
+        public SubInfoRecord createFromParcel(Parcel source) {
+            long mSubId = source.readLong();
+            String mIccId = source.readString();
+            int mSlotId = source.readInt();
+            String mDisplayName = source.readString();
+            int mNameSource = source.readInt();
+            int mColor = source.readInt();
+            String mNumber = source.readString();
+            int mDispalyNumberFormat = source.readInt();
+            int mDataRoaming = source.readInt();
+            int[] iconRes = new int[2];
+            source.readIntArray(iconRes);
+
+            return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber,
+                mDispalyNumberFormat, mDataRoaming, iconRes);
+        }
+
+        public SubInfoRecord[] newArray(int size) {
+            return new SubInfoRecord[size];
+        }
+    };
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mSubId);
+        dest.writeString(mIccId);
+        dest.writeInt(mSlotId);
+        dest.writeString(mDisplayName);
+        dest.writeInt(mNameSource);
+        dest.writeInt(mColor);
+        dest.writeString(mNumber);
+        dest.writeInt(mDispalyNumberFormat);
+        dest.writeInt(mDataRoaming);
+        dest.writeIntArray(mSimIconRes);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
new file mode 100644
index 0000000..859a890
--- /dev/null
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -0,0 +1,708 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+import static android.Manifest.permission.READ_PHONE_STATE;
+
+import android.app.ActivityManagerNative;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.UserHandle;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.telephony.Rlog;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.ISub;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+/**
+ *@hide
+ */
+public class SubscriptionManager implements BaseColumns {
+    private static final String LOG_TAG = "SUB";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    // An invalid subscription identifier
+    public static final long INVALID_SUB_ID = Long.MAX_VALUE;
+
+    // The default subscription identifier
+    public static final long DEFAULT_SUB_ID = Long.MAX_VALUE - 1;
+
+    public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+    public static final int DEFAULT_INT_VALUE = -100;
+
+    public static final String DEFAULT_STRING_VALUE = "N/A";
+
+    public static final int EXTRA_VALUE_NEW_SIM = 1;
+    public static final int EXTRA_VALUE_REMOVE_SIM = 2;
+    public static final int EXTRA_VALUE_REPOSITION_SIM = 3;
+    public static final int EXTRA_VALUE_NOCHANGE = 4;
+
+    public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus";
+    public static final String INTENT_KEY_SIM_COUNT = "simCount";
+    public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot";
+    public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus";
+
+    /**
+     * The ICC ID of a SIM.
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String ICC_ID = "icc_id";
+
+    /**
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String SIM_ID = "sim_id";
+
+    public static final int SIM_NOT_INSERTED = -1;
+
+    /**
+     * The display name of a SIM.
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String DISPLAY_NAME = "display_name";
+
+    public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
+
+    /**
+     * The display name source of a SIM.
+     * <P>Type: INT (int)</P>
+     */
+    public static final String NAME_SOURCE = "name_source";
+
+    public static final int DEFAULT_SOURCE = 0;
+
+    public static final int SIM_SOURCE = 1;
+
+    public static final int USER_INPUT = 2;
+
+    /**
+     * The color of a SIM.
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String COLOR = "color";
+
+    public static final int COLOR_1 = 0;
+
+    public static final int COLOR_2 = 1;
+
+    public static final int COLOR_3 = 2;
+
+    public static final int COLOR_4 = 3;
+
+    public static final int COLOR_DEFAULT = COLOR_1;
+
+    /**
+     * The phone number of a SIM.
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String NUMBER = "number";
+
+    /**
+     * The number display format of a SIM.
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+    public static final int DISPALY_NUMBER_NONE = 0;
+
+    public static final int DISPLAY_NUMBER_FIRST = 1;
+
+    public static final int DISPLAY_NUMBER_LAST = 2;
+
+    public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
+
+    /**
+     * Permission for data roaming of a SIM.
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String DATA_ROAMING = "data_roaming";
+
+    public static final int DATA_ROAMING_ENABLE = 1;
+
+    public static final int DATA_ROAMING_DISABLE = 0;
+
+    public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+    private static final int RES_TYPE_BACKGROUND_DARK = 0;
+
+    private static final int RES_TYPE_BACKGROUND_LIGHT = 1;
+
+    private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK);
+
+    private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT);
+
+    private static HashMap<Integer, Long> mSimInfo = new HashMap<Integer, Long>();
+
+    public SubscriptionManager() {
+        if (DBG) logd("SubscriptionManager created");
+    }
+
+    /**
+     * Get the SubInfoRecord according to an index
+     * @param context Context provided by caller
+     * @param subId The unique SubInfoRecord index in database
+     * @return SubInfoRecord, maybe null
+     */
+    public static SubInfoRecord getSubInfoUsingSubId(Context context, long subId) {
+        if (VDBG) logd("[getSubInfoUsingSubIdx]+ subId:" + subId);
+        if (subId <= 0) {
+            if (VDBG) logd("[getSubInfoUsingSubIdx]- subId <= 0");
+            return null;
+        }
+
+        SubInfoRecord subInfo = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subInfo = iSub.getSubInfoUsingSubId(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return subInfo;
+
+    }
+
+    /**
+     * Get the SubInfoRecord according to an IccId
+     * @param context Context provided by caller
+     * @param iccId the IccId of SIM card
+     * @return SubInfoRecord, maybe null
+     */
+    public static List<SubInfoRecord> getSubInfoUsingIccId(Context context, String iccId) {
+        if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId);
+        if (iccId == null) {
+            logd("[getSubInfoUsingIccId]- null iccid");
+            return null;
+        }
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getSubInfoUsingIccId(iccId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get the SubInfoRecord according to slotId
+     * @param context Context provided by caller
+     * @param slotId the slot which the SIM is inserted
+     * @return SubInfoRecord, maybe null
+     */
+    public static List<SubInfoRecord> getSubInfoUsingSlotId(Context context, int slotId) {
+        if (VDBG) logd("[getSubInfoUsingSlotId]- slotId=" + slotId);
+        if (slotId < 0) {
+            logd("[getSubInfoUsingSlotId]- return null, slotId < 0");
+            return null;
+        }
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getSubInfoUsingSlotId(slotId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get all the SubInfoRecord(s) in subinfo database
+     * @param context Context provided by caller
+     * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+     */
+    public static List<SubInfoRecord> getAllSubInfoList(Context context) {
+        if (VDBG) logd("[getAllSubInfoList]+");
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getAllSubInfoList();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+     * @param context Context provided by caller
+     * @return Array list of currently inserted SubInfoRecord(s)
+     */
+    public static List<SubInfoRecord> getActivatedSubInfoList(Context context) {
+        if (VDBG) logd("[getActivatedSubInfoList]+");
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getActivatedSubInfoList();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get the SUB count of all SUB(s) in subinfo database
+     * @param context Context provided by caller
+     * @return all SIM count in database, include what was inserted before
+     */
+    public static int getAllSubInfoCount(Context context) {
+        if (VDBG) logd("[getAllSubInfoCount]+");
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getAllSubInfoCount();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Add a new SubInfoRecord to subinfo database if needed
+     * @param context Context provided by caller
+     * @param iccId the IccId of the SIM card
+     * @param slotId the slot which the SIM is inserted
+     * @return the URL of the newly created row or the updated row
+     */
+    public static Uri addSubInfoRecord(Context context, String iccId, int slotId) {
+        if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
+        if (iccId == null) {
+            logd("[addSubInfoRecord]- null iccId");
+        }
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                // FIXME: This returns 1 on success, 0 on error should should we return it?
+                iSub.addSubInfoRecord(iccId, slotId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        // FIXME: Always returns null?
+        return null;
+
+    }
+
+    /**
+     * Set SIM color by simInfo index
+     * @param context Context provided by caller
+     * @param color the color of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setColor(Context context, int color, long subId) {
+        if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId);
+        int size = sSimBackgroundDarkRes.length;
+        if (subId <= 0 || color < 0 || color >= size) {
+            logd("[setColor]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setColor(color, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set display name by simInfo index
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDisplayName(Context context, String displayName, long subId) {
+        return setDisplayName(context, displayName, subId, -1);
+    }
+
+    /**
+     * Set display name by simInfo index with name source
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+     * @return the number of records updated
+     */
+    public static int setDisplayName(Context context, String displayName, long subId, long nameSource) {
+        if (VDBG) logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource);
+        if (subId <= 0) {
+            logd("[setDisplayName]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set phone number by subId
+     * @param context Context provided by caller
+     * @param number the phone number of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDispalyNumber(Context context, String number, long subId) {
+        if (VDBG) logd("[setDispalyNumber]+ number:" + number + " subId:" + subId);
+        if (number == null || subId <= 0) {
+            logd("[setDispalyNumber]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDispalyNumber(number, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+     * @param context Context provided by caller
+     * @param format the display format of phone number
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDisplayNumberFormat(Context context, int format, long subId) {
+        if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId);
+        if (format < 0 || subId <= 0) {
+            logd("[setDisplayNumberFormat]- fail, return -1");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDisplayNumberFormat(format, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set data roaming by simInfo index
+     * @param context Context provided by caller
+     * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDataRoaming(Context context, int roaming, long subId) {
+        if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
+        if (roaming < 0 || subId <= 0) {
+            logd("[setDataRoaming]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDataRoaming(roaming, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    public static int getSlotId(long subId) {
+        if (VDBG) logd("[getSlotId]+ subId:" + subId);
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getSlotId(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    public static long[] getSubId(int slotId) {
+        if (VDBG) logd("[getSubId]+ slotId:" + slotId);
+
+        long[] subId = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getSubId(slotId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return subId;
+    }
+
+    public static int getPhoneId(long subId) {
+        if (VDBG) logd("[getPhoneId]+ subId=" + subId);
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getPhoneId(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("[getPhoneId]- phonId=" + result);
+        return result;
+
+    }
+
+    private static int[] setSimResource(int type) {
+        int[] simResource = null;
+
+        switch (type) {
+            case RES_TYPE_BACKGROUND_DARK:
+                simResource = new int[] {
+                    com.android.internal.R.drawable.sim_dark_blue,
+                    com.android.internal.R.drawable.sim_dark_orange,
+                    com.android.internal.R.drawable.sim_dark_green,
+                    com.android.internal.R.drawable.sim_dark_purple
+                };
+                break;
+            case RES_TYPE_BACKGROUND_LIGHT:
+                simResource = new int[] {
+                    com.android.internal.R.drawable.sim_light_blue,
+                    com.android.internal.R.drawable.sim_light_orange,
+                    com.android.internal.R.drawable.sim_light_green,
+                    com.android.internal.R.drawable.sim_light_purple
+                };
+                break;
+        }
+
+        return simResource;
+    }
+
+    private static void logd(String msg) {
+        Rlog.d(LOG_TAG, "[SubManager] " + msg);
+    }
+
+    public static long normalizeSubId(long subId) {
+        long retVal = (subId == DEFAULT_SUB_ID) ? getDefaultSubId() : subId;
+        Rlog.d(LOG_TAG, "[SubManager] normalizeSubId subId=" + retVal);
+        return retVal;
+    }
+
+    public static boolean validSubId(long subId) {
+        return (subId != DEFAULT_SUB_ID) && (subId != -1);
+    }
+
+    /**
+     * @return the "system" defaultSubId on a voice capable device this
+     * will be getDefaultVoiceSubId() and on a data only device it will be
+     * getDefaultDataSubId().
+     */
+    public static long getDefaultSubId() {
+        long subId = 1;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getDefaultSubId();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("getDefaultSubId=" + subId);
+        return subId;
+    }
+
+    public static long getDefaultVoiceSubId() {
+        long subId = 1;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getDefaultVoiceSubId();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("getDefaultSubId, sub id = " + subId);
+        return subId;
+    }
+
+    public static void setDefaultVoiceSubId(long subId) {
+        if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.setDefaultVoiceSubId(subId);
+            }
+        } catch (RemoteException ex) {
+         // ignore it
+        }
+    }
+
+    public static long getPreferredSmsSubId() {
+        // FIXME add framework support to get the preferred sub
+        return getDefaultSubId();
+    }
+
+    public static long getPreferredDataSubId() {
+        // FIXME add framework support to get the preferred sub
+        return getDefaultSubId();
+    }
+
+    public static long getDefaultDataSubId() {
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                return iSub.getDefaultDataSubId();
+            } else {
+                return -1;
+            }
+        } catch (RemoteException ex) {
+            return -1;
+        }
+    }
+
+    public static void setDefaultDataSubId(long subId) {
+        if (VDBG) logd("setDataSubscription sub id = " + subId);
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.setDefaultDataSubId(subId);
+            }
+        } catch (RemoteException ex) {
+         // ignore it
+        }
+    }
+
+    public static void clearSubInfo()
+    {
+        if (VDBG) logd("[clearSubInfo]+");
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.clearSubInfo();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return;
+    }
+
+    public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
+        long [] subId = SubscriptionManager.getSubId(phoneId);
+        if ((subId != null) && (subId.length >= 1)) {
+            if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
+            intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); //FIXME: RENAME TO PHONE_ID_KEY ??
+            intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId[0]);
+        } else {
+            logd("putPhoneIdAndSubIdExtra: no valid subs");
+        }
+    }
+}
+
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3f65bca..aaee99f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -86,6 +86,22 @@
 
     private final Context mContext;
 
+    private static String multiSimConfig =
+            SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+
+    /** Enum indicating multisim variants
+     *  DSDS - Dual SIM Dual Standby
+     *  DSDA - Dual SIM Dual Active
+     *  TSTS - Triple SIM Triple Standby
+     **/
+    /** @hide */
+    public enum MultiSimVariants {
+        DSDS,
+        DSDA,
+        TSTS,
+        UNKNOWN
+    };
+
     /** @hide */
     public TelephonyManager(Context context) {
         Context appContext = context.getApplicationContext();
@@ -114,11 +130,61 @@
         return sInstance;
     }
 
+
+    /**
+     * Returns the multi SIM variant
+     * Returns DSDS for Dual SIM Dual Standby
+     * Returns DSDA for Dual SIM Dual Active
+     * Returns TSTS for Triple SIM Triple Standby
+     * Returns UNKNOWN for others
+     */
+    /** {@hide} */
+    public MultiSimVariants getMultiSimConfiguration() {
+        String mSimConfig =
+            SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+        if (mSimConfig.equals("dsds")) {
+            return MultiSimVariants.DSDS;
+        } else if (mSimConfig.equals("dsda")) {
+            return MultiSimVariants.DSDA;
+        } else if (mSimConfig.equals("tsts")) {
+            return MultiSimVariants.TSTS;
+        } else {
+            return MultiSimVariants.UNKNOWN;
+        }
+    }
+
+
+    /**
+     * Returns the number of phones available.
+     * Returns 1 for Single standby mode (Single SIM functionality)
+     * Returns 2 for Dual standby mode.(Dual SIM functionality)
+     */
+    /** {@hide} */
+    public int getPhoneCount() {
+        int phoneCount = 1;
+        switch (getMultiSimConfiguration()) {
+            case DSDS:
+            case DSDA:
+                phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
+                break;
+            case TSTS:
+                phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM;
+                break;
+        }
+        return phoneCount;
+    }
+
     /** {@hide} */
     public static TelephonyManager from(Context context) {
         return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
     }
 
+    /** {@hide} */
+    public boolean isMultiSimEnabled() {
+        return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
+            multiSimConfig.equals("tsts"));
+    }
+
     //
     // Broadcast Intent actions
     //
@@ -529,8 +595,23 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getDeviceId() {
+        return getDeviceId(getDefaultSim());
+    }
+
+    /**
+     * Returns the unique device ID of a subscription, for example, the IMEI for
+     * GSM and the MEID for CDMA phones. Return null if device ID is not available.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param slotId of which deviceID is returned
+     */
+    /** {@hide} */
+    public String getDeviceId(int slotId) {
+        long[] subId = SubscriptionManager.getSubId(slotId);
         try {
-            return getSubscriberInfo().getDeviceId();
+            return getSubscriberInfo().getDeviceIdUsingSubId(subId[0]);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -578,8 +659,23 @@
      * @hide
      */
     public void enableLocationUpdates() {
+            enableLocationUpdates(getDefaultSubscription());
+    }
+
+    /**
+     * Enables location update notifications for a subscription.
+     * {@link PhoneStateListener#onCellLocationChanged
+     * PhoneStateListener.onCellLocationChanged} will be called on location updates.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
+     * CONTROL_LOCATION_UPDATES}
+     *
+     * @param subId for which the location updates are enabled
+     */
+    /** @hide */
+    public void enableLocationUpdates(long subId) {
         try {
-            getITelephony().enableLocationUpdates();
+            getITelephony().enableLocationUpdatesUsingSubId(subId);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -595,8 +691,13 @@
      * @hide
      */
     public void disableLocationUpdates() {
+            disableLocationUpdates(getDefaultSubscription());
+    }
+
+    /** @hide */
+    public void disableLocationUpdates(long subId) {
         try {
-            getITelephony().disableLocationUpdates();
+            getITelephony().disableLocationUpdatesUsingSubId(subId);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -644,22 +745,37 @@
      * {@hide}
      */
     public int getCurrentPhoneType() {
+        return getCurrentPhoneType(getDefaultSubscription());
+    }
+
+    /**
+     * Returns a constant indicating the device phone type for a subscription.
+     *
+     * @see #PHONE_TYPE_NONE
+     * @see #PHONE_TYPE_GSM
+     * @see #PHONE_TYPE_CDMA
+     *
+     * @param subId for which phone type is returned
+     */
+    /** {@hide} */
+    public int getCurrentPhoneType(long subId) {
+
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getActivePhoneType();
+                return telephony.getActivePhoneTypeUsingSubId(subId);
             } else {
                 // This can happen when the ITelephony interface is not up yet.
-                return getPhoneTypeFromProperty();
+                return getPhoneTypeFromProperty(subId);
             }
         } catch (RemoteException ex) {
             // This shouldn't happen in the normal case, as a backup we
             // read from the system property.
-            return getPhoneTypeFromProperty();
+            return getPhoneTypeFromProperty(subId);
         } catch (NullPointerException ex) {
             // This shouldn't happen in the normal case, as a backup we
             // read from the system property.
-            return getPhoneTypeFromProperty();
+            return getPhoneTypeFromProperty(subId);
         }
     }
 
@@ -680,20 +796,35 @@
     }
 
     private int getPhoneTypeFromProperty() {
-        int type =
-            SystemProperties.getInt(TelephonyProperties.CURRENT_ACTIVE_PHONE,
-                    getPhoneTypeFromNetworkType());
-        return type;
+        return getPhoneTypeFromProperty(getDefaultSubscription());
+    }
+
+    /** {@hide} */
+    private int getPhoneTypeFromProperty(long subId) {
+        String type =
+            getTelephonyProperty
+                (TelephonyProperties.CURRENT_ACTIVE_PHONE, subId, null);
+        if (type != null) {
+            return (Integer.parseInt(type));
+        } else {
+            return getPhoneTypeFromNetworkType(subId);
+        }
     }
 
     private int getPhoneTypeFromNetworkType() {
+        return getPhoneTypeFromNetworkType(getDefaultSubscription());
+    }
+
+    /** {@hide} */
+    private int getPhoneTypeFromNetworkType(long subId) {
         // When the system property CURRENT_ACTIVE_PHONE, has not been set,
         // use the system property for default network type.
         // This is a fail safe, and can only happen at first boot.
-        int mode = SystemProperties.getInt("ro.telephony.default_network", -1);
-        if (mode == -1)
-            return PHONE_TYPE_NONE;
-        return getPhoneType(mode);
+        String mode = getTelephonyProperty("ro.telephony.default_network", subId, null);
+        if (mode != null) {
+            return TelephonyManager.getPhoneType(Integer.parseInt(mode));
+        }
+        return TelephonyManager.PHONE_TYPE_NONE;
     }
 
     /**
@@ -828,7 +959,23 @@
      * on a CDMA network).
      */
     public String getNetworkOperatorName() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA);
+        return getNetworkOperatorName(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the alphabetic name of current registered operator
+     * for a particular subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     * @param subId
+     */
+    /** {@hide} */
+    public String getNetworkOperatorName(long subId) {
+
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
+                subId, "");
     }
 
     /**
@@ -839,17 +986,48 @@
      * on a CDMA network).
      */
     public String getNetworkOperator() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC);
+        return getNetworkOperator(getDefaultSubscription());
     }
 
     /**
+     * Returns the numeric name (MCC+MNC) of current registered operator
+     * for a particular subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     *
+     * @param subId
+     */
+    /** {@hide} */
+   public String getNetworkOperator(long subId) {
+
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC,
+                subId, "");
+     }
+
+    /**
      * Returns true if the device is considered roaming on the current
      * network, for GSM purposes.
      * <p>
      * Availability: Only when user registered to a network.
      */
     public boolean isNetworkRoaming() {
-        return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
+        return isNetworkRoaming(getDefaultSubscription());
+    }
+
+    /**
+     * Returns true if the device is considered roaming on the current
+     * network for a subscription.
+     * <p>
+     * Availability: Only when user registered to a network.
+     *
+     * @param subId
+     */
+    /** {@hide} */
+    public boolean isNetworkRoaming(long subId) {
+        return "true".equals(getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
+                subId, null));
     }
 
     /**
@@ -861,7 +1039,23 @@
      * on a CDMA network).
      */
     public String getNetworkCountryIso() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
+        return getNetworkCountryIso(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the ISO country code equivalent of the current registered
+     * operator's MCC (Mobile Country Code) of a subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     *
+     * @param subId for which Network CountryIso is returned
+     */
+    /** {@hide} */
+    public String getNetworkCountryIso(long subId) {
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
+                subId, "");
     }
 
     /** Network type is unknown */
@@ -908,6 +1102,49 @@
 
     /**
      * Returns a constant indicating the radio technology (network type)
+     * currently in use on the device for a subscription.
+     * @return the network type
+     *
+     * @param subId for which network type is returned
+     *
+     * @see #NETWORK_TYPE_UNKNOWN
+     * @see #NETWORK_TYPE_GPRS
+     * @see #NETWORK_TYPE_EDGE
+     * @see #NETWORK_TYPE_UMTS
+     * @see #NETWORK_TYPE_HSDPA
+     * @see #NETWORK_TYPE_HSUPA
+     * @see #NETWORK_TYPE_HSPA
+     * @see #NETWORK_TYPE_CDMA
+     * @see #NETWORK_TYPE_EVDO_0
+     * @see #NETWORK_TYPE_EVDO_A
+     * @see #NETWORK_TYPE_EVDO_B
+     * @see #NETWORK_TYPE_1xRTT
+     * @see #NETWORK_TYPE_IDEN
+     * @see #NETWORK_TYPE_LTE
+     * @see #NETWORK_TYPE_EHRPD
+     * @see #NETWORK_TYPE_HSPAP
+     */
+    /** {@hide} */
+   public int getNetworkType(long subId) {
+       try {
+           ITelephony telephony = getITelephony();
+           if (telephony != null) {
+               return telephony.getNetworkTypeUsingSubId(subId);
+           } else {
+               // This can happen when the ITelephony interface is not up yet.
+               return NETWORK_TYPE_UNKNOWN;
+           }
+       } catch(RemoteException ex) {
+           // This shouldn't happen in the normal case
+           return NETWORK_TYPE_UNKNOWN;
+       } catch (NullPointerException ex) {
+           // This could happen before phone restarts due to crashing
+           return NETWORK_TYPE_UNKNOWN;
+       }
+   }
+
+    /**
+     * Returns a constant indicating the radio technology (network type)
      * currently in use on the device for data transmission.
      * @return the network type
      *
@@ -931,10 +1168,22 @@
      * @hide
      */
     public int getDataNetworkType() {
+        return getDataNetworkType(getDefaultSubscription());
+    }
+
+    /**
+     * Returns a constant indicating the radio technology (network type)
+     * currently in use on the device for data transmission for a subscription
+     * @return the network type
+     *
+     * @param subId for which network type is returned
+     */
+    /** {@hide} */
+    public int getDataNetworkType(long subId) {
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getDataNetworkType();
+                return telephony.getDataNetworkTypeUsingSubId(subId);
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -954,10 +1203,19 @@
      * @hide
      */
     public int getVoiceNetworkType() {
+        return getVoiceNetworkType(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the NETWORK_TYPE_xxxx for voice for a subId
+     *
+     */
+    /** {@hide} */
+    public int getVoiceNetworkType(long subId) {
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getVoiceNetworkType();
+                return telephony.getVoiceNetworkTypeUsingSubId(subId);
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -1023,6 +1281,13 @@
         return getNetworkTypeName(getNetworkType());
     }
 
+    /**
+     * Returns a string representation of the radio technology (network type)
+     * currently in use on the device.
+     * @param subId for which network type is returned
+     * @return the name of the radio technology
+     *
+     */
     /** {@hide} */
     public static String getNetworkTypeName(int type) {
         switch (type) {
@@ -1093,8 +1358,20 @@
      * @return true if a ICC card is present
      */
     public boolean hasIccCard() {
+        return hasIccCard(getDefaultSim());
+    }
+
+    /**
+     * @return true if a ICC card is present for a subscription
+     *
+     * @param slotId for which icc card presence is checked
+     */
+    /** {@hide} */
+    // FIXME Input argument slotId should be of type int
+    public boolean hasIccCard(long slotId) {
+
         try {
-            return getITelephony().hasIccCard();
+            return getITelephony().hasIccCardUsingSlotId(slotId);
         } catch (RemoteException ex) {
             // Assume no ICC card if remote exception which shouldn't happen
             return false;
@@ -1117,7 +1394,30 @@
      * @see #SIM_STATE_CARD_IO_ERROR
      */
     public int getSimState() {
-        String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE);
+        return getSimState(getDefaultSim());
+    }
+
+    /**
+     * Returns a constant indicating the state of the
+     * device SIM card in a slot.
+     *
+     * @param slotId
+     *
+     * @see #SIM_STATE_UNKNOWN
+     * @see #SIM_STATE_ABSENT
+     * @see #SIM_STATE_PIN_REQUIRED
+     * @see #SIM_STATE_PUK_REQUIRED
+     * @see #SIM_STATE_NETWORK_LOCKED
+     * @see #SIM_STATE_READY
+     */
+    /** {@hide} */
+    // FIXME the argument to pass is subId ??
+    public int getSimState(int slotId) {
+        long[] subId = SubscriptionManager.getSubId(slotId);
+        // FIXME Do not use a property to determine SIM_STATE, call
+        // appropriate method on some object.
+        String prop =
+            getTelephonyProperty(TelephonyProperties.PROPERTY_SIM_STATE, subId[0], "");
         if ("ABSENT".equals(prop)) {
             return SIM_STATE_ABSENT;
         }
@@ -1150,7 +1450,27 @@
      * @see #getSimState
      */
     public String getSimOperator() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
+        long subId = getDefaultSubscription();
+        Rlog.d(TAG, "getSimOperator(): default subId=" + subId);
+        return getSimOperator(subId);
+    }
+
+    /**
+     * Returns the MCC+MNC (mobile country code + mobile network code) of the
+     * provider of the SIM for a particular subscription. 5 or 6 decimal digits.
+     * <p>
+     * Availability: SIM state must be {@link #SIM_STATE_READY}
+     *
+     * @see #getSimState
+     *
+     * @param subId for which SimOperator is returned
+     */
+    /** {@hide} */
+    public String getSimOperator(long subId) {
+        String operator = getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC,
+                subId, "");
+        Rlog.d(TAG, "getSimOperator: subId=" + subId + " operator=" + operator);
+        return operator;
     }
 
     /**
@@ -1161,14 +1481,40 @@
      * @see #getSimState
      */
     public String getSimOperatorName() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA);
+        return getSimOperatorName(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the Service Provider Name (SPN).
+     * <p>
+     * Availability: SIM state must be {@link #SIM_STATE_READY}
+     *
+     * @see #getSimState
+     *
+     * @param subId for which SimOperatorName is returned
+     */
+    /** {@hide} */
+    public String getSimOperatorName(long subId) {
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA,
+                subId, "");
     }
 
     /**
      * Returns the ISO country code equivalent for the SIM provider's country code.
      */
     public String getSimCountryIso() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY);
+        return getSimCountryIso(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the ISO country code equivalent for the SIM provider's country code.
+     *
+     * @param subId for which SimCountryIso is returned
+     */
+    /** {@hide} */
+    public String getSimCountryIso(long subId) {
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
+                subId, "");
     }
 
     /**
@@ -1179,8 +1525,21 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getSimSerialNumber() {
+         return getSimSerialNumber(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the serial number for the given subscription, if applicable. Return null if it is
+     * unavailable.
+     * <p>
+     * @param subId for which Sim Serial number is returned
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     */
+    /** {@hide} */
+    public String getSimSerialNumber(long subId) {
         try {
-            return getSubscriberInfo().getIccSerialNumber();
+            return getSubscriberInfo().getIccSerialNumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1200,8 +1559,23 @@
      * @hide
      */
     public int getLteOnCdmaMode() {
+        return getLteOnCdmaMode(getDefaultSubscription());
+    }
+
+    /**
+     * Return if the current radio is LTE on CDMA for Subscription. This
+     * is a tri-state return value as for a period of time
+     * the mode may be unknown.
+     *
+     * @param subId for which radio is LTE on CDMA is returned
+     * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
+     * or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
+     *
+     */
+    /** {@hide} */
+    public int getLteOnCdmaMode(long subId) {
         try {
-            return getITelephony().getLteOnCdmaMode();
+            return getITelephony().getLteOnCdmaModeUsingSubId(subId);
         } catch (RemoteException ex) {
             // Assume no ICC card if remote exception which shouldn't happen
             return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
@@ -1225,8 +1599,23 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getSubscriberId() {
+        return getSubscriberId(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the unique subscriber ID, for example, the IMSI for a GSM phone
+     * for a subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId whose subscriber id is returned
+     */
+    /** {@hide} */
+    public String getSubscriberId(long subId) {
         try {
-            return getSubscriberInfo().getSubscriberId();
+            return getSubscriberInfo().getSubscriberIdUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1254,6 +1643,27 @@
     }
 
     /**
+     * Returns the Group Identifier Level1 for a GSM phone for a particular subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subscription whose subscriber id is returned
+     */
+    /** {@hide} */
+    public String getGroupIdLevel1(long subId) {
+        try {
+            return getSubscriberInfo().getGroupIdLevel1UsingSubId(subId);
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
      * Returns the phone number string for line 1, for example, the MSISDN
      * for a GSM phone. Return null if it is unavailable.
      * <p>
@@ -1261,8 +1671,22 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getLine1Number() {
+        return getLine1Number(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the phone number string for line 1, for example, the MSISDN
+     * for a GSM phone for a particular subscription. Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId whose phone number for line 1 is returned
+     */
+    /** {@hide} */
+    public String getLine1Number(long subId) {
         try {
-            return getSubscriberInfo().getLine1Number();
+            return getSubscriberInfo().getLine1NumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1281,8 +1705,23 @@
      * nobody seems to call this.
      */
     public String getLine1AlphaTag() {
+        return getLine1AlphaTag(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the alphabetic identifier associated with the line 1 number
+     * for a subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose alphabetic identifier associated with line 1 is returned
+     * nobody seems to call this.
+     */
+    /** {@hide} */
+    public String getLine1AlphaTag(long subId) {
         try {
-            return getSubscriberInfo().getLine1AlphaTag();
+            return getSubscriberInfo().getLine1AlphaTagUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1301,8 +1740,22 @@
      * @hide
      */
     public String getMsisdn() {
+        return getMsisdn(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the MSISDN string.
+     * for a GSM phone. Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId for which msisdn is returned
+     */
+    /** {@hide} */
+    public String getMsisdn(long subId) {
         try {
-            return getSubscriberInfo().getMsisdn();
+            return getSubscriberInfo().getMsisdnUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1318,8 +1771,21 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getVoiceMailNumber() {
+        return getVoiceMailNumber(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the voice mail number for a subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose voice mail number is returned
+     */
+    /** {@hide} */
+    public String getVoiceMailNumber(long subId) {
         try {
-            return getSubscriberInfo().getVoiceMailNumber();
+            return getSubscriberInfo().getVoiceMailNumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1337,8 +1803,21 @@
      * @hide
      */
     public String getCompleteVoiceMailNumber() {
+        return getCompleteVoiceMailNumber(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the complete voice mail number. Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
+     *
+     * @param subId
+     */
+    /** {@hide} */
+    public String getCompleteVoiceMailNumber(long subId) {
         try {
-            return getSubscriberInfo().getCompleteVoiceMailNumber();
+            return getSubscriberInfo().getCompleteVoiceMailNumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1355,8 +1834,20 @@
      * @hide
      */
     public int getVoiceMessageCount() {
+        return getVoiceMessageCount(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the voice mail count for a subscription. Return 0 if unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose voice message count is returned
+     */
+    /** {@hide} */
+    public int getVoiceMessageCount(long subId) {
         try {
-            return getITelephony().getVoiceMessageCount();
+            return getITelephony().getVoiceMessageCountUsingSubId(subId);
         } catch (RemoteException ex) {
             return 0;
         } catch (NullPointerException ex) {
@@ -1373,8 +1864,22 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getVoiceMailAlphaTag() {
+        return getVoiceMailAlphaTag(getDefaultSubscription());
+    }
+
+    /**
+     * Retrieves the alphabetic identifier associated with the voice
+     * mail number for a subscription.
+     * <p>
+     * Requires Permission:
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose alphabetic identifier associated with the
+     * voice mail number is returned
+     */
+    /** {@hide} */
+    public String getVoiceMailAlphaTag(long subId) {
         try {
-            return getSubscriberInfo().getVoiceMailAlphaTag();
+            return getSubscriberInfo().getVoiceMailAlphaTagUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1437,7 +1942,6 @@
         return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
     }
 
-
     /** Device call state: No activity. */
     public static final int CALL_STATE_IDLE = 0;
     /** Device call state: Ringing. A new call arrived and is
@@ -1453,8 +1957,19 @@
      * Returns a constant indicating the call state (cellular) on the device.
      */
     public int getCallState() {
+        return getCallState(getDefaultSubscription());
+    }
+
+    /**
+     * Returns a constant indicating the call state (cellular) on the device
+     * for a subscription.
+     *
+     * @param subId whose call state is returned
+     */
+    /** {@hide} */
+    public int getCallState(long subId) {
         try {
-            return getITelephony().getCallState();
+            return getITelephony().getCallStateUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return CALL_STATE_IDLE;
@@ -1575,8 +2090,8 @@
     public void listen(PhoneStateListener listener, int events) {
         String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
         try {
-            Boolean notifyNow = true;
-            sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
+            Boolean notifyNow = (getITelephony() != null);
+            sRegistry.listenUsingSubId(listener.mSubId, pkgForDebug, listener.callback, events, notifyNow);
         } catch (RemoteException ex) {
             // system process dead
         } catch (NullPointerException ex) {
@@ -1590,8 +2105,16 @@
      * @hide
      */
     public int getCdmaEriIconIndex() {
+        return getCdmaEriIconIndex(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the CDMA ERI icon index to display for a subscription
+     */
+    /** {@hide} */
+    public int getCdmaEriIconIndex(long subId) {
         try {
-            return getITelephony().getCdmaEriIconIndex();
+            return getITelephony().getCdmaEriIconIndexUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
@@ -1608,8 +2131,18 @@
      * @hide
      */
     public int getCdmaEriIconMode() {
+        return getCdmaEriIconMode(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the CDMA ERI icon mode for a subscription.
+     * 0 - ON
+     * 1 - FLASHING
+     */
+    /** {@hide} */
+    public int getCdmaEriIconMode(long subId) {
         try {
-            return getITelephony().getCdmaEriIconMode();
+            return getITelephony().getCdmaEriIconModeUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
@@ -1624,8 +2157,17 @@
      * @hide
      */
     public String getCdmaEriText() {
+        return getCdmaEriText(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the CDMA ERI text, of a subscription
+     *
+     */
+    /** {@hide} */
+    public String getCdmaEriText(long subId) {
         try {
-            return getITelephony().getCdmaEriText();
+            return getITelephony().getCdmaEriTextUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return null;
@@ -1924,6 +2466,286 @@
     }
 
     /**
+     * Returns Default subscription.
+     */
+    private static long getDefaultSubscription() {
+        return SubscriptionManager.getDefaultSubId();
+    }
+
+    /** {@hide} */
+    public int getDefaultSim() {
+        //TODO Need to get it from Telephony Devcontroller
+        return 0;
+    }
+
+    /**
+     * Sets the telephony property with the value specified.
+     *
+     * @hide
+     */
+    public static void setTelephonyProperty(String property, long subId, String value) {
+        String propVal = "";
+        String p[] = null;
+        String prop = SystemProperties.get(property);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
+
+        if (value == null) {
+            value = "";
+        }
+
+        if (prop != null) {
+            p = prop.split(",");
+        }
+
+        if (phoneId < 0) return;
+
+        for (int i = 0; i < phoneId; i++) {
+            String str = "";
+            if ((p != null) && (i < p.length)) {
+                str = p[i];
+            }
+            propVal = propVal + str + ",";
+        }
+
+        propVal = propVal + value;
+        if (p != null) {
+            for (int i = phoneId + 1; i < p.length; i++) {
+                propVal = propVal + "," + p[i];
+            }
+        }
+
+        // TODO: workaround for QC
+        if (property.length() > SystemProperties.PROP_NAME_MAX || propVal.length() > SystemProperties.PROP_VALUE_MAX) {
+            Rlog.d(TAG, "setTelephonyProperty length too long:" + property + ", " + propVal);
+            return;
+        }
+
+        Rlog.d(TAG, "setTelephonyProperty property=" + property + " propVal=" + propVal);
+        SystemProperties.set(property, propVal);
+    }
+
+    /**
+     * Convenience function for retrieving a value from the secure settings
+     * value list as an integer.  Note that internally setting values are
+     * always stored as strings; this function converts the string to an
+     * integer for you.
+     * <p>
+     * This version does not take a default value.  If the setting has not
+     * been set, or the string value is not a number,
+     * it throws {@link SettingNotFoundException}.
+     *
+     * @param cr The ContentResolver to access.
+     * @param name The name of the setting to retrieve.
+     * @param index The index of the list
+     *
+     * @throws SettingNotFoundException Thrown if a setting by the given
+     * name can't be found or the setting value is not an integer.
+     *
+     * @return The value at the given index of settings.
+     * @hide
+     */
+    public static int getIntAtIndex(android.content.ContentResolver cr,
+            String name, int index)
+            throws android.provider.Settings.SettingNotFoundException {
+        String v = android.provider.Settings.Global.getString(cr, name);
+        if (v != null) {
+            String valArray[] = v.split(",");
+            if ((index >= 0) && (index < valArray.length) && (valArray[index] != null)) {
+                try {
+                    return Integer.parseInt(valArray[index]);
+                } catch (NumberFormatException e) {
+                    //Log.e(TAG, "Exception while parsing Integer: ", e);
+                }
+            }
+        }
+        throw new android.provider.Settings.SettingNotFoundException(name);
+    }
+
+    /**
+     * Convenience function for updating settings value as coma separated
+     * integer values. This will either create a new entry in the table if the
+     * given name does not exist, or modify the value of the existing row
+     * with that name.  Note that internally setting values are always
+     * stored as strings, so this function converts the given value to a
+     * string before storing it.
+     *
+     * @param cr The ContentResolver to access.
+     * @param name The name of the setting to modify.
+     * @param index The index of the list
+     * @param value The new value for the setting to be added to the list.
+     * @return true if the value was set, false on database errors
+     * @hide
+     */
+    public static boolean putIntAtIndex(android.content.ContentResolver cr,
+            String name, int index, int value) {
+        String data = "";
+        String valArray[] = null;
+        String v = android.provider.Settings.Global.getString(cr, name);
+
+        if (v != null) {
+            valArray = v.split(",");
+        }
+
+        // Copy the elements from valArray till index
+        for (int i = 0; i < index; i++) {
+            String str = "";
+            if ((valArray != null) && (i < valArray.length)) {
+                str = valArray[i];
+            }
+            data = data + str + ",";
+        }
+
+        data = data + value;
+
+        // Copy the remaining elements from valArray if any.
+        if (valArray != null) {
+            for (int i = index+1; i < valArray.length; i++) {
+                data = data + "," + valArray[i];
+            }
+        }
+        return android.provider.Settings.Global.putString(cr, name, data);
+    }
+
+    /**
+     * Gets the telephony property.
+     *
+     * @hide
+     */
+    public static String getTelephonyProperty(String property, long subId, String defaultVal) {
+        String propVal = null;
+        int phoneId = SubscriptionManager.getPhoneId(subId);
+        String prop = SystemProperties.get(property);
+        if ((prop != null) && (prop.length() > 0)) {
+            String values[] = prop.split(",");
+            if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) {
+                propVal = values[phoneId];
+            }
+        }
+        return propVal == null ? defaultVal : propVal;
+    }
+
+    /** @hide */
+    public int getSimCount() {
+        if(isMultiSimEnabled()) {
+        //TODO Need to get it from Telephony Devcontroller
+            return 2;
+        } else {
+           return 1;
+        }
+    }
+
+    /**
+     * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+     * @return IMS Service Table or null if not present or not loaded
+     * @hide
+     */
+    public String getIsimIst() {
+        try {
+            return getSubscriberInfo().getIsimIst();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+     * @return an array of PCSCF strings with one PCSCF per string, or null if
+     *         not present or not loaded
+     * @hide
+     */
+    public String[] getIsimPcscf() {
+        try {
+            return getSubscriberInfo().getIsimPcscf();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the response of ISIM Authetification through RIL.
+     * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo.
+     * @return the response of ISIM Authetification, or null if not available
+     * @hide
+     * @deprecated
+     * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM
+     */
+    public String getIsimChallengeResponse(String nonce){
+        try {
+            return getSubscriberInfo().getIsimChallengeResponse(nonce);
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the response of SIM Authentication through RIL.
+     * Returns null if the Authentication hasn't been successful
+     * @param subId subscription ID to be queried
+     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+     * @param data authentication challenge data
+     * @return the response of SIM Authentication, or null if not available
+     * @hide
+     */
+    public String getIccSimChallengeResponse(long subId, int appType, String data) {
+        try {
+            return getSubscriberInfo().getIccSimChallengeResponse(subId, appType, data);
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone starts
+            return null;
+        }
+    }
+
+    /**
+     * Returns the response of SIM Authentication through RIL for the default subscription.
+     * Returns null if the Authentication hasn't been successful
+     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+     * @param data authentication challenge data
+     * @return the response of SIM Authentication, or null if not available
+     * @hide
+     */
+    public String getIccSimChallengeResponse(int appType, String data) {
+        return getIccSimChallengeResponse(getDefaultSubscription(), appType, data);
+    }
+
+    /**
+     * Get P-CSCF address from PCO after data connection is established or modified.
+     *
+     * @return array of P-CSCF address
+     * @hide
+     */
+    public String[] getPcscfAddress() {
+        try {
+            return getITelephony().getPcscfAddress();
+        } catch (RemoteException e) {
+            return new String[0];
+        }
+    }
+
+    /**
+     * Set IMS registration state
+     *
+     * @param Registration state
+     * @hide
+     */
+    public void setImsRegistrationState(boolean registered) {
+        try {
+            getITelephony().setImsRegistrationState(registered);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Get the preferred network type.
      * Used for device configuration by some CDMA operators.
      *
diff --git a/telephony/java/android/telephony/VoLteServiceState.aidl b/telephony/java/android/telephony/VoLteServiceState.aidl
new file mode 100644
index 0000000..59dd04f
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable VoLteServiceState;
+
diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java
new file mode 100644
index 0000000..afef601b
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Contains LTE network state related information.
+ *
+ * @hide
+ */
+public final class VoLteServiceState implements Parcelable {
+
+    private static final String LOG_TAG = "VoLteServiceState";
+    private static final boolean DBG = false;
+
+    //Use int max, as -1 is a valid value in signal strength
+    public static final int INVALID = 0x7FFFFFFF;
+
+    public static final int NOT_SUPPORTED = 0;
+    public static final int SUPPORTED = 1;
+
+    // Single Radio Voice Call Continuity(SRVCC) progress state
+    public static final int HANDOVER_STARTED   = 0;
+    public static final int HANDOVER_COMPLETED = 1;
+    public static final int HANDOVER_FAILED    = 2;
+    public static final int HANDOVER_CANCELED  = 3;
+
+    private int mSrvccState;
+
+    /**
+     * Create a new VoLteServiceState from a intent notifier Bundle
+     *
+     * This method is used by PhoneStateIntentReceiver and maybe by
+     * external applications.
+     *
+     * @param m Bundle from intent notifier
+     * @return newly created VoLteServiceState
+     *
+     * @hide
+     */
+    public static VoLteServiceState newFromBundle(Bundle m) {
+        VoLteServiceState ret;
+        ret = new VoLteServiceState();
+        ret.setFromNotifierBundle(m);
+        return ret;
+    }
+
+    /**
+     * Empty constructor
+     *
+     * @hide
+     */
+    public VoLteServiceState() {
+        initialize();
+    }
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public VoLteServiceState(int srvccState) {
+        initialize();
+
+        mSrvccState = srvccState;
+    }
+
+    /**
+     * Copy constructors
+     *
+     * @param s Source VoLteServiceState
+     *
+     * @hide
+     */
+    public VoLteServiceState(VoLteServiceState s) {
+        copyFrom(s);
+    }
+
+    /**
+     * Initialize values to defaults.
+     *
+     * @hide
+     */
+    private void initialize() {
+        mSrvccState = INVALID;
+    }
+
+    /**
+     * @hide
+     */
+    protected void copyFrom(VoLteServiceState s) {
+        mSrvccState = s.mSrvccState;
+    }
+
+    /**
+     * Construct a VoLteServiceState object from the given parcel.
+     *
+     * @hide
+     */
+    public VoLteServiceState(Parcel in) {
+        if (DBG) log("Size of VoLteServiceState parcel:" + in.dataSize());
+
+        mSrvccState = in.readInt();
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSrvccState);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable.Creator}
+     *
+     * @hide
+     */
+    public static final Parcelable.Creator<VoLteServiceState> CREATOR = new Parcelable.Creator() {
+        public VoLteServiceState createFromParcel(Parcel in) {
+            return new VoLteServiceState(in);
+        }
+
+        public VoLteServiceState[] newArray(int size) {
+            return new VoLteServiceState[size];
+        }
+    };
+
+    /**
+     * Validate the individual fields as per the range
+     * specified in ril.h
+     * Set to invalid any field that is not in the valid range
+     *
+     * @return
+     *      Valid values for all fields
+     * @hide
+     */
+    public void validateInput() {
+    }
+
+    public int hashCode() {
+        int primeNum = 31;
+        return ((mSrvccState * primeNum));
+    }
+
+    /**
+     * @return true if the LTE network states are the same
+     */
+    @Override
+    public boolean equals (Object o) {
+        VoLteServiceState s;
+
+        try {
+            s = (VoLteServiceState) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return (mSrvccState == s.mSrvccState);
+    }
+
+    /**
+     * @return string representation.
+     */
+    @Override
+    public String toString() {
+        return ("VoLteServiceState:"
+                + " " + mSrvccState);
+    }
+
+    /**
+     * Set VoLteServiceState based on intent notifier map
+     *
+     * @param m intent notifier map
+     * @hide
+     */
+    private void setFromNotifierBundle(Bundle m) {
+        mSrvccState = m.getInt("mSrvccState");
+    }
+
+    /**
+     * Set intent notifier Bundle based on VoLteServiceState
+     *
+     * @param m intent notifier Bundle
+     * @hide
+     */
+    public void fillInNotifierBundle(Bundle m) {
+        m.putInt("mSrvccState", mSrvccState);
+    }
+
+    public int getSrvccState() {
+        return mSrvccState;
+    }
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index f8dd7cf..745c9d0 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -37,6 +37,9 @@
 import com.android.i18n.phonenumbers.NumberParseException;
 import com.android.i18n.phonenumbers.PhoneNumberUtil;
 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
+import android.telephony.SubscriptionManager;
+
+import android.telephony.TelephonyManager;
 
 import java.util.Locale;
 
@@ -233,6 +236,7 @@
                 info.contactExists = true;
             }
             cursor.close();
+            cursor = null;
         }
 
         info.needUpdate = false;
@@ -269,6 +273,23 @@
     public static CallerInfo getCallerInfo(Context context, String number) {
         if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number...");
 
+        long subId = SubscriptionManager.getDefaultSubId();
+        return getCallerInfo(context, number, subId);
+    }
+
+    /**
+     * getCallerInfo given a phone number and subscription, look up in the call-log database
+     * for the matching caller id info.
+     * @param context the context used to get the ContentResolver
+     * @param number the phone number used to lookup caller id
+     * @param subId the subscription for checking for if voice mail number or not
+     * @return the CallerInfo which contains the caller id for the given
+     * number. The returned CallerInfo is null if no number is supplied. If
+     * a matching number is not found, then a generic caller info is returned,
+     * with all relevant fields empty or null.
+     */
+    public static CallerInfo getCallerInfo(Context context, String number, long subId) {
+
         if (TextUtils.isEmpty(number)) {
             return null;
         }
@@ -278,7 +299,7 @@
         // shortcut and skip the query.
         if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
             return new CallerInfo().markAsEmergency(context);
-        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+        } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
             return new CallerInfo().markAsVoiceMail();
         }
 
@@ -400,10 +421,17 @@
     // TODO: As in the emergency number handling, we end up writing a
     // string in the phone number field.
     /* package */ CallerInfo markAsVoiceMail() {
+
+        long subId = SubscriptionManager.getDefaultSubId();
+        return markAsVoiceMail(subId);
+
+    }
+
+    /* package */ CallerInfo markAsVoiceMail(long subId) {
         mIsVoiceMail = true;
 
         try {
-            String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+            String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag(subId);
 
             phoneNumber = voiceMailLabel;
         } catch (SecurityException se) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 34fed5e..fe403d9 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,12 +24,15 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.PhoneLookup;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
 /**
  * Helper class to make it easier to run asynchronous caller-id lookup queries.
@@ -75,6 +78,8 @@
         public Object cookie;
         public int event;
         public String number;
+
+        public long subId;
     }
 
 
@@ -207,11 +212,17 @@
                 // However, if there is any code that calls this method, we should
                 // check the parameters to make sure they're viable.
                 if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
+                if (cursor != null) {
+                    cursor.close();
+                }
                 return;
             }
 
             if (cw.event == EVENT_END_OF_QUEUE) {
                 release();
+                if (cursor != null) {
+                    cursor.close();
+                }
                 return;
             }
 
@@ -232,7 +243,7 @@
                     // comments at the top of CallerInfo class).
                     mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
                 } else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
-                    mCallerInfo = new CallerInfo().markAsVoiceMail();
+                    mCallerInfo = new CallerInfo().markAsVoiceMail(cw.subId);
                 } else {
                     mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
                     if (DBG) Rlog.d(LOG_TAG, "==> Got mCallerInfo: " + mCallerInfo);
@@ -289,6 +300,10 @@
                              " for token: " + token + mCallerInfo);
                 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
             }
+
+            if (cursor != null) {
+               cursor.close();
+            }
         }
     }
 
@@ -334,6 +349,25 @@
      */
     public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
             OnQueryCompleteListener listener, Object cookie) {
+
+        long subId = SubscriptionManager.getDefaultSubId();
+        return startQuery(token, context, number, listener, cookie, subId);
+    }
+
+    /**
+     * Factory method to start the query based on a number with specific subscription.
+     *
+     * Note: if the number contains an "@" character we treat it
+     * as a SIP address, and look it up directly in the Data table
+     * rather than using the PhoneLookup table.
+     * TODO: But eventually we should expose two separate methods, one for
+     * numbers and one for SIP addresses, and then have
+     * PhoneUtils.startGetCallerInfo() decide which one to call based on
+     * the phone type of the incoming connection.
+     */
+    public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
+            OnQueryCompleteListener listener, Object cookie, long subId) {
+
         if (DBG) {
             Rlog.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####");
             Rlog.d(LOG_TAG, "- number: " + /*number*/ "xxxxxxx");
@@ -397,11 +431,12 @@
         cw.listener = listener;
         cw.cookie = cookie;
         cw.number = number;
+        cw.subId = subId;
 
         // check to see if these are recognized numbers, and use shortcuts if we can.
         if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
             cw.event = EVENT_EMERGENCY_NUMBER;
-        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+        } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
             cw.event = EVENT_VOICEMAIL_NUMBER;
         } else {
             cw.event = EVENT_NEW_QUERY;
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3f36645..a95336e 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -23,6 +23,7 @@
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
+import android.telephony.VoLteServiceState;
 
 oneway interface IPhoneStateListener {
     void onServiceStateChanged(in ServiceState serviceState);
@@ -41,5 +42,6 @@
     void onPreciseCallStateChanged(in PreciseCallState callState);
     void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
     void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
+    void onVoLteServiceStateChanged(in VoLteServiceState lteState);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 03940dc..4734965 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -28,6 +28,13 @@
     String getDeviceId();
 
     /**
+     * Retrieves the unique device ID of a subId for the device, e.g., IMEI
+     * for GSM phones.
+     */
+    String getDeviceIdUsingSubId(long subId);
+
+
+    /**
      * Retrieves the software version number for the device, e.g., IMEI/SV
      * for GSM phones.
      */
@@ -39,46 +46,94 @@
     String getSubscriberId();
 
     /**
+     * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones.
+     */
+    String getSubscriberIdUsingSubId(long subId);
+
+    /**
      * Retrieves the Group Identifier Level1 for GSM phones.
      */
     String getGroupIdLevel1();
 
     /**
+     * Retrieves the Group Identifier Level1 for GSM phones of a subId.
+     */
+    String getGroupIdLevel1UsingSubId(long subId);
+
+    /**
      * Retrieves the serial number of the ICC, if applicable.
      */
     String getIccSerialNumber();
 
     /**
+     * Retrieves the serial number of a given subId.
+     */
+    String getIccSerialNumberUsingSubId(long subId);
+
+    /**
      * Retrieves the phone number string for line 1.
      */
     String getLine1Number();
 
     /**
+     * Retrieves the phone number string for line 1 of a subcription.
+     */
+    String getLine1NumberUsingSubId(long subId);
+
+
+    /**
      * Retrieves the alpha identifier for line 1.
      */
     String getLine1AlphaTag();
 
     /**
+     * Retrieves the alpha identifier for line 1 of a subId.
+     */
+    String getLine1AlphaTagUsingSubId(long subId);
+
+
+    /**
      * Retrieves MSISDN Number.
      */
     String getMsisdn();
 
     /**
+     * Retrieves the Msisdn of a subId.
+     */
+    String getMsisdnUsingSubId(long subId);
+
+    /**
      * Retrieves the voice mail number.
      */
     String getVoiceMailNumber();
 
     /**
+     * Retrieves the voice mail number of a given subId.
+     */
+    String getVoiceMailNumberUsingSubId(long subId);
+
+    /**
      * Retrieves the complete voice mail number.
      */
     String getCompleteVoiceMailNumber();
 
     /**
+     * Retrieves the complete voice mail number for particular subId
+     */
+    String getCompleteVoiceMailNumberUsingSubId(long subId);
+
+    /**
      * Retrieves the alpha identifier associated with the voice mail number.
      */
     String getVoiceMailAlphaTag();
 
     /**
+     * Retrieves the alpha identifier associated with the voice mail number
+     * of a subId.
+     */
+    String getVoiceMailAlphaTagUsingSubId(long subId);
+
+    /**
      * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
      * @return the IMPI, or null if not present or not loaded
      */
@@ -96,4 +151,38 @@
      *      not present or not loaded
      */
     String[] getIsimImpu();
+
+    /**
+     * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+     * @return IMS Service Table or null if not present or not loaded
+     */
+    String getIsimIst();
+
+    /**
+     * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+     * @return an array of PCSCF strings with one PCSCF per string, or null if
+     *      not present or not loaded
+     */
+    String[] getIsimPcscf();
+
+    /**
+     * TODO: Deprecate and remove this interface. Superceded by getIccsimChallengeResponse.
+     * Returns the response of ISIM Authetification through RIL.
+     * @return the response of ISIM Authetification, or null if
+     *     the Authentification hasn't been successed or isn't present iphonesubinfo.
+     */
+    String getIsimChallengeResponse(String nonce);
+
+    /**
+     * Returns the response of the SIM application on the UICC to authentication
+     * challenge/response algorithm. The data string and challenge response are
+     * Base64 encoded Strings.
+     * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
+     *
+     * @param subId subscription ID to be queried
+     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+     * @param data authentication challenge data
+     * @return challenge response
+     */
+    String getIccSimChallengeResponse(long subId, int appType, String data);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 6fc64ae..9e975e9 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -42,6 +42,13 @@
      List<SmsRawData> getAllMessagesFromIccEf(String callingPkg);
 
     /**
+     * Retrieves all messages currently stored on ICC.
+     * @param subId the subId id.
+     * @return list of SmsRawData of all sms on ICC
+     */
+    List<SmsRawData> getAllMessagesFromIccEfUsingSubId(in long subId, String callingPkg);
+
+    /**
      * Update the specified message on the ICC.
      *
      * @param messageIndex record index of message to update
@@ -56,6 +63,21 @@
             in byte[] pdu);
 
     /**
+     * Update the specified message on the ICC.
+     *
+     * @param messageIndex record index of message to update
+     * @param newStatus new message status (STATUS_ON_ICC_READ,
+     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
+     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
+     * @param pdu the raw PDU to store
+     * @param subId the subId id.
+     * @return success or not
+     *
+     */
+     boolean updateMessageOnIccEfUsingSubId(in long subId, String callingPkg,
+             int messageIndex, int newStatus, in byte[] pdu);
+
+    /**
      * Copy a raw SMS PDU to the ICC.
      *
      * @param pdu the raw PDU to store
@@ -67,6 +89,19 @@
     boolean copyMessageToIccEf(String callingPkg, int status, in byte[] pdu, in byte[] smsc);
 
     /**
+     * Copy a raw SMS PDU to the ICC.
+     *
+     * @param pdu the raw PDU to store
+     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
+     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
+     * @param subId the subId id.
+     * @return success or not
+     *
+     */
+    boolean copyMessageToIccEfUsingSubId(in long subId, String callingPkg, int status,
+            in byte[] pdu, in byte[] smsc);
+
+    /**
      * Send a data SMS.
      *
      * @param smsc the SMSC to send the message through, or NULL for the
@@ -93,6 +128,34 @@
             in byte[] data, in PendingIntent sentIntent, in PendingIntent deliveryIntent);
 
     /**
+     * Send a data SMS.
+     *
+     * @param smsc the SMSC to send the message through, or NULL for the
+     *  default SMSC
+     * @param data the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is sucessfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK<code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applicaitons,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param subId the subId id.
+     */
+    void sendDataUsingSubId(long subId, String callingPkg, in String destAddr,
+            in String scAddr, in int destPort, in byte[] data, in PendingIntent sentIntent,
+            in PendingIntent deliveryIntent);
+
+    /**
      * Send an SMS.
      *
      * @param smsc the SMSC to send the message through, or NULL for the
@@ -119,6 +182,34 @@
             in PendingIntent sentIntent, in PendingIntent deliveryIntent);
 
     /**
+     * Send an SMS.
+     *
+     * @param smsc the SMSC to send the message through, or NULL for the
+     *  default SMSC
+     * @param text the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is sucessfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK<code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applications,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param subId the subId on which the SMS has to be sent.
+     */
+    void sendTextUsingSubId(in long subId, String callingPkg, in String destAddr,
+            in String scAddr, in String text, in PendingIntent sentIntent,
+            in PendingIntent deliveryIntent);
+
+    /**
      * Inject an SMS PDU into the android platform.
      *
      * @param pdu is the byte array of pdu to be injected into android application framework
@@ -158,6 +249,34 @@
             in List<PendingIntent> deliveryIntents);
 
     /**
+     * Send a multi-part text based SMS.
+     *
+     * @param destinationAddress the address to send the message to
+     * @param scAddress is the service center address or null to use
+     *   the current default SMSC
+     * @param parts an <code>ArrayList</code> of strings that, in order,
+     *   comprise the original message
+     * @param sentIntents if not null, an <code>ArrayList</code> of
+     *   <code>PendingIntent</code>s (one for each message part) that is
+     *   broadcast when the corresponding message part has been sent.
+     *   The result code will be <code>Activity.RESULT_OK<code> for success,
+     *   or one of these errors:
+     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
+     *   <code>RESULT_ERROR_RADIO_OFF</code>
+     *   <code>RESULT_ERROR_NULL_PDU</code>.
+     * @param deliveryIntents if not null, an <code>ArrayList</code> of
+     *   <code>PendingIntent</code>s (one for each message part) that is
+     *   broadcast when the corresponding message part has been delivered
+     *   to the recipient.  The raw pdu of the status report is in the
+     *   extended data ("pdu").
+     * @param subId the subId on which the SMS has to be sent.
+     */
+    void sendMultipartTextUsingSubId(in long subId, String callingPkg,
+            in String destinationAddress, in String scAddress,
+            in List<String> parts, in List<PendingIntent> sentIntents,
+            in List<PendingIntent> deliveryIntents);
+
+    /**
      * Enable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier. Note that if two different clients enable the same
      * message identifier, they must both disable it for the device to stop
@@ -172,6 +291,21 @@
     boolean enableCellBroadcast(int messageIdentifier);
 
     /**
+     * Enable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier. Note that if two different clients enable the same
+     * message identifier, they must both disable it for the device to stop
+     * receiving those messages.
+     *
+     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be enabled
+     * @return true if successful, false otherwise
+     *
+     * @see #disableCellBroadcast(int)
+     */
+    boolean enableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
+    /**
      * Disable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier. Note that if two different clients enable the same
      * message identifier, they must both disable it for the device to stop
@@ -185,6 +319,21 @@
      */
     boolean disableCellBroadcast(int messageIdentifier);
 
+    /**
+     * Disable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier. Note that if two different clients enable the same
+     * message identifier, they must both disable it for the device to stop
+     * receiving those messages.
+     *
+     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be disabled
+     * @return true if successful, false otherwise
+     *
+     * @see #enableCellBroadcast(int)
+     */
+    boolean disableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
     /*
      * Enable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier range. Note that if two different clients enable
@@ -201,6 +350,23 @@
      */
     boolean enableCellBroadcastRange(int startMessageId, int endMessageId);
 
+    /*
+     * Enable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier range. Note that if two different clients enable
+     * a message identifier range, they must both disable it for the device
+     * to stop receiving those messages.
+     *
+     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be enabled
+     * @return true if successful, false otherwise
+     *
+     * @see #disableCellBroadcastRange(int, int)
+     */
+    boolean enableCellBroadcastRangeUsingSubId(long subId, int startMessageId, int endMessageId);
+
     /**
      * Disable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier range. Note that if two different clients enable
@@ -218,18 +384,52 @@
     boolean disableCellBroadcastRange(int startMessageId, int endMessageId);
 
     /**
+     * Disable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier range. Note that if two different clients enable
+     * a message identifier range, they must both disable it for the device
+     * to stop receiving those messages.
+     *
+     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be disabled
+     * @return true if successful, false otherwise
+     *
+     * @see #enableCellBroadcastRange(int, int, int)
+     */
+    boolean disableCellBroadcastRangeUsingSubId(long subId, int startMessageId,
+            int endMessageId);
+
+    /**
      * Returns the premium SMS send permission for the specified package.
      * Requires system permission.
      */
     int getPremiumSmsPermission(String packageName);
 
     /**
+     * Returns the premium SMS send permission for the specified package.
+     * Requires system permission.
+     */
+    int getPremiumSmsPermissionUsingSubId(long subId, String packageName);
+
+    /**
      * Set the SMS send permission for the specified package.
      * Requires system permission.
      */
     void setPremiumSmsPermission(String packageName, int permission);
 
     /**
+     * Set the SMS send permission for the specified package.
+     * Requires system permission.
+     */
+     /**
+     * Set the SMS send permission for the specified package.
+     * Requires system permission.
+     */
+    void setPremiumSmsPermissionUsingSubId(long subId, String packageName, int permission);
+
+    /**
      * SMS over IMS is supported if IMS is registered and SMS is supported
      * on IMS.
      *
@@ -240,6 +440,23 @@
     boolean isImsSmsSupported();
 
     /**
+     * SMS over IMS is supported if IMS is registered and SMS is supported
+     * on IMS.
+     * @param subId for subId which isImsSmsSupported is queried
+     * @return true if SMS over IMS is supported, false otherwise
+     *
+     * @see #getImsSmsFormat()
+     */
+    boolean isImsSmsSupportedUsingSubId(long subId);
+
+    /*
+     * get user prefered SMS subId
+     * @return subId id
+     */
+    long getPreferredSmsSubscription();
+
+
+    /**
      * Gets SMS format supported on IMS.  SMS over IMS format is
      * either 3GPP or 3GPP2.
      *
@@ -250,4 +467,25 @@
      * @see #isImsSmsSupported()
      */
     String getImsSmsFormat();
+
+    /**
+     * Gets SMS format supported on IMS.  SMS over IMS format is
+     * either 3GPP or 3GPP2.
+     * @param subId for subId which getImsSmsFormat is queried
+     * @return android.telephony.SmsMessage.FORMAT_3GPP,
+     *         android.telephony.SmsMessage.FORMAT_3GPP2
+     *      or android.telephony.SmsMessage.FORMAT_UNKNOWN
+     *
+     * @see #isImsSmsSupported()
+     */
+    String getImsSmsFormatUsingSubId(long subId);
+
+
+
+
+    /*
+     * Get SMS prompt property,  enabled or not
+     * @return true if enabled, false otherwise
+     */
+    boolean isSMSPromptEnabled();
 }
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
new file mode 100755
index 0000000..6021ccf
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -0,0 +1,153 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.internal.telephony;
+
+import android.app.PendingIntent;
+import android.telephony.SubInfoRecord;
+
+interface ISub {
+    /**
+     * Get the SubInfoRecord according to an index
+     * @param context Context provided by caller
+     * @param subId The unique SubInfoRecord index in database
+     * @return SubInfoRecord, maybe null
+     */
+    SubInfoRecord getSubInfoUsingSubId(long subId);
+
+    /**
+     * Get the SubInfoRecord according to an IccId
+     * @param context Context provided by caller
+     * @param iccId the IccId of SIM card
+     * @return SubInfoRecord, maybe null
+     */
+    List<SubInfoRecord> getSubInfoUsingIccId(String iccId);
+
+    /**
+     * Get the SubInfoRecord according to slotId
+     * @param context Context provided by caller
+     * @param slotId the slot which the SIM is inserted
+     * @return SubInfoRecord, maybe null
+     */
+    List<SubInfoRecord> getSubInfoUsingSlotId(int slotId);
+
+    /**
+     * Get all the SubInfoRecord(s) in subinfo database
+     * @param context Context provided by caller
+     * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+     */
+    List<SubInfoRecord> getAllSubInfoList();
+
+    /**
+     * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+     * @param context Context provided by caller
+     * @return Array list of currently inserted SubInfoRecord(s)
+     */
+    List<SubInfoRecord> getActivatedSubInfoList();
+
+    /**
+     * Get the SUB count of all SUB(s) in subinfo database
+     * @param context Context provided by caller
+     * @return all SIM count in database, include what was inserted before
+     */
+    int getAllSubInfoCount();
+
+    /**
+     * Add a new SubInfoRecord to subinfo database if needed
+     * @param context Context provided by caller
+     * @param iccId the IccId of the SIM card
+     * @param slotId the slot which the SIM is inserted
+     * @return the URL of the newly created row or the updated row
+     */
+    int addSubInfoRecord(String iccId, int slotId);
+
+    /**
+     * Set SIM color by simInfo index
+     * @param context Context provided by caller
+     * @param color the color of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setColor(int color, long subId);
+
+    /**
+     * Set display name by simInfo index
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDisplayName(String displayName, long subId);
+
+    /**
+     * Set display name by simInfo index with name source
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+     * @return the number of records updated
+     */
+    int setDisplayNameUsingSrc(String displayName, long subId, long nameSource);
+
+    /**
+     * Set phone number by subId
+     * @param context Context provided by caller
+     * @param number the phone number of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDispalyNumber(String number, long subId);
+
+    /**
+     * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+     * @param context Context provided by caller
+     * @param format the display format of phone number
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDisplayNumberFormat(int format, long subId);
+
+    /**
+     * Set data roaming by simInfo index
+     * @param context Context provided by caller
+     * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDataRoaming(int roaming, long subId);
+
+    int getSlotId(long subId);
+
+    long[] getSubId(int slotId);
+
+    long getDefaultSubId();
+
+    int clearSubInfo();
+
+    int getPhoneId(long subId);
+
+    /**
+     * Get the default data subscription
+     * @return Id of the data subscription
+     */
+    long getDefaultDataSubId();
+
+    void setDefaultDataSubId(long subId);
+
+    long getDefaultVoiceSubId();
+
+    void setDefaultVoiceSubId(long subId);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index acaa8de..407da87 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,14 +16,11 @@
 
 package com.android.internal.telephony;
 
-import android.content.ComponentName;
 import android.os.Bundle;
-import android.telephony.CellInfo;
+import java.util.List;
 import android.telephony.NeighboringCellInfo;
+import android.telephony.CellInfo;
 
-import java.util.List;
-
-import java.util.List;
 
 /**
  * Interface used to interact with the phone.  Mostly this is used by the
@@ -56,6 +53,13 @@
     boolean endCall();
 
     /**
+     * End call on particular subId or go to the Home screen
+     * @param subId user preferred subId.
+     * @return whether it hung up
+     */
+    boolean endCallUsingSubId(long subId);
+
+    /**
      * Answer the currently-ringing call.
      *
      * If there's already a current active call, that call will be
@@ -92,6 +96,23 @@
     boolean isOffhook();
 
     /**
+     * Check if a particular subId has an active or holding call
+     *
+     * @param subId user preferred subId.
+     * @return true if the phone state is OFFHOOK.
+     */
+    boolean isOffhookUsingSubId(long subId);
+
+    /**
+     * Check if an incoming phone call is ringing or call waiting
+     * on a particular subId.
+     *
+     * @param subId user preferred subId.
+     * @return true if the phone state is RINGING.
+     */
+    boolean isRingingUsingSubId(long subId);
+
+    /**
      * Check if an incoming phone call is ringing or call waiting.
      * @return true if the phone state is RINGING.
      */
@@ -104,12 +125,27 @@
     boolean isIdle();
 
     /**
+     * Check if the phone is idle on a particular subId.
+     *
+     * @param subId user preferred subId.
+     * @return true if the phone state is IDLE.
+     */
+    boolean isIdleUsingSubId(long subId);
+
+    /**
      * Check to see if the radio is on or not.
      * @return returns true if the radio is on.
      */
     boolean isRadioOn();
 
     /**
+     * Check to see if the radio is on or not on particular subId.
+     * @param subId user preferred subId.
+     * @return returns true if the radio is on.
+     */
+    boolean isRadioOnUsingSubId(long subId);
+
+    /**
      * Check if the SIM pin lock is enabled.
      * @return true if the SIM pin lock is enabled.
      */
@@ -128,6 +164,15 @@
     boolean supplyPin(String pin);
 
     /**
+     * Supply a pin to unlock the SIM for particular subId.
+     * Blocks until a result is determined.
+     * @param pin The pin to check.
+     * @param subId user preferred subId.
+     * @return whether the operation was a success.
+     */
+    boolean supplyPinUsingSubId(long subId, String pin);
+
+    /**
      * Supply puk to unlock the SIM and set SIM pin to new pin.
      *  Blocks until a result is determined.
      * @param puk The puk to check.
@@ -137,6 +182,16 @@
     boolean supplyPuk(String puk, String pin);
 
     /**
+     * Supply puk to unlock the SIM and set SIM pin to new pin.
+     *  Blocks until a result is determined.
+     * @param puk The puk to check.
+     *        pin The new pin to be set in SIM
+     * @param subId user preferred subId.
+     * @return whether the operation was a success.
+     */
+    boolean supplyPukUsingSubId(long subId, String puk, String pin);
+
+    /**
      * Supply a pin to unlock the SIM.  Blocks until a result is determined.
      * Returns a specific success/error code.
      * @param pin The pin to check.
@@ -146,6 +201,15 @@
     int[] supplyPinReportResult(String pin);
 
     /**
+     * Supply a pin to unlock the SIM.  Blocks until a result is determined.
+     * Returns a specific success/error code.
+     * @param pin The pin to check.
+     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+     *         retValue[1] = number of attempts remaining if known otherwise -1
+     */
+    int[] supplyPinReportResultUsingSubId(long subId, String pin);
+
+    /**
      * Supply puk to unlock the SIM and set SIM pin to new pin.
      * Blocks until a result is determined.
      * Returns a specific success/error code
@@ -157,6 +221,17 @@
     int[] supplyPukReportResult(String puk, String pin);
 
     /**
+     * Supply puk to unlock the SIM and set SIM pin to new pin.
+     * Blocks until a result is determined.
+     * Returns a specific success/error code
+     * @param puk The puk to check
+     *        pin The pin to check.
+     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+     *         retValue[1] = number of attempts remaining if known otherwise -1
+     */
+    int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin);
+
+    /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
      * without SEND (so <code>dial</code> is not appropriate).
      *
@@ -166,16 +241,38 @@
     boolean handlePinMmi(String dialString);
 
     /**
+     * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
+     * without SEND (so <code>dial</code> is not appropriate) for
+     * a particular subId.
+     * @param dialString the MMI command to be executed.
+     * @param subId user preferred subId.
+     * @return true if MMI command is executed.
+     */
+    boolean handlePinMmiUsingSubId(long subId, String dialString);
+
+    /**
      * Toggles the radio on or off.
      */
     void toggleRadioOnOff();
 
     /**
+     * Toggles the radio on or off on particular subId.
+     * @param subId user preferred subId.
+     */
+    void toggleRadioOnOffUsingSubId(long subId);
+
+    /**
      * Set the radio to on or off
      */
     boolean setRadio(boolean turnOn);
 
     /**
+     * Set the radio to on or off on particular subId.
+     * @param subId user preferred subId.
+     */
+    boolean setRadioUsingSubId(long subId, boolean turnOn);
+
+    /**
      * Set the radio to on or off unconditionally
      */
     boolean setRadioPower(boolean turnOn);
@@ -186,16 +283,35 @@
     void updateServiceLocation();
 
     /**
+     * Request to update location information for a subscrition in service state
+     * @param subId user preferred subId.
+     */
+    void updateServiceLocationUsingSubId(long subId);
+
+    /**
      * Enable location update notifications.
      */
     void enableLocationUpdates();
 
     /**
+     * Enable location update notifications.
+     * @param subId user preferred subId.
+     */
+    void enableLocationUpdatesUsingSubId(long subId);
+
+    /**
      * Disable location update notifications.
      */
     void disableLocationUpdates();
 
     /**
+     * Disable location update notifications.
+     * @param subId user preferred subId.
+     */
+    void disableLocationUpdatesUsingSubId(long subId);
+
+
+    /**
      * Enable a specific APN type.
      */
     int enableApnType(String type);
@@ -206,6 +322,16 @@
     int disableApnType(String type);
 
     /**
+     * Enable a specific APN type with subscription.
+     */
+    int enableApnTypeUsingSub(long subId, String type);
+
+    /**
+     * Disable a specific APN type with subscription.
+     */
+    int disableApnTypeUsingSub(long subId, String type);
+
+    /**
      * Allow mobile data connections.
      */
     boolean enableDataConnectivity();
@@ -228,6 +354,12 @@
     List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
 
      int getCallState();
+
+    /**
+     * Returns the call state for a subId.
+     */
+     int getCallStateUsingSubId(long subId);
+
      int getDataActivity();
      int getDataState();
 
@@ -239,11 +371,25 @@
     int getActivePhoneType();
 
     /**
+     * Returns the current active phone type as integer for particular subId.
+     * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
+     * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
+     * @param subId user preferred subId.
+     */
+    int getActivePhoneTypeUsingSubId(long subId);
+
+    /**
      * Returns the CDMA ERI icon index to display
      */
     int getCdmaEriIconIndex();
 
     /**
+     * Returns the CDMA ERI icon index to display on particular subId.
+     * @param subId user preferred subId.
+     */
+    int getCdmaEriIconIndexUsingSubId(long subId);
+
+    /**
      * Returns the CDMA ERI icon mode,
      * 0 - ON
      * 1 - FLASHING
@@ -251,11 +397,25 @@
     int getCdmaEriIconMode();
 
     /**
+     * Returns the CDMA ERI icon mode on particular subId,
+     * 0 - ON
+     * 1 - FLASHING
+     * @param subId user preferred subId.
+     */
+    int getCdmaEriIconModeUsingSubId(long subId);
+
+    /**
      * Returns the CDMA ERI text,
      */
     String getCdmaEriText();
 
     /**
+     * Returns the CDMA ERI text for particular subId,
+     * @param subId user preferred subId.
+     */
+    String getCdmaEriTextUsingSubId(long subId);
+
+    /**
      * Returns true if OTA service provisioning needs to run.
      * Only relevant on some technologies, others will always
      * return false.
@@ -268,26 +428,61 @@
     int getVoiceMessageCount();
 
     /**
+     * Returns the unread count of voicemails for a subId.
+     * @param subId user preferred subId.
+     * Returns the unread count of voicemails
+     */
+    int getVoiceMessageCountUsingSubId(long subId);
+
+    /**
       * Returns the network type for data transmission
       */
     int getNetworkType();
 
     /**
+     * Returns the network type of a subId.
+     * @param subId user preferred subId.
+     * Returns the network type
+     */
+    int getNetworkTypeUsingSubId(long subId);
+
+    /**
       * Returns the network type for data transmission
       */
     int getDataNetworkType();
 
     /**
+      * Returns the data network type of a subId
+      * @param subId user preferred subId.
+      * Returns the network type
+      */
+    int getDataNetworkTypeUsingSubId(long subId);
+
+    /**
       * Returns the network type for voice
       */
     int getVoiceNetworkType();
 
     /**
+      * Returns the voice network type of a subId
+      * @param subId user preferred subId.
+      * Returns the network type
+      */
+    int getVoiceNetworkTypeUsingSubId(long subId);
+
+    /**
      * Return true if an ICC card is present
      */
     boolean hasIccCard();
 
     /**
+     * Return true if an ICC card is present for a subId.
+     * @param slotId user preferred slotId.
+     * Return true if an ICC card is present
+     */
+    boolean hasIccCardUsingSlotId(long slotId);
+
+    /**
      * Return if the current radio is LTE on CDMA. This
      * is a tri-state return value as for a period of time
      * the mode may be unknown.
@@ -298,6 +493,16 @@
     int getLteOnCdmaMode();
 
     /**
+     * Return if the current radio is LTE on CDMA. This
+     * is a tri-state return value as for a period of time
+     * the mode may be unknown.
+     *
+     * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
+     * or {@link PHone#LTE_ON_CDMA_TRUE}
+     */
+    int getLteOnCdmaModeUsingSubId(long subId);
+
+    /**
      * Returns the all observed cell information of the device.
      */
     List<CellInfo> getAllCellInfo();
@@ -308,6 +513,12 @@
     void setCellInfoListRate(int rateInMillis);
 
     /**
+     * get default sim
+     * @return sim id
+     */
+    int getDefaultSim();
+
+    /**
      * Opens a logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -428,4 +639,16 @@
      * @return true on enabled
      */
     boolean getDataEnabled();
+
+    /**
+     * Get P-CSCF address from PCO after data connection is established or modified.
+     */
+    String[] getPcscfAddress();
+
+    /**
+     * Set IMS registration state
+     */
+    void setImsRegistrationState(boolean registered);
+
 }
+
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index b104c11..fd2d1c7 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -24,22 +24,36 @@
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
 import com.android.internal.telephony.IPhoneStateListener;
 
 interface ITelephonyRegistry {
     void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
-
+    void listenUsingSubId(in long subId, String pkg, IPhoneStateListener callback, int events,
+            boolean notifyNow);
     void notifyCallState(int state, String incomingNumber);
+    void notifyCallStateUsingSubId(in long subId, int state, String incomingNumber);
     void notifyServiceState(in ServiceState state);
+    void notifyServiceStateUsingSubId(in long subId, in ServiceState state);
     void notifySignalStrength(in SignalStrength signalStrength);
+    void notifySignalStrengthUsingSubId(in long subId, in SignalStrength signalStrength);
     void notifyMessageWaitingChanged(boolean mwi);
+    void notifyMessageWaitingChangedUsingSubId(in long subId, boolean mwi);
     void notifyCallForwardingChanged(boolean cfi);
+    void notifyCallForwardingChangedUsingSubId(in long subId, boolean cfi);
     void notifyDataActivity(int state);
+    void notifyDataActivityUsingSubId(in long subId, int state);
     void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, in LinkProperties linkProperties,
             in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
+    void notifyDataConnectionUsingSubId(long subId, int state, boolean isDataConnectivityPossible,
+            String reason, String apn, String apnType, in LinkProperties linkProperties,
+            in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
     void notifyDataConnectionFailed(String reason, String apnType);
+    void notifyDataConnectionFailedUsingSubId(long subId, String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
+    void notifyCellLocationUsingSubId(in long subId, in Bundle cellLocation);
     void notifyOtaspChanged(in int otaspMode);
     void notifyCellInfo(in List<CellInfo> cellInfo);
     void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
@@ -47,5 +61,7 @@
     void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
     void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
             String failCause);
+    void notifyCellInfoUsingSubId(in long subId, in List<CellInfo> cellInfo);
     void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
+    void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 08f4379..aecf955 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -58,6 +58,7 @@
     public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
     public static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE;
     public static final int PHONE_TYPE_THIRD_PARTY = RILConstants.THIRD_PARTY_PHONE;
+    public static final int PHONE_TYPE_IMS = RILConstants.IMS_PHONE;
 
     // Modes for LTE_ON_CDMA
     public static final int LTE_ON_CDMA_UNKNOWN = RILConstants.LTE_ON_CDMA_UNKNOWN;
@@ -133,4 +134,55 @@
     /** APN type for IA Initial Attach APN */
     public static final String APN_TYPE_IA = "ia";
 
+    // FIXME: This looks to be used as default phoneId, rename
+    // or use SubscriptionManager.DEFAULT_SUB_ID
+    public static final int DEFAULT_SUBSCRIPTION = 0;
+
+    // FIXME: This looks to be used as invalid phoneId, rename
+    // or use SubscriptionManager.INVALID_SUB_ID
+    public static final int INVALID_SUBSCRIPTION = -1;
+
+    public static final int RIL_CARD_MAX_APPS    = 8;
+
+    public static final int DEFAULT_CARD_INDEX   = 0;
+
+    public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
+
+    public static final int MAX_PHONE_COUNT_DUAL_SIM = 2;
+
+    public static final int MAX_PHONE_COUNT_TRI_SIM = 3;
+
+    public static final String SUBSCRIPTION_KEY  = "subscription";
+
+    public static final String SLOT_KEY  = "slot";
+
+    public static final String SUB_SETTING  = "subSettings";
+
+    public static final int SUB1 = 0;
+    public static final int SUB2 = 1;
+    public static final int SUB3 = 2;
+
+    public static final int EVENT_SUBSCRIPTION_ACTIVATED   = 500;
+    public static final int EVENT_SUBSCRIPTION_DEACTIVATED = 501;
+
+    // TODO: Remove these constants and use an int instead.
+    public static final int SIM_ID_1 = 0;
+    public static final int SIM_ID_2 = 1;
+    public static final int SIM_ID_3 = 2;
+    public static final int SIM_ID_4 = 3;
+
+    // ICC SIM Application Types
+    // TODO: Replace the IccCardApplicationStatus.AppType enums with these constants
+    public static final int APPTYPE_UNKNOWN = 0;
+    public static final int APPTYPE_SIM = 1;
+    public static final int APPTYPE_USIM = 2;
+    public static final int APPTYPE_RUIM = 3;
+    public static final int APPTYPE_CSIM = 4;
+    public static final int APPTYPE_ISIM = 5;
+
+    public enum CardUnavailableReason {
+        REASON_CARD_REMOVED,
+        REASON_RADIO_UNAVAILABLE,
+        REASON_SIM_REFRESH_RESET
+    };
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 815211c..0271d0a 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -57,6 +57,7 @@
                                                  retries needed */
     int MISSING_RESOURCE = 16;                /* no logical channel available */
     int NO_SUCH_ELEMENT = 17;                 /* application not found on SIM */
+    int SUBSCRIPTION_NOT_SUPPORTED = 26;      /* Subscription not supported */
 
     /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
     int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -85,6 +86,7 @@
     int CDMA_PHONE = 2;
     int SIP_PHONE  = 3;
     int THIRD_PARTY_PHONE = 4;
+    int IMS_PHONE = 5;
 
     int LTE_ON_CDMA_UNKNOWN = -1;
     int LTE_ON_CDMA_FALSE = 0;
@@ -282,6 +284,11 @@
     int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120;
     int RIL_REQUEST_NV_RESET_CONFIG = 121;
     int RIL_REQUEST_SET_RADIO_MODE = 122;
+    int RIL_REQUEST_DATA_IDLE = 123;
+    int RIL_REQUEST_SET_UICC_SUBSCRIPTION = 124;
+    int RIL_REQUEST_ALLOW_DATA = 125;
+    int RIL_REQUEST_GET_HARDWARE_CONFIG = 126;
+    int RIL_REQUEST_ICC_SIM_AUTHENTICATION = 127;
 
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
@@ -322,4 +329,7 @@
     int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035;
     int RIL_UNSOL_CELL_INFO_LIST = 1036;
     int RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037;
+    int RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038;
+    int RIL_UNSOL_SRVCC_STATE_NOTIFY = 1039;
+    int RIL_UNSOL_HARDWARE_CONFIG_CHANGED = 1040;
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 9ad2d42..5954947 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import android.content.Intent;
+
 /**
  * The intents that the telephony services broadcast.
  *
@@ -48,7 +50,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -69,7 +71,7 @@
      *
      * <p class="note">
      * Requires no permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -88,7 +90,7 @@
      *
      * <p class="note">
      * Requires no permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -114,7 +116,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -136,7 +138,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -176,7 +178,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -207,7 +209,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -225,7 +227,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -243,7 +245,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -315,4 +317,85 @@
     public static final String EXTRA_PLMN       = "plmn";
     public static final String EXTRA_SHOW_SPN   = "showSpn";
     public static final String EXTRA_SPN        = "spn";
+
+    /**
+     * <p>Broadcast Action: It indicates one column of a siminfo record has been changed
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li><em>columnName</em> - The siminfo column that is updated.</li>
+     *   <li><em>stringContent</em> - The string value of the updated column.</li>
+     *   <li><em>intContent</em> - The int value of the updated column.</li>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SIMINFO_CONTENT_CHANGE
+            = "android.intent.action.ACTION_SIMINFO_CONTENT_CHANGE";
+
+    /**
+     * <p>Broadcast Action: It indicates one column of a subinfo record has been changed
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li><em>columnName</em> - The siminfo column that is updated.</li>
+     *   <li><em>stringContent</em> - The string value of the updated column.</li>
+     *   <li><em>intContent</em> - The int value of the updated column.</li>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SUBINFO_CONTENT_CHANGE
+            = "android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE";
+
+    /**
+     * <p>Broadcast Action: It indicates siminfo update is completed when SIM inserted state change
+     * The intent will have the following extra values:</p>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SIMINFO_UPDATED
+            = "android.intent.action.ACTION_SIMINFO_UPDATED";
+
+    /**
+     * <p>Broadcast Action: It indicates subinfo record update is completed
+     * when SIM inserted state change
+     * The intent will have the following extra values:</p>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SUBINFO_RECORD_UPDATED
+            = "android.intent.action.ACTION_SUBINFO_RECORD_UPDATED";
+
+    public static final String EXTRA_COLUMN_NAME = "columnName";
+    public static final String EXTRA_INT_CONTENT = "intContent";
+    public static final String EXTRA_STRING_CONTENT = "stringContent";
+
+    /**
+     * Broadcast Action: The default subscription has changed.  This has the following
+     * extra values:</p>
+     * <ul>
+     *   <li><em>subscription</em> - A int, the current default subscription.</li>
+     * </ul>
+     */
+    public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
+
+    /**
+     * Broadcast Action: The default data subscription has changed.  This has the following
+     * extra values:</p>
+     * <ul>
+     *   <li><em>subscription</em> - A int, the current data default subscription.</li>
+     * </ul>
+     */
+    public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED";
+
+    /**
+     * Broadcast Action: The default voice subscription has changed.  This has the following
+     * extra values:</p>
+     * <ul>
+     *   <li><em>subscription</em> - A int, the current voice default subscription.</li>
+     * </ul>
+     */
+    public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index f95e081..5ec4247 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -187,4 +187,26 @@
      * Ignore RIL_UNSOL_NITZ_TIME_RECEIVED completely, used for debugging/testing.
      */
     static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz";
+
+     /**
+     * Property to set multi sim feature.
+     * Type:  String(dsds, dsda)
+     */
+    static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config";
+
+    /**
+     * Property to store default subscription.
+     */
+    static final String PROPERTY_DEFAULT_SUBSCRIPTION = "persist.radio.default.sub";
+
+    /**
+     * Property to enable MMS Mode.
+     * Type: string ( default = silent, enable to = prompt )
+     */
+    static final String PROPERTY_MMS_TRANSACTION = "mms.transaction";
+
+    /**
+     * Set to the sim count.
+     */
+    static final String PROPERTY_SIM_COUNT = "ro.telephony.sim.count";
 }