am b17cc8a8: Merge "Add moov/mdat and 500KB max A/V drift recommendations to Supported Media Formats doc. Also reformat encoding parameter recommendations into a single table." into honeycomb-mr1

* commit 'b17cc8a83fd819efcb79d78d005e16b3f04d08df':
  Add moov/mdat and 500KB max A/V drift recommendations to Supported Media Formats doc. Also reformat encoding parameter recommendations into a single table.
diff --git a/Android.mk b/Android.mk
index b266061..6216a2c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -123,10 +123,10 @@
 	core/java/android/nfc/ILlcpServiceSocket.aidl \
 	core/java/android/nfc/ILlcpSocket.aidl \
 	core/java/android/nfc/INfcAdapter.aidl \
+	core/java/android/nfc/INfcAdapterExtras.aidl \
 	core/java/android/nfc/INfcTag.aidl \
 	core/java/android/nfc/IP2pInitiator.aidl \
 	core/java/android/nfc/IP2pTarget.aidl \
-    core/java/android/nfc/INfcSecureElement.aidl \
 	core/java/android/os/IHardwareService.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 2eee813..023ce59 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -95,7 +95,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PerfTest_intermediates/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RSTest_intermediates/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware/IUsbManager.java)
-
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ccd65de..c9351af 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -416,7 +416,7 @@
         if (this.largeIcon != null) {
             that.largeIcon = Bitmap.createBitmap(this.largeIcon);
         }
-        that.iconLevel = that.iconLevel;
+        that.iconLevel = this.iconLevel;
         that.sound = this.sound; // android.net.Uri is immutable
         that.audioStreamType = this.audioStreamType;
 
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/LinkProperties.java b/core/java/android/net/LinkProperties.java
index b6e9751..81d62a0 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -91,7 +91,7 @@
     }
 
     public void addLinkAddress(LinkAddress address) {
-        mLinkAddresses.add(address);
+        if (address != null) mLinkAddresses.add(address);
     }
 
     public Collection<LinkAddress> getLinkAddresses() {
@@ -99,7 +99,7 @@
     }
 
     public void addDns(InetAddress dns) {
-        mDnses.add(dns);
+        if (dns != null) mDnses.add(dns);
     }
 
     public Collection<InetAddress> getDnses() {
@@ -107,7 +107,7 @@
     }
 
     public void addGateway(InetAddress gateway) {
-        mGateways.add(gateway);
+        if (gateway != null) mGateways.add(gateway);
     }
     public Collection<InetAddress> getGateways() {
         return Collections.unmodifiableCollection(mGateways);
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/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index d439a48..870127c 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -28,7 +28,7 @@
 import android.nfc.INfcTag;
 import android.nfc.IP2pTarget;
 import android.nfc.IP2pInitiator;
-import android.nfc.INfcSecureElement;
+import android.nfc.INfcAdapterExtras;
 
 /**
  * @hide
@@ -41,13 +41,12 @@
     INfcTag getNfcTagInterface();
     IP2pTarget getP2pTargetInterface();
     IP2pInitiator getP2pInitiatorInterface();
-    INfcSecureElement getNfcSecureElementInterface();
+    INfcAdapterExtras getNfcAdapterExtrasInterface();
 
     // NfcAdapter-class related methods
     boolean isEnabled();
     NdefMessage localGet();
     void localSet(in NdefMessage message);
-    void openTagConnection(in Tag tag);
     void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
             in IntentFilter[] filters, in TechListParcel techLists);
     void disableForegroundDispatch(in ComponentName activity);
@@ -59,12 +58,8 @@
     int createLlcpConnectionlessSocket(int sap);
     int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength);
     int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength);
-    int deselectSecureElement();
     boolean disable();
     boolean enable();
     String getProperties(String param);
-    int[] getSecureElementList();
-    int getSelectedSecureElement();
-    int selectSecureElement(int seId);
     int setProperties(String param, String value);
-}
\ No newline at end of file
+}
diff --git a/core/java/android/nfc/INfcSecureElement.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl
similarity index 63%
rename from core/java/android/nfc/INfcSecureElement.aidl
rename to core/java/android/nfc/INfcAdapterExtras.aidl
index aa98dd2..ab5c1a6 100755
--- a/core/java/android/nfc/INfcSecureElement.aidl
+++ b/core/java/android/nfc/INfcAdapterExtras.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -16,13 +16,15 @@
 
 package android.nfc;
 
+import android.os.Bundle;
+
 /**
  * {@hide}
  */
-interface INfcSecureElement {
-    int openSecureElementConnection();
-    int closeSecureElementConnection(int nativeHandle);
-    byte[] exchangeAPDU(int nativeHandle, in byte[] data);
-    int[] getSecureElementTechList(int nativeHandle);
-    byte[] getSecureElementUid(int nativeHandle);
-}
\ No newline at end of file
+interface INfcAdapterExtras {
+    Bundle open(IBinder b);
+    Bundle close();
+    Bundle transceive(in byte[] data_in);
+    int getCardEmulationRoute();
+    void setCardEmulationRoute(int route);    
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 8c56fda..4689804 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -157,31 +157,6 @@
     public static final String EXTRA_ID = "android.nfc.extra.ID";
 
     /**
-     * Broadcast Action: a transaction with a secure element has been detected.
-     * <p>
-     * Always contains the extra field
-     * {@link android.nfc.NfcAdapter#EXTRA_AID}
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_TRANSACTION_DETECTED =
-            "android.nfc.action.TRANSACTION_DETECTED";
-
-    /**
-     * Broadcast Action: an RF field ON has been detected.
-     * @hide
-     */
-    public static final String ACTION_RF_FIELD_ON_DETECTED =
-            "android.nfc.action.RF_FIELD_ON_DETECTED";
-
-    /**
-     * Broadcast Action: an RF Field OFF has been detected.
-     * @hide
-     */
-    public static final String ACTION_RF_FIELD_OFF_DETECTED =
-            "android.nfc.action.RF_FIELD_OFF_DETECTED";
-
-    /**
      * Broadcast Action: an adapter's state changed between enabled and disabled.
      *
      * The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains
@@ -201,15 +176,6 @@
     public static final String EXTRA_NEW_BOOLEAN_STATE = "android.nfc.isEnabled";
 
     /**
-     * Mandatory byte array extra field in
-     * {@link android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED}.
-     * <p>
-     * Contains the AID of the applet involved in the transaction.
-     * @hide
-     */
-    public static final String EXTRA_AID = "android.nfc.extra.AID";
-
-    /**
      * LLCP link status: The LLCP link is activated.
      * @hide
      */
@@ -691,39 +657,14 @@
     }
 
     /**
-     * Create an Nfc Secure Element Connection
      * @hide
      */
-    public NfcSecureElement createNfcSecureElementConnection() {
+    public INfcAdapterExtras getNfcAdapterExtrasInterface() {
         try {
-            return new NfcSecureElement(sService.getNfcSecureElementInterface());
+            return sService.getNfcAdapterExtrasInterface();
         } catch (RemoteException e) {
-            Log.e(TAG, "createNfcSecureElementConnection failed", e);
+            attemptDeadServiceRecovery(e);
             return null;
         }
     }
-
-    /**
-     * To change the Secure Element Card Emulation state (ON/OFF)
-     * @hide
-     */
-    public void changeNfcSecureElementCardEmulationState(boolean state)
-    {
-        int seId = 11259375;
-        if(state){
-            /* Enable card emulation */
-            try {
-                sService.selectSecureElement(seId);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Enable card emulation failed", e);
-            }
-        }else{
-            /* Disable card emulation */
-            try {
-                sService.deselectSecureElement();
-            } catch (RemoteException e) {
-                Log.e(TAG, " card emulation failed", e);
-            }
-        }
-    }
 }
diff --git a/core/java/android/nfc/NfcSecureElement.java b/core/java/android/nfc/NfcSecureElement.java
deleted file mode 100755
index 3b5f39e..0000000
--- a/core/java/android/nfc/NfcSecureElement.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc;
-
-import android.nfc.tech.TagTechnology;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-//import android.util.Log;
-
-/**
- * This class provides the primary API for managing all aspects Secure Element.
- * Get an instance of this class by calling
- * Context.getSystemService(Context.NFC_SERVICE).
- * @hide
- */
-public final class NfcSecureElement {
-
-    private static final String TAG = "NfcSecureElement";
-
-    private INfcSecureElement mService;
-
-
-    /**
-     * @hide
-     */
-    public NfcSecureElement(INfcSecureElement mSecureElementService) {
-        mService = mSecureElementService;
-    }
-
-    public int openSecureElementConnection(String seType) throws IOException {
-        if (seType.equals("SmartMX")) {
-            try {
-                int handle = mService.openSecureElementConnection();
-                // Handle potential errors
-                if (handle != 0) {
-                    return handle;
-                } else {
-                    throw new IOException("SmartMX connection not allowed");
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException in openSecureElementConnection(): ", e);
-                return 0;
-            }
-
-        } else if (seType.equals("UICC")) {
-            return 0;
-        } else {
-        	throw new IOException("Wrong Secure Element type");
-        }
-    }
-
-
-    public byte [] exchangeAPDU(int handle,byte [] data) throws IOException {
-
-
-        // Perform exchange APDU
-        try {
-            byte[] response = mService.exchangeAPDU(handle, data);
-            // Handle potential errors
-            if (response == null) {
-            	throw new IOException("Exchange APDU failed");
-            }
-            return response;
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in exchangeAPDU(): ", e);
-            return null;
-        }
-    }
-
-    public void closeSecureElementConnection(int handle) throws IOException {
-
-        try {
-            int status = mService.closeSecureElementConnection(handle);
-            // Handle potential errors
-            if (ErrorCodes.isError(status)) {
-            	throw new IOException("Error during the conection close");
-            };
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in closeSecureElement(): ", e);
-        }
-    }
-
-
-    /**
-     * Returns target type. constants.
-     *
-     * @return Secure Element technology type. The possible values are defined in
-     * {@link TagTechnology}
-     *
-     */
-    public int[] getSecureElementTechList(int handle) throws IOException {
-        try {
-            return mService.getSecureElementTechList(handle);
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getType(): ", e);
-            return null;
-        }
-    }
-
-    /**
-     * Returns Secure Element UID.
-     *
-     * @return Secure Element UID.
-     */
-    public byte[] getSecureElementUid(int handle) throws IOException {
-
-        byte[] uid = null;
-        try {
-            uid = mService.getSecureElementUid(handle);
-            // Handle potential errors
-            if (uid == null) {
-                throw new IOException("Get Secure Element UID failed");
-            }
-            return uid;
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getType(): ", e);
-            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/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index a53c6d0..7d6e18f 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1175,10 +1175,11 @@
                         }
                     }
                     mSurfaceHolder.mSurfaceLock.lock();
-                    // Make surface invalid.
-                    //mSurfaceHolder.mSurface.copyFrom(mSurface);
-                    mSurfaceHolder.mSurface = new Surface();
-                    mSurfaceHolder.mSurfaceLock.unlock();
+                    try {
+                        mSurfaceHolder.mSurface = new Surface();
+                    } finally {
+                        mSurfaceHolder.mSurfaceLock.unlock();
+                    }
                 }
             }
 
diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java
old mode 100644
new mode 100755
index 8edfe52..3f185aa
--- a/core/java/com/google/android/mms/pdu/PduParser.java
+++ b/core/java/com/google/android/mms/pdu/PduParser.java
@@ -29,6 +29,8 @@
 import java.util.Arrays;
 import java.util.HashMap;
 
+import android.content.res.Resources;
+
 public class PduParser {
     /**
      *  The next are WAP values defined in WSP specification.
@@ -1557,43 +1559,55 @@
                          * Attachment = <Octet 129>
                          * Inline = <Octet 130>
                          */
-                        int len = parseValueLength(pduDataStream);
-                        pduDataStream.mark(1);
-                        int thisStartPos = pduDataStream.available();
-                        int thisEndPos = 0;
-                        int value = pduDataStream.read();
 
-                        if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
-                            part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
-                        } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
-                            part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
-                        } else if (value == PduPart.P_DISPOSITION_INLINE) {
-                            part.setContentDisposition(PduPart.DISPOSITION_INLINE);
-                        } else {
-                            pduDataStream.reset();
-                            /* Token-text */
-                            part.setContentDisposition(parseWapString(pduDataStream, TYPE_TEXT_STRING));
-                        }
+                        /*
+                         * some carrier mmsc servers do not support content_disposition
+                         * field correctly
+                         */
+                        boolean contentDisposition = Resources.getSystem().getBoolean(com
+                                .android.internal.R.bool.config_mms_content_disposition_support);
 
-                        /* get filename parameter and skip other parameters */
-                        thisEndPos = pduDataStream.available();
-                        if (thisStartPos - thisEndPos < len) {
-                            value = pduDataStream.read();
-                            if (value == PduPart.P_FILENAME) { //filename is text-string
-                                part.setFilename(parseWapString(pduDataStream, TYPE_TEXT_STRING));
+                        if (contentDisposition) {
+                            int len = parseValueLength(pduDataStream);
+                            pduDataStream.mark(1);
+                            int thisStartPos = pduDataStream.available();
+                            int thisEndPos = 0;
+                            int value = pduDataStream.read();
+
+                            if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
+                                part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
+                            } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
+                                part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
+                            } else if (value == PduPart.P_DISPOSITION_INLINE) {
+                                part.setContentDisposition(PduPart.DISPOSITION_INLINE);
+                            } else {
+                                pduDataStream.reset();
+                                /* Token-text */
+                                part.setContentDisposition(parseWapString(pduDataStream
+                                        , TYPE_TEXT_STRING));
                             }
 
-                            /* skip other parameters */
+                            /* get filename parameter and skip other parameters */
                             thisEndPos = pduDataStream.available();
                             if (thisStartPos - thisEndPos < len) {
-                                int last = len - (thisStartPos - thisEndPos);
-                                byte[] temp = new byte[last];
-                                pduDataStream.read(temp, 0, last);
-                            }
-                        }
+                                value = pduDataStream.read();
+                                if (value == PduPart.P_FILENAME) { //filename is text-string
+                                    part.setFilename(parseWapString(pduDataStream
+                                            , TYPE_TEXT_STRING));
+                                }
 
-                        tempPos = pduDataStream.available();
-                        lastLen = length - (startPos - tempPos);
+                                /* skip other parameters */
+                                thisEndPos = pduDataStream.available();
+                                if (thisStartPos - thisEndPos < len) {
+                                    int last = len - (thisStartPos - thisEndPos);
+                                    byte[] temp = new byte[last];
+                                    pduDataStream.read(temp, 0, last);
+                                }
+                            }
+
+                            tempPos = pduDataStream.available();
+                            lastLen = length - (startPos - tempPos);
+                        }
                         break;
                     default:
                         if (LOCAL_LOGV) {
diff --git a/core/java/com/google/android/mms/util/PduCache.java b/core/java/com/google/android/mms/util/PduCache.java
index 7c3fad7..866ca1e 100644
--- a/core/java/com/google/android/mms/util/PduCache.java
+++ b/core/java/com/google/android/mms/util/PduCache.java
@@ -235,7 +235,7 @@
     }
 
     private void removeFromMessageBoxes(Uri key, PduCacheEntry entry) {
-        HashSet<Uri> msgBox = mThreads.get(entry.getMessageBox());
+        HashSet<Uri> msgBox = mThreads.get(Long.valueOf(entry.getMessageBox()));
         if (msgBox != null) {
             msgBox.remove(key);
         }
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 9e00a7d..09a5fd41 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -680,6 +680,15 @@
 
 static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
 {
+    // XXX temporary sanity check to debug crashes.
+    int uid = (int)(token>>32);
+    if (uid > 0 && uid < 999) {
+        // In Android currently there are no uids in this range.
+        char buf[128];
+        sprintf(buf, "Restoring bad calling ident: 0x%Lx", token);
+        jniThrowException(env, "java/lang/IllegalStateException", buf);
+        return;
+    }
     IPCThreadState::self()->restoreCallingIdentity(token);
 }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c684e7e..0c9a2ef 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -91,10 +91,15 @@
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
 
     <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
+    <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
+    <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
+    <protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
+
     <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
     <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
     <protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
 
+
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
old mode 100644
new mode 100755
index e46eecc..2037191
--- 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,10,0,2"</item>
+        <item>"mobile_ims,11,0,2"</item>
+        <item>"mobile_cbs,12,0,2"</item>
     </string-array>
 
     <!-- This string array should be overridden by the device to present a list of radio
@@ -563,4 +571,27 @@
 
     <!-- The VoiceMail default value is displayed to my own number if it is true -->
     <bool name="config_telephony_use_own_number_for_voicemail">false</bool>
+
+    <!-- If this value is true, Sms encoded as octet is decoded by utf8 decoder.
+         If false, decoded by Latin decoder. -->
+    <bool name="config_sms_utf8_support">false</bool>
+
+    <!-- If this value is true, The mms content-disposition field is supported correctly.
+         If false, Content-disposition fragments are ignored -->
+    <bool name="config_mms_content_disposition_support">true</bool>
+
+    <!-- If this value is true, the carrier supports sms delivery reports.
+         If false, sms delivery reports are not supported and the preference
+         option to enable/disable delivery reports is removed in the Messaging app. -->
+    <bool name="config_sms_delivery_reports_support">true</bool>
+
+    <!-- If this value is true, the carrier supports mms delivery reports.
+         If false, mms delivery reports are not supported and the preference
+         option to enable/disable delivery reports is removed in the Messaging app. -->
+    <bool name="config_mms_delivery_reports_support">true</bool>
+
+    <!-- If this value is true, the carrier supports mms read reports.
+         If false, mms read reports are not supported and the preference
+         option to enable/disable read reports is removed in the Messaging app. -->
+    <bool name="config_mms_read_reports_support">true</bool>
 </resources>
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 498c7b8..2caf211 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -220,40 +220,58 @@
         return ERROR_ALREADY_CONNECTED;
     }
 
-    struct hostent *ent = gethostbyname(server);
-    if (ent == NULL) {
+    if (port < 0 || port > (int) USHRT_MAX) {
+        return UNKNOWN_ERROR;
+    }
+
+    char service[sizeof("65536")];
+    sprintf(service, "%d", port);
+    struct addrinfo hints, *ai;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+    hints.ai_socktype = SOCK_STREAM;
+
+    int ret = getaddrinfo(server, service, &hints, &ai);
+    if (ret) {
         return ERROR_UNKNOWN_HOST;
     }
 
     CHECK_EQ(mSocket, -1);
-    mSocket = socket(AF_INET, SOCK_STREAM, 0);
-
-    if (mSocket < 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    setReceiveTimeout(30);  // Time out reads after 30 secs by default
 
     mState = CONNECTING;
+    status_t res = -1;
+    struct addrinfo *tmp;
+    for (tmp = ai; tmp; tmp = tmp->ai_next) {
+        mSocket = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
+        if (mSocket < 0) {
+            continue;
+        }
 
-    int s = mSocket;
+        setReceiveTimeout(30);  // Time out reads after 30 secs by default.
 
-    mLock.unlock();
+        int s = mSocket;
 
-    struct sockaddr_in addr;
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
-    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+        mLock.unlock();
 
-    status_t res = MyConnect(s, (const struct sockaddr *)&addr, sizeof(addr));
+        res = MyConnect(s, tmp->ai_addr, tmp->ai_addrlen);
 
-    mLock.lock();
+        mLock.lock();
 
-    if (mState != CONNECTING) {
-        return UNKNOWN_ERROR;
+        if (mState != CONNECTING) {
+            close(s);
+            freeaddrinfo(ai);
+            return UNKNOWN_ERROR;
+        }
+
+        if (res == OK) {
+            break;
+        }
+
+        close(s);
     }
 
+    freeaddrinfo(ai);
+
     if (res != OK) {
         close(mSocket);
         mSocket = -1;
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 7802efd..81c6167 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -22,11 +22,6 @@
         SkOmxPixelRef.cpp \
         StreamSource.cpp
 
-
-# add external/skia/src/images/SkImageDecoder_libjpeg.cpp
-LOCAL_SRC_FILES += \
-        ../../../../../external/skia/src/images/SkImageDecoder_libjpeg.cpp
-
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libskia \
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
new file mode 100644
index 0000000..131d898
--- /dev/null
+++ b/nfc-extras/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE:= com.android.nfc_extras
+
+include $(BUILD_JAVA_LIBRARY)
+
+# put the classes.jar, with full class files instead of classes.dex inside, into the dist directory
+$(call dist-for-goals, droidcore, $(full_classes_jar):com.android.nfc_extras.jar)
diff --git a/nfc-extras/com.android.nfc_extras.xml b/nfc-extras/com.android.nfc_extras.xml
new file mode 100644
index 0000000..370145d
--- /dev/null
+++ b/nfc-extras/com.android.nfc_extras.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<permissions>
+    <library name="com.android.nfc_extras"
+            file="/system/framework/com.android.nfc_extras.jar" />
+</permissions>
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
new file mode 100644
index 0000000..cf38bd1
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2011 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.nfc_extras;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.nfc.INfcAdapterExtras;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides additional methods on an {@link NfcAdapter} for Card Emulation
+ * and management of {@link NfcExecutionEnvironment}'s.
+ *
+ * There is a 1-1 relationship between an {@link NfcAdapterExtras} object and
+ * a {@link NfcAdapter} object.
+ */
+public final class NfcAdapterExtras {
+    private static final String TAG = "NfcAdapterExtras";
+
+    /**
+     * Broadcast Action: an RF field ON has been detected.
+     *
+     * <p class="note">This is an unreliable signal, and will be removed.
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+     * to receive.
+     */
+    public static final String ACTION_RF_FIELD_ON_DETECTED =
+            "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
+
+    /**
+     * Broadcast Action: an RF field OFF has been detected.
+     *
+     * <p class="note">This is an unreliable signal, and will be removed.
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+     * to receive.
+     */
+    public static final String ACTION_RF_FIELD_OFF_DETECTED =
+            "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
+
+    // protected by NfcAdapterExtras.class, and final after first construction
+    private static INfcAdapterExtras sService;
+    private static boolean sIsInitialized = false;
+    private static NfcAdapterExtras sSingleton;
+    private static NfcExecutionEnvironment sEmbeddedEe;
+    private static CardEmulationRoute sRouteOff;
+    private static CardEmulationRoute sRouteOnWhenScreenOn;
+
+    /**
+     * Get the {@link NfcAdapterExtras} for the given {@link NfcAdapter}.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @param adapter a {@link NfcAdapter}, must not be null
+     * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
+     */
+    public static NfcAdapterExtras get(NfcAdapter adapter) {
+        synchronized(NfcAdapterExtras.class) {
+            if (!sIsInitialized) {
+               sIsInitialized = true;
+               sService = adapter.getNfcAdapterExtrasInterface();
+               sEmbeddedEe = new NfcExecutionEnvironment(sService);
+               sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
+               sRouteOnWhenScreenOn = new CardEmulationRoute(
+                       CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
+               sSingleton = new NfcAdapterExtras();
+            }
+            return sSingleton;
+        }
+    }
+
+    private NfcAdapterExtras() {}
+
+    /**
+     * Immutable data class that describes a card emulation route.
+     */
+    public final static class CardEmulationRoute {
+        /**
+         * Card Emulation is turned off on this NfcAdapter.
+         * <p>This is the default routing state after boot.
+         */
+        public static final int ROUTE_OFF = 1;
+
+        /**
+         * Card Emulation is routed to {@link #nfcEe} only when the screen is on,
+         * otherwise it is turned off.
+         */
+        public static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
+
+        /**
+         * A route such as {@link #ROUTE_OFF} or {@link #ROUTE_ON_WHEN_SCREEN_ON}.
+         */
+        public final int route;
+
+        /**
+         * The {@link NFcExecutionEnvironment} that is Card Emulation is routed to.
+         * <p>null if {@link #route} is {@link #ROUTE_OFF}, otherwise not null.
+         */
+        public final NfcExecutionEnvironment nfcEe;
+
+        public CardEmulationRoute(int route, NfcExecutionEnvironment nfcEe) {
+            if (route == ROUTE_OFF && nfcEe != null) {
+                throw new IllegalArgumentException("must not specifiy a NFC-EE with ROUTE_OFF");
+            } else if (route != ROUTE_OFF && nfcEe == null) {
+                throw new IllegalArgumentException("must specifiy a NFC-EE for this route");
+            }
+            this.route = route;
+            this.nfcEe = nfcEe;
+        }
+    }
+
+    /**
+     * Get the routing state of this NFC EE.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @return
+     */
+    public CardEmulationRoute getCardEmulationRoute() {
+        try {
+            int route = sService.getCardEmulationRoute();
+            return route == CardEmulationRoute.ROUTE_OFF ?
+                    sRouteOff :
+                    sRouteOnWhenScreenOn;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return sRouteOff;
+        }
+    }
+
+    /**
+     * Set the routing state of this NFC EE.
+     *
+     * <p>This routing state is not persisted across reboot.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @param route a {@link #CardEmulationRoute}
+     */
+    public void setCardEmulationRoute(CardEmulationRoute route) {
+        try {
+            sService.setCardEmulationRoute(route.route);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+    }
+
+    /**
+     * Get the {@link NfcExecutionEnvironment} that is embedded with the
+     * {@link NFcAdapter}.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
+     */
+    public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
+        return sEmbeddedEe;
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
new file mode 100644
index 0000000..3efe492
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 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.nfc_extras;
+
+import java.io.IOException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.nfc.INfcAdapterExtras;
+import android.nfc.NfcAdapter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+public class NfcExecutionEnvironment {
+    private final INfcAdapterExtras mService;
+
+    /**
+     * Broadcast Action: An ISO-DEP AID was selected.
+     *
+     * <p>This happens as the result of a 'SELECT AID' command from an
+     * external NFC reader/writer.
+     *
+     * <p>Always contains the extra field {@link #EXTRA_AID}
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+     * to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_AID_SELECTED =
+        "com.android.nfc_extras.action.AID_SELECTED";
+
+    /**
+     * Mandatory byte array extra field in {@link #ACTION_AID_SELECTED}.
+     *
+     * <p>Contains the AID selected.
+     * @hide
+     */
+    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
+
+    NfcExecutionEnvironment(INfcAdapterExtras service) {
+        mService = service;
+    }
+
+    /**
+     * Open the NFC Execution Environment on its contact interface.
+     *
+     * <p>Only one process may open the secure element at a time. If it is
+     * already open, an {@link IOException} is thrown.
+     *
+     * <p>All other NFC functionality is disabled while the NFC-EE is open
+     * on its contact interface, so make sure to call {@link #close} once complete.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @throws IOException if the NFC-EE is already open, or some other error occurs
+     */
+    public void open() throws IOException {
+        try {
+            Bundle b = mService.open(new Binder());
+            throwBundle(b);
+        } catch (RemoteException e) {
+            return;
+        }
+    }
+
+    /**
+     * Close the NFC Execution Environment on its contact interface.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @throws IOException if the NFC-EE is already open, or some other error occurs
+     */
+    public void close() throws IOException {
+        try {
+            throwBundle(mService.close());
+        } catch (RemoteException e) {
+            return;
+        }
+    }
+
+    /**
+     * Send raw commands to the NFC-EE and receive the response.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @throws IOException if the NFC-EE is not open, or some other error occurs
+     */
+    public byte[] transceive(byte[] in) throws IOException {
+        Bundle b;
+        try {
+            b = mService.transceive(in);
+        } catch (RemoteException e) {
+            throw new IOException(e.getMessage());
+        }
+        throwBundle(b);
+        return b.getByteArray("out");
+    }
+
+    private static void throwBundle(Bundle b) throws IOException {
+        if (b.getInt("e") == -1) {
+            throw new IOException(b.getString("m"));
+        }
+    }
+}
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 a693e60..70a78df 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 fcb4c23..f170cb7 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];
@@ -2179,4 +2168,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..ba05837 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -91,6 +91,12 @@
     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_EHRPD = 13;
+    /** @hide */
+    public static final int RADIO_TECHNOLOGY_LTE = 14;
+    /** @hide */
+    public static final int RADIO_TECHNOLOGY_HSPAP = 15;
 
     /**
      * Available registration states for GSM, UMTS and CDMA.
@@ -424,6 +430,15 @@
         case 12:
             radioTechnology = "EvDo rev. B";
             break;
+        case 13:
+            radioTechnology = "eHRPD";
+            break;
+        case 14:
+            radioTechnology = "LTE";
+            break;
+        case 15:
+            radioTechnology = "HSPAP";
+            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..a86ea7e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -0,0 +1,166 @@
+/*
+ * 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;
+
+    /** A zero indicates that all waiting APNs had a permanent error */
+    private int mWaitingApnsPermanentFailureCountDown;
+
+    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 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;
+        mWaitingApnsPermanentFailureCountDown = mWaitingApns.size();
+    }
+
+    public int getWaitingApnsPermFailCount() {
+        return mWaitingApnsPermanentFailureCountDown;
+    }
+
+    public void decWaitingApnsPermFailCount() {
+        mWaitingApnsPermanentFailureCountDown--;
+    }
+
+    public ApnSetting getNextWaitingApn() {
+        ArrayList<ApnSetting> list = mWaitingApns;
+        ApnSetting apn = null;
+
+        if (list != null) {
+            if (!list.isEmpty()) {
+                apn = list.get(0);
+            }
+        }
+        return apn;
+    }
+
+    public void removeNextWaitingApn() {
+        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/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..9e1e0c6 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -20,25 +20,28 @@
 
 import android.os.Message;
 import android.os.Handler;
+import android.os.SystemProperties;
 
 
 /**
  * {@hide}
  */
 public interface CommandsInterface {
+    static final boolean LTE_AVAILABLE_ON_CDMA =
+        SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_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 +53,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 +79,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 +172,9 @@
     //***** Methods
 
     RadioState getRadioState();
+    RadioState getSimState();
+    RadioState getRuimState();
+    RadioState getNvState();
 
     /**
      * Fires on any RadioState transition
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 89513fd..e21e951 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -109,14 +109,17 @@
      * Used internally for saving disconnecting parameters.
      */
     protected static class DisconnectParams {
-        public DisconnectParams(Message onCompletedMsg) {
+        public DisconnectParams(String reason, Message onCompletedMsg) {
+            this.reason = reason;
             this.onCompletedMsg = onCompletedMsg;
         }
         public DisconnectParams(ResetSynchronouslyLock lockObj) {
+            this.reason = null;
             this.lockObj = lockObj;
         }
 
         public int tag;
+        public String reason;
         public Message onCompletedMsg;
         public ResetSynchronouslyLock lockObj;
     }
@@ -219,10 +222,9 @@
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
 
     //***** Member Variables
-    protected int mId;
+    protected ApnSetting mApn;
     protected int mTag;
     protected PhoneBase phone;
-    protected RetryManager mRetryMgr;
     protected int cid;
     protected LinkProperties mLinkProperties = new LinkProperties();
     protected LinkCapabilities mCapabilities = new LinkCapabilities();
@@ -244,10 +246,11 @@
 
 
    //***** Constructor
-    protected DataConnection(PhoneBase phone, String name, RetryManager rm) {
+    protected DataConnection(PhoneBase phone, String name, int id, RetryManager rm) {
         super(name);
         if (DBG) log("DataConnection constructor E");
         this.phone = phone;
+        mId = id;
         mRetryMgr = rm;
         this.cid = -1;
         clearSettings();
@@ -274,10 +277,8 @@
         if ((o != null) && (o instanceof DisconnectParams)) {
             DisconnectParams dp = (DisconnectParams)o;
             Message m = dp.onCompletedMsg;
-            if ((m != null) && (m.obj != null) && (m.obj instanceof String)) {
-                String reason = (String)m.obj;
-                if (TextUtils.equals(reason, Phone.REASON_RADIO_TURNED_OFF))
-                    discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
+            if (TextUtils.equals(dp.reason, Phone.REASON_RADIO_TURNED_OFF)) {
+                discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
             }
         }
         if (phone.mCM.getRadioState().isOn()) {
@@ -342,21 +343,100 @@
         clearSettings();
     }
 
-    public RetryManager getRetryMgr() {
-        return mRetryMgr;
+    /*
+     * **************************************************************************
+     * Begin Members and methods owned by DataConnectionTracker but stored
+     * in a DataConnection because there is one per connection.
+     * **************************************************************************
+     */
+
+    /*
+     * The id is owned by DataConnectionTracker.
+     */
+    private int mId;
+
+    /**
+     * Get the DataConnection ID
+     */
+    public int getDataConnectionId() {
+        return mId;
     }
 
+    /*
+     * The retry manager is currently owned by the DataConnectionTracker but is stored
+     * in the DataConnection because there is one per connection. These methods
+     * should only be used by the DataConnectionTracker although someday the retrying
+     * maybe managed by the DataConnection itself and these methods could disappear.
+     */
+    private RetryManager mRetryMgr;
+
+    /**
+     * @return retry manager retryCount
+     */
+    public int getRetryCount() {
+        return mRetryMgr.getRetryCount();
+    }
+
+    /**
+     * @return retry manager retryTimer
+     */
+    public int getRetryTimer() {
+        return mRetryMgr.getRetryTimer();
+    }
+
+    /**
+     * increaseRetryCount of retry manager
+     */
+    public void increaseRetryCount() {
+        mRetryMgr.increaseRetryCount();
+    }
+
+    /**
+     * @return retry manager isRetryNeeded
+     */
+    public boolean isRetryNeeded() {
+        return mRetryMgr.isRetryNeeded();
+    }
+
+    /**
+     * resetRetryCount of retry manager
+     */
+    public void resetRetryCount() {
+        mRetryMgr.resetRetryCount();
+    }
+
+    /**
+     * set retryForeverUsingLasttimeout of retry manager
+     */
+    public void retryForeverUsingLastTimeout() {
+        mRetryMgr.retryForeverUsingLastTimeout();
+    }
+
+    /**
+     * @return retry manager isRetryForever
+     */
+    public boolean isRetryForever() {
+        return mRetryMgr.isRetryForever();
+    }
+
+    /*
+     * **************************************************************************
+     * End members owned by DataConnectionTracker
+     * **************************************************************************
+     */
+
     /**
      * Clear all settings called when entering mInactiveState.
      */
     protected void clearSettings() {
         if (DBG) log("clearSettings");
 
-        this.createTime = -1;
-        this.lastFailTime = -1;
-        this.lastFailCause = FailCause.NONE;
+        createTime = -1;
+        lastFailTime = -1;
+        lastFailCause = FailCause.NONE;
 
         mLinkProperties = new LinkProperties();
+        mApn = null;
     }
 
     /**
@@ -884,7 +964,7 @@
      *        With AsyncResult.userObj set to the original msg.obj.
      */
     public void reset(Message onCompletedMsg) {
-        sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(onCompletedMsg)));
+        sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(null, onCompletedMsg)));
     }
 
     /**
@@ -935,8 +1015,8 @@
      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
      *        With AsyncResult.userObj set to the original msg.obj.
      */
-    public void disconnect(Message onCompletedMsg) {
-        sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(onCompletedMsg)));
+    public void disconnect(String reason, Message onCompletedMsg) {
+        sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg)));
     }
 
     // ****** The following are used for debugging.
@@ -964,13 +1044,6 @@
     }
 
     /**
-     * Get the DataConnection ID
-     */
-    public int getDataConnectionId() {
-        return mId;
-    }
-
-    /**
      * Return the LinkProperties for the connection.
      *
      * @return a copy of the LinkProperties, is never null.
@@ -1017,4 +1090,11 @@
     public FailCause getLastFailCause() {
         return lastFailCause;
     }
+
+    /**
+     * @return the current ApnSetting
+     */
+    public ApnSetting getApn() {
+        return mApn;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 7f8485b..fba73fb5 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -38,8 +38,11 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -97,14 +100,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;
@@ -117,8 +120,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 *****/
 
@@ -128,7 +131,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;
@@ -206,9 +212,6 @@
     protected int mNoRecvPollCount = 0;
     protected boolean mNetStatPollEnabled = false;
 
-    /** Manage the behavior of data retry after failure (TODO: One per connection in the future?) */
-    protected RetryManager mRetryMgr = new RetryManager();
-
     // wifi connection status will be updated by sticky intent
     protected boolean mIsWifiConnected = false;
 
@@ -242,9 +245,29 @@
     protected HashMap<Integer, DataConnection> mDataConnections =
         new HashMap<Integer, DataConnection>();
 
+    /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
+    protected HashMap<String, Integer> mApnToDataConnectionId =
+                                    new HashMap<String, Integer>();
+
+    /** Phone.APN_TYPE_* ===> ApnContext */
+    protected ConcurrentHashMap<String, ApnContext> mApnContexts;
+
     /* Currently active APN */
     protected ApnSetting mActiveApn;
 
+    /** allApns holds all apns */
+    protected ArrayList<ApnSetting> mAllApns = null;
+
+    /** preferred apn */
+    protected ApnSetting mPreferredApn = null;
+
+    /** Is packet service restricted by network */
+    protected boolean mIsPsRestricted = false;
+
+
+    /* Once disposed dont handle any messages */
+    protected boolean mIsDisposed = false;
+
     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
     {
         @Override
@@ -261,15 +284,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);
@@ -287,6 +303,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
      */
@@ -320,6 +348,7 @@
     }
 
     public void dispose() {
+        mIsDisposed = true;
         mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
     }
 
@@ -333,23 +362,6 @@
         return mActivity;
     }
 
-    public State getState() {
-        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
      */
@@ -360,9 +372,26 @@
 
     public boolean isApnTypeActive(String type) {
         // TODO: support simultaneous with List instead
+        if (Phone.APN_TYPE_DUN.equals(type)) {
+            ApnSetting dunApn = fetchDunApn();
+            if (dunApn != null) {
+                return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
+            }
+        }
         return mActiveApn != null && mActiveApn.canHandleType(type);
     }
 
+    protected ApnSetting fetchDunApn() {
+        Context c = mPhone.getContext();
+        String apnData = Settings.Secure.getString(c.getContentResolver(),
+                Settings.Secure.TETHER_DUN_APN);
+        ApnSetting dunSetting = ApnSetting.fromString(apnData);
+        if (dunSetting != null) return dunSetting;
+
+        apnData = c.getResources().getString(R.string.config_tether_apndata);
+        return ApnSetting.fromString(apnData);
+    }
+
     public String[] getActiveApnTypes() {
         String[] result;
         if (mActiveApn != null) {
@@ -374,17 +403,8 @@
         return result;
     }
 
-    public String getActiveApnType() {
-        String result;
-        if (mActiveApn != null) {
-            result = apnIdToType(mActiveApn.id);
-        } else {
-            result = null;
-        }
-        return result;
-    }
-
-    protected String getActiveApnString() {
+    /** TODO: See if we can remove */
+    public String getActiveApnString() {
         String result = null;
         if (mActiveApn != null) {
             result = mActiveApn.apn;
@@ -392,17 +412,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.
@@ -412,7 +421,7 @@
                 Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
             if (mPhone.getServiceState().getRoaming()) {
                 if (enabled) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                 }
                 sendMessage(obtainMessage(EVENT_ROAMING_ON));
             }
@@ -429,10 +438,19 @@
         }
     }
 
-
+    // abstract methods
     protected abstract String getActionIntentReconnectAlarm();
+    protected abstract void startNetStatPoll();
+    protected abstract void stopNetStatPoll();
+    protected abstract void restartRadio();
+    protected abstract void log(String s);
+    protected abstract void loge(String s);
+    protected abstract boolean isDataAllowed();
+    protected abstract boolean isApnTypeAvailable(String type);
+    public    abstract State getState(String apnType);
+    protected abstract void setState(State s);
+    protected abstract void gotoIdleAndNotifyDataConnection(String reason);
 
-    // abstract handler methods
     protected abstract boolean onTrySetupData(String reason);
     protected abstract void onRoamingOff();
     protected abstract void onRoamingOn();
@@ -440,10 +458,10 @@
     protected abstract void onRadioOffOrNotAvailable();
     protected abstract void onDataSetupComplete(AsyncResult ar);
     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
-    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(String cause);
 
     @Override
     public void handleMessage(Message msg) {
@@ -463,7 +481,7 @@
 
             case EVENT_ROAMING_OFF:
                 if (getDataOnRoamingEnabled() == false) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                 }
                 onRoamingOff();
                 break;
@@ -498,19 +516,24 @@
                 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((String) msg.obj);
                 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);
                 break;
             }
-            case EVENT_RESET_DONE:
+            case EVENT_RESET_DONE: {
                 onResetDone((AsyncResult) msg.obj);
                 break;
+            }
             case CMD_SET_DATA_ENABLE: {
                 log("CMD_SET_DATA_ENABLE msg=" + msg);
                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
@@ -536,16 +559,6 @@
         return result;
     }
 
-    protected abstract void startNetStatPoll();
-
-    protected abstract void stopNetStatPoll();
-
-    protected abstract void restartRadio();
-
-    protected abstract void log(String s);
-
-    protected abstract void loge(String s);
-
     protected int apnTypeToId(String type) {
         if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
             return APN_DEFAULT_ID;
@@ -557,6 +570,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;
         }
@@ -574,16 +593,18 @@
             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;
         }
     }
 
-    protected abstract boolean isApnTypeAvailable(String type);
-
-    protected abstract void setState(State s);
-
     protected LinkProperties getLinkProperties(String apnType) {
         int id = apnTypeToId(apnType);
         if (isApnIdEnabled(id)) {
@@ -704,13 +725,12 @@
         return possible;
     }
 
-    protected abstract boolean isDataAllowed();
-
     public boolean isApnTypeEnabled(String apnType) {
         if (apnType == null) {
-            apnType = getActiveApnType();
+            return false;
+        } else {
+            return isApnIdEnabled(apnTypeToId(apnType));
         }
-        return isApnIdEnabled(apnTypeToId(apnType));
     }
 
     protected synchronized boolean isApnIdEnabled(int id) {
@@ -826,7 +846,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
@@ -855,6 +875,22 @@
     }
 
     /**
+     * Called when EVENT_RESET_DONE is received so goto
+     * IDLE state and send notifications to those interested.
+     *
+     * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
+     * TODO - needs to pass some notion of which connection is reset..
+     */
+    protected void onResetDone(AsyncResult ar) {
+        if (DBG) log("EVENT_RESET_DONE");
+        String reason = null;
+        if (ar.userObj instanceof String) {
+            reason = (String) ar.userObj;
+        }
+        gotoIdleAndNotifyDataConnection(reason);
+    }
+
+    /**
      * Prevent mobile data connections from being established, or once again
      * allow mobile data connections. If the state toggles, then either tear
      * down or set up data, as appropriate to match the new state.
@@ -881,10 +917,10 @@
             }
             if (prevEnabled != getAnyDataEnabled()) {
                 if (!prevEnabled) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
-                    onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+                    cleanUpAllConnections(null);
                 }
             }
         }
@@ -894,6 +930,18 @@
         return mDataEnabled;
     }
 
+    public void cleanUpAllConnections(String cause) {
+        Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS);
+        msg.obj = cause;
+        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) {
@@ -904,12 +952,18 @@
                     Settings.Secure.MOBILE_DATA, enable ? 1 : 0);
             if (prevEnabled != getAnyDataEnabled()) {
                 if (!prevEnabled) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
-                    onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+                    onCleanUpConnection(true, APN_DEFAULT_ID, Phone.REASON_DATA_DISABLED);
                 }
             }
         }
     }
+
+    protected void resetAllRetryCounts() {
+        for (DataConnection dc : mDataConnections.values()) {
+            dc.resetRetryCount();
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index e270ce9..dbfc0d4 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,9 @@
     private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
     private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
 
+    static final boolean LTE_AVAILABLE_ON_CDMA =
+            SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_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 +430,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 +619,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..779b125 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(null);
             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..ab0bb63 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(TelephonyProperties.PROPERTY_NETWORK_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,14 @@
 
         case RILConstants.NETWORK_MODE_GLOBAL:
             return Phone.PHONE_TYPE_CDMA;
+
+        case RILConstants.NETWORK_MODE_LTE_ONLY:
+            if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA,
+                    false)) {
+                return Phone.PHONE_TYPE_CDMA;
+            } else {
+                return Phone.PHONE_TYPE_GSM;
+            }
         default:
             return Phone.PHONE_TYPE_GSM;
         }
@@ -166,8 +185,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..1d47405 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -207,9 +207,8 @@
  */
 public final class RIL extends BaseCommands implements CommandsInterface {
     static final String LOG_TAG = "RILJ";
-    private static final boolean DBG = false;
-    static final boolean RILJ_LOGD = Config.LOGD;
-    static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV;
+    static final boolean RILJ_LOGD = true;
+    static final boolean RILJ_LOGV = false; // STOP SHIP if true
 
     /**
      * Wake lock timeout should be longer than the longest timeout in
@@ -638,6 +637,14 @@
             case RILConstants.NETWORK_MODE_GLOBAL:
                 mPhoneType = RILConstants.CDMA_PHONE;
                 break;
+            case RILConstants.NETWORK_MODE_LTE_ONLY:
+                if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA,
+                        false)) {
+                    mPhoneType = RILConstants.CDMA_PHONE;
+                } else {
+                    mPhoneType = RILConstants.GSM_PHONE;
+                }
+                break;
             default:
                 mPhoneType = RILConstants.CDMA_PHONE;
         }
@@ -1389,33 +1396,29 @@
         if(mInitialRadioStateChange) {
             synchronized (mStateMonitor) {
                 if (!mState.isOn()) {
-                    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);
+                    setPreferredNetworkType(mNetworkMode, null);
 
                     RILRequest rrCs = RILRequest.obtain(
                                    RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, null);
                     rrCs.mp.writeInt(1);
                     rrCs.mp.writeInt(mCdmaSubscription);
-                    if (RILJ_LOGD) riljLog(rrCs.serialString() + "> "
-                    + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription);
+                    if (RILJ_LOGD) {
+                        riljLog(rrCs.serialString() + "> "
+                                + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription);
+                    }
                     send(rrCs);
                 }
             }
         }
-        RILRequest rr
-                = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
+        RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
 
         rr.mp.writeInt(1);
         rr.mp.writeInt(on ? 1 : 0);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+        if (RILJ_LOGD) {
+            riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                    + (on ? " on" : " off"));
+        }
 
         send(rr);
     }
@@ -2065,8 +2068,9 @@
                 if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
                 setRadioPower(false, null);
             } else {
-                if (DBG) Log.d(LOG_TAG, "Radio OFF @ init");
+                if (RILJ_LOGD) Log.d(LOG_TAG, "Radio OFF @ init");
                 setRadioState(newState);
+                setPreferredNetworkType(mNetworkMode, null);
             }
             mInitialRadioStateChange = false;
         } else {
@@ -2361,7 +2365,10 @@
             case RIL_REQUEST_GET_IMSI:
             case RIL_REQUEST_GET_IMEI:
             case RIL_REQUEST_GET_IMEISV:
-                return "";
+                if (!RILJ_LOGV) {
+                    // If not versbose logging just return and don't display IMSI and IMEI, IMEISV
+                    return "";
+                }
         }
 
         StringBuilder sb;
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index cdf1977..4faf297 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -66,6 +66,11 @@
     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_CDMA_EVDO  = 8; /* LTE, CDMA and EvDo */
+    int NETWORK_MODE_LTE_GSM_WCDMA  = 9; /* LTE, GSM/WCDMA */
+    int NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
+    int NETWORK_MODE_LTE_ONLY       = 11; /* LTE Only mode. */
+
     int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;
 
     /* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */
@@ -138,10 +143,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/gsm/RestrictedState.java b/telephony/java/com/android/internal/telephony/RestrictedState.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/RestrictedState.java
rename to telephony/java/com/android/internal/telephony/RestrictedState.java
index 3f7d5d7..ad2b88d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java
+++ b/telephony/java/com/android/internal/telephony/RestrictedState.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm;
+package com.android.internal.telephony;
 
 import android.telephony.ServiceState;
 
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..5501361 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -29,23 +29,6 @@
  */
 public abstract class ServiceStateTracker extends Handler {
 
-    /**
-     *  Access technology currently in use.
-     */
-    protected static final int DATA_ACCESS_UNKNOWN = 0;
-    protected static final int DATA_ACCESS_GPRS = 1;
-    protected static final int DATA_ACCESS_EDGE = 2;
-    protected static final int DATA_ACCESS_UMTS = 3;
-    protected static final int DATA_ACCESS_CDMA_IS95A = 4;
-    protected static final int DATA_ACCESS_CDMA_IS95B = 5;
-    protected static final int DATA_ACCESS_CDMA_1xRTT = 6;
-    protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7;
-    protected static final int DATA_ACCESS_CDMA_EvDo_A = 8;
-    protected static final int DATA_ACCESS_HSDPA = 9;
-    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 CommandsInterface cm;
 
     public ServiceState ss;
@@ -53,6 +36,9 @@
 
     public SignalStrength mSignalStrength;
 
+    // TODO - this should not be public
+    public RestrictedState mRestrictedState = new RestrictedState();
+
     /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
     static public final int OTASP_UNINITIALIZED = 0;
     static public final int OTASP_UNKNOWN = 1;
@@ -74,9 +60,17 @@
      */
     protected boolean dontPollSignalStrength = false;
 
-    protected RegistrantList networkAttachedRegistrants = new RegistrantList();
-    protected RegistrantList roamingOnRegistrants = new RegistrantList();
-    protected RegistrantList roamingOffRegistrants = new RegistrantList();
+    protected RegistrantList mRoamingOnRegistrants = new RegistrantList();
+    protected RegistrantList mRoamingOffRegistrants = new RegistrantList();
+    protected RegistrantList mAttachedRegistrants = new RegistrantList();
+    protected RegistrantList mDetachedRegistrants = new RegistrantList();
+    protected RegistrantList mNetworkAttachedRegistrants = new RegistrantList();
+    protected RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList();
+    protected RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList();
+
+    /* Radio power off pending flag and tag counter */
+    private boolean mPendingRadioPowerOffAfterDataOff = false;
+    private int mPendingRadioPowerOffAfterDataOffTag = 0;
 
     protected  static final boolean DBG = true;
 
@@ -86,8 +80,6 @@
     /** Waiting period before recheck gprs and voice registration. */
     public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
 
-    public static final int DATA_STATE_POLL_SLEEP_MS = 100;
-
     /** GSM events */
     protected static final int EVENT_RADIO_STATE_CHANGED               = 1;
     protected static final int EVENT_NETWORK_STATE_CHANGED             = 2;
@@ -163,7 +155,6 @@
     protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure";
 
     public ServiceStateTracker() {
-
     }
 
     public boolean getDesiredPowerState() {
@@ -180,7 +171,7 @@
      */
     public  void registerForRoamingOn(Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
-        roamingOnRegistrants.add(r);
+        mRoamingOnRegistrants.add(r);
 
         if (ss.getRoaming()) {
             r.notifyRegistrant();
@@ -188,7 +179,7 @@
     }
 
     public  void unregisterForRoamingOn(Handler h) {
-        roamingOnRegistrants.remove(h);
+        mRoamingOnRegistrants.remove(h);
     }
 
     /**
@@ -201,7 +192,7 @@
      */
     public  void registerForRoamingOff(Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
-        roamingOffRegistrants.add(r);
+        mRoamingOffRegistrants.add(r);
 
         if (!ss.getRoaming()) {
             r.notifyRegistrant();
@@ -209,7 +200,7 @@
     }
 
     public  void unregisterForRoamingOff(Handler h) {
-        roamingOffRegistrants.remove(h);
+        mRoamingOffRegistrants.remove(h);
     }
 
     /**
@@ -272,7 +263,29 @@
         }
     }
 
-    public abstract void handleMessage(Message msg);
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case EVENT_SET_RADIO_POWER_OFF:
+                synchronized(this) {
+                    if (mPendingRadioPowerOffAfterDataOff &&
+                            (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) {
+                        if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
+                        hangupAndPowerOff();
+                        mPendingRadioPowerOffAfterDataOffTag += 1;
+                        mPendingRadioPowerOffAfterDataOff = false;
+                    } else {
+                        log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 +
+                                "!= tag=" + mPendingRadioPowerOffAfterDataOffTag);
+                    }
+                }
+                break;
+
+            default:
+                log("Unhandled message with number: " + msg.what);
+                break;
+        }
+    }
 
     protected abstract Phone getPhone();
     protected abstract void handlePollStateResult(int what, AsyncResult ar);
@@ -280,12 +293,152 @@
     protected abstract void setPowerStateToDesired();
     protected abstract void log(String s);
 
+    public abstract int getCurrentDataConnectionState();
+    public abstract boolean isConcurrentVoiceAndDataAllowed();
+
+    /**
+     * Registration point for transition into DataConnection 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) {
+        Registrant r = new Registrant(h, what, obj);
+        mAttachedRegistrants.add(r);
+
+        if (getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
+            r.notifyRegistrant();
+        }
+    }
+    public void unregisterForDataConnectionAttached(Handler h) {
+        mAttachedRegistrants.remove(h);
+    }
+
+    /**
+     * Registration point for transition into DataConnection 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) {
+        Registrant r = new Registrant(h, what, obj);
+        mDetachedRegistrants.add(r);
+
+        if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
+            r.notifyRegistrant();
+        }
+    }
+    public void unregisterForDataConnectionDetached(Handler h) {
+        mDetachedRegistrants.remove(h);
+    }
+
+    /**
+     * Registration point for transition into network attached.
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj in Message.obj
+     */
+    public void registerForNetworkAttached(Handler h, int what, Object obj) {
+        Registrant r = new Registrant(h, what, obj);
+
+        mNetworkAttachedRegistrants.add(r);
+        if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
+            r.notifyRegistrant();
+        }
+    }
+    public void unregisterForNetworkAttached(Handler h) {
+        mNetworkAttachedRegistrants.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) {
+        Registrant r = new Registrant(h, what, obj);
+        mPsRestrictEnabledRegistrants.add(r);
+
+        if (mRestrictedState.isPsRestricted()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForPsRestrictedEnabled(Handler h) {
+        mPsRestrictEnabledRegistrants.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) {
+        Registrant r = new Registrant(h, what, obj);
+        mPsRestrictDisabledRegistrants.add(r);
+
+        if (mRestrictedState.isPsRestricted()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForPsRestrictedDisabled(Handler h) {
+        mPsRestrictDisabledRegistrants.remove(h);
+    }
+
     /**
      * 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 void powerOffRadioSafely(DataConnectionTracker dcTracker) {
+        synchronized (this) {
+            if (!mPendingRadioPowerOffAfterDataOff) {
+                if (dcTracker.isAnyActiveDataConnections()) {
+                    dcTracker.cleanUpAllConnections(null);
+                    Message msg = Message.obtain(this);
+                    msg.what = EVENT_SET_RADIO_POWER_OFF;
+                    msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
+                    if (sendMessageDelayed(msg, 30000)) {
+                        if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
+                        mPendingRadioPowerOffAfterDataOff = true;
+                    } else {
+                        log("Cannot send delayed Msg, turn off radio right away.");
+                        hangupAndPowerOff();
+                    }
+                } else {
+                    dcTracker.cleanUpAllConnections(null);
+                    if (DBG) log("Data disconnected, turn off radio right away.");
+                    hangupAndPowerOff();
+                }
+            }
+        }
+    }
+
+    /**
+     * process the pending request to turn radio off after data is disconnected
+     *
+     * return true if there is pending request to process; false otherwise.
+     */
+    public boolean processPendingRadioPowerOffAfterDataOff() {
+        synchronized(this) {
+            if (mPendingRadioPowerOffAfterDataOff) {
+                if (DBG) log("Process pending request to turn radio off.");
+                mPendingRadioPowerOffAfterDataOffTag += 1;
+                hangupAndPowerOff();
+                mPendingRadioPowerOffAfterDataOff = false;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Hang up all voice call and turn off radio. Implemented by derived class.
+     */
+    protected abstract void hangupAndPowerOff();
 
     /** Cancel a pending (if any) pollState() operation */
     protected void cancelPollState() {
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index e6189be..4927006 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -72,6 +72,11 @@
      */
     static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country";
 
+    /** 'true' if device supports both LTE and CDMA mode of operation.
+     *  Availability: Set only on devices supporting LTE and CDMA.
+     */
+    static final String PROPERTY_NETWORK_LTE_ON_CDMA = "telephony.lte_on_cdma";
+
     static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
 
     //****** SIM Card
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 1e23e34..a6c7777 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -118,6 +118,8 @@
     private static IccRecords mIccRecords;
 
     // Service members.
+    // Protects singleton instance lazy initialization.
+    private static final Object sInstanceLock = new Object();
     private static CatService sInstance;
     private CommandsInterface mCmdIf;
     private Context mContext;
@@ -373,25 +375,30 @@
 
     private void encodeOptionalTags(CommandDetails cmdDet,
             ResultCode resultCode, Input cmdInput, ByteArrayOutputStream buf) {
-        switch (AppInterface.CommandType.fromInt(cmdDet.typeOfCommand)) {
-            case GET_INKEY:
-                // ETSI TS 102 384,27.22.4.2.8.4.2.
-                // If it is a response for GET_INKEY command and the response timeout
-                // occured, then add DURATION TLV for variable timeout case.
-                if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
-                    (cmdInput != null) && (cmdInput.duration != null)) {
-                    getInKeyResponse(buf, cmdInput);
-                }
-                break;
-            case PROVIDE_LOCAL_INFORMATION:
-                if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
-                    (resultCode.value() == ResultCode.OK.value())) {
-                    getPliResponse(buf);
-                }
-                break;
-            default:
-                CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
-                break;
+        CommandType cmdType = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand);
+        if (cmdType != null) {
+            switch (cmdType) {
+                case GET_INKEY:
+                    // ETSI TS 102 384,27.22.4.2.8.4.2.
+                    // If it is a response for GET_INKEY command and the response timeout
+                    // occured, then add DURATION TLV for variable timeout case.
+                    if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
+                        (cmdInput != null) && (cmdInput.duration != null)) {
+                        getInKeyResponse(buf, cmdInput);
+                    }
+                    break;
+                case PROVIDE_LOCAL_INFORMATION:
+                    if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
+                        (resultCode.value() == ResultCode.OK.value())) {
+                        getPliResponse(buf);
+                    }
+                    break;
+                default:
+                    CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
+                    break;
+            }
+        } else {
+            CatLog.d(this, "encodeOptionalTags() bad Cmd:" + cmdDet.typeOfCommand);
         }
     }
 
@@ -515,26 +522,28 @@
      */
     public static CatService getInstance(CommandsInterface ci, IccRecords ir,
             Context context, IccFileHandler fh, IccCard ic) {
-        if (sInstance == null) {
-            if (ci == null || ir == null || context == null || fh == null
-                    || ic == null) {
-                return null;
-            }
-            HandlerThread thread = new HandlerThread("Cat Telephony service");
-            thread.start();
-            sInstance = new CatService(ci, ir, context, fh, ic);
-            CatLog.d(sInstance, "NEW sInstance");
-        } else if ((ir != null) && (mIccRecords != ir)) {
-            CatLog.d(sInstance, "Reinitialize the Service with SIMRecords");
-            mIccRecords = ir;
+        synchronized (sInstanceLock) {
+            if (sInstance == null) {
+                if (ci == null || ir == null || context == null || fh == null
+                        || ic == null) {
+                    return null;
+                }
+                HandlerThread thread = new HandlerThread("Cat Telephony service");
+                thread.start();
+                sInstance = new CatService(ci, ir, context, fh, ic);
+                CatLog.d(sInstance, "NEW sInstance");
+            } else if ((ir != null) && (mIccRecords != ir)) {
+                CatLog.d(sInstance, "Reinitialize the Service with SIMRecords");
+                mIccRecords = ir;
 
-            // re-Register for SIM ready event.
-            mIccRecords.registerForRecordsLoaded(sInstance, MSG_ID_ICC_RECORDS_LOADED, null);
-            CatLog.d(sInstance, "sr changed reinitialize and return current sInstance");
-        } else {
-            CatLog.d(sInstance, "Return current sInstance");
+                // re-Register for SIM ready event.
+                mIccRecords.registerForRecordsLoaded(sInstance, MSG_ID_ICC_RECORDS_LOADED, null);
+                CatLog.d(sInstance, "sr changed reinitialize and return current sInstance");
+            } else {
+                CatLog.d(sInstance, "Return current sInstance");
+            }
+            return sInstance;
         }
-        return sInstance;
     }
 
     /**
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..8fd6de1
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -0,0 +1,177 @@
+/*
+ * 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);
+
+        mSIMRecords = new SIMRecords(this);
+        mSimCard = new SimCard(this, LOG_TAG, DBG);
+    }
+
+    @Override
+    protected void initSST() {
+        mSST = new CdmaLteServiceStateTracker(this);
+    }
+
+    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 {
+            switch (mDataConnection.getState(apnType)) {
+                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..31abe34 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,25 @@
 
     // Constructors
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
-        this(context,ci,notifier, false);
+        super(notifier, context, ci, false);
+        initSST();
+        init(context, notifier);
     }
 
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
             boolean unitTestMode) {
         super(notifier, context, ci, unitTestMode);
+        initSST();
+        init(context, notifier);
+    }
 
+    protected void initSST() {
+        mSST = new CdmaServiceStateTracker(this);
+    }
+
+    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);
@@ -168,7 +177,7 @@
         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
-        mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null);
+        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
         mCM.registerForNVReady(this, EVENT_NV_READY, null);
         mCM.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
 
@@ -220,7 +229,7 @@
             mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
             mCM.unregisterForOn(this); //EVENT_RADIO_ON
             mCM.unregisterForNVReady(this); //EVENT_NV_READY
-            mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
+            mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK
             mCM.unSetOnSuppServiceNotification(this);
             removeCallbacks(mExitEcmRunnable);
 
@@ -270,10 +279,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";
     }
@@ -616,7 +633,7 @@
                 mDataConnection.isApnTypeActive(apnType) == false) {
             ret = DataState.DISCONNECTED;
         } else {
-            switch (mDataConnection.getState()) {
+            switch (mDataConnection.getState(apnType)) {
                 case FAILED:
                 case IDLE:
                     ret = DataState.DISCONNECTED;
@@ -625,7 +642,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/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 1a0dbc2..cccc053 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -33,8 +33,8 @@
     private static final String LOG_TAG = "CDMA";
 
     // ***** Constructor
-    private CdmaDataConnection(CDMAPhone phone, String name, RetryManager rm) {
-        super(phone, name, rm);
+    private CdmaDataConnection(CDMAPhone phone, String name, int id, RetryManager rm) {
+        super(phone, name, id, rm);
     }
 
     /**
@@ -49,11 +49,10 @@
         synchronized (mCountLock) {
             mCount += 1;
         }
-        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone,
-                "CdmaDataConnection-" + mCount, rm);
+        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount,
+                id, rm);
         cdmaDc.start();
         if (DBG) cdmaDc.log("Made " + cdmaDc.getName());
-        cdmaDc.mId = id;
         return cdmaDc;
     }
 
@@ -68,6 +67,7 @@
     protected void onConnect(ConnectionParams cp) {
         if (DBG) log("CdmaDataConnection Connecting...");
 
+        mApn = cp.apn;
         createTime = -1;
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 8c36106..05361cd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -104,8 +104,8 @@
         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.registerForCdmaDataConnectionAttached(this, EVENT_TRY_SETUP_DATA, null);
-        p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null);
+        p.mSST.registerForDataConnectionAttached(this, EVENT_TRY_SETUP_DATA, null);
+        p.mSST.registerForDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null);
         p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
         p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
         p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null);
@@ -118,6 +118,8 @@
 
     @Override
     public void dispose() {
+        cleanUpConnection(false, null);
+
         super.dispose();
 
         // Unregister from all events
@@ -128,8 +130,8 @@
         mPhone.mCM.unregisterForDataNetworkStateChanged(this);
         mCdmaPhone.mCT.unregisterForVoiceCallEnded(this);
         mCdmaPhone.mCT.unregisterForVoiceCallStarted(this);
-        mCdmaPhone.mSST.unregisterForCdmaDataConnectionAttached(this);
-        mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this);
+        mCdmaPhone.mSST.unregisterForDataConnectionAttached(this);
+        mCdmaPhone.mSST.unregisterForDataConnectionDetached(this);
         mCdmaPhone.mSST.unregisterForRoamingOn(this);
         mCdmaPhone.mSST.unregisterForRoamingOff(this);
         mPhone.mCM.unregisterForCdmaOtaProvision(this);
@@ -158,6 +160,11 @@
     }
 
     @Override
+    public synchronized State getState(String apnType) {
+        return mState;
+    }
+
+    @Override
     protected boolean isApnTypeAvailable(String type) {
         for (String s : mSupportedApnTypes) {
             if (TextUtils.equals(type, s)) {
@@ -167,30 +174,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 +183,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 +197,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 +245,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.
@@ -288,7 +269,7 @@
             if(conn != null) {
                 if (tearDown) {
                     if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
-                    conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE,
+                    conn.disconnect(reason, obtainMessage(EVENT_DISCONNECT_DONE,
                             conn.getDataConnectionId(), 0, reason));
                     notificationDeferred = true;
                 } else {
@@ -354,7 +335,7 @@
         setState(State.CONNECTED);
         notifyDataConnection(reason);
         startNetStatPoll();
-        mRetryMgr.resetRetryCount();
+        mDataConnections.get(0).resetRetryCount();
     }
 
     private void resetPollStats() {
@@ -386,7 +367,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(null);
         sendEmptyMessageDelayed(EVENT_RESTART_RADIO, TIME_DELAYED_TO_RESTART_RADIO);
         mPendingRestartRadio = true;
     }
@@ -504,7 +485,7 @@
              * at the last time until the state is changed.
              * TODO: Make this configurable?
              */
-            int nextReconnectDelay = mRetryMgr.getRetryTimer();
+            int nextReconnectDelay = mDataConnections.get(0).getRetryTimer();
             log("Data Connection activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
@@ -518,7 +499,7 @@
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
                     mReconnectIntent);
 
-            mRetryMgr.increaseRetryCount();
+            mDataConnections.get(0).increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 log("NOT Posting Data Connection Unavailable notification "
@@ -534,7 +515,7 @@
         notifyDataAvailability(null);
     }
 
-    private void gotoIdleAndNotifyDataConnection(String reason) {
+    protected void gotoIdleAndNotifyDataConnection(String reason) {
         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
         setState(State.IDLE);
         notifyDataConnection(reason);
@@ -543,14 +524,14 @@
 
     protected void onRecordsLoaded() {
         if (mState == State.FAILED) {
-            cleanUpConnection(false, null);
+            cleanUpAllConnections(null);
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onNVReady() {
         if (mState == State.FAILED) {
-            cleanUpConnection(false, null);
+            cleanUpAllConnections(null);
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
     }
@@ -560,6 +541,7 @@
      */
     @Override
     protected void onEnableNewApn() {
+        // No mRequestedApnType check; only one connection is supported
         cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
     }
 
@@ -588,7 +570,7 @@
             trySetupData(Phone.REASON_ROAMING_ON);
         } else {
             if (DBG) log("Tear down data connection on roaming.");
-            cleanUpConnection(true, Phone.REASON_ROAMING_ON);
+            cleanUpAllConnections(null);
         }
     }
 
@@ -609,7 +591,7 @@
         notifyDataAvailability(null);
 
         if (mState != State.IDLE) {
-            cleanUpConnection(true, null);
+            cleanUpAllConnections(null);
         }
     }
 
@@ -618,7 +600,7 @@
      */
     @Override
     protected void onRadioOffOrNotAvailable() {
-        mRetryMgr.resetRetryCount();
+        mDataConnections.get(0).resetRetryCount();
 
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -626,7 +608,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(null);
         }
     }
 
@@ -693,25 +675,11 @@
     }
 
     /**
-     * Called when EVENT_RESET_DONE is received so goto
-     * IDLE state and send notifications to those interested.
-     */
-    @Override
-    protected void onResetDone(AsyncResult ar) {
-      if (DBG) log("EVENT_RESET_DONE");
-      String reason = null;
-      if (ar.userObj instanceof String) {
-          reason = (String) ar.userObj;
-      }
-      gotoIdleAndNotifyDataConnection(reason);
-    }
-
-    /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
     @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 +692,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 {
@@ -733,34 +701,40 @@
             }
             notifyDataAvailability(Phone.REASON_VOICE_CALL_ENDED);
         } else {
-            mRetryMgr.resetRetryCount();
+            mDataConnections.get(0).resetRetryCount();
             // in case data setup was attempted when we were on a voice call
             trySetupData(Phone.REASON_VOICE_CALL_ENDED);
         }
     }
 
     @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(String cause) {
+        // Only one CDMA connection is supported
+        cleanUpConnection(true, cause);
+    }
+
     private void createAllDataConnectionList() {
         CdmaDataConnection dataConn;
 
-        /** TODO: Use one retry manager for all connections for now */
-        RetryManager rm = mRetryMgr;
-        if (!rm.configure(SystemProperties.get("ro.cdma.data_retry_config"))) {
-            if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) {
-                // Should never happen, log an error and default to a simple linear sequence.
-                log("Could not configure using DEFAULT_DATA_RETRY_CONFIG="
-                        + DEFAULT_DATA_RETRY_CONFIG);
-                rm.configure(20, 2000, 1000);
-            }
-        }
-
+        String retryConfig = SystemProperties.get("ro.cdma.data_retry_config");
         for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
-            int id = mUniqueIdGenerator.getAndIncrement();
+            RetryManager rm = new RetryManager();
+            if (!rm.configure(retryConfig)) {
+                if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+                    // Should never happen, log an error and default to a simple linear sequence.
+                    log("Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+                            + DEFAULT_DATA_RETRY_CONFIG);
+                    rm.configure(20, 2000, 1000);
+                }
+            }
 
+            int id = mUniqueIdGenerator.getAndIncrement();
             dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm);
             mDataConnections.put(id, dataConn);
         }
@@ -779,7 +753,7 @@
         } else {
             if (mState == State.FAILED) {
                 cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
-                mRetryMgr.resetRetryCount();
+                mDataConnections.get(0).resetRetryCount();
 
                 CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation());
                 EventLog.writeEvent(EventLogTags.CDMA_DATA_SETUP_FAILED,
@@ -797,7 +771,7 @@
                 switch (otaPrivision[0]) {
                 case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED:
                 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED:
-                    mRetryMgr.resetRetryCount();
+                    mDataConnections.get(0).resetRetryCount();
                     break;
                 default:
                     break;
@@ -894,7 +868,7 @@
     @Override
     public void handleMessage (Message msg) {
 
-        if (!mPhone.mIsTheCurrentActivePhone) {
+        if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
             log("Ignore CDMA msgs since CDMA phone is inactive");
             return;
         }
@@ -933,6 +907,11 @@
     }
 
     @Override
+    public boolean isAnyActiveDataConnections() {
+        return (mState != State.IDLE);
+    }
+
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s);
     }
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..7ca3bea
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -0,0 +1,463 @@
+/*
+ * 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.RestrictedState;
+import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
+
+public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
+    static final String LOG_TAG = "CDMA";
+
+    CDMALTEPhone mCdmaLtePhone;
+
+    private int gprsState = ServiceState.STATE_OUT_OF_SERVICE;
+
+    private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE;
+
+    public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
+        super(phone);
+        mCdmaLtePhone = phone;
+        log("CdmaLteServiceStateTracker Constructors");
+    }
+
+    /**
+     * @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;
+
+            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 ServiceState.RADIO_TECHNOLOGY_IS95A:
+            case ServiceState.RADIO_TECHNOLOGY_IS95B:
+                ret = "CDMA";
+                break;
+            case ServiceState.RADIO_TECHNOLOGY_1xRTT:
+                ret = "CDMA - 1xRTT";
+                break;
+            case ServiceState.RADIO_TECHNOLOGY_EVDO_0:
+                ret = "CDMA - EvDo rev. 0";
+                break;
+            case ServiceState.RADIO_TECHNOLOGY_EVDO_A:
+                ret = "CDMA - EvDo rev. A";
+                break;
+            case ServiceState.RADIO_TECHNOLOGY_EVDO_B:
+                ret = "CDMA - EvDo rev. B";
+                break;
+            case ServiceState.RADIO_TECHNOLOGY_LTE:
+                ret = "LTE";
+                break;
+            case ServiceState.RADIO_TECHNOLOGY_EHRPD:
+                ret = "CDMA - eHRPD";
+                break;
+            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 == ServiceState.RADIO_TECHNOLOGY_LTE) &&
+                 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) ||
+                ((networkType == ServiceState.RADIO_TECHNOLOGY_EHRPD) &&
+                 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE));
+
+        boolean hasMultiApnSupport =
+                (((newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE) ||
+                  (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) &&
+                 ((networkType != ServiceState.RADIO_TECHNOLOGY_LTE) &&
+                  (networkType != ServiceState.RADIO_TECHNOLOGY_EHRPD)));
+
+        boolean hasLostMultiApnSupport =
+            ((newNetworkType >= ServiceState.RADIO_TECHNOLOGY_IS95A) &&
+             (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_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) {
+            mNetworkAttachedRegistrants.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) {
+            mAttachedRegistrants.notifyRegistrants();
+        }
+
+        if (hasCdmaDataConnectionDetached) {
+            mDetachedRegistrants.notifyRegistrants();
+        }
+
+        if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)
+                && (phone.mDataConnection instanceof CdmaDataConnectionTracker)) {
+            phone.notifyDataConnection();
+        }
+
+        if (hasRoamingOn) {
+            mRoamingOnRegistrants.notifyRegistrants();
+        }
+
+        if (hasRoamingOff) {
+            mRoamingOffRegistrants.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 >= ServiceState.RADIO_TECHNOLOGY_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..07f9e38 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.telephony.cdma;
 
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
-
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataConnectionTracker;
@@ -61,7 +59,7 @@
 /**
  * {@hide}
  */
-final class CdmaServiceStateTracker extends ServiceStateTracker {
+public class CdmaServiceStateTracker extends ServiceStateTracker {
     static final String LOG_TAG = "CDMA";
 
     CDMAPhone phone;
@@ -86,10 +84,10 @@
             NITZ_UPDATE_DIFF_DEFAULT);
 
     /**
-     *  Values correspond to ServiceStateTracker.DATA_ACCESS_ definitions.
+     *  Values correspond to ServiceState.RADIO_TECHNOLOGY_ 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 +97,21 @@
     /**
      * 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 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;
@@ -143,8 +139,6 @@
     private boolean isEriTextLoaded = false;
     private boolean isSubscriptionFromRuim = false;
 
-    private boolean mPendingRadioPowerOffAfterDataOff = false;
-
     /* Used only for debugging purposes. */
     private String mRegistrationDeniedReason;
 
@@ -232,57 +226,6 @@
         if (DBG) log("CdmaServiceStateTracker finalized");
     }
 
-    void registerForNetworkAttach(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-        networkAttachedRegistrants.add(r);
-
-        if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
-            r.notifyRegistrant();
-        }
-    }
-
-    void unregisterForNetworkAttach(Handler h) {
-        networkAttachedRegistrants.remove(h);
-    }
-
-    /**
-     * Registration point for transition into Data attached.
-     * @param h handler to notify
-     * @param what what code of message when delivered
-     * @param obj placed in Message.obj
-     */
-    void registerForCdmaDataConnectionAttached(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-        cdmaDataConnectionAttachedRegistrants.add(r);
-
-        if (cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE) {
-            r.notifyRegistrant();
-        }
-    }
-
-    void unregisterForCdmaDataConnectionAttached(Handler h) {
-        cdmaDataConnectionAttachedRegistrants.remove(h);
-    }
-
-    /**
-     * Registration point for transition into Data detached.
-     * @param h handler to notify
-     * @param what what code of message when delivered
-     * @param obj placed in Message.obj
-     */
-    void registerForCdmaDataConnectionDetached(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-        cdmaDataConnectionDetachedRegistrants.add(r);
-
-        if (cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE) {
-            r.notifyRegistrant();
-        }
-    }
-
-    void unregisterForCdmaDataConnectionDetached(Handler h) {
-        cdmaDataConnectionDetachedRegistrants.remove(h);
-    }
-
     /**
      * Registration point for subscription info ready
      * @param h handler to notify
@@ -540,18 +483,8 @@
             }
             break;
 
-        case EVENT_SET_RADIO_POWER_OFF:
-            synchronized(this) {
-                if (mPendingRadioPowerOffAfterDataOff) {
-                    if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
-                    hangupAndPowerOff();
-                    mPendingRadioPowerOffAfterDataOff = false;
-                }
-            }
-            break;
-
         default:
-            Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
+            super.handleMessage(msg);
         break;
         }
     }
@@ -566,50 +499,13 @@
             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();
+            powerOffRadioSafely(dcTracker);
         } // Otherwise, we're in the desired state
     }
 
     @Override
-    protected 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 (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
-                        if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
-                        mPendingRadioPowerOffAfterDataOff = true;
-                    } else {
-                        Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
-                        hangupAndPowerOff();
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
     protected void updateSpnDisplay() {
         // TODO RUIM SPN is not implemented, EF_SPN has to be read and Display Condition
         //   Character Encoding, Language Indicator and SPN has to be set, something like below:
@@ -647,14 +543,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;
 
@@ -677,155 +726,13 @@
                 return;
             }
 
-            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW &&
-                    err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
+            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
                 Log.e(LOG_TAG,
                         "RIL implementation has returned an error where it must succeed",
                         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 +803,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 +815,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,24 +870,24 @@
         }
     }
 
-    private static String networkTypeToString(int type) {
+    protected static String networkTypeToString(int type) {
         String ret = "unknown";
 
         switch (type) {
-        case DATA_ACCESS_CDMA_IS95A:
-        case DATA_ACCESS_CDMA_IS95B:
+        case ServiceState.RADIO_TECHNOLOGY_IS95A:
+        case ServiceState.RADIO_TECHNOLOGY_IS95B:
             ret = "CDMA";
             break;
-        case DATA_ACCESS_CDMA_1xRTT:
+        case ServiceState.RADIO_TECHNOLOGY_1xRTT:
             ret = "CDMA - 1xRTT";
             break;
-        case DATA_ACCESS_CDMA_EvDo_0:
+        case ServiceState.RADIO_TECHNOLOGY_EVDO_0:
             ret = "CDMA - EvDo rev. 0";
             break;
-        case DATA_ACCESS_CDMA_EvDo_A:
+        case ServiceState.RADIO_TECHNOLOGY_EVDO_A:
             ret = "CDMA - EvDo rev. A";
             break;
-        case DATA_ACCESS_CDMA_EvDo_B:
+        case ServiceState.RADIO_TECHNOLOGY_EVDO_B:
             ret = "CDMA - EvDo rev. B";
             break;
         default:
@@ -994,7 +900,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 +937,7 @@
         }
     }
 
-    private void pollStateDone() {
+    protected void pollStateDone() {
         if (DBG) log("Poll ServiceState done: oldSS=[" + ss + "] newSS=[" + newSS + "]");
 
         boolean hasRegistered =
@@ -1095,7 +1001,7 @@
         }
 
         if (hasRegistered) {
-            networkAttachedRegistrants.notifyRegistrants();
+            mNetworkAttachedRegistrants.notifyRegistrants();
         }
 
         if (hasChanged) {
@@ -1150,11 +1056,11 @@
         }
 
         if (hasCdmaDataConnectionAttached) {
-            cdmaDataConnectionAttachedRegistrants.notifyRegistrants();
+            mAttachedRegistrants.notifyRegistrants();
         }
 
         if (hasCdmaDataConnectionDetached) {
-            cdmaDataConnectionDetachedRegistrants.notifyRegistrants();
+            mDetachedRegistrants.notifyRegistrants();
         }
 
         if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) {
@@ -1162,11 +1068,11 @@
         }
 
         if (hasRoamingOn) {
-            roamingOnRegistrants.notifyRegistrants();
+            mRoamingOnRegistrants.notifyRegistrants();
         }
 
         if (hasRoamingOff) {
-            roamingOffRegistrants.notifyRegistrants();
+            mRoamingOffRegistrants.notifyRegistrants();
         }
 
         if (hasLocationChanged) {
@@ -1234,7 +1140,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 +1159,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 {
@@ -1279,6 +1185,7 @@
         case 7: // RADIO_TECHNOLOGY_EVDO_0
         case 8: // RADIO_TECHNOLOGY_EVDO_A
         case 12: // RADIO_TECHNOLOGY_EVDO_B
+        case 13: // RADIO_TECHNOLOGY_EHRPD
             retVal = ServiceState.STATE_IN_SERVICE;
             break;
         default:
@@ -1289,7 +1196,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 +1226,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 +1576,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.
@@ -1707,24 +1621,6 @@
     }
 
     /**
-     * process the pending request to turn radio off after data is disconnected
-     *
-     * return true if there is pending request to process; false otherwise.
-     */
-    public boolean processPendingRadioPowerOffAfterDataOff() {
-        synchronized(this) {
-            if (mPendingRadioPowerOffAfterDataOff) {
-                if (DBG) log("Process pending request to turn radio off.");
-                removeMessages(EVENT_SET_RADIO_POWER_OFF);
-                hangupAndPowerOff();
-                mPendingRadioPowerOffAfterDataOff = false;
-                return true;
-            }
-            return false;
-        }
-    }
-
-    /**
      * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED
      */
     int getOtasp() {
@@ -1750,7 +1646,8 @@
         Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
     }
 
-    private void hangupAndPowerOff() {
+    @Override
+    protected void hangupAndPowerOff() {
         // hang up all active voice calls
         phone.mCT.ringingCall.hangupIfAlive();
         phone.mCT.backgroundCall.hangupIfAlive();
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
old mode 100644
new mode 100755
index cf06dab..7a45e15
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -34,6 +34,9 @@
 import com.android.internal.util.BitwiseInputStream;
 import com.android.internal.util.BitwiseOutputStream;
 
+import android.content.res.Resources;
+
+
 
 /**
  * An object to encode and decode CDMA SMS bearer data.
@@ -582,7 +585,6 @@
                     uData.payload = new byte[0];
                     uData.numFields = 0;
                 } else {
-                    uData.payload = uData.payload;
                     uData.numFields = uData.payload.length;
                 }
             } else {
@@ -910,6 +912,16 @@
         return true;
     }
 
+    private static String decodeUtf8(byte[] data, int offset, int numFields)
+        throws CodingException
+    {
+        try {
+            return new String(data, offset, numFields, "UTF-8");
+        } catch (java.io.UnsupportedEncodingException ex) {
+            throw new CodingException("UTF-8 decode failed: " + ex);
+        }
+    }
+
     private static String decodeUtf16(byte[] data, int offset, int numFields)
         throws CodingException
     {
@@ -994,9 +1006,15 @@
         }
         switch (userData.msgEncoding) {
         case UserData.ENCODING_OCTET:
+            /*
+            *  Octet decoding depends on the carrier service.
+            */
+            boolean decodingtypeUTF8 = Resources.getSystem()
+                    .getBoolean(com.android.internal.R.bool.config_sms_utf8_support);
+
             // Strip off any padding bytes, meaning any differences between the length of the
-            // array and the target length specified by numFields.  This is to avoid any confusion
-            // by code elsewhere that only considers the payload array length.
+            // array and the target length specified by numFields.  This is to avoid any
+            // confusion by code elsewhere that only considers the payload array length.
             byte[] payload = new byte[userData.numFields];
             int copyLen = userData.numFields < userData.payload.length
                     ? userData.numFields : userData.payload.length;
@@ -1004,9 +1022,13 @@
             System.arraycopy(userData.payload, 0, payload, 0, copyLen);
             userData.payload = payload;
 
-            // There are many devices in the market that send 8bit text sms (latin encoded) as
-            // octet encoded.
-            userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+            if (!decodingtypeUTF8) {
+                // There are many devices in the market that send 8bit text sms (latin encoded) as
+                // octet encoded.
+                userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+            } else {
+                userData.payloadStr = decodeUtf8(userData.payload, offset, userData.numFields);
+            }
             break;
         case UserData.ENCODING_IA5:
         case UserData.ENCODING_7BIT_ASCII:
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index c17197e..36094a1 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;
@@ -160,7 +159,7 @@
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnUSSD(this, EVENT_USSD, null);
         mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
-        mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null);
+        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
 
         if (false) {
             try {
@@ -210,7 +209,7 @@
             mSIMRecords.unregisterForRecordsLoaded(this); //EVENT_SIM_RECORDS_LOADED
             mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
             mCM.unregisterForOn(this); //EVENT_RADIO_ON
-            mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
+            mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK
             mCM.unSetOnUSSD(this);
             mCM.unSetOnSuppServiceNotification(this);
 
@@ -283,6 +282,14 @@
         return mSIMRecords.getVoiceCallForwardingFlag();
     }
 
+    public CallTracker getCallTracker() {
+        return mCT;
+    }
+
+    public ServiceStateTracker getServiceStateTracker() {
+        return mSST;
+    }
+
     public List<? extends MmiCode>
     getPendingMmiCodes() {
         return mPendingMMIs;
@@ -305,7 +312,7 @@
                 mDataConnection.isApnTypeActive(apnType) == false) {
             ret = DataState.DISCONNECTED;
         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
-            switch (mDataConnection.getState()) {
+            switch (mDataConnection.getState(apnType)) {
                 case FAILED:
                 case IDLE:
                     ret = DataState.DISCONNECTED;
@@ -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/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
index 7dc2504..0870d5b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
@@ -374,11 +374,11 @@
                 } else if (phone.getIccCard().getState() != SimCard.State.READY) {
                     return DisconnectCause.ICC_ERROR;
                 } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
-                    if (phone.mSST.rs.isCsRestricted()) {
+                    if (phone.mSST.mRestrictedState.isCsRestricted()) {
                         return DisconnectCause.CS_RESTRICTED;
-                    } else if (phone.mSST.rs.isCsEmergencyRestricted()) {
+                    } else if (phone.mSST.mRestrictedState.isCsEmergencyRestricted()) {
                         return DisconnectCause.CS_RESTRICTED_EMERGENCY;
-                    } else if (phone.mSST.rs.isCsNormalRestricted()) {
+                    } else if (phone.mSST.mRestrictedState.isCsNormalRestricted()) {
                         return DisconnectCause.CS_RESTRICTED_NORMAL;
                     } else {
                         return DisconnectCause.ERROR_UNSPECIFIED;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 4689b2d..b0b2ac5 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;
 
@@ -34,11 +36,11 @@
     private static final String LOG_TAG = "GSM";
 
     //***** 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) {
-        super(phone, name, rm);
+    private GsmDataConnection(PhoneBase phone, String name, int id, RetryManager rm) {
+        super(phone, name, id, rm);
     }
 
     /**
@@ -49,15 +51,14 @@
      * @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;
         }
-        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount, rm);
+        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount,
+                id, rm);
         gsmDc.start();
         if (DBG) gsmDc.log("Made " + gsmDc.getName());
-        gsmDc.mId = id;
-        gsmDc.mRetryMgr = rm;
         return gsmDc;
     }
 
@@ -71,13 +72,13 @@
     @Override
     protected
     void onConnect(ConnectionParams cp) {
-        apn = cp.apn;
+        mApn = cp.apn;
 
-        if (DBG) log("Connecting to carrier: '" + apn.carrier
-                + "' APN: '" + apn.apn
-                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+        if (DBG) log("Connecting to carrier: '" + mApn.carrier
+                + "' APN: '" + mApn.apn
+                + "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
 
-        setHttpProxy (apn.proxy, apn.port);
+        setHttpProxy (mApn.proxy, mApn.port);
 
         createTime = -1;
         lastFailTime = -1;
@@ -87,35 +88,47 @@
         Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
         msg.obj = cp;
 
-        int authType = apn.authType;
+        int authType = mApn.authType;
         if (authType == -1) {
-            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+            authType = (mApn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
                 RILConstants.SETUP_DATA_AUTH_NONE;
         }
 
         String protocol;
         if (phone.getServiceState().getRoaming()) {
-            protocol = apn.roamingProtocol;
+            protocol = mApn.roamingProtocol;
         } else {
-            protocol = apn.protocol;
+            protocol = mApn.protocol;
         }
 
         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),
+                mApn.apn, mApn.user, mApn.password,
+                Integer.toString(authType),
                 protocol, msg);
     }
 
-    @Override
-    protected void clearSettings() {
-        super.clearSettings();
-        apn = null;
+    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
     public String toString() {
-        return "State=" + getCurrentState().getName() + " Apn=" + apn +
+        return "State=" + getCurrentState().getName() + " Apn=" + mApn +
                " create=" + createTime + " lastFail=" + lastFailTime +
                " lastFailCause=" + lastFailCause;
     }
@@ -129,11 +142,12 @@
             // Do not apply the race condition workaround for MMS APN
             // if Proxy is an IP-address.
             // Otherwise, the default APN will not be restored anymore.
-            if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
-                || !isIpAddress(apn.mmsProxy)) {
+            if (!mApn.types[0].equals(Phone.APN_TYPE_MMS)
+                || !isIpAddress(mApn.mmsProxy)) {
                 log(String.format(
                         "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s",
-                        apn.types[0], Phone.APN_TYPE_MMS, apn.mmsProxy, isIpAddress(apn.mmsProxy)));
+                        mApn.types[0], Phone.APN_TYPE_MMS, mApn.mmsProxy,
+                        isIpAddress(mApn.mmsProxy)));
                 return false;
             }
         }
@@ -145,27 +159,41 @@
         Log.d(LOG_TAG, "[" + getName() + "] " + s);
     }
 
-    public ApnSetting getApn() {
-        return this.apn;
-    }
-
     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: '" + mApn.proxy + "' port: '" + mApn.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) {
         if (address == null) return false;
 
-        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
+        return Patterns.IP_ADDRESS.matcher(address).matches();
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index c57f2f1..891a237 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.
      */
@@ -92,64 +102,60 @@
     //useful for debugging
     boolean mFailNextConnect = false;
 
-    /**
-     * allApns holds all apns for this sim spn, retrieved from
-     * the Carrier DB.
-     *
-     * Create once after simcard info is loaded
-     */
-    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>();
-
-    /** Is packet service restricted by network */
-    private boolean mIsPsRestricted = false;
-
     //***** Constants
 
     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,33 +165,58 @@
                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
 
         /** Create the default connection */
-        createDataConnection(Phone.APN_TYPE_DEFAULT);
+        mApnContexts = new ConcurrentHashMap<String, ApnContext>();
+        initApncontextsAndDataConnection();
         broadcastMessenger();
     }
 
     @Override
     public void dispose() {
+        cleanUpAllConnections(false, null);
+
         super.dispose();
 
         //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 +227,231 @@
         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;
+    }
+
+    @Override
+    protected void setState(State s) {
+        if (DBG) log("setState should not be used in GSM" + s);
+    }
+
+    // Return state of specific apn type
+    @Override
+    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 +470,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 +525,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);
-                mRetryMgr.resetRetryCount();
+            // Only check for default APN state
+            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+            if (defaultApnContext.getState() == State.FAILED) {
+                cleanUpConnection(false, defaultApnContext);
+                defaultApnContext.getDataConnection().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 +558,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 +573,190 @@
         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) +
+                    " isPsRestricted=" + 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);
+            mApnContexts.put(type, apnContext);
+        }
+        apnContext.setReason(reason);
+
+        return trySetupData(apnContext);
+
+    }
+
+    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(String cause) {
+        cleanUpAllConnections(true, cause);
+    }
+
+    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);
+        if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
+            if (DBG) log("state is in " + apnContext.getState());
+            return;
+        }
 
-        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;
+        if (apnContext.getState() == State.FAILED) {
+            if (DBG) log("state is in FAILED");
+            apnContext.setState(State.IDLE);
+            return;
+        }
+
+        GsmDataConnection conn = apnContext.getDataConnection();
+        if (conn != null) {
+            apnContext.setState(State.DISCONNECTING);
+            if (tearDown ) {
+                Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+                conn.disconnect(apnContext.getReason(), msg);
             } else {
-                if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
                 conn.resetSynchronously();
-                notificationDeferred = false;
+                apnContext.setState(State.IDLE);
+                mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
             }
         }
-        stopNetStatPoll();
 
-        if (!notificationDeferred) {
-            if (DBG) log("cleanupConnection: !notificationDeferred");
-            gotoIdleAndNotifyDataConnection(reason);
+        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
@@ -439,6 +799,7 @@
                 result.add(apn);
             } while (cursor.moveToNext());
         }
+        if (DBG) log("createApnList: X result=" + result);
         return result;
     }
 
@@ -453,27 +814,64 @@
         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.getNextWaitingApn();
+        if (apn == null) {
+            if (DBG) log("setupData: return for no apn found!");
+            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 +896,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!!!!
+            defaultApnContext.getDataConnection().resetRetryCount();
+            defaultApnContext.setReason(Phone.REASON_APN_CHANGED);
+            trySetupData(defaultApnContext);
         }
     }
 
@@ -537,28 +939,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 +988,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;
+        apnContext.getDataConnection().resetRetryCount();
     }
 
-    private void gotoIdleAndNotifyDataConnection(String reason) {
+    // TODO: For multiple Active APNs not exactly sure how to do this.
+    protected void gotoIdleAndNotifyDataConnection(String reason) {
         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
-        setState(State.IDLE);
         notifyDataConnection(reason);
         mActiveApn = null;
     }
@@ -608,18 +1032,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 +1052,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 +1070,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(this);
         /* 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,107 +1208,132 @@
         return retry;
     }
 
-    private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
-        if (mState == State.FAILED) {
-            /** TODO: Retrieve retry manager from connection itself */
-            if (!mRetryMgr.isRetryNeeded()) {
-                if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
+    private void reconnectAfterFail(FailCause lastFailCauseCode, ApnContext apnContext) {
+        if (apnContext == null) {
+            Log.d(LOG_TAG, "It is impossible");
+            return;
+        }
+        if (apnContext.getState() == State.FAILED) {
+            if (!apnContext.getDataConnection().isRetryNeeded()) {
+                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.
-                    mRetryMgr.retryForeverUsingLastTimeout();
+                    // We've re-registerd once now just retry forever.
+                    apnContext.getDataConnection().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);
-                    mRetryMgr.resetRetryCount();
+                    mPhone.getServiceStateTracker().reRegisterNetwork(null);
+                    apnContext.getDataConnection().resetRetryCount();
                     return;
                 }
             }
 
-            int nextReconnectDelay = mRetryMgr.getRetryTimer();
+            int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
             log("PDP activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
             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();
+            apnContext.getDataConnection().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();
-            mRetryMgr.resetRetryCount();
-        } else if (mApnToDataConnectionId.get(mRequestedApnType) == null) {
-            log("onEnableNewApn mRequestedApnType=" + mRequestedApnType +
+            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+            defaultApnContext.getDataConnection().resetRetryCount();
+        } else if (mApnToDataConnectionId.get(apnContext.getApnType()) == null) {
+            log("onEnableNewApn ApnType=" + apnContext.getApnType() +
                     " missing, make a new connection");
-            int id = createDataConnection(mRequestedApnType);
-            mRetryMgr = mDataConnections.get(id).getRetryMgr();
-            mRetryMgr.resetRetryCount();
+            int id = createDataConnection(apnContext.getApnType());
+            mDataConnections.get(id).resetRetryCount();
         } else {
             log("oneEnableNewApn connection already exists, nothing to setup");
         }
 
         // 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 +1342,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);
         }
     }
@@ -908,7 +1357,10 @@
     protected void onRadioOffOrNotAvailable() {
         // Make sure our reconnect delay starts at the initial value
         // next time the radio comes on
-        mRetryMgr.resetRetryCount();
+
+        for (DataConnection dc : mDataConnections.values()) {
+            dc.resetRetryCount();
+        }
         mReregisterOnReconnectFailure = false;
 
         if (mPhone.getSimulatedRadioControl() != null) {
@@ -917,28 +1369,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 +1405,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 +1447,35 @@
             }
 
             // Count permanent failures and remove the APN we just tried
-            mWaitingApnsPermanentFailureCountDown -= cause.isPermanentFail() ? 1 : 0;
-            mWaitingApns.remove(0);
-            if (DBG) log(String.format("onDataSetupComplete: mWaitingApns.size=%d" +
-                            " mWaitingApnsPermanenatFailureCountDown=%d",
-                            mWaitingApns.size(), mWaitingApnsPermanentFailureCountDown));
+            if (cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount();
+
+            apnContext.removeNextWaitingApn();
+            if (DBG) {
+                log(String.format("onDataSetupComplete: WaitingApns.size=%d" +
+                        " WaitingApnsPermFailureCountDown=%d",
+                        apnContext.getWaitingApns().size(),
+                        apnContext.getWaitingApnsPermFailCount()));
+            }
 
             // See if there are more APN's to try
-            if (mWaitingApns.isEmpty()) {
-                if (mWaitingApnsPermanentFailureCountDown == 0) {
-                    if (DBG) log("onDataSetupComplete: Permanent failures stop retrying");
-                    notifyNoData(cause);
+            if (apnContext.getWaitingApns().isEmpty()) {
+                if (apnContext.getWaitingApnsPermFailCount() == 0) {
+                    if (DBG) {
+                        log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
+                    }
+                    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,34 +1485,47 @@
      */
     @Override
     protected void onDisconnectDone(int connId, AsyncResult ar) {
-        if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId);
-        String reason = null;
-        if (ar.userObj instanceof String) {
-           reason = (String) ar.userObj;
-        }
-        setState(State.IDLE);
-        notifyDataConnection(reason);
-        mActiveApn = null;
-        if (retryAfterDisconnected(reason)) {
-            trySetupData(reason);
-        }
-    }
+        ApnContext apnContext = null;
 
-    /**
-     * Called when EVENT_RESET_DONE is received.
-     */
-    @Override
-    protected void onResetDone(AsyncResult ar) {
-        if (DBG) log("EVENT_RESET_DONE");
-        String reason = null;
-        if (ar.userObj instanceof String) {
-            reason = (String) ar.userObj;
+        if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId);
+        if (ar.userObj instanceof ApnContext) {
+            apnContext = (ApnContext) ar.userObj;
         }
-        gotoIdleAndNotifyDataConnection(reason);
+
+        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+
+        apnContext.setState(State.IDLE);
+        apnContext.setApnSetting(null);
+
+        // if all data connection are gone, check whether Airplane mode request was
+        // pending.
+        if (!isConnected()) {
+            if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
+                // Radio will be turned off. No need to retry data setup
+                return;
+            }
+        }
+
+        // Check if APN disabled.
+        if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
+           mApnContexts.remove(apnContext.getApnType());
+           return;
+        }
+
+        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);
+        }
     }
 
     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 +1534,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 +1542,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 {
@@ -1073,16 +1552,43 @@
             }
         } else {
             // reset reconnect timer
-            mRetryMgr.resetRetryCount();
+            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+            defaultApnContext.getDataConnection().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,10 +1597,11 @@
      */
     private void createAllApnList() {
         mAllApns = new ArrayList<ApnSetting>();
-        String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
+        String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (operator != null) {
             String selection = "numeric = '" + operator + "'";
+            if (DBG) log("createAllApnList: selection=" + selection);
 
             Cursor cursor = mPhone.getContext().getContentResolver().query(
                     Telephony.Carriers.CONTENT_URI, null, selection, null, null);
@@ -1108,17 +1615,19 @@
         }
 
         if (mAllApns.isEmpty()) {
-            if (DBG) log("No APN found for carrier: " + operator);
+            if (DBG) log("createAllApnList: 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");
             if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
                 mPreferredApn = null;
                 setPreferredApn(-1);
             }
+            if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
         }
+        if (DBG) log("createAllApnList: X mAllApns=" + mAllApns);
     }
 
     /** Return the id for a new data connection */
@@ -1147,7 +1656,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);
 
@@ -1164,17 +1673,6 @@
         }
     }
 
-    private ApnSetting fetchDunApn() {
-        Context c = mPhone.getContext();
-        String apnData = Settings.Secure.getString(c.getContentResolver(),
-                                    Settings.Secure.TETHER_DUN_APN);
-        ApnSetting dunSetting = ApnSetting.fromString(apnData);
-        if (dunSetting != null) return dunSetting;
-
-        apnData = c.getResources().getString(R.string.config_tether_apndata);
-        return ApnSetting.fromString(apnData);
-    }
-
     /**
      * Build a list of APNs to be used to create PDP's.
      *
@@ -1188,20 +1686,22 @@
         if (requestedApnType.equals(Phone.APN_TYPE_DUN)) {
             ApnSetting dun = fetchDunApn();
             if (dun != null) apnList.add(dun);
+            if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
             return apnList;
         }
 
-        String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
+        String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (canSetPreferApn && mPreferredApn != null) {
                 log("Preferred APN:" + operator + ":"
                         + mPreferredApn.numeric + ":" + mPreferredApn);
                 if (mPreferredApn.numeric.equals(operator)) {
-                    log("Waiting APN set to preferred APN");
                     apnList.add(mPreferredApn);
+                    if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
                     return apnList;
                 } else {
+                    if (DBG) log("buildWaitingApns: no preferred APN");
                     setPreferredApn(-1);
                     mPreferredApn = null;
                 }
@@ -1215,25 +1715,10 @@
                 }
             }
         }
+        if (DBG) log("buildWaitingApns: X apnList=" + apnList);
         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++) {
@@ -1244,9 +1729,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) {
@@ -1302,7 +1787,7 @@
     public void handleMessage (Message msg) {
         if (DBG) log("GSMDataConnTrack handleMessage "+msg);
 
-        if (!mGsmPhone.mIsTheCurrentActivePhone) {
+        if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
             log("Ignore GSM msgs since GSM phone is inactive");
             return;
         }
@@ -1312,12 +1797,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:
@@ -1363,18 +1856,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);
-                        mRetryMgr.resetRetryCount();
+                        cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
+                        resetAllRetryCounts();
                         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);
@@ -1382,6 +1894,23 @@
         }
     }
 
+    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
+    public boolean isAnyActiveDataConnections() {
+        return isConnected();
+    }
+
     @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..ef3eed8 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -23,6 +23,7 @@
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.MccTable;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RestrictedState;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
@@ -75,7 +76,6 @@
     GsmCellLocation cellLoc;
     GsmCellLocation newCellLoc;
     int mPreferredNetworkType;
-    RestrictedState rs;
 
     private int gprsState = ServiceState.STATE_OUT_OF_SERVICE;
     private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE;
@@ -85,7 +85,7 @@
     private int mNewReasonDataDenied = -1;
 
     /**
-     *  Values correspond to ServiceStateTracker.DATA_ACCESS_ definitions.
+     *  Values correspond to ServiceState.RADIO_TECHNOLOGY_ definitions.
      */
     private int networkType = 0;
     private int newNetworkType = 0;
@@ -107,11 +107,6 @@
      */
     private boolean mEmergencyOnly = false;
 
-    private RegistrantList gprsAttachedRegistrants = new RegistrantList();
-    private RegistrantList gprsDetachedRegistrants = new RegistrantList();
-    private RegistrantList psRestrictEnabledRegistrants = new RegistrantList();
-    private RegistrantList psRestrictDisabledRegistrants = 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
@@ -169,8 +164,6 @@
     static final int PS_NOTIFICATION = 888;  // Id to update and cancel PS restricted
     static final int CS_NOTIFICATION = 999;  // Id to update and cancel CS restricted
 
-    static final int MAX_NUM_DATA_STATE_READS = 15;
-
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -206,7 +199,6 @@
         newSS = new ServiceState();
         cellLoc = new GsmCellLocation();
         newCellLoc = new GsmCellLocation();
-        rs = new RestrictedState();
         mSignalStrength = new SignalStrength();
 
         PowerManager powerManager =
@@ -272,97 +264,6 @@
         return phone;
     }
 
-    /**
-     * 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
-     */
-    void registerForGprsAttached(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-        gprsAttachedRegistrants.add(r);
-
-        if (gprsState == ServiceState.STATE_IN_SERVICE) {
-            r.notifyRegistrant();
-        }
-    }
-
-    void unregisterForGprsAttached(Handler h) {
-        gprsAttachedRegistrants.remove(h);
-    }
-
-    void registerForNetworkAttach(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-        networkAttachedRegistrants.add(r);
-
-        if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
-            r.notifyRegistrant();
-        }
-    }
-
-    void unregisterForNetworkAttach(Handler h) {
-        networkAttachedRegistrants.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
-     */
-    void registerForGprsDetached(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-        gprsDetachedRegistrants.add(r);
-
-        if (gprsState == ServiceState.STATE_OUT_OF_SERVICE) {
-            r.notifyRegistrant();
-        }
-    }
-
-    void unregisterForGprsDetached(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
-     */
-    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);
-
-        if (rs.isPsRestricted()) {
-            r.notifyRegistrant();
-        }
-    }
-
-    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
-     */
-    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);
-
-        if (rs.isPsRestricted()) {
-            r.notifyRegistrant();
-        }
-    }
-
-    void unregisterForPsRestrictedDisabled(Handler h) {
-        psRestrictDisabledRegistrants.remove(h);
-    }
-
     public void handleMessage (Message msg) {
         AsyncResult ar;
         int[] ints;
@@ -556,7 +457,7 @@
                 break;
 
             default:
-                Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
+                super.handleMessage(msg);
             break;
         }
     }
@@ -567,36 +468,14 @@
             && 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();
+            DataConnectionTracker dcTracker = phone.mDataConnection;
+            powerOffRadioSafely(dcTracker);
         } // Otherwise, we're in the desired state
     }
 
     @Override
-    protected void powerOffRadioSafely() {
-        // clean data connection
-        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;
-        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);
-        }
-
+    protected void hangupAndPowerOff() {
         // hang up all active voice calls
         if (phone.isInCall()) {
             phone.mCT.ringingCall.hangupIfAlive();
@@ -674,8 +553,7 @@
                 return;
             }
 
-            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW &&
-                    err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
+            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
                 Log.e(LOG_TAG,
                         "RIL implementation has returned an error where it must succeed" +
                         ar.exception);
@@ -877,22 +755,22 @@
         String ret = "unknown";
 
         switch (type) {
-            case DATA_ACCESS_GPRS:
+            case ServiceState.RADIO_TECHNOLOGY_GPRS:
                 ret = "GPRS";
                 break;
-            case DATA_ACCESS_EDGE:
+            case ServiceState.RADIO_TECHNOLOGY_EDGE:
                 ret = "EDGE";
                 break;
-            case DATA_ACCESS_UMTS:
+            case ServiceState.RADIO_TECHNOLOGY_UMTS:
                 ret = "UMTS";
                 break;
-            case DATA_ACCESS_HSDPA:
+            case ServiceState.RADIO_TECHNOLOGY_HSDPA:
                 ret = "HSDPA";
                 break;
-            case DATA_ACCESS_HSUPA:
+            case ServiceState.RADIO_TECHNOLOGY_HSUPA:
                 ret = "HSUPA";
                 break;
-            case DATA_ACCESS_HSPA:
+            case ServiceState.RADIO_TECHNOLOGY_HSPA:
                 ret = "HSPA";
                 break;
             default:
@@ -988,7 +866,7 @@
         }
 
         if (hasRegistered) {
-            networkAttachedRegistrants.notifyRegistrants();
+            mNetworkAttachedRegistrants.notifyRegistrants();
         }
 
         if (hasChanged) {
@@ -1065,23 +943,23 @@
         }
 
         if (hasGprsAttached) {
-            gprsAttachedRegistrants.notifyRegistrants();
+            mAttachedRegistrants.notifyRegistrants();
         }
 
         if (hasGprsDetached) {
-            gprsDetachedRegistrants.notifyRegistrants();
+            mDetachedRegistrants.notifyRegistrants();
         }
 
         if (hasNetworkTypeChanged) {
-            phone.notifyDataConnection();
+            phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED, Phone.APN_TYPE_ALL);
         }
 
         if (hasRoamingOn) {
-            roamingOnRegistrants.notifyRegistrants();
+            mRoamingOnRegistrants.notifyRegistrants();
         }
 
         if (hasRoamingOff) {
-            roamingOffRegistrants.notifyRegistrants();
+            mRoamingOffRegistrants.notifyRegistrants();
         }
 
         if (hasLocationChanged) {
@@ -1229,7 +1107,7 @@
         Log.d(LOG_TAG, "[DSAC DEB] " + "onRestrictedStateChanged");
         RestrictedState newRs = new RestrictedState();
 
-        Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at enter "+ rs);
+        Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at enter "+ mRestrictedState);
 
         if (ar.exception == null) {
             int[] ints = (int[])ar.result;
@@ -1249,11 +1127,11 @@
 
             Log.d(LOG_TAG, "[DSAC DEB] " + "new rs "+ newRs);
 
-            if (!rs.isPsRestricted() && newRs.isPsRestricted()) {
-                psRestrictEnabledRegistrants.notifyRegistrants();
+            if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) {
+                mPsRestrictEnabledRegistrants.notifyRegistrants();
                 setNotification(PS_ENABLED);
-            } else if (rs.isPsRestricted() && !newRs.isPsRestricted()) {
-                psRestrictDisabledRegistrants.notifyRegistrants();
+            } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) {
+                mPsRestrictDisabledRegistrants.notifyRegistrants();
                 setNotification(PS_DISABLED);
             }
 
@@ -1262,7 +1140,7 @@
              * there are 4 x 4 combinations in current and new restricted states
              * and we only need to notify when state is changed.
              */
-            if (rs.isCsRestricted()) {
+            if (mRestrictedState.isCsRestricted()) {
                 if (!newRs.isCsRestricted()) {
                     // remove all restriction
                     setNotification(CS_DISABLED);
@@ -1273,7 +1151,8 @@
                     // remove emergency restriction
                     setNotification(CS_NORMAL_ENABLED);
                 }
-            } else if (rs.isCsEmergencyRestricted() && !rs.isCsNormalRestricted()) {
+            } else if (mRestrictedState.isCsEmergencyRestricted() &&
+                    !mRestrictedState.isCsNormalRestricted()) {
                 if (!newRs.isCsRestricted()) {
                     // remove all restriction
                     setNotification(CS_DISABLED);
@@ -1284,7 +1163,8 @@
                     // remove emergency restriction and enable normal restriction
                     setNotification(CS_NORMAL_ENABLED);
                 }
-            } else if (!rs.isCsEmergencyRestricted() && rs.isCsNormalRestricted()) {
+            } else if (!mRestrictedState.isCsEmergencyRestricted() &&
+                    mRestrictedState.isCsNormalRestricted()) {
                 if (!newRs.isCsRestricted()) {
                     // remove all restriction
                     setNotification(CS_DISABLED);
@@ -1308,9 +1188,9 @@
                 }
             }
 
-            rs = newRs;
+            mRestrictedState = newRs;
         }
-        Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ rs);
+        Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ mRestrictedState);
     }
 
     /** code is registration state 0-5 from TS 27.007 7.2 */
@@ -1401,12 +1281,16 @@
         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() {
-        return (networkType >= DATA_ACCESS_UMTS);
+    public boolean isConcurrentVoiceAndDataAllowed() {
+        return (networkType >= ServiceState.RADIO_TECHNOLOGY_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..e69989a 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,13 +471,18 @@
     /** 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;
         }
 
         // Length = length of MCC + length of MNC
         // length of mcc = 3 (TS 23.003 Section 2.2)
+        if (SystemProperties.getInt(com.android.internal.telephony.TelephonyProperties
+                .PROPERTY_NETWORK_LTE_ON_CDMA, 0) == 1) {
+            Log.e(LOG_TAG, "getSIMOperatorNumeric: STOPSHIP bad numeric operators in lte");
+            return SystemProperties.get("ro.cdma.home.operator.numeric", "310004");
+        }
         return imsi.substring(0, 3 + mncLength);
     }
 
@@ -547,7 +553,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 +708,7 @@
                     countVoiceMessages = -1;
                 }
 
-                ((GSMPhone) phone).notifyMessageWaitingIndicator();
+                phone.notifyMessageWaitingIndicator();
             break;
 
             case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
@@ -731,7 +737,7 @@
                         countVoiceMessages = 0;
                     }
 
-                    ((GSMPhone) phone).notifyMessageWaitingIndicator();
+                    phone.notifyMessageWaitingIndicator();
                 }
             break;
 
@@ -842,7 +848,7 @@
                     callForwardingEnabled =
                         ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
 
-                    ((GSMPhone) phone).notifyCallForwardingIndicator();
+                    phone.notifyCallForwardingIndicator();
                 }
                 break;
 
@@ -1042,7 +1048,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 +1158,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 +1184,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 +1234,7 @@
 
         recordsLoadedRegistrants.notifyRegistrants(
             new AsyncResult(null, null, null));
-        ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
+        phone.mSimCard.broadcastIccStateChangedIntent(
                 SimCard.INTENT_VALUE_ICC_LOADED, null);
     }
 
@@ -1249,11 +1255,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..781746c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -19,6 +19,9 @@
 import android.util.Log;
 
 import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.TelephonyProperties;
+import android.os.SystemProperties;
 
 /**
  * {@hide}
@@ -34,6 +37,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(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA, false)) {
+            mPhone.mCM.registerForNVReady(mHandler, EVENT_ICC_READY, null);
+        }
+    }
+
     @Override
     public void dispose() {
         //Unregister for all events