Do not merge: Revert the revert of "LTE Changes for Telephony including Multiple PDN support and IPV6 support"

This reverts commit eca208fae6d1b6ae9c8c0e42eee092e86dbddbb7
and is the first of the LTE commits in master being back ported
to the LTE branch.

Change-Id: I17d4a1b779ed74bc7dfb409d2c1a30f60fdb27c7
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cab8ed2..26f375d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -221,12 +221,32 @@
 
     /** {@hide} */
     public static final int TYPE_DUMMY       = 8;
+
     /** {@hide} */
     public static final int TYPE_ETHERNET    = 9;
-    /** {@hide} TODO: Need to adjust this for WiMAX. */
-    public static final int MAX_RADIO_TYPE   = TYPE_DUMMY;
-    /** {@hide} TODO: Need to adjust this for WiMAX. */
-    public static final int MAX_NETWORK_TYPE = TYPE_DUMMY;
+    /**
+     * Over the air Adminstration.
+     * {@hide}
+     */
+    public static final int TYPE_MOBILE_FOTA = 10;
+
+    /**
+     * IP Multimedia Subsystem
+     * {@hide}
+     */
+    public static final int TYPE_MOBILE_IMS  = 11;
+
+    /**
+     * Carrier Branded Services
+     * {@hide}
+     */
+    public static final int TYPE_MOBILE_CBS  = 12;
+
+    /** {@hide} */
+    public static final int MAX_RADIO_TYPE   = TYPE_MOBILE_CBS;
+
+    /** {@hide} */
+    public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_CBS;
 
     public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
 
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index e04964e..5b4da66 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -437,7 +437,8 @@
                 retValue = true;
                 break;
             case Phone.APN_REQUEST_STARTED:
-                // no need to do anything - we're already due some status update intents
+                // set IDLE here , avoid the following second FAILED not sent out
+                mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null);
                 retValue = true;
                 break;
             case Phone.APN_REQUEST_FAILED:
@@ -546,6 +547,12 @@
                 return Phone.APN_TYPE_DUN;
             case ConnectivityManager.TYPE_MOBILE_HIPRI:
                 return Phone.APN_TYPE_HIPRI;
+            case ConnectivityManager.TYPE_MOBILE_FOTA:
+                return Phone.APN_TYPE_FOTA;
+            case ConnectivityManager.TYPE_MOBILE_IMS:
+                return Phone.APN_TYPE_IMS;
+            case ConnectivityManager.TYPE_MOBILE_CBS:
+                return Phone.APN_TYPE_CBS;
             default:
                 sloge("Error mapping networkType " + netType + " to apnType.");
                 return null;
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 62f66b6..d2d2557 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1723,6 +1723,14 @@
 
         public static final String TYPE = "type";
 
+        public static final String INACTIVE_TIMER = "inactivetimer";
+
+        // Only if enabled try Data Connection.
+        public static final String ENABLED = "enabled";
+
+        // Rules apply based on class.
+        public static final String CLASS = "class";
+
         /**
          * The protocol to be used to connect to this APN.
          *
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b24ee9e..be11662 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -51,6 +51,11 @@
          manager will disable alpha trasformation in animations where not
          strictly needed. -->
     <bool name="config_sf_limitedAlpha">false</bool>
+
+    <!-- Default value used to block data calls if ims is not
+         connected.  If you use the ims apn DCT will block
+         any other apn from connecting until ims apn is connected-->
+    <bool name="ImsConnectedDefaultValue">false</bool>
     
     <!-- Flag indicating whether the surface flinger is inefficient
          at performing a blur.  Used by parts of the UI to turn off
@@ -133,6 +138,9 @@
         <item>"mobile_mms,2,0,2"</item>
         <item>"mobile_supl,3,0,2"</item>
         <item>"mobile_hipri,5,0,3"</item>
+        <item>"mobile_fota,8,0,2"</item>
+        <item>"mobile_ims,9,0,2"</item>
+        <item>"mobile_cbs,10,0,2"</item>
     </string-array>
 
     <!-- This string array should be overridden by the device to present a list of radio
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4g.png
new file mode 100644
index 0000000..84ac927
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 0273a4c..826ac92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -246,6 +246,16 @@
               R.drawable.stat_sys_data_fully_out_3g,
               R.drawable.stat_sys_data_fully_inandout_3g }
         };
+    private static final int[][] sDataNetType_4g = {
+            { R.drawable.stat_sys_data_connected_4g,
+              R.drawable.stat_sys_data_in_4g,
+              R.drawable.stat_sys_data_out_4g,
+              R.drawable.stat_sys_data_inandout_4g },
+            { R.drawable.stat_sys_data_fully_connected_4g,
+              R.drawable.stat_sys_data_fully_in_4g,
+              R.drawable.stat_sys_data_fully_out_4g,
+              R.drawable.stat_sys_data_fully_inandout_4g }
+        };
     private static final int[][] sDataNetType_e = {
             { R.drawable.stat_sys_data_connected_e,
               R.drawable.stat_sys_data_in_e,
@@ -670,9 +680,12 @@
         case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
         case TelephonyManager.NETWORK_TYPE_EVDO_A:
         case TelephonyManager.NETWORK_TYPE_EVDO_B:
+        case TelephonyManager.NETWORK_TYPE_EHRPD:
             mDataIconList = sDataNetType_3g[mInetCondition];
             break;
-        // TODO - add support for NETWORK_TYPE_LTE and NETWORK_TYPE_EHRPD
+        case TelephonyManager.NETWORK_TYPE_LTE:
+            mDataIconList = sDataNetType_4g[mInetCondition];
+            break;
         default:
             mDataIconList = sDataNetType_g[mInetCondition];
         break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 69585ab..6b9551b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -427,10 +427,14 @@
             case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
             case TelephonyManager.NETWORK_TYPE_EVDO_A:
             case TelephonyManager.NETWORK_TYPE_EVDO_B:
+            case TelephonyManager.NETWORK_TYPE_EHRPD:
                 mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_3g;
                 break;
-            // TODO - add support for NETWORK_TYPE_LTE and NETWORK_TYPE_EHRPD
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+                mDataTypeIconId = R.drawable.stat_sys_signal_4g;
+                break;
             default:
                 mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_gprs;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 29d35e3..9093b3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -124,5 +124,18 @@
               R.drawable.stat_sys_data_fully_inandout_1x }
             };
 
+    // LTE and eHRPD
+    static final int[][] DATA_4G = {
+            { R.drawable.stat_sys_data_connected_4g,
+              R.drawable.stat_sys_data_in_4g,
+              R.drawable.stat_sys_data_out_4g,
+              R.drawable.stat_sys_data_inandout_4g },
+            { R.drawable.stat_sys_data_fully_connected_4g,
+              R.drawable.stat_sys_data_fully_in_4g,
+              R.drawable.stat_sys_data_fully_out_4g,
+              R.drawable.stat_sys_data_fully_inandout_4g }
+        };
+
+
 }
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 14a6b96..b7d0a8f 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -696,15 +696,10 @@
         // TODO - move this into the MobileDataStateTracker
         int usedNetworkType = networkType;
         if(networkType == ConnectivityManager.TYPE_MOBILE) {
-            if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
-                usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
-            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
-                usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
-            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
-                    TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
-                usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
-            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
-                usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+            usedNetworkType = convertFeatureToNetworkType(feature);
+            if (usedNetworkType < 0) {
+                Slog.e(TAG, "Can't match any netTracker!");
+                usedNetworkType = networkType;
             }
         }
         NetworkStateTracker network = mNetTrackers[usedNetworkType];
@@ -848,15 +843,9 @@
             // TODO - move to MobileDataStateTracker
             int usedNetworkType = networkType;
             if (networkType == ConnectivityManager.TYPE_MOBILE) {
-                if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
-                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
-                } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
-                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
-                } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
-                        TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
-                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
-                } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
-                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+                usedNetworkType = convertFeatureToNetworkType(feature);
+                if (usedNetworkType < 0) {
+                    usedNetworkType = networkType;
                 }
             }
             tracker =  mNetTrackers[usedNetworkType];
@@ -2174,4 +2163,24 @@
     private void loge(String s) {
         Slog.e(TAG, s);
     }
+    int convertFeatureToNetworkType(String feature){
+        int networkType = -1;
+        if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+            networkType = ConnectivityManager.TYPE_MOBILE_MMS;
+        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+            networkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
+                TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
+            networkType = ConnectivityManager.TYPE_MOBILE_DUN;
+        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+            networkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
+            networkType = ConnectivityManager.TYPE_MOBILE_FOTA;
+        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
+            networkType = ConnectivityManager.TYPE_MOBILE_IMS;
+        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
+            networkType = ConnectivityManager.TYPE_MOBILE_CBS;
+        }
+        return networkType;
+    }
 }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 290f2c1..5dcb820 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -91,6 +91,10 @@
     public static final int RADIO_TECHNOLOGY_HSPA = 11;
     /** @hide */
     public static final int RADIO_TECHNOLOGY_EVDO_B = 12;
+    /** @hide */
+    public static final int RADIO_TECHNOLOGY_LTE = 13;
+    /** @hide */
+    public static final int RADIO_TECHNOLOGY_EHRPD = 14;
 
     /**
      * Available registration states for GSM, UMTS and CDMA.
@@ -424,6 +428,12 @@
         case 12:
             radioTechnology = "EvDo rev. B";
             break;
+        case 13:
+            radioTechnology = "LTE";
+            break;
+        case 14:
+            radioTechnology = "eHRPD";
+            break;
         default:
             Log.w(LOG_TAG, "mRadioTechnology variable out of range.");
         break;
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java
new file mode 100644
index 0000000..bd1bc1d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2006 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 com.android.internal.telephony;
+
+import android.app.PendingIntent;
+
+import android.util.Log;
+import java.util.ArrayList;
+import com.android.internal.telephony.gsm.GsmDataConnection;
+
+/**
+ * Maintain the Apn context
+ */
+public class ApnContext {
+
+    public static final int PENDING_ACTION_NONE = 1;
+    public static final int PENDING_ACTION_RECONNECT = 2;
+    public static final int PENDING_ACTION_APN_DISABLE = 3;
+    public final String LOG_TAG;
+
+    int pendingAction;
+
+    protected static final boolean DBG = true;
+
+    String mApnType;
+
+    DataConnectionTracker.State mState;
+
+    ArrayList<ApnSetting> mWaitingApns = null;
+
+    private int mWaitingApnsPermanentFailureCountDown = 0;
+
+    ApnSetting mApnSetting;
+
+    GsmDataConnection mDataConnection;
+
+    String mReason;
+
+    PendingIntent mReconnectIntent;
+
+    public ApnContext(String apnType, String logTag) {
+        mApnType = apnType;
+        mState = DataConnectionTracker.State.IDLE;
+        setReason(Phone.REASON_DATA_ENABLED);
+        pendingAction = PENDING_ACTION_NONE;
+        LOG_TAG = logTag;
+    }
+
+    public int getPendingAction() {
+        return pendingAction;
+    }
+
+    public void setPendingAction(int pa) {
+        pendingAction = pa;
+    }
+
+    public int getPermFailCount() {
+        return mWaitingApnsPermanentFailureCountDown;
+    }
+
+    public void decPermFailCount() {
+        mWaitingApnsPermanentFailureCountDown--;
+    }
+
+    public String getApnType() {
+        return mApnType;
+    }
+
+    public GsmDataConnection getDataConnection() {
+        return mDataConnection;
+    }
+
+    public void setDataConnection(GsmDataConnection dataConnection) {
+        mDataConnection = dataConnection;
+    }
+
+    public ApnSetting getApnSetting() {
+        return mApnSetting;
+    }
+
+    public void setApnSetting(ApnSetting apnSetting) {
+        mApnSetting = apnSetting;
+    }
+
+    public void setWaitingApns(ArrayList<ApnSetting> waitingApns) {
+        mWaitingApns = waitingApns;
+    }
+
+    public ApnSetting getNextApn() {
+        ArrayList<ApnSetting> list = mWaitingApns;
+        ApnSetting apn = null;
+
+        if (list != null) {
+            if (!list.isEmpty()) {
+                apn = list.get(0);
+            }
+        }
+        return apn;
+    }
+
+    public void removeNextApn() {
+        if ((mWaitingApns != null) && (!mWaitingApns.isEmpty())) {
+            mWaitingApns.remove(0);
+        }
+    }
+
+    public ArrayList<ApnSetting> getWaitingApns() {
+        return mWaitingApns;
+    }
+
+    public void setState(DataConnectionTracker.State s) {
+        if (DBG)
+            log("setState: " + s + " for type " + mApnType + ", previous state:" + mState);
+
+        mState = s;
+
+        if (mState == DataConnectionTracker.State.FAILED) {
+            if (mWaitingApns != null)
+                mWaitingApns.clear(); // when teardown the connection and set to IDLE
+        }
+    }
+
+    public DataConnectionTracker.State getState() {
+        return mState;
+    }
+
+    public void setReason(String reason) {
+        if (DBG)
+            log("set reason as " + reason + ", for type " + mApnType + ",current state " + mState);
+        mReason = reason;
+    }
+
+    public String getReason() {
+        return mReason;
+    }
+
+    public void setReconnectIntent(PendingIntent intent) {
+        if (DBG)
+            log("set ReconnectIntent for type " + mApnType);
+        mReconnectIntent = intent;
+    }
+
+    public PendingIntent getReconnectIntent() {
+        return mReconnectIntent;
+    }
+
+    protected void log(String s) {
+        Log.d(LOG_TAG, "[ApnContext] " + s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/ApnSetting.java b/telephony/java/com/android/internal/telephony/ApnSetting.java
index 20dbaf3..3c93a68 100644
--- a/telephony/java/com/android/internal/telephony/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/ApnSetting.java
@@ -38,12 +38,17 @@
     public String numeric;
     public String protocol;
     public String roamingProtocol;
+    public boolean enabled;
+
+    int timer;
+    int apnclass;
 
     public ApnSetting(int id, String numeric, String carrier, String apn,
             String proxy, String port,
             String mmsc, String mmsProxy, String mmsPort,
             String user, String password, int authType, String[] types,
-            String protocol, String roamingProtocol) {
+            String protocol, String roamingProtocol,
+            boolean enabled, int timer, int apnclass) {
         this.id = id;
         this.numeric = numeric;
         this.carrier = carrier;
@@ -59,6 +64,9 @@
         this.types = types;
         this.protocol = protocol;
         this.roamingProtocol = roamingProtocol;
+        this.enabled = enabled;
+        this.timer = timer;
+        this.apnclass = apnclass;
     }
 
     /**
@@ -77,7 +85,7 @@
      * v2 format:
      *   [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <mmsc>, <mmsproxy>,
      *   <mmsport>, <user>, <password, <authtype>, <mcc>, <mnc>,
-     *   <type>[| <type>...], <protocol>, <roaming_protocol>
+     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <enabled>, <timer>, <apnclass>
      *
      * Note that the strings generated by toString() do not contain the username
      * and password and thus cannot be read by this method.
@@ -110,11 +118,16 @@
 
         String[] typeArray;
         String protocol, roamingProtocol;
+        boolean enabled;
+        int timer, apnclass;
         if (version == 1) {
             typeArray = new String[a.length - 13];
             System.arraycopy(a, 13, typeArray, 0, a.length - 13);
             protocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
             roamingProtocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
+            enabled = true;
+            timer = 0;
+            apnclass = 0;
         } else {
             if (a.length < 16) {
                 return null;
@@ -122,10 +135,14 @@
             typeArray = a[13].split("\\s*\\|\\s*");
             protocol = a[14];
             roamingProtocol = a[15];
+            enabled = Integer.parseInt(a[16]) != 0;
+            timer = Integer.parseInt(a[17]);
+            apnclass = Integer.parseInt(a[18]);
         }
 
         return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8],
-                a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol);
+                a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol,
+                enabled,timer,apnclass);
     }
 
     public String toString() {
@@ -149,6 +166,9 @@
         }
         sb.append(", ").append(protocol);
         sb.append(", ").append(roamingProtocol);
+        sb.append(", ").append(enabled);
+        sb.append(", ").append(timer);
+        sb.append(", ").append(apnclass);
         return sb.toString();
     }
 
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 9b19600..0fc81b0 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -34,6 +34,9 @@
     //***** Instance Variables
     protected Context mContext;
     protected RadioState mState = RadioState.RADIO_UNAVAILABLE;
+    protected RadioState mSimState = RadioState.RADIO_UNAVAILABLE;
+    protected RadioState mRuimState = RadioState.RADIO_UNAVAILABLE;
+    protected RadioState mNvState = RadioState.RADIO_UNAVAILABLE;
     protected Object mStateMonitor = new Object();
 
     protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList();
@@ -105,6 +108,18 @@
         return mState;
     }
 
+    public RadioState getSimState() {
+        return mSimState;
+    }
+
+    public RadioState getRuimState() {
+        return mRuimState;
+    }
+
+    public RadioState getNvState() {
+        return mNvState;
+    }
+
 
     public void registerForRadioStateChanged(Handler h, int what, Object obj) {
         Registrant r = new Registrant (h, what, obj);
@@ -200,7 +215,7 @@
         synchronized (mStateMonitor) {
             mSIMReadyRegistrants.add(r);
 
-            if (mState.isSIMReady()) {
+            if (mSimState.isSIMReady()) {
                 r.notifyRegistrant(new AsyncResult(null, null, null));
             }
         }
@@ -219,7 +234,7 @@
         synchronized (mStateMonitor) {
             mRUIMReadyRegistrants.add(r);
 
-            if (mState.isRUIMReady()) {
+            if (mRuimState.isRUIMReady()) {
                 r.notifyRegistrant(new AsyncResult(null, null, null));
             }
         }
@@ -238,7 +253,7 @@
         synchronized (mStateMonitor) {
             mNVReadyRegistrants.add(r);
 
-            if (mState.isNVReady()) {
+            if (mNvState.isNVReady()) {
                 r.notifyRegistrant(new AsyncResult(null, null, null));
             }
         }
@@ -256,7 +271,7 @@
         synchronized (mStateMonitor) {
             mSIMLockedRegistrants.add(r);
 
-            if (mState == RadioState.SIM_LOCKED_OR_ABSENT) {
+            if (mSimState == RadioState.SIM_LOCKED_OR_ABSENT) {
                 r.notifyRegistrant(new AsyncResult(null, null, null));
             }
         }
@@ -274,7 +289,7 @@
         synchronized (mStateMonitor) {
             mRUIMLockedRegistrants.add(r);
 
-            if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) {
+            if (mRuimState == RadioState.RUIM_LOCKED_OR_ABSENT) {
                 r.notifyRegistrant(new AsyncResult(null, null, null));
             }
         }
@@ -653,6 +668,22 @@
                 return;
             }
 
+            // FIXME: Use Constants or Enums
+            if(mState.getType() == 0) {
+                mSimState = mState;
+                mRuimState = mState;
+                mNvState = mState;
+            }
+            else if (mState.getType() == 1) {
+                mSimState = mState;
+            }
+            else if (mState.getType() == 2) {
+                mRuimState = mState;
+            }
+            else if (mState.getType() == 3) {
+                mNvState = mState;
+            }
+
             mRadioStateChangedRegistrants.notifyRegistrants();
 
             if (mState.isAvailable() && !oldState.isAvailable()) {
diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java
index 9619a66..31f9e18 100644
--- a/telephony/java/com/android/internal/telephony/CallTracker.java
+++ b/telephony/java/com/android/internal/telephony/CallTracker.java
@@ -119,6 +119,10 @@
 
     //***** Overridden from Handler
     public abstract void handleMessage (Message msg);
+    public abstract void registerForVoiceCallStarted(Handler h, int what, Object obj);
+    public abstract void unregisterForVoiceCallStarted(Handler h);
+    public abstract void registerForVoiceCallEnded(Handler h, int what, Object obj);
+    public abstract void unregisterForVoiceCallEnded(Handler h);
 
     protected abstract void log(String msg);
 
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index ad21a18..ea38543 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -20,25 +20,29 @@
 
 import android.os.Message;
 import android.os.Handler;
+import android.os.SystemProperties;
 
 
 /**
  * {@hide}
  */
 public interface CommandsInterface {
+    // TODO: Get rid of mot from property.
+    static final boolean LTE_AVAILABLE_ON_CDMA =
+        SystemProperties.getBoolean("ro.mot.lte_on_cdma", false);
     enum RadioState {
-        RADIO_OFF,         /* Radio explicitly powered off (e.g. CFUN=0) */
-        RADIO_UNAVAILABLE, /* Radio unavailable (e.g. resetting or not booted) */
-        SIM_NOT_READY,     /* Radio is on, but the SIM interface is not ready */
-        SIM_LOCKED_OR_ABSENT,  /* SIM PIN locked, PUK required, network
-                               personalization, or SIM absent */
-        SIM_READY,         /* Radio is on and SIM interface is available */
-        RUIM_NOT_READY,    /* Radio is on, but the RUIM interface is not ready */
-        RUIM_READY,        /* Radio is on and the RUIM interface is available */
-        RUIM_LOCKED_OR_ABSENT, /* RUIM PIN locked, PUK required, network
-                                  personalization locked, or RUIM absent */
-        NV_NOT_READY,      /* Radio is on, but the NV interface is not available */
-        NV_READY;          /* Radio is on and the NV interface is available */
+        RADIO_OFF(0),         /* Radio explictly powered off (eg CFUN=0) */
+        RADIO_UNAVAILABLE(0), /* Radio unavailable (eg, resetting or not booted) */
+        SIM_NOT_READY(1),     /* Radio is on, but the SIM interface is not ready */
+        SIM_LOCKED_OR_ABSENT(1),  /* SIM PIN locked, PUK required, network
+                                     personalization, or SIM absent */
+        SIM_READY(1),         /* Radio is on and SIM interface is available */
+        RUIM_NOT_READY(2),    /* Radio is on, but the RUIM interface is not ready */
+        RUIM_READY(2),        /* Radio is on and the RUIM interface is available */
+        RUIM_LOCKED_OR_ABSENT(2), /* RUIM PIN locked, PUK required, network
+                                     personalization locked, or RUIM absent */
+        NV_NOT_READY(3),      /* Radio is on, but the NV interface is not available */
+        NV_READY(3);          /* Radio is on and the NV interface is available */
 
         public boolean isOn() /* and available...*/ {
             return this == SIM_NOT_READY
@@ -50,6 +54,14 @@
                     || this == NV_NOT_READY
                     || this == NV_READY;
         }
+        private int stateType;
+        private RadioState (int type) {
+            stateType = type;
+        }
+
+        public int getType() {
+            return stateType;
+        }
 
         public boolean isAvailable() {
             return this != RADIO_UNAVAILABLE;
@@ -68,17 +80,25 @@
         }
 
         public boolean isGsm() {
-            return this == SIM_NOT_READY
-                    || this == SIM_LOCKED_OR_ABSENT
-                    || this == SIM_READY;
+            if (LTE_AVAILABLE_ON_CDMA) {
+                return false;
+            } else {
+                return this == SIM_NOT_READY
+                        || this == SIM_LOCKED_OR_ABSENT
+                        || this == SIM_READY;
+            }
         }
 
         public boolean isCdma() {
-            return this ==  RUIM_NOT_READY
-                    || this == RUIM_READY
-                    || this == RUIM_LOCKED_OR_ABSENT
-                    || this == NV_NOT_READY
-                    || this == NV_READY;
+            if (LTE_AVAILABLE_ON_CDMA) {
+                return true;
+            } else {
+                return this ==  RUIM_NOT_READY
+                        || this == RUIM_READY
+                        || this == RUIM_LOCKED_OR_ABSENT
+                        || this == NV_NOT_READY
+                        || this == NV_READY;
+            }
         }
     }
 
@@ -153,6 +173,9 @@
     //***** Methods
 
     RadioState getRadioState();
+    RadioState getSimState();
+    RadioState getRuimState();
+    RadioState getNvState();
 
     /**
      * Fires on any RadioState transition
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 7c616d6..460b553 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -99,14 +99,14 @@
     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
     protected static final int EVENT_VOICE_CALL_STARTED = 14;
     protected static final int EVENT_VOICE_CALL_ENDED = 15;
-    protected static final int EVENT_GPRS_DETACHED = 19;
+    protected static final int EVENT_DATA_CONNECTION_DETACHED = 19;
     protected static final int EVENT_LINK_STATE_CHANGED = 20;
     protected static final int EVENT_ROAMING_ON = 21;
     protected static final int EVENT_ROAMING_OFF = 22;
     protected static final int EVENT_ENABLE_NEW_APN = 23;
     protected static final int EVENT_RESTORE_DEFAULT_APN = 24;
     protected static final int EVENT_DISCONNECT_DONE = 25;
-    protected static final int EVENT_GPRS_ATTACHED = 26;
+    protected static final int EVENT_DATA_CONNECTION_ATTACHED = 26;
     protected static final int EVENT_START_NETSTAT_POLL = 27;
     protected static final int EVENT_START_RECOVERY = 28;
     protected static final int EVENT_APN_CHANGED = 29;
@@ -119,8 +119,8 @@
     protected static final int EVENT_RESTART_RADIO = 36;
     protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = 37;
     protected static final int EVENT_RESET_DONE = 38;
-
     public static final int CMD_SET_DATA_ENABLE = 39;
+    public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = 40;
 
     /***** Constants *****/
 
@@ -130,7 +130,10 @@
     protected static final int APN_SUPL_ID = 2;
     protected static final int APN_DUN_ID = 3;
     protected static final int APN_HIPRI_ID = 4;
-    protected static final int APN_NUM_TYPES = 5;
+    protected static final int APN_IMS_ID = 5;
+    protected static final int APN_FOTA_ID = 6;
+    protected static final int APN_CBS_ID = 7;
+    protected static final int APN_NUM_TYPES = 8;
 
     public static final int DISABLED = 0;
     public static final int ENABLED = 1;
@@ -263,15 +266,8 @@
                 startNetStatPoll();
             } else if (action.equals(getActionIntentReconnectAlarm())) {
                 log("Reconnect alarm. Previous state was " + mState);
+                onActionIntentReconnectAlarm(intent);
 
-                String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-                if (mState == State.FAILED) {
-                    Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
-                    msg.arg1 = 0; // tearDown is false
-                    msg.obj = reason;
-                    sendMessage(msg);
-                }
-                sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
@@ -289,6 +285,18 @@
         }
     };
 
+    protected void onActionIntentReconnectAlarm(Intent intent) {
+        String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
+        if (mState == State.FAILED) {
+            Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
+            msg.arg1 = 0; // tearDown is false
+            msg.arg2 = 0;
+            msg.obj = reason;
+            sendMessage(msg);
+        }
+        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+    }
+
     /**
      * Default constructor
      */
@@ -336,22 +344,10 @@
     }
 
     public State getState() {
+        // TODO: reimplement to use apnType better yet REMOVE.
         return mState;
     }
 
-    public String getStateInString() {
-        switch (mState) {
-            case IDLE:          return "IDLE";
-            case INITING:       return "INIT";
-            case CONNECTING:    return "CING";
-            case SCANNING:      return "SCAN";
-            case CONNECTED:     return "CNTD";
-            case DISCONNECTING: return "DING";
-            case FAILED:        return "FAIL";
-            default:            return "ERRO";
-        }
-    }
-
     /**
      * @return the data connections
      */
@@ -393,7 +389,7 @@
         return result;
     }
 
-    public String getActiveApnType() {
+    private String getActiveApnType() {
         String result;
         if (mActiveApn != null) {
             result = apnIdToType(mActiveApn.id);
@@ -403,7 +399,7 @@
         return result;
     }
 
-    protected String getActiveApnString() {
+    public String getActiveApnString() {
         String result = null;
         if (mActiveApn != null) {
             result = mActiveApn.apn;
@@ -411,17 +407,6 @@
         return result;
     }
 
-    /**
-     * The data connection is expected to be setup while device
-     *  1. has Icc card
-     *  2. registered for data service
-     *  3. user doesn't explicitly disable data service
-     *  4. wifi is not on
-     *
-     * @return false while no data connection if all above requirements are met.
-     */
-    public abstract boolean isDataConnectionAsDesired();
-
     //The data roaming setting is now located in the shared preferences.
     //  See if the requested preference value is the same as that stored in
     //  the shared values.  If it is not, then update it.
@@ -462,7 +447,8 @@
     protected abstract void onResetDone(AsyncResult ar);
     protected abstract void onVoiceCallStarted();
     protected abstract void onVoiceCallEnded();
-    protected abstract void onCleanUpConnection(boolean tearDown, String reason);
+    protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
+    protected abstract void onCleanUpAllConnections();
 
     @Override
     public void handleMessage(Message msg) {
@@ -517,11 +503,15 @@
                 onVoiceCallEnded();
                 break;
 
-            case EVENT_CLEAN_UP_CONNECTION:
-                boolean tearDown = (msg.arg1 == 0) ? false : true;
-                onCleanUpConnection(tearDown, (String) msg.obj);
+            case EVENT_CLEAN_UP_ALL_CONNECTIONS: {
+                onCleanUpAllConnections();
                 break;
-
+            }
+            case EVENT_CLEAN_UP_CONNECTION: {
+                boolean tearDown = (msg.arg1 == 0) ? false : true;
+                onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
+                break;
+            }
             case EVENT_SET_INTERNAL_DATA_ENABLE: {
                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
                 onSetInternalDataEnabled(enabled);
@@ -576,6 +566,12 @@
             return APN_DUN_ID;
         } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
             return APN_HIPRI_ID;
+        } else if (TextUtils.equals(type, Phone.APN_TYPE_IMS)) {
+            return APN_IMS_ID;
+        } else if (TextUtils.equals(type, Phone.APN_TYPE_FOTA)) {
+            return APN_FOTA_ID;
+        } else if (TextUtils.equals(type, Phone.APN_TYPE_CBS)) {
+            return APN_CBS_ID;
         } else {
             return APN_INVALID_ID;
         }
@@ -593,6 +589,12 @@
             return Phone.APN_TYPE_DUN;
         case APN_HIPRI_ID:
             return Phone.APN_TYPE_HIPRI;
+        case APN_IMS_ID:
+            return Phone.APN_TYPE_IMS;
+        case APN_FOTA_ID:
+            return Phone.APN_TYPE_FOTA;
+        case APN_CBS_ID:
+            return Phone.APN_TYPE_CBS;
         default:
             log("Unknown id (" + id + ") in apnIdToType");
             return Phone.APN_TYPE_DEFAULT;
@@ -845,7 +847,7 @@
                 dataEnabled[apnId] = false;
                 enabledCount--;
                 if (enabledCount == 0) {
-                    onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+                    onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
                 }
 
                 // send the disconnect msg manually, since the normal route wont send
@@ -903,7 +905,7 @@
                     mRetryMgr.resetRetryCount();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
-                    onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+                    cleanUpAllConnections();
                 }
             }
         }
@@ -913,6 +915,17 @@
         return mDataEnabled;
     }
 
+    public void cleanUpAllConnections() {
+        Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS);
+        sendMessage(msg);
+    }
+
+    public boolean isAnyActiveDataConnections() {
+        // TODO: Remember if there are any connected or
+        // loop asking each DC/APN?
+        return true;
+    }
+
     protected void onSetDataEnabled(boolean enable) {
         boolean prevEnabled = getAnyDataEnabled();
         if (mDataEnabled != enable) {
@@ -926,7 +939,7 @@
                     mRetryMgr.resetRetryCount();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
-                    onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+                    onCleanUpConnection(true, APN_DEFAULT_ID, Phone.REASON_DATA_DISABLED);
                 }
             }
         }
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index e270ce9..d9c2e9a 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.CommandsInterface.RadioState;
+import android.os.SystemProperties;
 
 /**
  * {@hide}
@@ -85,6 +86,10 @@
     private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
     private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
 
+    // FIXME: remove mot from property
+    static final boolean LTE_AVAILABLE_ON_CDMA =
+        SystemProperties.getBoolean("ro.mot.lte_on_cdma", false);
+
     /*
       UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
       PIN_REQUIRED state, the query for ICC status returns UNKNOWN before it
@@ -426,6 +431,9 @@
             broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
                   INTENT_VALUE_LOCKED_NETWORK);
         }
+        if (oldState != State.READY && newState == State.READY && LTE_AVAILABLE_ON_CDMA) {
+            mPhone.mSIMRecords.onSimReady();
+        }
     }
 
     /**
@@ -612,14 +620,16 @@
             currentRadioState == RadioState.SIM_NOT_READY     ||
             currentRadioState == RadioState.RUIM_NOT_READY    ||
             currentRadioState == RadioState.NV_NOT_READY      ||
-            currentRadioState == RadioState.NV_READY) {
+            (currentRadioState == RadioState.NV_READY && !LTE_AVAILABLE_ON_CDMA)) {
             return IccCard.State.NOT_READY;
         }
 
         if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT  ||
             currentRadioState == RadioState.SIM_READY             ||
             currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
-            currentRadioState == RadioState.RUIM_READY) {
+            currentRadioState == RadioState.RUIM_READY ||
+            (currentRadioState == RadioState.NV_READY && LTE_AVAILABLE_ON_CDMA)) {
+
 
             int index;
 
diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java
index 9f60a6c..4cf21ee 100644
--- a/telephony/java/com/android/internal/telephony/IccCardApplication.java
+++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java
@@ -28,7 +28,8 @@
         APPTYPE_SIM,
         APPTYPE_USIM,
         APPTYPE_RUIM,
-        APPTYPE_CSIM
+        APPTYPE_CSIM,
+        APPTYPE_ISIM
     };
 
     public enum AppState{
@@ -115,6 +116,7 @@
             case 2: newType = AppType.APPTYPE_USIM;    break;
             case 3: newType = AppType.APPTYPE_RUIM;    break;
             case 4: newType = AppType.APPTYPE_CSIM;    break;
+            case 5: newType = AppType.APPTYPE_ISIM;    break;
             default:
                 throw new RuntimeException(
                             "Unrecognized RIL_AppType: " +type);
diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java
index b12d2d4..b40f945 100644
--- a/telephony/java/com/android/internal/telephony/IccConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccConstants.java
@@ -58,6 +58,13 @@
     static final int EF_CST = 0x6f32;
     static final int EF_RUIM_SPN =0x6F41;
 
+    //ISIM access
+    static final int EF_IMPU = 0x6f04;
+    static final int EF_IMPI = 0x6f02;
+    static final int EF_DOMAIN = 0x6f03;
+    static final int EF_IST = 0x6f07;
+    static final int EF_PCSCF = 0x6f09;
+
     // SMS record length from TS 51.011 10.5.3
     static public final int SMS_RECORD_LENGTH = 176;
 
@@ -67,4 +74,7 @@
     static final String DF_GRAPHICS = "5F50";
     static final String DF_GSM = "7F20";
     static final String DF_CDMA = "7F25";
+
+    //ISIM access
+    static final String DF_ADFISIM = "7FFF";
 }
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index acb86d4..7450047 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -125,6 +125,12 @@
     static final String APN_TYPE_DUN = "dun";
     /** APN type for HiPri traffic */
     static final String APN_TYPE_HIPRI = "hipri";
+    /** APN type for FOTA */
+    static final String APN_TYPE_FOTA = "fota";
+    /** APN type for IMS */
+    static final String APN_TYPE_IMS = "ims";
+    /** APN type for CBS */
+    static final String APN_TYPE_CBS = "cbs";
 
     // "Features" accessible through the connectivity manager
     static final String FEATURE_ENABLE_MMS = "enableMMS";
@@ -132,6 +138,9 @@
     static final String FEATURE_ENABLE_DUN = "enableDUN";
     static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
     static final String FEATURE_ENABLE_DUN_ALWAYS = "enableDUNAlways";
+    static final String FEATURE_ENABLE_FOTA = "enableFOTA";
+    static final String FEATURE_ENABLE_IMS = "enableIMS";
+    static final String FEATURE_ENABLE_CBS = "enableCBS";
 
     /**
      * Return codes for <code>enableApnType()</code>
@@ -140,6 +149,7 @@
     static final int APN_REQUEST_STARTED    = 1;
     static final int APN_TYPE_NOT_AVAILABLE = 2;
     static final int APN_REQUEST_FAILED     = 3;
+    static final int APN_ALREADY_INACTIVE   = 4;
 
 
     /**
@@ -164,6 +174,7 @@
     static final String REASON_PS_RESTRICT_ENABLED = "psRestrictEnabled";
     static final String REASON_PS_RESTRICT_DISABLED = "psRestrictDisabled";
     static final String REASON_SIM_LOADED = "simLoaded";
+    static final String REASON_NW_TYPE_CHANGED = "nwTypeChanged";
 
     // Used for band mode selection methods
     static final int BM_UNSPECIFIED = 0; // selected by baseband automatically
@@ -193,6 +204,7 @@
     int NT_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
     int NT_MODE_GLOBAL       = RILConstants.NETWORK_MODE_GLOBAL;
 
+    int NT_MODE_LTE_ONLY     = RILConstants.NETWORK_MODE_LTE_ONLY;
     int PREFERRED_NT_MODE    = RILConstants.PREFERRED_NETWORK_MODE;
 
 
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 54341b1..5408ce9 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -38,6 +38,8 @@
 
 import com.android.internal.R;
 import com.android.internal.telephony.test.SimulatedRadioControl;
+import com.android.internal.telephony.gsm.SIMRecords;
+import com.android.internal.telephony.gsm.SimCard;
 
 import java.util.Locale;
 
@@ -116,6 +118,9 @@
     int mCallRingDelay;
     public boolean mIsTheCurrentActivePhone = true;
     boolean mIsVoiceCapable = true;
+    public SIMRecords mSIMRecords;
+    public SimCard mSimCard;
+    public SMSDispatcher mSMS;
 
     /**
      * Set a system property, unless we're in unit test mode
@@ -237,7 +242,8 @@
     public void dispose() {
         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
             mCM.unSetOnCallRing(this);
-            mDataConnection.onCleanUpConnection(false, REASON_RADIO_TURNED_OFF);
+            // Must cleanup all connectionS and needs to use sendMessage!
+            mDataConnection.cleanUpAllConnections();
             mIsTheCurrentActivePhone = false;
         }
     }
@@ -662,6 +668,20 @@
     }
 
     /**
+    * Retrieves the ServiceStateTracker of the phone instance.
+    */
+    public ServiceStateTracker getServiceStateTracker() {
+        return null;
+    }
+
+    /**
+    * Get call tracker
+    */
+    public CallTracker getCallTracker() {
+        return null;
+    }
+
+    /**
      *  Query the status of the CDMA roaming preference
      */
     public void queryCdmaRoamingPreference(Message response) {
@@ -1080,4 +1100,14 @@
         Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
                 "called, GSMPhone inactive.");
     }
+
+    // Called by SimRecords which is constructed with a PhoneBase instead of a GSMPhone.
+    public void notifyCallForwardingIndicator() {
+        // This function should be overridden by the class GSMPhone. Not implemented in CDMAPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public void notifyDataConnectionFailed(String reason, String apnType) {
+        mNotifier.notifyDataConnectionFailed(this, reason, apnType);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java
index 2e391cb..c25a53d 100644
--- a/telephony/java/com/android/internal/telephony/PhoneFactory.java
+++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java
@@ -21,8 +21,10 @@
 import android.os.Looper;
 import android.provider.Settings;
 import android.util.Log;
+import android.os.SystemProperties;
 
 import com.android.internal.telephony.cdma.CDMAPhone;
+import com.android.internal.telephony.cdma.CDMALTEPhone;
 import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.sip.SipPhone;
 import com.android.internal.telephony.sip.SipPhoneFactory;
@@ -34,6 +36,9 @@
     static final String LOG_TAG = "PHONE";
     static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000;
     static final int SOCKET_OPEN_MAX_RETRY = 3;
+    static final boolean LTE_AVAILABLE_ON_CDMA =
+        SystemProperties.getBoolean("ro.mot.lte_on_cdma", false);
+
     //***** Class Variables
 
     static private Phone sProxyPhone = null;
@@ -115,9 +120,15 @@
                     sProxyPhone = new PhoneProxy(new GSMPhone(context,
                             sCommandsInterface, sPhoneNotifier));
                 } else if (phoneType == Phone.PHONE_TYPE_CDMA) {
-                    Log.i(LOG_TAG, "Creating CDMAPhone");
-                    sProxyPhone = new PhoneProxy(new CDMAPhone(context,
-                            sCommandsInterface, sPhoneNotifier));
+                    if (LTE_AVAILABLE_ON_CDMA == false ) {
+                        Log.i(LOG_TAG, "Creating CDMAPhone");
+                        sProxyPhone = new PhoneProxy(new CDMAPhone(context,
+                                sCommandsInterface, sPhoneNotifier));
+                    } else {
+                        Log.i(LOG_TAG, "Creating CDMALTEPhone");
+                        sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,
+                                sCommandsInterface, sPhoneNotifier));
+                    }
                 }
 
                 sMadeDefaults = true;
@@ -147,6 +158,13 @@
 
         case RILConstants.NETWORK_MODE_GLOBAL:
             return Phone.PHONE_TYPE_CDMA;
+
+        case RILConstants.NETWORK_MODE_LTE_ONLY:
+            if (SystemProperties.getBoolean("ro.mot.lte_on_cdma", false)) {
+                return Phone.PHONE_TYPE_CDMA;
+            } else {
+                return Phone.PHONE_TYPE_GSM;
+            }
         default:
             return Phone.PHONE_TYPE_GSM;
         }
@@ -166,8 +184,13 @@
 
     public static Phone getCdmaPhone() {
         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
-            Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier);
-            return phone;
+            if (LTE_AVAILABLE_ON_CDMA == false) {
+                Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier);
+                return phone;
+            } else {
+                Phone phone = new CDMALTEPhone(sContext, sCommandsInterface, sPhoneNotifier);
+                return phone;
+            }
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 15b23bb..49497b4 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -741,6 +741,10 @@
          return mActivePhone.getCdmaEriIconMode();
     }
 
+    public Phone getActivePhone() {
+         return mActivePhone;
+    }
+
     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete){
         mActivePhone.sendBurstDtmf(dtmfString, on, off, onComplete);
     }
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 804ace4..1d194d0 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -638,6 +638,13 @@
             case RILConstants.NETWORK_MODE_GLOBAL:
                 mPhoneType = RILConstants.CDMA_PHONE;
                 break;
+            case RILConstants.NETWORK_MODE_LTE_ONLY:
+                if (SystemProperties.getBoolean("ro.mot.lte_on_cdma", false)) {
+                    mPhoneType = RILConstants.CDMA_PHONE;
+                } else {
+                    mPhoneType = RILConstants.GSM_PHONE;
+                }
+                break;
             default:
                 mPhoneType = RILConstants.CDMA_PHONE;
         }
@@ -2064,6 +2071,14 @@
                  */
                 if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
                 setRadioPower(false, null);
+                // MultimodeRIL needs to know the preferred network at power up.
+                RILRequest rrPnt = RILRequest.obtain(
+                                   RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, null);
+                rrPnt.mp.writeInt(1);
+                rrPnt.mp.writeInt(mNetworkMode);
+                if (RILJ_LOGD) riljLog(rrPnt.serialString() + "> "
+                        + requestToString(rrPnt.mRequest) + " : " + mNetworkMode);
+                send(rrPnt);
             } else {
                 if (DBG) Log.d(LOG_TAG, "Radio OFF @ init");
                 setRadioState(newState);
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index cdf1977..8c9fb79 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -66,6 +66,8 @@
     int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */
     int NETWORK_MODE_GLOBAL         = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL)
                                             AVAILABLE Application Settings menu*/
+    int NETWORK_MODE_LTE_ONLY       = 8; /* LTE Only mode. Used only for testing purposes.Not
+                                            user selectable from regular UI */
     int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;
 
     /* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */
@@ -138,10 +140,12 @@
     int RIL_RESTRICTED_STATE_PS_ALL = 0x10;
 
     /** Data profile for RIL_REQUEST_SETUP_DATA_CALL */
-    static final int DATA_PROFILE_DEFAULT   = 0;
-    static final int DATA_PROFILE_TETHERED  = 1;
-    static final int DATA_PROFILE_OEM_BASE  = 1000;
-
+    public static final int DATA_PROFILE_DEFAULT   = 0;
+    public static final int DATA_PROFILE_TETHERED  = 1;
+    public static final int DATA_PROFILE_IMS       = 2;
+    public static final int DATA_PROFILE_FOTA      = 3;
+    public static final int DATA_PROFILE_CBS       = 4;
+    public static final int DATA_PROFILE_OEM_BASE  = 1000;
 
     int RIL_REQUEST_GET_SIM_STATUS = 1;
     int RIL_REQUEST_ENTER_SIM_PIN = 2;
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index befee8c..6af9b1c 100755
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -582,7 +582,7 @@
      *         {@link Activity#RESULT_OK} if the message has been broadcast
      *         to applications
      */
-    protected abstract int dispatchMessage(SmsMessageBase sms);
+    public abstract int dispatchMessage(SmsMessageBase sms);
 
 
     /**
@@ -916,7 +916,7 @@
      * @param response
      *            Callback message is empty on completion
      */
-    protected abstract void activateCellBroadcastSms(int activate, Message response);
+    public abstract void activateCellBroadcastSms(int activate, Message response);
 
     /**
      * Query the current configuration of cell broadcast SMS.
@@ -925,7 +925,7 @@
      *            Callback message contains the configuration from the modem on completion
      *            @see #setCellBroadcastConfig
      */
-    protected abstract void getCellBroadcastSmsConfig(Message response);
+    public abstract void getCellBroadcastSmsConfig(Message response);
 
     /**
      * Configure cell broadcast SMS.
@@ -937,7 +937,7 @@
      * @param response
      *            Callback message is empty on completion
      */
-    protected abstract void setCellBroadcastConfig(int[] configValuesArray, Message response);
+    public abstract void setCellBroadcastConfig(int[] configValuesArray, Message response);
 
     /**
      * Send an acknowledge message.
@@ -1006,6 +1006,27 @@
         return new SmsTracker(data, sentIntent, deliveryIntent);
     }
 
+    public void initSipStack(boolean isObg) {
+        // This function should be overridden by the classes that support
+        // switching modes such as the CdmaSMSDispatcher.
+        // Not implemented in GsmSMSDispatcher.
+        Log.e(TAG, "Error! This function should never be executed.");
+    }
+
+    public void switchToCdma() {
+        // This function should be overridden by the classes that support
+        // switching modes such as the CdmaSMSDispatcher.
+        // Not implemented in GsmSMSDispatcher.
+        Log.e(TAG, "Error! This function should never be executed.");
+    }
+
+    public void switchToGsm() {
+        // This function should be overridden by the classes that support
+        // switching modes such as the CdmaSMSDispatcher.
+        // Not implemented in GsmSMSDispatcher.
+        Log.e(TAG, "Error! This function should never be executed.");
+    }
+
     private DialogInterface.OnClickListener mListener =
         new DialogInterface.OnClickListener() {
 
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 3f9ffc3..0acbfe3 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -45,6 +45,8 @@
     protected static final int DATA_ACCESS_HSUPA = 10;
     protected static final int DATA_ACCESS_HSPA = 11;
     protected static final int DATA_ACCESS_CDMA_EvDo_B = 12;
+    protected static final int DATA_ACCESS_LTE = 13;
+    protected static final int DATA_ACCESS_EHRPD = 14;
 
     protected CommandsInterface cm;
 
@@ -280,12 +282,51 @@
     protected abstract void setPowerStateToDesired();
     protected abstract void log(String s);
 
+    private void logUnexpectedGsmMethodCall(String name) {
+        log("SSST" + "Error! " + name + "() in ServiceStateTracker should not be " +
+        "called, GsmServiceStateTracker inactive.");
+    }
+
+    public abstract int getCurrentDataConnectionState();
+    public abstract boolean isConcurrentVoiceAndDataAllowed();
+    public void registerForDataConnectionAttached(Handler h, int what, Object obj) {
+        logUnexpectedGsmMethodCall("registerForDataConnectionAttached");
+    }
+
+    public void unregisterForDataConnectionAttached(Handler h) {
+        logUnexpectedGsmMethodCall("unregisterForDataConnectionAttached");
+    }
+
+    public void registerForDataConnectionDetached(Handler h, int what, Object obj) {
+        logUnexpectedGsmMethodCall("registerForDataConnectionDetached");
+    }
+
+    public void unregisterForDataConnectionDetached(Handler h) {
+        logUnexpectedGsmMethodCall("unregisterForDataConnectionDetached");
+    }
+
+    public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
+        logUnexpectedGsmMethodCall("registerForPsRestrictedEnabled");
+    }
+
+    public void unregisterForPsRestrictedEnabled(Handler h) {
+        logUnexpectedGsmMethodCall("unregisterForPsRestrictedEnabled");
+    }
+
+    public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
+        logUnexpectedGsmMethodCall("registerForPsRestrictedDisabled");
+    }
+
+    public void unregisterForPsRestrictedDisabled(Handler h) {
+        logUnexpectedGsmMethodCall("registerForPsRestrictedDisabled");
+    }
+
     /**
      * Clean up existing voice and data connection then turn off radio power.
      *
      * Hang up the existing voice calls to decrease call drop rate.
      */
-    protected abstract void powerOffRadioSafely();
+    public abstract void powerOffRadioSafely();
 
     /** Cancel a pending (if any) pollState() operation */
     protected void cancelPollState() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
new file mode 100644
index 0000000..300670f
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2006 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 com.android.internal.telephony.cdma;
+
+import android.os.SystemProperties;
+import android.content.Context;
+import android.net.Uri;
+import android.content.Context;
+import android.provider.Telephony;
+import android.content.ContentValues;
+import android.database.SQLException;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+
+import com.android.internal.telephony.gsm.SIMRecords;
+import com.android.internal.telephony.gsm.SimCard;
+import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.DataConnectionTracker;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.PhoneNotifier;
+import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
+
+import android.util.Log;
+
+public class CDMALTEPhone extends CDMAPhone {
+    static final String LOG_TAG = "CDMA";
+
+    private static final boolean DBG = true;
+
+    // Constructors
+    public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
+        this(context, ci, notifier, false);
+        log("CDMALTEPhone Constructors");
+    }
+
+    public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
+            boolean unitTestMode) {
+        super(context, ci, notifier, false);
+        mSST = new CdmaLteServiceStateTracker(this);
+        init(context, notifier);
+
+        mSIMRecords = new SIMRecords(this);
+        mSimCard = new SimCard(this, LOG_TAG, DBG);
+    }
+
+    public void dispose() {
+        synchronized (PhoneProxy.lockForRadioTechnologyChange) {
+            super.dispose();
+            mSIMRecords.dispose();
+            mSimCard.dispose();
+        }
+    }
+
+    @Override
+    public void removeReferences() {
+        super.removeReferences();
+        this.mSIMRecords = null;
+        this.mSimCard = null;
+    }
+
+    @Override
+    public ServiceStateTracker getServiceStateTracker() {
+        return mSST;
+    }
+
+    public IccCard getIccCard() {
+        return mSimCard;
+    }
+
+    @Override
+    public String getIccSerialNumber() {
+        return mSIMRecords.iccid;
+    }
+
+    @Override
+    public DataState getDataConnectionState(String apnType) {
+        boolean isCdmaDataConnectionTracker = false;
+        if (mDataConnection instanceof CdmaDataConnectionTracker) {
+            isCdmaDataConnectionTracker = true;
+        }
+        log("getDataConnectionState");
+        DataState ret = DataState.DISCONNECTED;
+
+        if (!isCdmaDataConnectionTracker && (SystemProperties.get("adb.connected", "").length()
+                > 0)) {
+            // We're connected to an ADB host and we have USB networking
+            // turned on. No matter what the radio state is,
+            // we report data connected
+
+            ret = DataState.CONNECTED;
+        } else if (mSST == null) {
+            // Radio Technology Change is ongoning, dispose() and
+            // removeReferences() have
+            // already been called
+
+            ret = DataState.DISCONNECTED;
+        } else if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
+            // If we're out of service, open TCP sockets may still work
+            // but no data will flow
+            ret = DataState.DISCONNECTED;
+        } else if (mDataConnection.isApnTypeEnabled(apnType) == false) {
+            ret = DataState.DISCONNECTED;
+        } else {
+            DataConnectionTracker.State state;
+            if (isCdmaDataConnectionTracker) {
+                state = mDataConnection.getState();
+            } else {
+                state = ((GsmDataConnectionTracker)mDataConnection).getState(apnType);
+            }
+            switch (state) {
+                case FAILED:
+                case IDLE:
+                    ret = DataState.DISCONNECTED;
+                    break;
+
+                case CONNECTED:
+                case DISCONNECTING:
+                    if (mCT.state != Phone.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed()) {
+                        ret = DataState.SUSPENDED;
+                    } else {
+                        ret = DataState.CONNECTED;
+                    }
+                    break;
+
+                case INITING:
+                case CONNECTING:
+                case SCANNING:
+                    ret = DataState.CONNECTING;
+                    break;
+            }
+        }
+
+        return ret;
+    }
+
+    public boolean updateCurrentCarrierInProvider() {
+        if (mSIMRecords != null) {
+            try {
+                Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
+                ContentValues map = new ContentValues();
+                map.put(Telephony.Carriers.NUMERIC, mSIMRecords.getSIMOperatorNumeric());
+                mContext.getContentResolver().insert(uri, map);
+                return true;
+            } catch (SQLException e) {
+                Log.e(LOG_TAG, "[CDMALTEPhone] Can't store current operator", e);
+            }
+        }
+        return false;
+    }
+
+    public String getActiveApn(String apnType) {
+        if (mDataConnection instanceof CdmaDataConnectionTracker)
+            return mDataConnection.getActiveApnString();
+
+        return ((GsmDataConnectionTracker)mDataConnection).getActiveApnString(apnType);
+    }
+
+    protected void log(String s) {
+        if (DBG)
+            Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 74adebd..2c7243e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -66,6 +66,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.CallTracker;
 
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
@@ -97,7 +98,6 @@
 
     // Instance Variables
     CdmaCallTracker mCT;
-    CdmaSMSDispatcher mSMS;
     CdmaServiceStateTracker mSST;
     RuimRecords mRuimRecords;
     RuimCard mRuimCard;
@@ -141,16 +141,21 @@
 
     // Constructors
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
-        this(context,ci,notifier, false);
+        super(notifier, context, ci, false);
+        mSST = new CdmaServiceStateTracker (this);
+        init(context, notifier);
     }
 
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
             boolean unitTestMode) {
         super(notifier, context, ci, unitTestMode);
+        mSST = new CdmaServiceStateTracker (this);
+        init(context, notifier);
+    }
 
+    protected void init(Context context, PhoneNotifier notifier) {
         mCM.setPhoneType(Phone.PHONE_TYPE_CDMA);
         mCT = new CdmaCallTracker(this);
-        mSST = new CdmaServiceStateTracker (this);
         mSMS = new CdmaSMSDispatcher(this);
         mIccFileHandler = new RuimFileHandler(this);
         mRuimRecords = new RuimRecords(this);
@@ -270,10 +275,18 @@
         return mSST.ss;
     }
 
+    public CallTracker getCallTracker() {
+        return mCT;
+    }
+
     public Phone.State getState() {
         return mCT.state;
     }
 
+    public ServiceStateTracker getServiceStateTracker() {
+        return mSST;
+    }
+
     public String getPhoneName() {
         return "CDMA";
     }
@@ -625,7 +638,7 @@
                 case CONNECTED:
                 case DISCONNECTING:
                     if ( mCT.state != Phone.State.IDLE
-                            && !mSST.isConcurrentVoiceAndData()) {
+                            && !mSST.isConcurrentVoiceAndDataAllowed()) {
                         ret = DataState.SUSPENDED;
                     } else {
                         ret = DataState.CONNECTED;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index a89f783..79f4152 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -134,6 +134,10 @@
     public void registerForVoiceCallStarted(Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
         voiceCallStartedRegistrants.add(r);
+        // Notify if in call when registering
+        if (state != Phone.State.IDLE) {
+            r.notifyRegistrant(new AsyncResult(null, null, null));
+        }
     }
     public void unregisterForVoiceCallStarted(Handler h) {
         voiceCallStartedRegistrants.remove(h);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index fbe455e..1a15393 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -430,7 +430,7 @@
                 } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
                         || serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
                     return DisconnectCause.OUT_OF_SERVICE;
-                } else if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY
+                } else if (phone.mCM.getNvState() != CommandsInterface.RadioState.NV_READY
                         && phone.getIccCard().getState() != RuimCard.State.READY) {
                     return DisconnectCause.ICC_ERROR;
                 } else if (causeCode==CallFailCause.NORMAL_CLEARING) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 8c36106..8307a48 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -167,30 +167,6 @@
         return false;
     }
 
-    /**
-     * The data connection is expected to be setup while device
-     *  1. has ruim card or non-volatile data store
-     *  2. registered to data connection service
-     *  3. user doesn't explicitly disable data service
-     *  4. wifi is not on
-     *
-     * @return false while no data connection if all above requirements are met.
-     */
-    @Override
-    public boolean isDataConnectionAsDesired() {
-        boolean roaming = mPhone.getServiceState().getRoaming();
-
-        if (((mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) ||
-                 mCdmaPhone.mRuimRecords.getRecordsLoaded()) &&
-                (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() ==
-                 ServiceState.STATE_IN_SERVICE) &&
-                (!roaming || getDataOnRoamingEnabled()) &&
-                !mIsWifiConnected ) {
-            return (mState == State.CONNECTED);
-        }
-        return true;
-    }
-
     @Override
     protected boolean isDataAllowed() {
         int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState();
@@ -200,9 +176,9 @@
         boolean allowed =
                     (psState == ServiceState.STATE_IN_SERVICE ||
                             mAutoAttachOnCreation) &&
-                    (mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY ||
+                    (mPhone.mCM.getNvState() == CommandsInterface.RadioState.NV_READY ||
                             mCdmaPhone.mRuimRecords.getRecordsLoaded()) &&
-                    (mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
+                    (mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
                             mPhone.getState() == Phone.State.IDLE) &&
                     !roaming &&
                     mInternalDataEnabled &&
@@ -214,11 +190,11 @@
             if (!((psState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
                 reason += " - psState= " + psState;
             }
-            if (!(mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY ||
+            if (!(mPhone.mCM.getNvState() == CommandsInterface.RadioState.NV_READY ||
                     mCdmaPhone.mRuimRecords.getRecordsLoaded())) {
-                reason += " - radioState= " + mPhone.mCM.getRadioState() + " - RUIM not loaded";
+                reason += " - radioState= " + mPhone.mCM.getNvState() + " - RUIM not loaded";
             }
-            if (!(mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
+            if (!(mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
                     mPhone.getState() == Phone.State.IDLE)) {
                 reason += " - concurrentVoiceAndData not allowed and state= " + mPhone.getState();
             }
@@ -262,9 +238,7 @@
     }
 
     /**
-     * Cleanup all connections.
-     *
-     * TODO: Cleanup only a specified connection passed as a parameter.
+     * Cleanup the CDMA data connection (only one is supported)
      *
      * @param tearDown true if the underlying DataConnection should be disconnected.
      * @param reason for the clean up.
@@ -337,7 +311,7 @@
             apnId = mDefaultApnId;
         }
         mActiveApn = new ApnSetting(apnId, "", "", "", "", "", "", "", "", "",
-                                    "", 0, types, "IP", "IP");
+                                    "", 0, types, "IP", "IP", true, 0, 0);
         if (DBG) log("setupData: mActiveApn=" + mActiveApn);
 
         Message msg = obtainMessage();
@@ -386,7 +360,7 @@
     protected void restartRadio() {
         if (DBG) log("Cleanup connection and wait " +
                 (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio");
-        cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
+        cleanUpAllConnections();
         sendEmptyMessageDelayed(EVENT_RESTART_RADIO, TIME_DELAYED_TO_RESTART_RADIO);
         mPendingRestartRadio = true;
     }
@@ -543,14 +517,14 @@
 
     protected void onRecordsLoaded() {
         if (mState == State.FAILED) {
-            cleanUpConnection(false, null);
+            cleanUpAllConnections();
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onNVReady() {
         if (mState == State.FAILED) {
-            cleanUpConnection(false, null);
+            cleanUpAllConnections();
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
     }
@@ -560,6 +534,7 @@
      */
     @Override
     protected void onEnableNewApn() {
+        // No mRequestedApnType check; only one connection is supported
         cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
     }
 
@@ -588,7 +563,7 @@
             trySetupData(Phone.REASON_ROAMING_ON);
         } else {
             if (DBG) log("Tear down data connection on roaming.");
-            cleanUpConnection(true, Phone.REASON_ROAMING_ON);
+            cleanUpAllConnections();
         }
     }
 
@@ -609,7 +584,7 @@
         notifyDataAvailability(null);
 
         if (mState != State.IDLE) {
-            cleanUpConnection(true, null);
+            cleanUpAllConnections();
         }
     }
 
@@ -626,7 +601,7 @@
             log("We're on the simulator; assuming radio off is meaningless");
         } else {
             if (DBG) log("Radio is off and clean up all connection");
-            cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF);
+            cleanUpAllConnections();
         }
     }
 
@@ -711,7 +686,7 @@
      */
     @Override
     protected void onVoiceCallStarted() {
-        if (mState == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) {
+        if (mState == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed()) {
             stopNetStatPoll();
             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
             notifyDataAvailability(Phone.REASON_VOICE_CALL_STARTED);
@@ -724,7 +699,7 @@
     @Override
     protected void onVoiceCallEnded() {
         if (mState == State.CONNECTED) {
-            if (!mCdmaPhone.mSST.isConcurrentVoiceAndData()) {
+            if (!mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed()) {
                 startNetStatPoll();
                 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
             } else {
@@ -740,10 +715,17 @@
     }
 
     @Override
-    protected void onCleanUpConnection(boolean tearDown, String reason) {
+    protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
+        // No apnId check; only one connection is supported
         cleanUpConnection(tearDown, reason);
     }
 
+    @Override
+    protected void onCleanUpAllConnections() {
+        // Only one CDMA connection is supported
+        cleanUpConnection(true, null);
+    }
+
     private void createAllDataConnectionList() {
         CdmaDataConnection dataConn;
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
new file mode 100644
index 0000000..5883555
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2008 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 com.android.internal.telephony.cdma;
+
+import com.android.internal.telephony.DataConnectionTracker;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.RILConstants;
+
+import android.telephony.SignalStrength;
+import android.telephony.ServiceState;
+import android.telephony.cdma.CdmaCellLocation;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.os.AsyncResult;
+import android.os.Message;
+
+import android.util.Log;
+import android.util.EventLog;
+
+import com.android.internal.telephony.gsm.RestrictedState;
+import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
+
+public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
+    static final String LOG_TAG = "CDMA";
+
+    CDMALTEPhone mCdmaLtePhone;
+
+    private RestrictedState rs;
+
+    private int gprsState = ServiceState.STATE_OUT_OF_SERVICE;
+
+    private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE;
+
+    private RegistrantList gprsAttachedRegistrants = new RegistrantList();
+
+    private RegistrantList gprsDetachedRegistrants = new RegistrantList();
+
+    private RegistrantList psRestrictEnabledRegistrants = new RegistrantList();
+
+    private RegistrantList psRestrictDisabledRegistrants = new RegistrantList();
+
+    public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
+        super(phone);
+        mCdmaLtePhone = phone;
+        rs = new RestrictedState();
+        log("CdmaLteServiceStateTracker Constructors");
+    }
+
+    // Added 9 new functions needed in GsmDataConnectionTracker, functions were
+    // copied over from GsmServiceStateTracker.
+    /**
+     * Registration point for transition into GPRS attached.
+     *
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForDataConnectionAttached(Handler h, int what, Object obj) {
+        log("registerForDataConnectionAttached ");
+        Registrant r = new Registrant(h, what, obj);
+        gprsAttachedRegistrants.add(r);
+
+        if (gprsState == ServiceState.STATE_IN_SERVICE) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForDataConnectionAttached(Handler h) {
+        gprsAttachedRegistrants.remove(h);
+    }
+
+    /**
+     * Registration point for transition into GPRS detached.
+     *
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForDataConnectionDetached(Handler h, int what, Object obj) {
+        log("registerForDataConnectionDetached ");
+        Registrant r = new Registrant(h, what, obj);
+        gprsDetachedRegistrants.add(r);
+        if (gprsState == ServiceState.STATE_OUT_OF_SERVICE) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForDataConnectionDetached(Handler h) {
+        gprsDetachedRegistrants.remove(h);
+    }
+
+    /**
+     * Registration point for transition into packet service restricted zone.
+     *
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
+        log("registerForPsRestrictedEnabled ");
+        Registrant r = new Registrant(h, what, obj);
+        psRestrictEnabledRegistrants.add(r);
+
+        if (rs.isPsRestricted()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForPsRestrictedEnabled(Handler h) {
+        psRestrictEnabledRegistrants.remove(h);
+    }
+
+    /**
+     * Registration point for transition out of packet service restricted zone.
+     *
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
+        log("registerForPsRestrictedDisabled ");
+        Registrant r = new Registrant(h, what, obj);
+        psRestrictDisabledRegistrants.add(r);
+
+        if (rs.isPsRestricted()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForPsRestrictedDisabled(Handler h) {
+        psRestrictDisabledRegistrants.remove(h);
+    }
+
+    /**
+     * @return The current GPRS state. IN_SERVICE is the same as "attached" and
+     *         OUT_OF_SERVICE is the same as detached.
+     */
+    public int getCurrentDataConnectionState() {
+        return gprsState;
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        AsyncResult ar;
+        int[] ints;
+        String[] strings;
+        if (msg.what == EVENT_POLL_STATE_GPRS) {
+            log("handleMessage EVENT_POLL_STATE_GPRS");
+            ar = (AsyncResult)msg.obj;
+            handlePollStateResult(msg.what, ar);
+        } else {
+            super.handleMessage(msg);
+        }
+    }
+
+    /**
+     * The LTE data connection state, only return true here
+     */
+    @Override
+    protected boolean checkAdditionalDataAvaiable() {
+        return newGPRSState != ServiceState.STATE_IN_SERVICE;
+    }
+
+    /**
+     * Handle the result of one of the pollState()-related requests
+     */
+    @Override
+    protected void handlePollStateResultMessage(int what, AsyncResult ar) {
+        if (what == EVENT_POLL_STATE_GPRS) {
+            log("handlePollStateResultMessage EVENT_POLL_STATE_GPRS");
+            String states[] = (String[])ar.result;
+
+            int type = 0;
+            int regState = -1;
+            if (states.length > 0) {
+                try {
+                    regState = Integer.parseInt(states[0]);
+
+                    // states[3] (if present) is the current radio technology
+                    if (states.length >= 4 && states[3] != null) {
+                        type = Integer.parseInt(states[3]);
+                    }
+                } catch (NumberFormatException ex) {
+                    Log.w(LOG_TAG,
+                            "[CdmaLteServiceStateTracker] error parsing GprsRegistrationState: "
+                                    + ex);
+                }
+            }
+
+            newGPRSState = regCodeToServiceState(regState);
+            // Not sure if this is needed in CDMALTE phone.
+            // mDataRoaming = regCodeIsRoaming(regState);
+            if (newGPRSState == ServiceState.STATE_IN_SERVICE) {
+                this.newCdmaDataConnectionState = newGPRSState;
+                newNetworkType = type;
+                newSS.setRadioTechnology(type);
+            }
+        } else {
+            super.handlePollStateResultMessage(what, ar);
+        }
+    }
+
+    @Override
+    protected void setSignalStrengthDefaultValues() {
+        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false);
+    }
+
+    @Override
+    protected void pollState() {
+        pollingContext = new int[1];
+        pollingContext[0] = 0;
+
+        switch (cm.getRadioState()) {
+            case RADIO_UNAVAILABLE:
+                newSS.setStateOutOfService();
+                newCellLoc.setStateInvalid();
+                setSignalStrengthDefaultValues();
+                mGotCountryCode = false;
+
+                pollStateDone();
+                break;
+
+            case RADIO_OFF:
+                newSS.setStateOff();
+                newCellLoc.setStateInvalid();
+                setSignalStrengthDefaultValues();
+                mGotCountryCode = false;
+
+                pollStateDone();
+                break;
+
+            case SIM_NOT_READY:
+            case SIM_LOCKED_OR_ABSENT:
+            case SIM_READY:
+                log("Radio Technology Change ongoing, setting SS to off");
+                newSS.setStateOff();
+                newCellLoc.setStateInvalid();
+                setSignalStrengthDefaultValues();
+                mGotCountryCode = false;
+                // NOTE: pollStateDone() is not needed in this case
+                break;
+
+            default:
+                // Issue all poll-related commands at once, then count
+                // down the responses which are allowed to arrive
+                // out-of-order.
+
+                pollingContext[0]++;
+                // RIL_REQUEST_OPERATOR is necessary for CDMA
+                cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
+
+                pollingContext[0]++;
+                // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA
+                cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA,
+                        pollingContext));
+
+                int networkMode = android.provider.Settings.Secure.getInt(phone.getContext()
+                        .getContentResolver(),
+                        android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+                        RILConstants.PREFERRED_NETWORK_MODE);
+                Log.v(LOG_TAG, "[CdmaLteServiceStateTracker] The network mode here is = "
+                        + networkMode);
+                if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL)
+                        || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) {
+                    pollingContext[0]++;
+                    // RIL_REQUEST_DATA_REGISTRATION_STATE
+                    cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS,
+                                                pollingContext));
+                }
+                break;
+        }
+    }
+
+    protected static String networkTypeToString(int type) {
+        String ret = "unknown";
+
+        switch (type) {
+            case DATA_ACCESS_CDMA_IS95A:
+            case DATA_ACCESS_CDMA_IS95B:
+                ret = "CDMA";
+                break;
+            case DATA_ACCESS_CDMA_1xRTT:
+                ret = "CDMA - 1xRTT";
+                break;
+            case DATA_ACCESS_CDMA_EvDo_0:
+                ret = "CDMA - EvDo rev. 0";
+                break;
+            case DATA_ACCESS_CDMA_EvDo_A:
+                ret = "CDMA - EvDo rev. A";
+                break;
+            case DATA_ACCESS_CDMA_EvDo_B:
+                ret = "CDMA - EvDo rev. B";
+                break;
+            case DATA_ACCESS_LTE:
+                ret = "LTE";
+                break;
+            case DATA_ACCESS_EHRPD:
+                ret = "CDMA - eHRPD";
+            default:
+                if (DBG) {
+                    Log.e(LOG_TAG, " [CdmaLteServiceStateTracker] Wrong network."
+                           + " Can not return a string.");
+                }
+                break;
+        }
+        return ret;
+    }
+
+    @Override
+    protected void pollStateDone() {
+        log("Poll ServiceState done: oldSS=[" + ss + "] newSS=[" + newSS + "]");
+
+        boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE
+                && newSS.getState() == ServiceState.STATE_IN_SERVICE;
+
+        boolean hasDeregistered = ss.getState() == ServiceState.STATE_IN_SERVICE
+                && newSS.getState() != ServiceState.STATE_IN_SERVICE;
+
+        boolean hasCdmaDataConnectionAttached =
+            this.cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE
+                && this.newCdmaDataConnectionState == ServiceState.STATE_IN_SERVICE;
+
+        boolean hasCdmaDataConnectionDetached =
+            this.cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE
+                && this.newCdmaDataConnectionState != ServiceState.STATE_IN_SERVICE;
+
+        boolean hasCdmaDataConnectionChanged =
+            cdmaDataConnectionState != newCdmaDataConnectionState;
+
+        boolean hasNetworkTypeChanged = networkType != newNetworkType;
+
+        boolean hasChanged = !newSS.equals(ss);
+
+        boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
+
+        boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
+
+        boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
+
+        boolean has4gHandoff =
+            ((networkType == DATA_ACCESS_LTE) && (newNetworkType == DATA_ACCESS_EHRPD))
+                || ((networkType == DATA_ACCESS_EHRPD) && (newNetworkType == DATA_ACCESS_LTE));
+
+        boolean hasMultiApnSupport =
+            (((newNetworkType == DATA_ACCESS_LTE) || (newNetworkType == DATA_ACCESS_EHRPD)) 
+                    && ((networkType != DATA_ACCESS_LTE) && (networkType != DATA_ACCESS_EHRPD)));
+
+        boolean hasLostMultiApnSupport =
+            ((newNetworkType >= DATA_ACCESS_CDMA_IS95A)
+                    && (newNetworkType <= DATA_ACCESS_CDMA_EvDo_A));
+
+        log("hasRegistered = " + hasRegistered + " hasCdmaDataConnectionAttached = "
+                + hasCdmaDataConnectionAttached + " hasCdmaDataConnectionChanged = "
+                + hasCdmaDataConnectionChanged + " hasNetworkTypeChanged = "
+                + hasNetworkTypeChanged + " has4gHandoff = " + has4gHandoff
+                + " hasMultiApnSupport = " + hasMultiApnSupport + " hasLostMultiApnSupport = "
+                + hasLostMultiApnSupport);
+        // Add an event log when connection state changes
+        if (ss.getState() != newSS.getState()
+                || cdmaDataConnectionState != newCdmaDataConnectionState) {
+            EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(),
+                    cdmaDataConnectionState, newSS.getState(), newCdmaDataConnectionState);
+        }
+
+        ServiceState tss;
+        tss = ss;
+        ss = newSS;
+        newSS = tss;
+        // clean slate for next time
+        newSS.setStateOutOfService();
+
+        // TODO: 4G Tech Handoff
+        // if (has4gHandoff) {
+        // Message msg = phone.mDataConnection.obtainMessage(
+        // DataConnectionTracker.EVENT_4G_TECHNOLOGY_CHANGE);
+        // phone.mDataConnection.sendMessage(msg);
+        // }
+
+        if ((hasMultiApnSupport)
+                && (phone.mDataConnection instanceof CdmaDataConnectionTracker)) {
+            log("GsmDataConnectionTracker Created");
+            phone.mDataConnection.dispose();
+            phone.mDataConnection = new GsmDataConnectionTracker(mCdmaLtePhone);
+        }
+
+        if ((hasLostMultiApnSupport)
+                && (phone.mDataConnection instanceof GsmDataConnectionTracker)) {
+            log("GsmDataConnectionTracker disposed");
+            phone.mDataConnection.dispose();
+            phone.mDataConnection = new CdmaDataConnectionTracker((CDMAPhone)phone);
+        }
+
+        CdmaCellLocation tcl = cellLoc;
+        cellLoc = newCellLoc;
+        newCellLoc = tcl;
+
+        cdmaDataConnectionState = newCdmaDataConnectionState;
+        networkType = newNetworkType;
+
+        gprsState = newCdmaDataConnectionState;
+
+        newSS.setStateOutOfService(); // clean slate for next time
+
+        if (hasNetworkTypeChanged) {
+            phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
+                    networkTypeToString(networkType));
+        }
+
+        if (hasRegistered) {
+            networkAttachedRegistrants.notifyRegistrants();
+        }
+
+        if (hasChanged) {
+            if (cm.getNvState().isNVReady()) {
+                String eriText;
+                // Now the CDMAPhone sees the new ServiceState so it can get the
+                // new ERI text
+                if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
+                    eriText = phone.getCdmaEriText();
+                } else {
+                    // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
+                    // for
+                    // mRegistrationState 0,2,3 and 4
+                    eriText = phone.getContext()
+                            .getText(com.android.internal.R.string.roamingTextSearching).toString();
+                }
+                ss.setCdmaEriText(eriText);
+            }
+
+            String operatorNumeric;
+
+            phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
+                    ss.getOperatorAlphaLong());
+
+            operatorNumeric = ss.getOperatorNumeric();
+            phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
+
+            if (operatorNumeric == null) {
+                phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
+            } else {
+                String isoCountryCode = "";
+                try {
+                    isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric
+                            .substring(0, 3)));
+                } catch (NumberFormatException ex) {
+                    Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
+                } catch (StringIndexOutOfBoundsException ex) {
+                    Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
+                }
+
+                phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
+                        isoCountryCode);
+                mGotCountryCode = true;
+                if (mNeedFixZone) {
+                    fixTimeZone(isoCountryCode);
+                }
+            }
+
+            phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
+                    ss.getRoaming() ? "true" : "false");
+
+            updateSpnDisplay();
+            phone.notifyServiceStateChanged(ss);
+        }
+
+        if (hasCdmaDataConnectionAttached) {
+            cdmaDataConnectionAttachedRegistrants.notifyRegistrants();
+            gprsAttachedRegistrants.notifyRegistrants();
+        }
+
+        if (hasCdmaDataConnectionDetached) {
+            cdmaDataConnectionDetachedRegistrants.notifyRegistrants();
+            gprsDetachedRegistrants.notifyRegistrants();
+        }
+
+        if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)
+                && (phone.mDataConnection instanceof CdmaDataConnectionTracker)) {
+            phone.notifyDataConnection();
+        }
+
+        if (hasRoamingOn) {
+            roamingOnRegistrants.notifyRegistrants();
+        }
+
+        if (hasRoamingOff) {
+            roamingOffRegistrants.notifyRegistrants();
+        }
+
+        if (hasLocationChanged) {
+            phone.notifyLocationChanged();
+        }
+    }
+
+    protected void onSignalStrengthResult(AsyncResult ar) {
+        SignalStrength oldSignalStrength = mSignalStrength;
+
+        if (ar.exception != null) {
+            // Most likely radio is resetting/disconnected change to default
+            // values.
+            setSignalStrengthDefaultValues();
+        } else {
+            int[] ints = (int[])ar.result;
+            int lteCqi = 99, lteRsrp = -1;
+            int lteRssi = 99;
+            int offset = 2;
+            int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
+            int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160;
+            int evdoRssi = (ints[offset + 2] > 0) ? -ints[offset + 2] : -120;
+            int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1;
+            int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4]
+                    : -1;
+            if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
+                lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
+                lteRsrp = (ints[offset + 6] > 0) ? -ints[offset + 7] : -1;
+                lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 6] : 99;
+            }
+
+            if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
+                mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
+                        evdoSnr, false);
+            } else {
+                mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
+                        evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true);
+            }
+        }
+
+        try {
+            phone.notifySignalStrength();
+        } catch (NullPointerException ex) {
+            log("onSignalStrengthResult() Phone already destroyed: " + ex
+                    + "SignalStrength not notified");
+        }
+    }
+
+    public boolean isConcurrentVoiceAndDataAllowed() {
+        // Note: it needs to be confirmed which CDMA network types
+        // can support voice and data calls concurrently.
+        // For the time-being, the return value will be false.
+        // return (networkType >= DATA_ACCESS_LTE);
+        return false;
+    }
+
+    @Override
+    protected void log(String s) {
+        if (DBG)
+            Log.d(LOG_TAG, "[CdmaLteServiceStateTracker] " + s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 6bd2d09..c0bfd23 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -94,7 +94,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected int dispatchMessage(SmsMessageBase smsb) {
+    public int dispatchMessage(SmsMessageBase smsb) {
 
         // If sms is null, means there was a parsing error.
         if (smsb == null) {
@@ -485,19 +485,19 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void activateCellBroadcastSms(int activate, Message response) {
+    public void activateCellBroadcastSms(int activate, Message response) {
         mCm.setCdmaBroadcastActivation((activate == 0), response);
     }
 
     /** {@inheritDoc} */
     @Override
-    protected void getCellBroadcastSmsConfig(Message response) {
+    public void getCellBroadcastSmsConfig(Message response) {
         mCm.getCdmaBroadcastConfig(response);
     }
 
     /** {@inheritDoc} */
     @Override
-    protected void setCellBroadcastConfig(int[] configValuesArray, Message response) {
+    public void setCellBroadcastConfig(int[] configValuesArray, Message response) {
         mCm.setCdmaBroadcastConfig(configValuesArray, response);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 0debb42..31250ad 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -61,7 +61,7 @@
 /**
  * {@hide}
  */
-final class CdmaServiceStateTracker extends ServiceStateTracker {
+public class CdmaServiceStateTracker extends ServiceStateTracker {
     static final String LOG_TAG = "CDMA";
 
     CDMAPhone phone;
@@ -88,8 +88,8 @@
     /**
      *  Values correspond to ServiceStateTracker.DATA_ACCESS_ definitions.
      */
-    private int networkType = 0;
-    private int newNetworkType = 0;
+    protected int networkType = 0;
+    protected int newNetworkType = 0;
 
     private boolean mCdmaRoaming = false;
     private int mRoamingIndicator;
@@ -99,23 +99,23 @@
     /**
      * Initially assume no data connection.
      */
-    private int cdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
-    private int newCdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
-    private int mRegistrationState = -1;
-    private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
-    private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
-    private RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
+    protected int cdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
+    protected int newCdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
+    protected int mRegistrationState = -1;
+    protected RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
+    protected RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
+    protected RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
 
     /**
      * Sometimes we get the NITZ time before we know what country we
      * are in. Keep the time zone information from the NITZ string so
      * we can fix the time zone once know the country.
      */
-    private boolean mNeedFixZone = false;
+    protected boolean mNeedFixZone = false;
     private int mZoneOffset;
     private boolean mZoneDst;
     private long mZoneTime;
-    private boolean mGotCountryCode = false;
+    protected boolean mGotCountryCode = false;
     String mSavedTimeZone;
     long mSavedTime;
     long mSavedAtTime;
@@ -566,37 +566,21 @@
             cm.setRadioPower(true, null);
         } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
             DataConnectionTracker dcTracker = phone.mDataConnection;
-            if (! dcTracker.isDataConnectionAsDesired()) {
-                EventLog.writeEvent(EventLogTags.DATA_NETWORK_STATUS_ON_RADIO_OFF,
-                        dcTracker.getStateInString(),
-                        dcTracker.getAnyDataEnabled() ? 1 : 0);
-            }
 
             // If it's on and available and we want it off gracefully
             powerOffRadioSafely();
         } // Otherwise, we're in the desired state
     }
 
+    // TODO: Consider moving this method to DataConnectionTracker
     @Override
-    protected void powerOffRadioSafely() {
+    public void powerOffRadioSafely() {
         DataConnectionTracker dcTracker = phone.mDataConnection;
 
-        Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
-        msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
-
         synchronized (this) {
             if (!mPendingRadioPowerOffAfterDataOff) {
-                DataConnectionTracker.State currentState = dcTracker.getState();
-                if (currentState != DataConnectionTracker.State.CONNECTED
-                    && currentState != DataConnectionTracker.State.DISCONNECTING
-                    && currentState != DataConnectionTracker.State.INITING) {
-                    msg.arg1 = 0; // tearDown is false as it is not needed.
-                    dcTracker.sendMessage(msg);
-                    if (DBG) log("Data disconnected, turn off radio right away.");
-                    hangupAndPowerOff();
-                } else {
-                    msg.arg1 = 1; // tearDown is true
-                    dcTracker.sendMessage(msg);
+                if (dcTracker.isAnyActiveDataConnections()) {
+                    dcTracker.cleanUpAllConnections();
                     if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
                         if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
                         mPendingRadioPowerOffAfterDataOff = true;
@@ -604,6 +588,10 @@
                         Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
                         hangupAndPowerOff();
                     }
+                } else {
+                    dcTracker.cleanUpAllConnections();
+                    if (DBG) log("Data disconnected, turn off radio right away.");
+                    hangupAndPowerOff();
                 }
             }
         }
@@ -647,14 +635,167 @@
     }
 
     /**
-     * Handle the result of one of the pollState()-related requests
-     */
+    * The LTE data connection state, only return true here
+    */
+    protected boolean checkAdditionalDataAvaiable(){
+        return true;
+    }
 
-    @Override
-    protected void handlePollStateResult (int what, AsyncResult ar) {
+    /**
+    * Hanlde the PollStateResult message
+    */
+    protected void handlePollStateResultMessage(int what, AsyncResult ar){
         int ints[];
         String states[];
+        switch (what) {
+        case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE.
+            states = (String[])ar.result;
 
+            int registrationState = 4;     //[0] registrationState
+            int radioTechnology = -1;      //[3] radioTechnology
+            int baseStationId = -1;        //[4] baseStationId
+            //[5] baseStationLatitude
+            int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG;
+            //[6] baseStationLongitude
+            int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
+            int cssIndicator = 0;          //[7] init with 0, because it is treated as a boolean
+            int systemId = 0;              //[8] systemId
+            int networkId = 0;             //[9] networkId
+            int roamingIndicator = -1;     //[10] Roaming indicator
+            int systemIsInPrl = 0;         //[11] Indicates if current system is in PRL
+            int defaultRoamingIndicator = 0;  //[12] Is default roaming indicator from PRL
+            int reasonForDenial = 0;       //[13] Denial reason if registrationState = 3
+
+            if (states.length == 14) {
+                try {
+                    if (states[0] != null) {
+                        registrationState = Integer.parseInt(states[0]);
+                    }
+                    if (states[3] != null) {
+                        radioTechnology = Integer.parseInt(states[3]);
+                    }
+                    if (states[4] != null) {
+                        baseStationId = Integer.parseInt(states[4]);
+                    }
+                    if (states[5] != null) {
+                        baseStationLatitude = Integer.parseInt(states[5]);
+                    }
+                    if (states[6] != null) {
+                        baseStationLongitude = Integer.parseInt(states[6]);
+                    }
+                    // Some carriers only return lat-lngs of 0,0
+                    if (baseStationLatitude == 0 && baseStationLongitude == 0) {
+                        baseStationLatitude  = CdmaCellLocation.INVALID_LAT_LONG;
+                        baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
+                    }
+                    if (states[7] != null) {
+                        cssIndicator = Integer.parseInt(states[7]);
+                    }
+                    if (states[8] != null) {
+                        systemId = Integer.parseInt(states[8]);
+                    }
+                    if (states[9] != null) {
+                        networkId = Integer.parseInt(states[9]);
+                    }
+                    if (states[10] != null) {
+                        roamingIndicator = Integer.parseInt(states[10]);
+                    }
+                    if (states[11] != null) {
+                        systemIsInPrl = Integer.parseInt(states[11]);
+                    }
+                    if (states[12] != null) {
+                        defaultRoamingIndicator = Integer.parseInt(states[12]);
+                    }
+                    if (states[13] != null) {
+                        reasonForDenial = Integer.parseInt(states[13]);
+                    }
+                } catch (NumberFormatException ex) {
+                    Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
+                }
+            } else {
+                throw new RuntimeException("Warning! Wrong number of parameters returned from "
+                                     + "RIL_REQUEST_REGISTRATION_STATE: expected 14 got "
+                                     + states.length);
+            }
+
+            mRegistrationState = registrationState;
+            // When registration state is roaming and TSB58
+            // roaming indicator is not in the carrier-specified
+            // list of ERIs for home system, mCdmaRoaming is true.
+            mCdmaRoaming =
+                    regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
+            newSS.setState (regCodeToServiceState(registrationState));
+
+            if(checkAdditionalDataAvaiable()) {
+                this.newCdmaDataConnectionState =
+                        radioTechnologyToDataServiceState(radioTechnology);
+                newSS.setRadioTechnology(radioTechnology);
+                newNetworkType = radioTechnology;
+            }
+
+            newSS.setCssIndicator(cssIndicator);
+            newSS.setSystemAndNetworkId(systemId, networkId);
+            mRoamingIndicator = roamingIndicator;
+            mIsInPrl = (systemIsInPrl == 0) ? false : true;
+            mDefaultRoamingIndicator = defaultRoamingIndicator;
+
+
+            // Values are -1 if not available.
+            newCellLoc.setCellLocationData(baseStationId, baseStationLatitude,
+                    baseStationLongitude, systemId, networkId);
+
+            if (reasonForDenial == 0) {
+                mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN;
+            } else if (reasonForDenial == 1) {
+                mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH;
+            } else {
+                mRegistrationDeniedReason = "";
+            }
+
+            if (mRegistrationState == 3) {
+                if (DBG) log("Registration denied, " + mRegistrationDeniedReason);
+            }
+            break;
+
+        case EVENT_POLL_STATE_OPERATOR_CDMA: // Handle RIL_REQUEST_OPERATOR
+            String opNames[] = (String[])ar.result;
+
+            if (opNames != null && opNames.length >= 3) {
+                // If the NUMERIC field isn't valid use PROPERTY_CDMA_HOME_OPERATOR_NUMERIC
+                if ((opNames[2] == null) || (opNames[2].length() < 5)
+                        || ("00000".equals(opNames[2]))) {
+                    opNames[2] = SystemProperties.get(
+                            CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "00000");
+                    if (DBG) {
+                        log("RIL_REQUEST_OPERATOR.response[2], the numeric, " +
+                                " is bad. Using SystemProperties '" +
+                                        CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC +
+                                "'= " + opNames[2]);
+                    }
+                }
+                if (cm.getNvState().isNVReady()) {
+                    // In CDMA in case on NV, the ss.mOperatorAlphaLong is set later with the
+                    // ERI text, so here it is ignored what is coming from the modem.
+                    newSS.setOperatorName(null, opNames[1], opNames[2]);
+                } else {
+                    newSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
+                }
+            } else {
+                Log.w(LOG_TAG, "error parsing opNames");
+            }
+            break;
+        default:
+            Log.e(LOG_TAG, "RIL response handle in wrong phone!"
+                + " Expected CDMA RIL request and get GSM RIL request.");
+        break;
+        }
+    }
+
+    /**
+     * Handle the result of one of the pollState() - related requests
+     */
+    @Override
+    protected void handlePollStateResult (int what, AsyncResult ar) {
         // Ignore stale requests from last poll.
         if (ar.userObj != pollingContext) return;
 
@@ -684,148 +825,7 @@
                         ar.exception);
             }
         } else try {
-            switch (what) {
-            case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE.
-                states = (String[])ar.result;
-
-                int registrationState = 4;     //[0] registrationState
-                int radioTechnology = -1;      //[3] radioTechnology
-                int baseStationId = -1;        //[4] baseStationId
-                //[5] baseStationLatitude
-                int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG;
-                //[6] baseStationLongitude
-                int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
-                int cssIndicator = 0;          //[7] init with 0, because it is treated as a boolean
-                int systemId = 0;              //[8] systemId
-                int networkId = 0;             //[9] networkId
-                int roamingIndicator = -1;     //[10] Roaming indicator
-                int systemIsInPrl = 0;         //[11] Indicates if current system is in PRL
-                int defaultRoamingIndicator = 0;  //[12] Is default roaming indicator from PRL
-                int reasonForDenial = 0;       //[13] Denial reason if registrationState = 3
-
-                if (states.length == 14) {
-                    try {
-                        if (states[0] != null) {
-                            registrationState = Integer.parseInt(states[0]);
-                        }
-                        if (states[3] != null) {
-                            radioTechnology = Integer.parseInt(states[3]);
-                        }
-                        if (states[4] != null) {
-                            baseStationId = Integer.parseInt(states[4]);
-                        }
-                        if (states[5] != null) {
-                            baseStationLatitude = Integer.parseInt(states[5]);
-                        }
-                        if (states[6] != null) {
-                            baseStationLongitude = Integer.parseInt(states[6]);
-                        }
-                        // Some carriers only return lat-lngs of 0,0
-                        if (baseStationLatitude == 0 && baseStationLongitude == 0) {
-                            baseStationLatitude  = CdmaCellLocation.INVALID_LAT_LONG;
-                            baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
-                        }
-                        if (states[7] != null) {
-                            cssIndicator = Integer.parseInt(states[7]);
-                        }
-                        if (states[8] != null) {
-                            systemId = Integer.parseInt(states[8]);
-                        }
-                        if (states[9] != null) {
-                            networkId = Integer.parseInt(states[9]);
-                        }
-                        if (states[10] != null) {
-                            roamingIndicator = Integer.parseInt(states[10]);
-                        }
-                        if (states[11] != null) {
-                            systemIsInPrl = Integer.parseInt(states[11]);
-                        }
-                        if (states[12] != null) {
-                            defaultRoamingIndicator = Integer.parseInt(states[12]);
-                        }
-                        if (states[13] != null) {
-                            reasonForDenial = Integer.parseInt(states[13]);
-                        }
-                    } catch (NumberFormatException ex) {
-                        Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
-                    }
-                } else {
-                    throw new RuntimeException("Warning! Wrong number of parameters returned from "
-                                         + "RIL_REQUEST_REGISTRATION_STATE: expected 14 got "
-                                         + states.length);
-                }
-
-                mRegistrationState = registrationState;
-                // When registration state is roaming and TSB58
-                // roaming indicator is not in the carrier-specified
-                // list of ERIs for home system, mCdmaRoaming is true.
-                mCdmaRoaming =
-                        regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
-                newSS.setState (regCodeToServiceState(registrationState));
-
-                this.newCdmaDataConnectionState =
-                        radioTechnologyToDataServiceState(radioTechnology);
-                newSS.setRadioTechnology(radioTechnology);
-                newNetworkType = radioTechnology;
-
-                newSS.setCssIndicator(cssIndicator);
-                newSS.setSystemAndNetworkId(systemId, networkId);
-                mRoamingIndicator = roamingIndicator;
-                mIsInPrl = (systemIsInPrl == 0) ? false : true;
-                mDefaultRoamingIndicator = defaultRoamingIndicator;
-
-
-                // Values are -1 if not available.
-                newCellLoc.setCellLocationData(baseStationId, baseStationLatitude,
-                        baseStationLongitude, systemId, networkId);
-
-                if (reasonForDenial == 0) {
-                    mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN;
-                } else if (reasonForDenial == 1) {
-                    mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH;
-                } else {
-                    mRegistrationDeniedReason = "";
-                }
-
-                if (mRegistrationState == 3) {
-                    if (DBG) log("Registration denied, " + mRegistrationDeniedReason);
-                }
-                break;
-
-            case EVENT_POLL_STATE_OPERATOR_CDMA: // Handle RIL_REQUEST_OPERATOR
-                String opNames[] = (String[])ar.result;
-
-                if (opNames != null && opNames.length >= 3) {
-                    // If the NUMERIC field isn't valid use PROPERTY_CDMA_HOME_OPERATOR_NUMERIC
-                    if ((opNames[2] == null) || (opNames[2].length() < 5)
-                            || ("00000".equals(opNames[2]))) {
-                        opNames[2] = SystemProperties.get(
-                                CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "00000");
-                        if (DBG) {
-                            log("RIL_REQUEST_OPERATOR.response[2], the numeric, " +
-                                    " is bad. Using SystemProperties '" +
-                                            CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC +
-                                    "'= " + opNames[2]);
-                        }
-                    }
-                    if (cm.getRadioState().isNVReady()) {
-                        // In CDMA in case on NV, the ss.mOperatorAlphaLong is set later with the
-                        // ERI text, so here it is ignored what is coming from the modem.
-                        newSS.setOperatorName(null, opNames[1], opNames[2]);
-                    } else {
-                        newSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
-                    }
-                } else {
-                    Log.w(LOG_TAG, "error parsing opNames");
-                }
-                break;
-
-            default:
-                Log.e(LOG_TAG, "RIL response handle in wrong phone!"
-                    + " Expected CDMA RIL request and get GSM RIL request.");
-            break;
-            }
-
+            handlePollStateResultMessage(what, ar);
         } catch (RuntimeException ex) {
             Log.e(LOG_TAG, "Exception while polling service state. "
                     + "Probably malformed RIL response.", ex);
@@ -896,9 +896,8 @@
 
     }
 
-    private void setSignalStrengthDefaultValues() {
-        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1,
-                -1, -1, -1, -1, -1, false);
+    protected void setSignalStrengthDefaultValues() {
+        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, false);
     }
 
     /**
@@ -909,7 +908,7 @@
      * and start over again if the radio notifies us that some
      * event has changed
      */
-    private void
+    protected void
     pollState() {
         pollingContext = new int[1];
         pollingContext[0] = 0;
@@ -964,7 +963,7 @@
         }
     }
 
-    private static String networkTypeToString(int type) {
+    protected static String networkTypeToString(int type) {
         String ret = "unknown";
 
         switch (type) {
@@ -994,7 +993,7 @@
         return ret;
     }
 
-    private void fixTimeZone(String isoCountryCode) {
+    protected void fixTimeZone(String isoCountryCode) {
         TimeZone zone = null;
         // If the offset is (0, false) and the time zone property
         // is set, use the time zone property rather than GMT.
@@ -1031,7 +1030,7 @@
         }
     }
 
-    private void pollStateDone() {
+    protected void pollStateDone() {
         if (DBG) log("Poll ServiceState done: oldSS=[" + ss + "] newSS=[" + newSS + "]");
 
         boolean hasRegistered =
@@ -1234,7 +1233,7 @@
      *  send signal-strength-changed notification if changed
      *  Called both for solicited and unsolicited signal strength updates
      */
-    private void
+    protected void
     onSignalStrengthResult(AsyncResult ar) {
         SignalStrength oldSignalStrength = mSignalStrength;
 
@@ -1253,7 +1252,7 @@
             //log(String.format("onSignalStrengthResult cdmaDbm=%d cdmaEcio=%d evdoRssi=%d evdoEcio=%d evdoSnr=%d",
             //        cdmaDbm, cdmaEcio, evdoRssi, evdoEcio, evdoSnr));
             mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio,
-                    evdoRssi, evdoEcio, evdoSnr, -1, -1, -1, -1, -1, false);
+                    evdoRssi, evdoEcio, evdoSnr, false);
         }
 
         try {
@@ -1289,7 +1288,7 @@
     }
 
     /** code is registration state 0-5 from TS 27.007 7.2 */
-    private int
+    protected int
     regCodeToServiceState(int code) {
         switch (code) {
         case 0: // Not searching and not registered
@@ -1319,6 +1318,13 @@
     }
 
     /**
+    * TODO: In the future, we need remove getCurrentCdmaDataConnectionState
+    */
+    public int getCurrentDataConnectionState() {
+        return cdmaDataConnectionState;
+    }
+
+    /**
      * code is registration state 0-5 from TS 27.007 7.2
      * returns true if registered roam, false otherwise
      */
@@ -1662,7 +1668,7 @@
      * @return true if phone is camping on a technology
      * that could support voice and data simultaneously.
      */
-    boolean isConcurrentVoiceAndData() {
+    public boolean isConcurrentVoiceAndDataAllowed() {
         // Note: it needs to be confirmed which CDMA network types
         // can support voice and data calls concurrently.
         // For the time-being, the return value will be false.
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index c17197e..3f1a91b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -33,6 +33,7 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import com.android.internal.telephony.CallTracker;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -72,6 +73,7 @@
 import com.android.internal.telephony.UUSInfo;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.IccVmNotSupportedException;
+import com.android.internal.telephony.ServiceStateTracker;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
@@ -100,9 +102,6 @@
     // Instance Variables
     GsmCallTracker mCT;
     GsmServiceStateTracker mSST;
-    GsmSMSDispatcher mSMS;
-    SIMRecords mSIMRecords;
-    SimCard mSimCard;
     CatService mStkService;
     ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>();
     SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
@@ -283,6 +282,14 @@
         return mSIMRecords.getVoiceCallForwardingFlag();
     }
 
+    public CallTracker getCallTracker() {
+        return mCT;
+    }
+
+    public ServiceStateTracker getServiceStateTracker() {
+        return mSST;
+    }
+
     public List<? extends MmiCode>
     getPendingMmiCodes() {
         return mPendingMMIs;
@@ -314,7 +321,7 @@
                 case CONNECTED:
                 case DISCONNECTING:
                     if ( mCT.state != Phone.State.IDLE
-                            && !mSST.isConcurrentVoiceAndData()) {
+                            && !mSST.isConcurrentVoiceAndDataAllowed()) {
                         ret = DataState.SUSPENDED;
                     } else {
                         ret = DataState.CONNECTED;
@@ -404,7 +411,7 @@
         mNotifier.notifySignalStrength(this);
     }
 
-    /*package*/ void
+    public void
     notifyDataConnectionFailed(String reason, String apnType) {
         mNotifier.notifyDataConnectionFailed(this, reason, apnType);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 4689b2d..9f7673c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -19,10 +19,12 @@
 import android.os.Message;
 import android.util.Log;
 import android.util.Patterns;
+import android.text.TextUtils;
 
 import com.android.internal.telephony.ApnSetting;
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.RetryManager;
 
@@ -36,8 +38,10 @@
     //***** Instance Variables
     private ApnSetting apn;
 
+    protected int mProfileId = RILConstants.DATA_PROFILE_DEFAULT;
+    protected String mActiveApnType = Phone.APN_TYPE_DEFAULT;
     //***** Constructor
-    private GsmDataConnection(GSMPhone phone, String name, RetryManager rm) {
+    private GsmDataConnection(PhoneBase phone, String name, RetryManager rm) {
         super(phone, name, rm);
     }
 
@@ -49,7 +53,7 @@
      * @param rm the RetryManager
      * @return GsmDataConnection that was created.
      */
-    static GsmDataConnection makeDataConnection(GSMPhone phone, int id, RetryManager rm) {
+    static GsmDataConnection makeDataConnection(PhoneBase phone, int id, RetryManager rm) {
         synchronized (mCountLock) {
             mCount += 1;
         }
@@ -102,11 +106,29 @@
 
         phone.mCM.setupDataCall(
                 Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
-                Integer.toString(RILConstants.DATA_PROFILE_DEFAULT),
-                apn.apn, apn.user, apn.password, Integer.toString(authType),
+                Integer.toString(mProfileId),
+                apn.apn, apn.user, apn.password,
+                Integer.toString(authType),
                 protocol, msg);
     }
 
+    public void setProfileId(int profileId) {
+        mProfileId = profileId;
+    }
+
+    public int getProfileId() {
+        return mProfileId;
+    }
+
+    public int getCid() {
+        // 'cid' has been defined in parent class
+        return cid;
+    }
+
+    public void setActiveApnType(String apnType) {
+        mActiveApnType = apnType;
+    }
+
     @Override
     protected void clearSettings() {
         super.clearSettings();
@@ -150,17 +172,35 @@
     }
 
     private void setHttpProxy(String httpProxy, String httpPort) {
-        if (httpProxy == null || httpProxy.length() == 0) {
-            phone.setSystemProperty("net.gprs.http-proxy", null);
-            return;
-        }
 
-        if (httpPort == null || httpPort.length() == 0) {
-            httpPort = "8080";     // Default to port 8080
-        }
+        if (DBG) log("set http proxy for"
+                + "' APN: '" + mActiveApnType
+                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+        if(TextUtils.equals(mActiveApnType, Phone.APN_TYPE_DEFAULT)) {
+            if (httpProxy == null || httpProxy.length() == 0) {
+                phone.setSystemProperty("net.gprs.http-proxy", null);
+                return;
+            }
 
-        phone.setSystemProperty("net.gprs.http-proxy",
-                "http://" + httpProxy + ":" + httpPort + "/");
+            if (httpPort == null || httpPort.length() == 0) {
+                httpPort = "8080";     // Default to port 8080
+            }
+
+            phone.setSystemProperty("net.gprs.http-proxy",
+                    "http://" + httpProxy + ":" + httpPort + "/");
+        } else {
+            if (httpProxy == null || httpProxy.length() == 0) {
+                phone.setSystemProperty("net.gprs.http-proxy." + mActiveApnType, null);
+                return;
+            }
+
+            if (httpPort == null || httpPort.length() == 0) {
+                httpPort = "8080";  // Default to port 8080
+            }
+
+            phone.setSystemProperty("net.gprs.http-proxy." + mActiveApnType,
+                    "http://" + httpProxy + ":" + httpPort + "/");
+        }
     }
 
     private boolean isIpAddress(String address) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 55cffba..f90e801 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -22,11 +22,14 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.ProxyProperties;
 import android.net.TrafficStats;
 import android.net.Uri;
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemClock;
@@ -36,24 +39,32 @@
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
+import android.preference.PreferenceManager;
 
 import com.android.internal.R;
+import com.android.internal.telephony.ApnContext;
 import com.android.internal.telephony.ApnSetting;
 import com.android.internal.telephony.DataCallState;
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.DataConnection.FailCause;
+import com.android.internal.telephony.RILConstants;
 
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.HashMap;
 
 /**
@@ -62,7 +73,6 @@
 public final class GsmDataConnectionTracker extends DataConnectionTracker {
     protected final String LOG_TAG = "GSM";
 
-    private GSMPhone mGsmPhone;
     /**
      * Handles changes to the APN db.
      */
@@ -100,22 +110,15 @@
      */
     private ArrayList<ApnSetting> mAllApns = null;
 
-    /**
-     * waitingApns holds all apns that are waiting to be connected
-     *
-     * It is a subset of allApns and has the same format
-     */
-    private ArrayList<ApnSetting> mWaitingApns = null;
-    private int mWaitingApnsPermanentFailureCountDown = 0;
     private ApnSetting mPreferredApn = null;
 
-      /** The DataConnection being setup */
-    private GsmDataConnection mPendingDataConnection;
-
     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
     private HashMap<String, Integer> mApnToDataConnectionId =
                                     new HashMap<String, Integer>();
 
+    /** Phone.APN_TYPE_* ===> ApnContext */
+    private ConcurrentHashMap<String, ApnContext> mApnContexts;
+
     /** Is packet service restricted by network */
     private boolean mIsPsRestricted = false;
 
@@ -124,32 +127,55 @@
     private static final int POLL_PDP_MILLIS = 5 * 1000;
 
     private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect";
+    private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "type";
 
     static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
     static final String APN_ID = "apn_id";
     private boolean canSetPreferApn = false;
 
+    @Override
+    protected void onActionIntentReconnectAlarm(Intent intent) {
+        log("GPRS reconnect alarm. Previous state was " + mState);
+
+        String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
+        String type = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
+        ApnContext apnContext = mApnContexts.get(type);
+        if (apnContext != null) {
+            apnContext.setReason(reason);
+            if (apnContext.getState() == State.FAILED) {
+                Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
+                msg.arg1 = 0; // tearDown is false
+                msg.obj = (ApnContext)apnContext;
+                sendMessage(msg);
+            }
+            sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
+        }
+    }
+
     /** Watches for changes to the APN db. */
     private ApnChangeObserver mApnObserver;
 
     //***** Constructor
 
-    GsmDataConnectionTracker(GSMPhone p) {
+    public GsmDataConnectionTracker(PhoneBase p) {
         super(p);
-        mGsmPhone = p;
 
         p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
         p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
         p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
-        p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
-        p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
-        p.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null);
-        p.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null);
-        p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
-        p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
-        p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null);
-        p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null);
+        p.getCallTracker().registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
+        p.getCallTracker().registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
+        p.getServiceStateTracker().registerForDataConnectionAttached(this,
+                EVENT_DATA_CONNECTION_ATTACHED, null);
+        p.getServiceStateTracker().registerForDataConnectionDetached(this,
+                EVENT_DATA_CONNECTION_DETACHED, null);
+        p.getServiceStateTracker().registerForRoamingOn(this, EVENT_ROAMING_ON, null);
+        p.getServiceStateTracker().registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
+        p.getServiceStateTracker().registerForPsRestrictedEnabled(this,
+                EVENT_PS_RESTRICT_ENABLED, null);
+        p.getServiceStateTracker().registerForPsRestrictedDisabled(this,
+                EVENT_PS_RESTRICT_DISABLED, null);
 
         mDataConnectionTracker = this;
         mResolver = mPhone.getContext().getContentResolver();
@@ -159,7 +185,8 @@
                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
 
         /** Create the default connection */
-        createDataConnection(Phone.APN_TYPE_DEFAULT);
+        mApnContexts = new ConcurrentHashMap<String, ApnContext>();
+        initApncontextsAndDataConnection();
         broadcastMessenger();
     }
 
@@ -170,22 +197,44 @@
         //Unregister for all events
         mPhone.mCM.unregisterForAvailable(this);
         mPhone.mCM.unregisterForOffOrNotAvailable(this);
-        mGsmPhone.mSIMRecords.unregisterForRecordsLoaded(this);
+        mPhone.mSIMRecords.unregisterForRecordsLoaded(this);
         mPhone.mCM.unregisterForDataNetworkStateChanged(this);
-        mGsmPhone.mCT.unregisterForVoiceCallEnded(this);
-        mGsmPhone.mCT.unregisterForVoiceCallStarted(this);
-        mGsmPhone.mSST.unregisterForGprsAttached(this);
-        mGsmPhone.mSST.unregisterForGprsDetached(this);
-        mGsmPhone.mSST.unregisterForRoamingOn(this);
-        mGsmPhone.mSST.unregisterForRoamingOff(this);
-        mGsmPhone.mSST.unregisterForPsRestrictedEnabled(this);
-        mGsmPhone.mSST.unregisterForPsRestrictedDisabled(this);
+        mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
+        mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
+        mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this);
+        mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this);
+        mPhone.getServiceStateTracker().unregisterForRoamingOn(this);
+        mPhone.getServiceStateTracker().unregisterForRoamingOff(this);
+        mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
+        mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
 
         mPhone.getContext().getContentResolver().unregisterContentObserver(this.mApnObserver);
+        mApnContexts.clear();
 
         destroyDataConnections();
     }
 
+    /**
+     * The only circumstances under which we report that data connectivity is not
+     * possible are
+     * <ul>
+     * <li>Data is disallowed (roaming, power state, voice call, etc).</li>
+     * <li>The current data state is {@code DISCONNECTED} for a reason other than
+     * having explicitly disabled connectivity. In other words, data is not available
+     * because the phone is out of coverage or some like reason.</li>
+     * </ul>
+     * @return {@code true} if data connectivity is possible, {@code false} otherwise.
+     */
+    @Override
+    protected boolean isDataPossible() {
+        boolean possible = (isDataAllowed()
+                && getAnyDataEnabled() && (getOverallState() == State.CONNECTED));
+        if (!possible && DBG && isDataAllowed()) {
+            log("Data not possible.  No coverage: dataState = " + getOverallState());
+        }
+        return possible;
+    }
+
     @Override
     protected void finalize() {
         if(DBG) log("finalize");
@@ -196,41 +245,225 @@
         return INTENT_RECONNECT_ALARM;
     }
 
+    protected void initApncontextsAndDataConnection() {
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
+        boolean defaultEnabled = !sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
+        // create default type context only if enabled
+        if (defaultEnabled) {
+            ApnContext apnContext = new ApnContext(Phone.APN_TYPE_DEFAULT, LOG_TAG);
+            mApnContexts.put(apnContext.getApnType(), apnContext);
+            createDataConnection(Phone.APN_TYPE_DEFAULT);
+        }
+    }
+
     @Override
-    protected void setState(State s) {
-        if (DBG) log ("setState: " + s);
-        if (mState != s) {
-            EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, mState.toString(), s.toString());
-            mState = s;
+    protected LinkProperties getLinkProperties(String apnType) {
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext != null && apnContext.getDataConnection() != null) {
+             if (DBG) log("get active pdp is not null, return link properites for " + apnType);
+             return apnContext.getDataConnection().getLinkProperties();
+        } else {
+            if (DBG) log("return new LinkProperties");
+            return new LinkProperties();
+        }
+    }
+
+    @Override
+    protected LinkCapabilities getLinkCapabilities(String apnType) {
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext!=null && apnContext.getDataConnection() != null) {
+             if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType);
+             return apnContext.getDataConnection().getLinkCapabilities();
+        } else {
+            if (DBG) log("return new LinkCapabilities");
+            return new LinkCapabilities();
+        }
+    }
+
+    @Override
+    // Return all active apn types
+    public synchronized String[] getActiveApnTypes() {
+        if (DBG) log("get all active apn types");
+        ArrayList<String> result = new ArrayList<String>();
+
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+        while (it.hasNext()) {
+            ApnContext apnContext = it.next();
+                result.add(apnContext.getApnType());
         }
 
-        if (mState == State.FAILED) {
-            if (mWaitingApns != null)
-                mWaitingApns.clear(); // when tear down the connection and set to IDLE
+        return (String[])result.toArray(new String[0]);
+    }
+
+    @Override
+    /**
+     * Return DEFAULT APN due to the limit of the interface
+     */
+    public synchronized String getActiveApnString() {
+        if (DBG) log( "get default active apn string");
+        ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+        if (defaultApnContext != null && defaultApnContext.getApnSetting() != null) {
+            return defaultApnContext.getApnSetting().apn;
+        }
+        return null;
+    }
+
+    // Return active apn of specific apn type
+    public synchronized String getActiveApnString(String apnType) {
+        if (DBG) log( "get active apn string for type:" + apnType);
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext != null && apnContext.getApnSetting() != null) {
+            return apnContext.getApnSetting().apn;
+        }
+        return null;
+    }
+
+    // Return state of specific apn type
+    public synchronized State getState(String apnType) {
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext != null) {
+            return apnContext.getState();
+        }
+        return State.FAILED;
+    }
+
+    // Return state of overall
+    public State getOverallState() {
+        boolean isConnecting = false;
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+        while (it.hasNext()) {
+            ApnContext apnContext = it.next();
+            if (apnContext.getState() == State.CONNECTED ||
+                    apnContext.getState() == State.DISCONNECTING) {
+                if (DBG) log("overall state is CONNECTED");
+                return State.CONNECTED;
+            }
+            else if (apnContext.getState() == State.CONNECTING
+                    || apnContext.getState() == State.INITING) {
+                isConnecting = true;
+            }
+        }
+        if (isConnecting) {
+            if (DBG) log( "overall state is CONNECTING");
+            return State.CONNECTING;
+        } else {
+            if (DBG) log( "overall state is IDLE");
+            return State.IDLE;
         }
     }
 
     /**
-     * The data connection is expected to be setup while device
-     *  1. has sim card
-     *  2. registered to gprs service
-     *  3. user doesn't explicitly disable data service
-     *  4. wifi is not on
+     * Ensure that we are connected to an APN of the specified type.
      *
-     * @return false while no data connection if all above requirements are met.
+     * @param type the APN type
+     * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
+     *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
+     *         broadcast will be sent by the ConnectivityManager when a
+     *         connection to the APN has been established.
      */
     @Override
-    public boolean isDataConnectionAsDesired() {
-        boolean roaming = mPhone.getServiceState().getRoaming();
+    public synchronized int enableApnType(String apnType) {
+        if (DBG) log("calling enableApnType with type:" + apnType);
 
-        if (mGsmPhone.mSIMRecords.getRecordsLoaded() &&
-                mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
-                (!roaming || getDataOnRoamingEnabled()) &&
-            !mIsWifiConnected &&
-            !mIsPsRestricted ) {
-            return (mState == State.CONNECTED);
+        if (!isApnTypeAvailable(apnType)) {
+            if (DBG) log("type not available");
+            return Phone.APN_TYPE_NOT_AVAILABLE;
         }
-        return true;
+
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext==null) {
+            // Is there a Proxy type for this?
+            apnContext = getProxyActiveApnType(apnType);
+            if (apnContext != null ) {
+                notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnContext, apnType);
+                return Phone.APN_REQUEST_STARTED;
+            }
+            apnContext = new ApnContext(apnType, LOG_TAG);
+            if (DBG) log("New apn type context for type "+apnType);
+            mApnContexts.put(apnType, apnContext);
+        }
+
+        // If already active, return
+        log("enableApnType(" + apnType + ")" + ", mState(" + apnContext.getState() + ")");
+
+        if (apnContext.getState() == State.INITING) {
+            if (DBG) log("return APN_REQUEST_STARTED");
+            return Phone.APN_REQUEST_STARTED;
+        }
+        else if (apnContext.getState() == State.CONNECTED) {
+            if (DBG) log("return APN_ALREADY_ACTIVE");
+            return Phone.APN_ALREADY_ACTIVE;
+        }
+        else if (apnContext.getState() == State.DISCONNECTING) {
+            if (DBG) log("requested APN while disconnecting");
+            apnContext.setPendingAction(ApnContext.PENDING_ACTION_RECONNECT);
+            return Phone.APN_REQUEST_STARTED;
+        }
+
+        if (DBG) log("new apn request for type " + apnType + " is to be handled");
+        sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN, apnContext));
+        if (DBG) log("return APN_REQUEST_STARTED");
+        return Phone.APN_REQUEST_STARTED;
+    }
+
+    // Returns for ex: if HIGHPRI is supported by DEFAULT
+    public ApnContext getProxyActiveApnType(String type) {
+
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+
+        while(it.hasNext()) {
+            ApnContext apnContext = it.next();
+            if (apnContext.getApnSetting() != null && mActiveApn.canHandleType(type))
+            return apnContext;
+        }
+        return null;
+    }
+
+    // A new APN has gone active and needs to send events to catch up with the
+    // current condition
+    private void notifyApnIdUpToCurrent(String reason, ApnContext apnContext, String type) {
+        switch (apnContext.getState()) {
+            case IDLE:
+            case INITING:
+                break;
+            case CONNECTING:
+            case SCANNING:
+                mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTING);
+                break;
+            case CONNECTED:
+            case DISCONNECTING:
+                mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTING);
+                mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTED);
+                break;
+        }
+    }
+
+    @Override
+    public synchronized int disableApnType(String type) {
+        if (DBG) log("calling disableApnType with type:" + type);
+        ApnContext apnContext = mApnContexts.get(type);
+
+        if (apnContext != null) {
+            apnContext.setPendingAction(ApnContext.PENDING_ACTION_APN_DISABLE);
+
+            if (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED) {
+                Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
+                msg.arg1 = 1; // tearDown is true;
+                apnContext.setReason(Phone.REASON_DATA_DISABLED);
+                msg.obj = apnContext;
+                sendMessage(msg);
+                if (DBG) log("return APN_REQUEST_STARTED");
+                return Phone.APN_REQUEST_STARTED;
+            } else {
+                if (DBG) log("return APN_ALREADY_INACTIVE");
+                return Phone.APN_ALREADY_INACTIVE;
+            }
+
+        } else {
+            if (DBG)
+                log("no apn context was found, return APN_REQUEST_FAILED");
+            return Phone.APN_REQUEST_FAILED;
+        }
     }
 
     @Override
@@ -249,12 +482,53 @@
         return false;
     }
 
+    protected boolean isEnabled(String apnType) {
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext == null) return false;
+        if (apnContext.getState() == State.DISCONNECTING
+                && apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Report on whether data connectivity is enabled for any APN.
+     * @return {@code false} if data connectivity has been explicitly disabled,
+     * {@code true} otherwise.
+     */
+    @Override
+    public synchronized boolean getAnyDataEnabled() {
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+
+        if (!(mInternalDataEnabled && mDataEnabled)) return false;
+        if (mApnContexts.isEmpty()) return false;
+        while (it.hasNext()) {
+            ApnContext apnContext= it.next();
+            // Make sure we dont have a context that going down
+            // and is explicitly disabled.
+            if (!(apnContext.getState() == State.DISCONNECTING
+                    && apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isDataAllowed(ApnContext apnContext) {
+        if(apnContext.getState() == State.DISCONNECTING
+                && apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
+            return false;
+        }
+        return isDataAllowed();
+    }
+
     //****** Called from ServiceStateTracker
     /**
      * Invoked when ServiceStateTracker observes a transition from GPRS
      * attach to detach.
      */
-    protected void onGprsDetached() {
+    protected void onDataConnectionDetached() {
         /*
          * We presently believe it is unnecessary to tear down the PDP context
          * when GPRS detaches, but we should stop the network polling.
@@ -263,27 +537,29 @@
         notifyDataConnection(Phone.REASON_GPRS_DETACHED);
     }
 
-    private void onGprsAttached() {
-        if (mState == State.CONNECTED) {
+    private void onDataConnectionAttached() {
+        if (getOverallState() == State.CONNECTED) {
             startNetStatPoll();
             notifyDataConnection(Phone.REASON_GPRS_ATTACHED);
         } else {
-            if (mState == State.FAILED) {
-                cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED);
+            // Only check for default APN state
+            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+            if (defaultApnContext.getState() == State.FAILED) {
+                cleanUpConnection(false, defaultApnContext);
                 mRetryMgr.resetRetryCount();
             }
-            trySetupData(Phone.REASON_GPRS_ATTACHED);
+            trySetupData(Phone.REASON_GPRS_ATTACHED, Phone.APN_TYPE_DEFAULT);
         }
     }
 
     @Override
     protected boolean isDataAllowed() {
-        int gprsState = mGsmPhone.mSST.getCurrentGprsState();
-        boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState();
+        int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState();
+        boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
 
         boolean allowed =
                     (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
-                    mGsmPhone.mSIMRecords.getRecordsLoaded() &&
+                    mPhone.mSIMRecords.getRecordsLoaded() &&
                     mPhone.getState() == Phone.State.IDLE &&
                     mInternalDataEnabled &&
                     (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
@@ -294,7 +570,7 @@
             if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
                 reason += " - gprs= " + gprsState;
             }
-            if (!mGsmPhone.mSIMRecords.getRecordsLoaded()) reason += " - SIM not loaded";
+            if (!mPhone.mSIMRecords.getRecordsLoaded()) reason += " - SIM not loaded";
             if (mPhone.getState() != Phone.State.IDLE) {
                 reason += " - PhoneState= " + mPhone.getState();
             }
@@ -309,94 +585,198 @@
         return allowed;
     }
 
-    private boolean trySetupData(String reason) {
-        if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
+    private boolean trySetupData(String reason, String type) {
+        if (DBG)
+            log("***trySetupData for type:" + type+" due to " + (reason == null ? "(unspecified)" : reason));
+        log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
 
+        if (type == null) {
+            type = Phone.APN_TYPE_DEFAULT;
+        }
+
+        ApnContext apnContext = mApnContexts.get(type);
+
+        if (apnContext == null ){
+            if (DBG) log("***new apn context for type:" + type);
+            apnContext = new ApnContext(type, LOG_TAG);
+            if (apnContext == null) {
+                if (DBG) log("***new apn context failed ");
+                return false;
+            }
+            mApnContexts.put(type, apnContext);
+        }
+        apnContext.setReason(reason);
+
+        return trySetupData(apnContext);
+
+    }
+
+    @Override
+    protected void setState(State s) {
+        if (DBG) log("setState should not be used in GSM" + s);
+    }
+
+    private boolean trySetupData(ApnContext apnContext) {
+
+        if (DBG)
+            log("trySetupData for type:" + apnContext.getApnType() +
+                " due to " + apnContext.getReason());
         log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
 
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
-            setState(State.CONNECTED);
-            notifyDataConnection(reason);
+            apnContext.setState(State.CONNECTED);
+            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
 
             log("(fix?) We're on the simulator; assuming data is connected");
             return true;
         }
 
-        int gprsState = mGsmPhone.mSST.getCurrentGprsState();
-        boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState();
+        boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
 
-        if (((mState == State.IDLE) || (mState == State.SCANNING)) &&
-                isDataAllowed() && getAnyDataEnabled()) {
+        if ((apnContext.getState() == State.IDLE || apnContext.getState() == State.SCANNING) &&
+                isDataAllowed(apnContext) && getAnyDataEnabled()) {
 
-            if (mState == State.IDLE) {
-                mWaitingApns = buildWaitingApns(mRequestedApnType);
-                mWaitingApnsPermanentFailureCountDown = mWaitingApns.size();
-                if (mWaitingApns.isEmpty()) {
+            if (apnContext.getState() == State.IDLE) {
+                ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());
+                if (waitingApns.isEmpty()) {
                     if (DBG) log("No APN found");
-                    notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
-                    notifyOffApnsOfAvailability(reason, false);
+                    notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN, apnContext);
+                    notifyOffApnsOfAvailability(apnContext.getReason(), false);
                     return false;
                 } else {
-                    log ("Create from allApns : " + apnListToString(mAllApns));
+                    apnContext.setWaitingApns(waitingApns);
+                    log ("Create from mAllApns : " + apnListToString(mAllApns));
                 }
             }
 
             if (DBG) {
-                log ("Setup waitngApns : " + apnListToString(mWaitingApns));
+                log ("Setup watingApns : " + apnListToString(apnContext.getWaitingApns()));
             }
-            boolean retValue = setupData(reason);
-            notifyOffApnsOfAvailability(reason, retValue);
+            // apnContext.setReason(apnContext.getReason());
+            boolean retValue = setupData(apnContext);
+            notifyOffApnsOfAvailability(apnContext.getReason(), retValue);
             return retValue;
         } else {
-            notifyOffApnsOfAvailability(reason, false);
+            // TODO: check the condition.
+            if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)
+                && (apnContext.getState() == State.IDLE
+                    || apnContext.getState() == State.SCANNING))
+                mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
+            notifyOffApnsOfAvailability(apnContext.getReason(), false);
             return false;
         }
     }
 
+    @Override
+    // Disabled apn's still need avail/unavail notificiations - send them out
+    protected void notifyOffApnsOfAvailability(String reason, boolean availability) {
+        if (mAvailability == availability) return;
+        mAvailability = availability;
+
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+        while (it.hasNext()) {
+            ApnContext apnContext = it.next();
+            // FIXME: Dont understand why this needs to be done!!
+            // This information is not available (DISABLED APNS)
+            if (false) {
+                if (DBG) log("notify disconnected for type:" + apnContext.getApnType());
+                mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
+                                            apnContext.getApnType(),
+                                            Phone.DataState.DISCONNECTED);
+            }
+        }
+    }
+
+    /**
+     * If tearDown is true, this only tears down a CONNECTED session. Presently,
+     * there is no mechanism for abandoning an INITING/CONNECTING session,
+     * but would likely involve cancelling pending async requests or
+     * setting a flag or new state to ignore them when they came in
+     * @param tearDown true if the underlying GsmDataConnection should be
+     * disconnected.
+     * @param reason reason for the clean up.
+     */
+    protected void cleanUpAllConnections(boolean tearDown, String reason) {
+        if (DBG) log("Clean up all connections due to " + reason);
+
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+        while (it.hasNext()) {
+            ApnContext apnContext = it.next();
+                apnContext.setReason(reason);
+            cleanUpConnection(tearDown, apnContext);
+        }
+
+        stopNetStatPoll();
+        // TODO: Do we need mRequestedApnType?
+        mRequestedApnType = Phone.APN_TYPE_DEFAULT;
+    }
+
     /**
      * Cleanup all connections.
      *
      * TODO: Cleanup only a specified connection passed as a parameter.
+     *       Also, make sure when you clean up a conn, if it is last apply
+     *       logic as though it is cleanupAllConnections
      *
      * @param tearDown true if the underlying DataConnection should be disconnected.
      * @param reason for the clean up.
      */
-    private void cleanUpConnection(boolean tearDown, String reason) {
-        if (DBG) log("Clean up connection due to " + reason);
+
+    @Override
+    protected void onCleanUpAllConnections() {
+        cleanUpAllConnections(true, null);
+    }
+
+    private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
+
+        if (apnContext == null) {
+            if (DBG) log("apn context is null");
+            return;
+        }
+
+        if (DBG) log("Clean up connection due to " + apnContext.getReason());
 
         // Clear the reconnect alarm, if set.
-        if (mReconnectIntent != null) {
+        if (apnContext.getReconnectIntent() != null) {
             AlarmManager am =
                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-            am.cancel(mReconnectIntent);
-            mReconnectIntent = null;
+            am.cancel(apnContext.getReconnectIntent());
+            apnContext.setReconnectIntent(null);
         }
 
-        setState(State.DISCONNECTING);
-
-        boolean notificationDeferred = false;
-        for (DataConnection conn : mDataConnections.values()) {
-            if (tearDown) {
-                if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
-                conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE,
-                        conn.getDataConnectionId(), 0, reason));
-                notificationDeferred = true;
-            } else {
-                if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
-                conn.resetSynchronously();
-                notificationDeferred = false;
-            }
+        if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
+            if (DBG) log("state is in " + apnContext.getState());
+            return;
         }
-        stopNetStatPoll();
 
-        if (!notificationDeferred) {
-            if (DBG) log("cleanupConnection: !notificationDeferred");
-            gotoIdleAndNotifyDataConnection(reason);
+        if (apnContext.getState() == State.FAILED) {
+            if (DBG) log("state is in FAILED");
+            apnContext.setState(State.IDLE);
+            return;
+        }
+
+        GsmDataConnection pdp = apnContext.getDataConnection();
+        if (tearDown && pdp!=null) {
+            apnContext.setState(State.DISCONNECTING);
+            Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+            pdp.disconnect(msg);
+            return;
+        } else if (pdp != null) {
+            pdp.clearSettings();
+        }
+
+        if (!tearDown) {
+            apnContext.setState(State.IDLE);
+            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+        }
+        if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
+           mApnContexts.remove(apnContext.getApnType());
         }
     }
 
+
     /**
      * @param types comma delimited list of APN types
      * @return array of APN types
@@ -419,6 +799,8 @@
             do {
                 String[] types = parseTypes(
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
+                int enabled =
+                    cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.ENABLED));
                 ApnSetting apn = new ApnSetting(
                         cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
@@ -435,7 +817,11 @@
                         types,
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
                         cursor.getString(cursor.getColumnIndexOrThrow(
-                                Telephony.Carriers.ROAMING_PROTOCOL)));
+                                Telephony.Carriers.ROAMING_PROTOCOL)),
+                        (enabled == 0 ? false : true),
+                        cursor.getInt(cursor.getColumnIndexOrThrow(
+                                Telephony.Carriers.INACTIVE_TIMER)),
+                        cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.CLASS)));
                 result.add(apn);
             } while (cursor.moveToNext());
         }
@@ -453,27 +839,71 @@
         return null;
     }
 
-    private boolean setupData(String reason) {
-        ApnSetting apn;
-        GsmDataConnection gdc;
+    protected GsmDataConnection findReadyDataConnection(ApnSetting apn) {
+        if (DBG)
+            log("findReadyDataConnection for apn string <" +
+                (apn!=null?(apn.toString()):"null") +">");
+        for (DataConnection conn : mDataConnections.values()) {
+            GsmDataConnection dc = (GsmDataConnection) conn;
+            if (DBG) log("dc apn string <" +
+                         (dc.getApn() != null ? (dc.getApn().toString()) : "null") + ">");
+            if (dc.getApn() != null && apn != null
+                && dc.getApn().toString().equals(apn.toString())) {
+                return dc;
+            }
+        }
+        return null;
+    }
 
-        apn = getNextApn();
-        if (apn == null) return false;
-        gdc = findFreeDataConnection();
-        if (gdc == null) {
+
+    private boolean setupData(ApnContext apnContext) {
+        if (DBG) log("enter setupData!");
+        ApnSetting apn;
+        GsmDataConnection dc;
+
+        int profileId = getApnProfileID(apnContext.getApnType());
+        apn = apnContext.getNextApn();
+        if (apn == null) {
+            if (DBG) log("setupData: return for no apn found!");
+            return false;
+        }
+
+        if (((mPhone.getServiceState().getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EHRPD)
+            || (mPhone.getServiceState().getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_LTE))
+            && (!apn.enabled)) {
+            if (DBG) log("setupData: apn is desabled by carrier!");
+            return false;
+        }
+
+        dc = findReadyDataConnection(apn);
+
+        if (dc == null) {
+            if (DBG) log("setupData: No ready GsmDataConnection found!");
+            // TODO: When allocating you are mapping type to id. If more than 1 free,
+            // then could findFreeDataConnection get the wrong one??
+            dc = findFreeDataConnection();
+        }
+
+        if (dc == null) {
             if (DBG) log("setupData: No free GsmDataConnection found!");
             return false;
         }
-        mActiveApn = apn;
-        mPendingDataConnection = gdc;
+
+        apnContext.setApnSetting(apn);
+        apnContext.setDataConnection(dc);
+        dc.setProfileId( profileId );
+        dc.setActiveApnType(apnContext.getApnType());
 
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
-        msg.obj = reason;
-        gdc.connect(msg, apn);
+        msg.obj = apnContext;
 
-        setState(State.INITING);
-        notifyDataConnection(reason);
+        if (DBG) log("dc connect!");
+        dc.connect(msg, apn);
+
+        apnContext.setState(State.INITING);
+        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+        if (DBG) log("setupData: initing!");
         return true;
     }
 
@@ -498,24 +928,28 @@
      * Handles changes to the APN database.
      */
     private void onApnChanged() {
+        // TODO: How to handle when multiple APNs are active?
         boolean isConnected;
 
-        isConnected = (mState != State.IDLE && mState != State.FAILED);
+        ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+        isConnected = (defaultApnContext.getState() != State.IDLE
+                       && defaultApnContext.getState() != State.FAILED);
 
-        // The "current" may no longer be valid.  MMS depends on this to send properly.
-        mGsmPhone.updateCurrentCarrierInProvider();
+        if (mPhone instanceof GSMPhone) {
+            // The "current" may no longer be valid.  MMS depends on this to send properly. TBD
+            ((GSMPhone)mPhone).updateCurrentCarrierInProvider();
+        }
 
         // TODO: It'd be nice to only do this if the changed entrie(s)
         // match the current operator.
         createAllApnList();
-        if (mState != State.DISCONNECTING) {
-            cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
-            if (!isConnected) {
-                // reset reconnect timer
-                mRetryMgr.resetRetryCount();
-                mReregisterOnReconnectFailure = false;
-                trySetupData(Phone.REASON_APN_CHANGED);
-            }
+        if (DBG) log("onApnChanged clean all connections");
+        cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
+        if (!isConnected) {
+            // TODO: Won't work for multiple connections!!!!
+            mRetryMgr.resetRetryCount();
+            defaultApnContext.setReason(Phone.REASON_APN_CHANGED);
+            trySetupData(defaultApnContext);
         }
     }
 
@@ -537,28 +971,46 @@
             return;
         }
 
-        if (mState == State.CONNECTED) {
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+        while (it.hasNext()) {
+            ApnContext apnContext = it.next();
+            onDataStateChanged(dataCallStates, explicitPoll, apnContext);
+        }
+    }
+
+    private void onDataStateChanged (ArrayList<DataCallState> dataCallStates,
+                                     boolean explicitPoll,
+                                     ApnContext apnContext) {
+
+        if (apnContext == null) {
+            // Should not happen
+            return;
+        }
+
+        if (apnContext.getState() == State.CONNECTED) {
             // The way things are supposed to work, the PDP list
             // should not contain the CID after it disconnects.
             // However, the way things really work, sometimes the PDP
             // context is still listed with active = false, which
             // makes it hard to distinguish an activating context from
             // an activated-and-then deactivated one.
-            if (!dataCallStatesHasCID(dataCallStates, mCidActive)) {
+            if (!dataCallStatesHasCID(dataCallStates, apnContext.getDataConnection().getCid())) {
                 // It looks like the PDP context has deactivated.
                 // Tear everything down and try to reconnect.
 
-                log("PDP connection has dropped. Reconnecting");
+                Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
 
                 // Add an event log when the network drops PDP
+                int cid = -1;
                 GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
-                EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP,
-                        loc != null ? loc.getCid() : -1,
+                if (loc != null) cid = loc.getCid();
+                EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
                         TelephonyManager.getDefault().getNetworkType());
 
-                cleanUpConnection(true, null);
+                cleanUpConnection(true, apnContext);
                 return;
-            } else if (!dataCallStatesHasActiveCID(dataCallStates, mCidActive)) {
+            } else if (!dataCallStatesHasActiveCID(dataCallStates,
+                    apnContext.getDataConnection().getCid())) {
                 // Here, we only consider this authoritative if we asked for the
                 // PDP list. If it was an unsolicited response, we poll again
                 // to make sure everyone agrees on the initial state.
@@ -568,33 +1020,37 @@
                     mPhone.mCM.getPDPContextList(
                             this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
                 } else {
-                    log("PDP connection has dropped (active=false case). "
+                    Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
                                     + " Reconnecting");
 
                     // Log the network drop on the event log.
+                    int cid = -1;
                     GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
-                    EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP,
-                            loc != null ? loc.getCid() : -1,
+                    if (loc != null) cid = loc.getCid();
+                    EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
                             TelephonyManager.getDefault().getNetworkType());
 
-                    cleanUpConnection(true, null);
+                    cleanUpConnection(true, apnContext);
                 }
             }
         }
     }
 
-    private void notifyDefaultData(String reason) {
-        setState(State.CONNECTED);
-        notifyDataConnection(reason);
+    private void notifyDefaultData(ApnContext apnContext) {
+        if (DBG)
+            log("notifyDefaultData for type: " + apnContext.getApnType()
+                + ", reason:" + apnContext.getReason());
+        apnContext.setState(State.CONNECTED);
+        // setState(State.CONNECTED);
+        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
         startNetStatPoll();
         // reset reconnect timer
         mRetryMgr.resetRetryCount();
-        mReregisterOnReconnectFailure = false;
     }
 
+    // TODO: For multiple Active APNs not exactly sure how to do this.
     private void gotoIdleAndNotifyDataConnection(String reason) {
         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
-        setState(State.IDLE);
         notifyDataConnection(reason);
         mActiveApn = null;
     }
@@ -608,18 +1064,18 @@
     }
 
     private void doRecovery() {
-        if (mState == State.CONNECTED) {
+        if (getOverallState() == State.CONNECTED) {
             int maxPdpReset = Settings.Secure.getInt(mResolver,
                     Settings.Secure.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
                     DEFAULT_MAX_PDP_RESET_FAIL);
             if (mPdpResetCount < maxPdpReset) {
                 mPdpResetCount++;
                 EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv);
-                cleanUpConnection(true, Phone.REASON_PDP_RESET);
+                cleanUpAllConnections(true, Phone.REASON_PDP_RESET);
             } else {
                 mPdpResetCount = 0;
                 EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv);
-                mGsmPhone.mSST.reRegisterNetwork(null);
+                mPhone.getServiceStateTracker().reRegisterNetwork(null);
             }
             // TODO: Add increasingly drastic recovery steps, eg,
             // reset the radio, reset the device.
@@ -628,7 +1084,7 @@
 
     @Override
     protected void startNetStatPoll() {
-        if (mState == State.CONNECTED && mNetStatPollEnabled == false) {
+        if (getOverallState() == State.CONNECTED && mNetStatPollEnabled == false) {
             log("[DataConnection] Start poll NetStat");
             resetPollStats();
             mNetStatPollEnabled = true;
@@ -646,8 +1102,8 @@
     @Override
     protected void restartRadio() {
         log("************TURN OFF RADIO**************");
-        cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
-        mGsmPhone.mSST.powerOffRadioSafely();
+        cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
+        mPhone.getServiceStateTracker().powerOffRadioSafely();
         /* Note: no need to call setRadioPower(true).  Assuming the desired
          * radio power state is still ON (as tracked by ServiceStateTracker),
          * ServiceStateTracker will call setRadioPower when it receives the
@@ -784,24 +1240,26 @@
         return retry;
     }
 
-    private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
-        if (mState == State.FAILED) {
-            /** TODO: Retrieve retry manager from connection itself */
+    private void reconnectAfterFail(FailCause lastFailCauseCode, ApnContext apnContext) {
+        if (apnContext == null) {
+            Log.d(LOG_TAG, "It is impossible");
+            return;
+        }
+        if (apnContext.getState() == State.FAILED) {
             if (!mRetryMgr.isRetryNeeded()) {
-                if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
+                if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)){
                     // if no more retries on a secondary APN attempt, tell the world and revert.
                     notifyDataConnection(Phone.REASON_APN_FAILED);
-                    onEnableApn(apnTypeToId(mRequestedApnType), DISABLED);
                     return;
                 }
                 if (mReregisterOnReconnectFailure) {
-                    // We've re-registered once now just retry forever.
+                    // We've re-registerd once now just retry forever.
                     mRetryMgr.retryForeverUsingLastTimeout();
                 } else {
-                    // Try to re-register to the network.
+                    // Try to Re-register to the network.
                     log("PDP activate failed, Reregistering to the network");
                     mReregisterOnReconnectFailure = true;
-                    mGsmPhone.mSST.reRegisterNetwork(null);
+                    mPhone.getServiceStateTracker().reRegisterNetwork(null);
                     mRetryMgr.resetRetryCount();
                     return;
                 }
@@ -814,48 +1272,61 @@
             AlarmManager am =
                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
             Intent intent = new Intent(INTENT_RECONNECT_ALARM);
-            intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason);
-            mReconnectIntent = PendingIntent.getBroadcast(
-                    mPhone.getContext(), 0, intent, 0);
+            intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
+            // Should put an extra of apn type?
+            intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType());
+            apnContext.setReconnectIntent(PendingIntent.getBroadcast (
+                    mPhone.getContext(), 0, intent, 0));
             am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
-                    mReconnectIntent);
+                    apnContext.getReconnectIntent());
 
             mRetryMgr.increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
-                log("NOT Posting GPRS Unavailable notification "
+                Log.d(LOG_TAG, "NOT Posting GPRS Unavailable notification "
                                 + "-- likely transient error");
             } else {
-                notifyNoData(lastFailCauseCode);
+                notifyNoData(lastFailCauseCode, apnContext);
             }
         }
     }
 
-    private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode) {
-        setState(State.FAILED);
+    private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode,
+                              ApnContext apnContext) {
+        if (DBG) log( "notifyNoData for type:" + apnContext.getApnType());
+        apnContext.setState(State.FAILED);
+        if (lastFailCauseCode.isPermanentFail()
+            && (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT))) {
+            mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
+        }
     }
 
     private void onRecordsLoaded() {
         createAllApnList();
-        if (mState == State.FAILED) {
-            cleanUpConnection(false, null);
+        ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+        if (defaultApnContext!=null ) {
+            defaultApnContext.setReason(Phone.REASON_SIM_LOADED);
+            if (defaultApnContext.getState() == State.FAILED) {
+                if (DBG) log("onRecordsLoaded clean connection");
+                cleanUpConnection(false, defaultApnContext);
+            }
+            sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA,defaultApnContext ));
         }
-        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
-    @Override
-    protected void onEnableNewApn() {
-        log("onEnableNewApn E");
+    protected void onEnableNewApn(ApnContext apnContext ) {
         // change our retry manager to use the appropriate numbers for the new APN
-        if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
+        log("onEnableNewApn with ApnContext E");
+        if (apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
             log("onEnableNewApn default type");
-            mRetryMgr = mPendingDataConnection.getRetryMgr();
+            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+            mRetryMgr = defaultApnContext.getDataConnection().getRetryMgr();
             mRetryMgr.resetRetryCount();
-        } else if (mApnToDataConnectionId.get(mRequestedApnType) == null) {
-            log("onEnableNewApn mRequestedApnType=" + mRequestedApnType +
+        } else if (mApnToDataConnectionId.get(apnContext.getApnType()) == null) {
+            log("onEnableNewApn ApnType=" + apnContext.getApnType() +
                     " missing, make a new connection");
-            int id = createDataConnection(mRequestedApnType);
+            int id = createDataConnection(apnContext.getApnType());
             mRetryMgr = mDataConnections.get(id).getRetryMgr();
             mRetryMgr.resetRetryCount();
         } else {
@@ -864,27 +1335,39 @@
 
         // TODO:  To support simultaneous PDP contexts, this should really only call
         // cleanUpConnection if it needs to free up a GsmDataConnection.
-        cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
-        log("onEnableNewApn X");
+        if (DBG) log("onEnableNewApn setup data");
+        if (apnContext.getState() == State.FAILED) {
+            if (DBG) log("previous state is FAILED, reset to IDLE");
+            apnContext.setState(State.IDLE);
+        }
+        trySetupData(apnContext);
+        log("onEnableNewApn with ApnContext X");
     }
 
     @Override
+    // TODO: We shouldnt need this.
     protected boolean onTrySetupData(String reason) {
-        return trySetupData(reason);
+        return trySetupData(reason, Phone.APN_TYPE_DEFAULT);
+    }
+
+    protected boolean onTrySetupData(ApnContext apnContext) {
+        return trySetupData(apnContext);
     }
 
     @Override
+    // TODO: Need to understand if more than DEFAULT is impacted?
     protected void onRoamingOff() {
-        trySetupData(Phone.REASON_ROAMING_OFF);
+        trySetupData(Phone.REASON_ROAMING_OFF, Phone.APN_TYPE_DEFAULT);
     }
 
     @Override
+    // TODO: Need to understand if more than DEFAULT is impacted?
     protected void onRoamingOn() {
         if (getDataOnRoamingEnabled()) {
-            trySetupData(Phone.REASON_ROAMING_ON);
+            trySetupData(Phone.REASON_ROAMING_ON, Phone.APN_TYPE_DEFAULT);
         } else {
             if (DBG) log("Tear down data connection on roaming.");
-            cleanUpConnection(true, Phone.REASON_ROAMING_ON);
+            cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
         }
     }
 
@@ -893,13 +1376,13 @@
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
-            setState(State.CONNECTED);
+            // setState(State.CONNECTED);
             notifyDataConnection(null);
 
             log("We're on the simulator; assuming data is connected");
         }
 
-        if (mState != State.IDLE) {
+        if (getOverallState() != State.IDLE) {
             cleanUpConnection(true, null);
         }
     }
@@ -917,28 +1400,30 @@
             log("We're on the simulator; assuming radio off is meaningless");
         } else {
             if (DBG) log("Radio is off and clean up all connection");
-            // TODO: Should we reset mRequestedApnType to "default"?
-            cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF);
+            cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
         }
     }
 
     @Override
     protected void onDataSetupComplete(AsyncResult ar) {
-        /** TODO: Which connection is completing should be a parameter */
-        String reason = null;
-        if (ar.userObj instanceof String) {
-            reason = (String) ar.userObj;
+
+        ApnContext apnContext = null;
+
+        if(ar.userObj instanceof ApnContext){
+            apnContext = (ApnContext)ar.userObj;
         }
 
         if (ar.exception == null) {
-            if(DBG) {
-                log(String.format("onDataSetupComplete: success apn=%s", mWaitingApns.get(0).apn));
-            }
+            // Everything is setup
             // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
-            mLinkProperties = getLinkProperties(mPendingDataConnection);
-            mLinkCapabilities = getLinkCapabilities(mPendingDataConnection);
+            if (DBG) {
+                log(String.format("onDataSetupComplete: success apn=%s",
+                    apnContext.getWaitingApns().get(0).apn));
+            }
+            mLinkProperties = getLinkProperties(apnContext.getDataConnection());
+            mLinkCapabilities = getLinkCapabilities(apnContext.getDataConnection());
 
-            ApnSetting apn = mPendingDataConnection.getApn();
+            ApnSetting apn = apnContext.getDataConnection().getApn();
             if (apn.proxy != null && apn.proxy.length() != 0) {
                 try {
                     ProxyProperties proxy = new ProxyProperties(apn.proxy,
@@ -951,29 +1436,34 @@
             }
 
             // everything is setup
-            if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
+            if(TextUtils.equals(apnContext.getApnType(),Phone.APN_TYPE_DEFAULT)) {
                 SystemProperties.set("gsm.defaultpdpcontext.active", "true");
-                        if (canSetPreferApn && mPreferredApn == null) {
-                            log("PREFERRED APN is null");
-                            mPreferredApn = mActiveApn;
-                            setPreferredApn(mPreferredApn.id);
-                        }
+                if (canSetPreferApn && mPreferredApn == null) {
+                    log("PREFERED APN is null");
+                    mPreferredApn = apnContext.getApnSetting();
+                    if (mPreferredApn != null) {
+                        setPreferredApn(mPreferredApn.id);
+                    }
+                }
             } else {
                 SystemProperties.set("gsm.defaultpdpcontext.active", "false");
             }
-            notifyDefaultData(reason);
+            notifyDefaultData(apnContext);
 
             // TODO: For simultaneous PDP support, we need to build another
             // trigger another TRY_SETUP_DATA for the next APN type.  (Note
             // that the existing connection may service that type, in which
             // case we should try the next type, etc.
+            // I dont believe for simultaneous PDP you need to trigger. Each
+            // Connection should be independent and they can be setup simultaneously
+            // So, dont have to wait till one is finished.
         } else {
             GsmDataConnection.FailCause cause;
             cause = (GsmDataConnection.FailCause) (ar.result);
             if (DBG) {
                 String apnString;
                 try {
-                    apnString = mWaitingApns.get(0).apn;
+                    apnString = apnContext.getWaitingApns().get(0).apn;
                 } catch (Exception e) {
                     apnString = "<unknown>";
                 }
@@ -988,28 +1478,31 @@
             }
 
             // Count permanent failures and remove the APN we just tried
-            mWaitingApnsPermanentFailureCountDown -= cause.isPermanentFail() ? 1 : 0;
-            mWaitingApns.remove(0);
+            // TODO: Where is mWaitingApnsPermanentFailureCountDown initialized
+            if (cause.isPermanentFail())
+                apnContext.decPermFailCount();
+
+            apnContext.removeNextApn();
             if (DBG) log(String.format("onDataSetupComplete: mWaitingApns.size=%d" +
                             " mWaitingApnsPermanenatFailureCountDown=%d",
-                            mWaitingApns.size(), mWaitingApnsPermanentFailureCountDown));
+                            apnContext.getWaitingApns().size(), apnContext.getPermFailCount()));
 
             // See if there are more APN's to try
-            if (mWaitingApns.isEmpty()) {
-                if (mWaitingApnsPermanentFailureCountDown == 0) {
+            if (apnContext.getWaitingApns().isEmpty()) {
+                if (apnContext.getPermFailCount() == 0) {
                     if (DBG) log("onDataSetupComplete: Permanent failures stop retrying");
-                    notifyNoData(cause);
+                    apnContext.setState(State.FAILED);
                     notifyDataConnection(Phone.REASON_APN_FAILED);
                 } else {
                     if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
-                    startDelayedRetry(cause, reason);
+                    startDelayedRetry(cause, apnContext);
                 }
             } else {
                 if (DBG) log("onDataSetupComplete: Try next APN");
-                setState(State.SCANNING);
+                apnContext.setState(State.SCANNING);
                 // Wait a bit before trying the next APN, so that
                 // we're not tying up the RIL command channel
-                sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
+                sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext), APN_DELAY_MILLIS);
             }
         }
     }
@@ -1019,16 +1512,31 @@
      */
     @Override
     protected void onDisconnectDone(int connId, AsyncResult ar) {
+        ApnContext apnContext = null;
+
         if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId);
-        String reason = null;
-        if (ar.userObj instanceof String) {
-           reason = (String) ar.userObj;
+        if (ar.userObj instanceof ApnContext) {
+            apnContext = (ApnContext) ar.userObj;
         }
-        setState(State.IDLE);
-        notifyDataConnection(reason);
-        mActiveApn = null;
-        if (retryAfterDisconnected(reason)) {
-            trySetupData(reason);
+
+        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+        // Check if APN disabled.
+        if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
+           mApnContexts.remove(apnContext.getApnType());
+           return;
+        }
+
+        apnContext.setState(State.IDLE);
+        apnContext.setApnSetting(null);
+        if (TextUtils.equals(apnContext.getApnType(), Phone.APN_TYPE_DEFAULT)
+            && retryAfterDisconnected(apnContext.getReason())) {
+            SystemProperties.set("gsm.defaultpdpcontext.active", "false");
+            trySetupData(apnContext);
+        }
+        else if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_RECONNECT)
+        {
+            apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
+            trySetupData(apnContext);
         }
     }
 
@@ -1046,7 +1554,7 @@
     }
 
     protected void onPollPdp() {
-        if (mState == State.CONNECTED) {
+        if (getOverallState() == State.CONNECTED) {
             // only poll when connected
             mPhone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
             sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
@@ -1055,7 +1563,7 @@
 
     @Override
     protected void onVoiceCallStarted() {
-        if (mState == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) {
+        if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
             stopNetStatPoll();
             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
         }
@@ -1063,8 +1571,8 @@
 
     @Override
     protected void onVoiceCallEnded() {
-        if (mState == State.CONNECTED) {
-            if (!mGsmPhone.mSST.isConcurrentVoiceAndData()) {
+        if (isConnected()) {
+            if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                 startNetStatPoll();
                 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
             } else {
@@ -1076,13 +1584,39 @@
             mRetryMgr.resetRetryCount();
             mReregisterOnReconnectFailure = false;
             // in case data setup was attempted when we were on a voice call
-            trySetupData(Phone.REASON_VOICE_CALL_ENDED);
+            trySetupData(Phone.REASON_VOICE_CALL_ENDED, Phone.APN_TYPE_DEFAULT);
         }
     }
 
     @Override
-    protected void onCleanUpConnection(boolean tearDown, String reason) {
-        cleanUpConnection(tearDown, reason);
+    protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
+        if (DBG) log("onCleanUpConnection");
+        ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
+        cleanUpConnection(tearDown, apnContext);
+    }
+
+    protected boolean isConnected() {
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+         while (it.hasNext()) {
+            ApnContext apnContext = it.next();
+            if (apnContext.getState() == State.CONNECTED) {
+            return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void notifyDataConnection(String reason) {
+        if (DBG) log("notify all enabled connection for:" + reason);
+        Iterator<ApnContext> it = mApnContexts.values().iterator();
+        while (it.hasNext()) {
+            ApnContext apnContext = it.next();
+            if (DBG) log("notify for type:"+apnContext.getApnType());
+            mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
+                    apnContext.getApnType());
+        }
+        notifyDataAvailability(reason);
     }
 
     /**
@@ -1091,7 +1625,7 @@
      */
     private void createAllApnList() {
         mAllApns = new ArrayList<ApnSetting>();
-        String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
+        String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (operator != null) {
             String selection = "numeric = '" + operator + "'";
@@ -1110,7 +1644,8 @@
         if (mAllApns.isEmpty()) {
             if (DBG) log("No APN found for carrier: " + operator);
             mPreferredApn = null;
-            notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
+            // TODO: What is the right behaviour?
+            //notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
         } else {
             mPreferredApn = getPreferredApn();
             log("Get PreferredAPN");
@@ -1147,7 +1682,7 @@
         }
 
         int id = mUniqueIdGenerator.getAndIncrement();
-        DataConnection conn = GsmDataConnection.makeDataConnection(mGsmPhone, id, rm);
+        DataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm);
         mDataConnections.put(id, conn);
         mApnToDataConnectionId.put(apnType, id);
 
@@ -1180,7 +1715,7 @@
             return apnList;
         }
 
-        String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
+        String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (canSetPreferApn && mPreferredApn != null) {
@@ -1207,22 +1742,6 @@
         return apnList;
     }
 
-    /**
-     * Get next apn in waitingApns
-     * @return the first apn found in waitingApns, null if none
-     */
-    private ApnSetting getNextApn() {
-        ArrayList<ApnSetting> list = mWaitingApns;
-        ApnSetting apn = null;
-
-        if (list != null) {
-            if (!list.isEmpty()) {
-                apn = list.get(0);
-            }
-        }
-        return apn;
-    }
-
     private String apnListToString (ArrayList<ApnSetting> apns) {
         StringBuilder result = new StringBuilder();
         for (int i = 0, size = apns.size(); i < size; i++) {
@@ -1233,9 +1752,9 @@
         return result.toString();
     }
 
-    private void startDelayedRetry(GsmDataConnection.FailCause cause, String reason) {
-        notifyNoData(cause);
-        reconnectAfterFail(cause, reason);
+    private void startDelayedRetry(GsmDataConnection.FailCause cause, ApnContext apnContext) {
+        notifyNoData(cause, apnContext);
+        reconnectAfterFail(cause, apnContext);
     }
 
     private void setPreferredApn(int pos) {
@@ -1291,7 +1810,7 @@
     public void handleMessage (Message msg) {
         if (DBG) log("GSMDataConnTrack handleMessage "+msg);
 
-        if (!mGsmPhone.mIsTheCurrentActivePhone) {
+        if (!mPhone.mIsTheCurrentActivePhone) {
             log("Ignore GSM msgs since GSM phone is inactive");
             return;
         }
@@ -1301,12 +1820,20 @@
                 onRecordsLoaded();
                 break;
 
-            case EVENT_GPRS_DETACHED:
-                onGprsDetached();
+        case EVENT_ENABLE_NEW_APN:
+                ApnContext apnContext = null;
+                if (msg.obj instanceof ApnContext) {
+                    apnContext = (ApnContext)msg.obj;
+                }
+                onEnableNewApn(apnContext);
                 break;
 
-            case EVENT_GPRS_ATTACHED:
-                onGprsAttached();
+            case EVENT_DATA_CONNECTION_DETACHED:
+                onDataConnectionDetached();
+                break;
+
+            case EVENT_DATA_CONNECTION_ATTACHED:
+                onDataConnectionAttached();
                 break;
 
             case EVENT_DATA_STATE_CHANGED:
@@ -1352,18 +1879,37 @@
                  */
                 log("[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
                 mIsPsRestricted  = false;
-                if (mState == State.CONNECTED) {
+                if (isConnected()) {
                     startNetStatPoll();
                 } else {
+                    // TODO: Should all PDN states be checked to fail?
                     if (mState == State.FAILED) {
-                        cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
+                        cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
                         mRetryMgr.resetRetryCount();
                         mReregisterOnReconnectFailure = false;
                     }
-                    trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
+                    trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, Phone.APN_TYPE_DEFAULT);
+                }
+                break;
+            case EVENT_TRY_SETUP_DATA:
+                if (msg.obj instanceof ApnContext) {
+                    onTrySetupData((ApnContext)msg.obj);
+                } else {
+                    if (msg.obj instanceof String) {
+                        onTrySetupData((String)msg.obj);
+                    }
                 }
                 break;
 
+            case EVENT_CLEAN_UP_CONNECTION:
+                boolean tearDown = (msg.arg1 == 0) ? false : true;
+                if (msg.obj instanceof ApnContext) {
+                    cleanUpConnection(tearDown, (ApnContext)msg.obj);
+                } else {
+                    Log.e(LOG_TAG,
+                          "[GsmDataConnectionTracker] connectpion cleanup request w/o apn context");
+                }
+                break;
             default:
                 // handle the message in the super class DataConnectionTracker
                 super.handleMessage(msg);
@@ -1371,6 +1917,18 @@
         }
     }
 
+    protected int getApnProfileID(String apnType) {
+        if (TextUtils.equals(apnType, Phone.APN_TYPE_IMS)) {
+            return RILConstants.DATA_PROFILE_IMS;
+        } else if (TextUtils.equals(apnType, Phone.APN_TYPE_FOTA)) {
+            return RILConstants.DATA_PROFILE_FOTA;
+        } else if (TextUtils.equals(apnType, Phone.APN_TYPE_CBS)) {
+            return RILConstants.DATA_PROFILE_CBS;
+        } else {
+            return RILConstants.DATA_PROFILE_DEFAULT;
+        }
+    }
+
     @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index f576b4e..21a12f1 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -99,7 +99,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected int dispatchMessage(SmsMessageBase smsb) {
+    public int dispatchMessage(SmsMessageBase smsb) {
 
         // If sms is null, means there was a parsing error.
         if (smsb == null) {
@@ -383,7 +383,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void activateCellBroadcastSms(int activate, Message response) {
+    public void activateCellBroadcastSms(int activate, Message response) {
         // Unless CBS is implemented for GSM, this point should be unreachable.
         Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
         response.recycle();
@@ -391,7 +391,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void getCellBroadcastSmsConfig(Message response){
+    public void getCellBroadcastSmsConfig(Message response){
         // Unless CBS is implemented for GSM, this point should be unreachable.
         Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
         response.recycle();
@@ -399,7 +399,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected  void setCellBroadcastConfig(int[] configValuesArray, Message response) {
+    public  void setCellBroadcastConfig(int[] configValuesArray, Message response) {
         // Unless CBS is implemented for GSM, this point should be unreachable.
         Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
         response.recycle();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index ac83808..416184d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -278,7 +278,8 @@
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    void registerForGprsAttached(Handler h, int what, Object obj) {
+    @Override
+    public void registerForDataConnectionAttached(Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
         gprsAttachedRegistrants.add(r);
 
@@ -287,7 +288,8 @@
         }
     }
 
-    void unregisterForGprsAttached(Handler h) {
+    @Override
+    public void unregisterForDataConnectionAttached(Handler h) {
         gprsAttachedRegistrants.remove(h);
     }
 
@@ -329,7 +331,7 @@
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
+    public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
         Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled ");
         Registrant r = new Registrant(h, what, obj);
         psRestrictEnabledRegistrants.add(r);
@@ -339,7 +341,7 @@
         }
     }
 
-    void unregisterForPsRestrictedEnabled(Handler h) {
+    public void unregisterForPsRestrictedEnabled(Handler h) {
         psRestrictEnabledRegistrants.remove(h);
     }
 
@@ -349,7 +351,7 @@
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
+    public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
         Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled ");
         Registrant r = new Registrant(h, what, obj);
         psRestrictDisabledRegistrants.add(r);
@@ -359,7 +361,7 @@
         }
     }
 
-    void unregisterForPsRestrictedDisabled(Handler h) {
+    public void unregisterForPsRestrictedDisabled(Handler h) {
         psRestrictDisabledRegistrants.remove(h);
     }
 
@@ -567,33 +569,21 @@
             && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
             cm.setRadioPower(true, null);
         } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
-            DataConnectionTracker dcTracker = phone.mDataConnection;
-            if (! dcTracker.isDataConnectionAsDesired()) {
-                EventLog.writeEvent(EventLogTags.DATA_NETWORK_STATUS_ON_RADIO_OFF,
-                        dcTracker.getStateInString(), dcTracker.getAnyDataEnabled() ? 1 : 0);
-            }
             // If it's on and available and we want it off gracefully
             powerOffRadioSafely();
         } // Otherwise, we're in the desired state
     }
 
     @Override
-    protected void powerOffRadioSafely() {
-        // clean data connection
+    public void powerOffRadioSafely() {
+        // Cleanup all connections
         DataConnectionTracker dcTracker = phone.mDataConnection;
-        Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
-        msg.arg1 = 1; // tearDown is true
-        msg.obj = GSMPhone.REASON_RADIO_TURNED_OFF;
+        Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_ALL_CONNECTIONS);
         dcTracker.sendMessage(msg);
 
         // poll data state up to 15 times, with a 100ms delay
         // totaling 1.5 sec. Normal data disable action will finish in 100ms.
         for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) {
-            if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED
-                    && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) {
-                Log.d(LOG_TAG, "Data shutdown complete.");
-                break;
-            }
             SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
         }
 
@@ -1073,7 +1063,7 @@
         }
 
         if (hasNetworkTypeChanged) {
-            phone.notifyDataConnection();
+            phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED, Phone.APN_TYPE_ALL);
         }
 
         if (hasRoamingOn) {
@@ -1401,11 +1391,15 @@
         return gprsState;
     }
 
+    public int getCurrentDataConnectionState() {
+        return gprsState;
+    }
+
     /**
      * @return true if phone is camping on a technology (eg UMTS)
      * that could support voice and data simultaneously.
      */
-    boolean isConcurrentVoiceAndData() {
+    public boolean isConcurrentVoiceAndDataAllowed() {
         return (networkType >= DATA_ACCESS_UMTS);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 3b133da..11ce83e 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -35,6 +35,7 @@
 import com.android.internal.telephony.IccVmFixedException;
 import com.android.internal.telephony.IccVmNotSupportedException;
 import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.PhoneBase;
 
 import java.util.ArrayList;
 
@@ -165,7 +166,7 @@
 
     // ***** Constructor
 
-    SIMRecords(GSMPhone p) {
+    public SIMRecords(PhoneBase p) {
         super(p);
 
         adnCache = new AdnRecordCache(phone);
@@ -364,7 +365,7 @@
 
         countVoiceMessages = countWaiting;
 
-        ((GSMPhone) phone).notifyMessageWaitingIndicator();
+        phone.notifyMessageWaitingIndicator();
 
         try {
             if (efMWIS != null) {
@@ -413,7 +414,7 @@
 
         callForwardingEnabled = enable;
 
-        ((GSMPhone) phone).notifyCallForwardingIndicator();
+        phone.notifyCallForwardingIndicator();
 
         try {
             if (mEfCfis != null) {
@@ -470,7 +471,7 @@
     /** Returns the 5 or 6 digit MCC/MNC of the operator that
      *  provided the SIM card. Returns null of SIM is not yet ready
      */
-    String getSIMOperatorNumeric() {
+    public String getSIMOperatorNumeric() {
         if (imsi == null || mncLength == UNINITIALIZED || mncLength == UNKNOWN) {
             return null;
         }
@@ -547,7 +548,7 @@
                     // finally have both the imsi and the mncLength and can parse the imsi properly
                     MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
                 }
-                ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
+                phone.mSimCard.broadcastIccStateChangedIntent(
                         SimCard.INTENT_VALUE_ICC_IMSI, null);
             break;
 
@@ -702,7 +703,7 @@
                     countVoiceMessages = -1;
                 }
 
-                ((GSMPhone) phone).notifyMessageWaitingIndicator();
+                phone.notifyMessageWaitingIndicator();
             break;
 
             case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
@@ -731,7 +732,7 @@
                         countVoiceMessages = 0;
                     }
 
-                    ((GSMPhone) phone).notifyMessageWaitingIndicator();
+                    phone.notifyMessageWaitingIndicator();
                 }
             break;
 
@@ -842,7 +843,7 @@
                     callForwardingEnabled =
                         ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
 
-                    ((GSMPhone) phone).notifyCallForwardingIndicator();
+                    phone.notifyCallForwardingIndicator();
                 }
                 break;
 
@@ -1042,7 +1043,7 @@
                 // Refer TS 51.011 Section 10.3.46 for the content description
                 callForwardingEnabled = ((data[1] & 0x01) != 0);
 
-                ((GSMPhone) phone).notifyCallForwardingIndicator();
+                phone.notifyCallForwardingIndicator();
                 break;
 
             case EVENT_GET_CSP_CPHS_DONE:
@@ -1152,7 +1153,7 @@
             System.arraycopy(ba, 1, pdu, 0, n - 1);
             SmsMessage message = SmsMessage.createFromPdu(pdu);
 
-            ((GSMPhone) phone).mSMS.dispatchMessage(message);
+            phone.mSMS.dispatchMessage(message);
         }
     }
 
@@ -1178,7 +1179,7 @@
                 System.arraycopy(ba, 1, pdu, 0, n - 1);
                 SmsMessage message = SmsMessage.createFromPdu(pdu);
 
-                ((GSMPhone) phone).mSMS.dispatchMessage(message);
+                phone.mSMS.dispatchMessage(message);
 
                 // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
                 // 1 == "received by MS from network; message read"
@@ -1228,7 +1229,7 @@
 
         recordsLoadedRegistrants.notifyRegistrants(
             new AsyncResult(null, null, null));
-        ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
+        phone.mSimCard.broadcastIccStateChangedIntent(
                 SimCard.INTENT_VALUE_ICC_LOADED, null);
     }
 
@@ -1249,11 +1250,11 @@
         }
     }
 
-    private void onSimReady() {
+    public void onSimReady() {
         /* broadcast intent SIM_READY here so that we can make sure
           READY is sent before IMSI ready
         */
-        ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
+        phone.mSimCard.broadcastIccStateChangedIntent(
                 SimCard.INTENT_VALUE_ICC_READY, null);
 
         fetchSimRecords();
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index 835cb29..5a2f871 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -19,6 +19,8 @@
 import android.util.Log;
 
 import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.PhoneBase;
+import android.os.SystemProperties;
 
 /**
  * {@hide}
@@ -34,6 +36,21 @@
         updateStateProperty();
     }
 
+    /**
+    * We have the Sim card for LTE on CDMA phone
+    */
+    public SimCard(PhoneBase phone, String logTag, Boolean dbg) {
+        super(phone, logTag, dbg);
+        mPhone.mCM.registerForSIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
+        mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+        mPhone.mCM.registerForSIMReady(mHandler, EVENT_ICC_READY, null);
+        updateStateProperty();
+
+        if(SystemProperties.getBoolean("ro.mot.lte_on_cdma", false)) {
+            mPhone.mCM.registerForNVReady(mHandler, EVENT_ICC_READY, null);
+        }
+    }
+
     @Override
     public void dispose() {
         //Unregister for all events
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
index 1032074..a1078c1 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
@@ -58,21 +58,21 @@
         testString = "Vodafone IT,web.omnitel.it,,,,,,,,,222,10,,DUN";
         expected_apn =  new ApnSetting(
                 -1, "22210", "Vodafone IT", "web.omnitel.it", "", "",
-                "", "", "", "", "", 0, dunTypes, "IP", "IP");
+                "", "", "", "", "", 0, dunTypes, "IP", "IP", true, 0, 0);
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
 
         // A v2 string.
         testString = "[ApnSettingV2] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP";
         expected_apn =  new ApnSetting(
                 -1, "12345", "Name", "apn", "", "",
-                "", "", "", "", "", 0, mmsTypes, "IPV6", "IP");
+                "", "", "", "", "", 0, mmsTypes, "IPV6", "IP", true, 0, 0);
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
 
         // A v2 string with spaces.
         testString = "[ApnSettingV2] Name,apn, ,,,,,,,,123,45,,mms|*,IPV4V6, IP";
         expected_apn =  new ApnSetting(
                 -1, "12345", "Name", "apn", "", "",
-                "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP");
+                "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP", true, 0, 0);
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
 
         // Return null if insufficient fields given.
@@ -87,7 +87,7 @@
         String[] incorrectTypes = {"mms|*", "IPV6"};
         expected_apn =  new ApnSetting(
                 -1, "12345", "Name", "apn", "", "",
-                "", "", "", "", "", 0, incorrectTypes, "IP", "IP");
+                "", "", "", "", "", 0, incorrectTypes, "IP", "IP", true, 0, 0);
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
     }
 
@@ -98,7 +98,7 @@
         ApnSetting apn =  new ApnSetting(
                 99, "12345", "Name", "apn", "proxy", "port",
                 "mmsc", "mmsproxy", "mmsport", "user", "password", 0,
-                types, "IPV4V6", "IP");
+                types, "IPV4V6", "IP", true, 0, 0);
         String expected = "[ApnSettingV2] Name, 99, 12345, apn, proxy, " +
                 "mmsc, mmsproxy, mmsport, port, 0, default | *, " +
                 "IPV4V6, IP";