Merge change I5038c78f

* changes:
  Add missing shared libraries in linker commands.  Currently these libraries are linked implicitly via dependencies of other shared libraries.
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index b590449..dfb775f 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -74,6 +74,7 @@
     private int mNativeData;
     private BluetoothEventLoop mEventLoop;
     private boolean mIsAirplaneSensitive;
+    private boolean mIsAirplaneToggleable;
     private int mBluetoothState;
     private boolean mRestart = false;  // need to call enable() after disable()
     private boolean mIsDiscovering;
@@ -370,7 +371,7 @@
                                                 "Need BLUETOOTH_ADMIN permission");
 
         // Airplane mode can prevent Bluetooth radio from being turned on.
-        if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
             return false;
         }
         if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
@@ -545,7 +546,7 @@
                 mEventLoop.onPropertyChanged(propVal);
             }
 
-            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
                 disable(false);
             }
 
@@ -1597,10 +1598,17 @@
     };
 
     private void registerForAirplaneMode(IntentFilter filter) {
-        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
+        final ContentResolver resolver = mContext.getContentResolver();
+        final String airplaneModeRadios = Settings.System.getString(resolver,
                 Settings.System.AIRPLANE_MODE_RADIOS);
-        mIsAirplaneSensitive = airplaneModeRadios == null
-                ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+        final String toggleableRadios = Settings.System.getString(resolver,
+                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+
+        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
+                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+        mIsAirplaneToggleable = toggleableRadios == null ? false :
+                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
+
         if (mIsAirplaneSensitive) {
             filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         }
@@ -1661,6 +1669,7 @@
         }
 
         pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
+        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
 
         pw.println("Local address = " + getAddress());
         pw.println("Local name = " + getName());
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 7809fed..99d5520 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -16,43 +16,137 @@
 
 package com.android.internal.telephony;
 
+import com.android.internal.telephony.gsm.ApnSetting;
+
+import com.android.internal.util.HierarchicalState;
+import com.android.internal.util.HierarchicalStateMachine;
+
 import android.os.AsyncResult;
-import android.os.Handler;
 import android.os.Message;
-import android.util.Log;
+import android.os.SystemProperties;
+import android.util.EventLog;
 
 /**
  * {@hide}
+ *
+ * DataConnection HierarchicalStateMachine.
+ *
+ * This is an abstract base class for representing a single data connection.
+ * Instances of this class such as <code>CdmaDataConnection</code> and
+ * <code>GsmDataConnection</code>, * represent a connection via the cellular network.
+ * There may be multiple data connections and all of them are managed by the
+ * <code>DataConnectionTracker</code>.
+ *
+ * Instances are asynchronous state machines and have two primary entry points
+ * <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned
+ * hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult
+ * object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful
+ * with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>.
+ * If an error <code>AsyncResult.result = FailCause</code> and
+ * <code>AsyncResult.exception = new Exception()</code>.
+ *
+ * The other public methods are provided for debugging.
+ *
+ * Below is the state machine description for this class.
+ *
+ * DataConnection {
+ *   + mDefaultState {
+ *        EVENT_RESET { clearSettings, >mInactiveState }.
+ *        EVENT_CONNECT {  notifyConnectCompleted(FailCause.UNKNOWN) }.
+ *        EVENT_DISCONNECT { notifyDisconnectCompleted }.
+ *
+ *        // Ignored messages
+ *        EVENT_SETUP_DATA_CONNECTION_DONE,
+ *        EVENT_GET_LAST_FAIL_DONE,
+ *        EVENT_DEACTIVATE_DONE.
+ *     }
+ *   ++ # mInactiveState {
+ *            EVENT_RESET.
+ *            EVENT_CONNECT {startConnecting, >mActivatingState }.
+ *        }
+ *   ++   mActivatingState {
+ *            EVENT_DISCONNECT { %EVENT_DISCONNECT }.
+ *            EVENT_SETUP_DATA_CONNECTION_DONE {
+ *                  if (SUCCESS) { notifyConnectCompleted(FailCause.NONE), >mActiveState }.
+ *                  if (ERR_BadCommand) {
+ *                         notifyConnectCompleted(FailCause.UNKNOWN), >mInactiveState }.
+ *                  if (ERR_BadDns) { tearDownData($DEACTIVATE_DONE), >mDisconnectingBadDnsState }.
+ *                  if (ERR_Other) { getLastDataCallFailCause($EVENT_GET_LAST_FAIL_DONE) }.
+ *                  if (ERR_Stale) {}.
+ *            }
+ *            EVENT_GET_LAST_FAIL_DONE { notifyConnectCompleted(result), >mInactive }.
+ *        }
+ *   ++   mActiveState {
+ *            EVENT_DISCONNECT { tearDownData($EVENT_DEACTIVATE_DONE), >mDisconnecting }.
+ *        }
+ *   ++   mDisconnectingState {
+ *            EVENT_DEACTIVATE_DONE { notifyDisconnectCompleted, >mInactiveState }.
+ *        }
+ *   ++   mDisconnectingBadDnsState {
+ *            EVENT_DEACTIVATE_DONE { notifyConnectComplete(FailCause.UNKNOWN), >mInactiveState }.
+ *        }
+ *  }
  */
-public abstract class DataConnection extends Handler {
+public abstract class DataConnection extends HierarchicalStateMachine {
+    protected static final boolean DBG = true;
 
-    // the inherited class
+    protected static Object mCountLock = new Object();
+    protected static int mCount;
 
-    public enum State {
-        ACTIVE, /* has active data connection */
-        ACTIVATING, /* during connecting process */
-        INACTIVE; /* has empty data connection */
+    /**
+     * Class returned by onSetupConnectionCompleted.
+     */
+    protected enum SetupResult {
+        ERR_BadCommand,
+        ERR_BadDns,
+        ERR_Other,
+        ERR_Stale,
+        SUCCESS;
 
+        public FailCause mFailCause;
+
+        @Override
         public String toString() {
             switch (this) {
-            case ACTIVE:
-                return "active";
-            case ACTIVATING:
-                return "setting up";
-            default:
-                return "inactive";
+                case ERR_BadCommand: return "Bad Command";
+                case ERR_BadDns: return "Bad DNS";
+                case ERR_Other: return "Other error";
+                case ERR_Stale: return "Stale command";
+                case SUCCESS: return "SUCCESS";
+                default: return "unknown";
             }
         }
-
-        public boolean isActive() {
-            return this == ACTIVE;
-        }
-
-        public boolean isInactive() {
-            return this == INACTIVE;
-        }
     }
 
+    /**
+     * Used internally for saving connecting parameters.
+     */
+    protected static class ConnectionParams {
+        public ConnectionParams(ApnSetting apn, Message onCompletedMsg) {
+            this.apn = apn;
+            this.onCompletedMsg = onCompletedMsg;
+        }
+
+        public int tag;
+        public ApnSetting apn;
+        public Message onCompletedMsg;
+    }
+
+    /**
+     * Used internally for saving disconnecting parameters.
+     */
+    protected static class DisconnectParams {
+        public DisconnectParams(Message onCompletedMsg) {
+            this.onCompletedMsg = onCompletedMsg;
+        }
+
+        public int tag;
+        public Message onCompletedMsg;
+    }
+
+    /**
+     * Returned as the reason for a connection failure.
+     */
     public enum FailCause {
         NONE,
         OPERATOR_BARRED,
@@ -71,8 +165,7 @@
         GPRS_REGISTRATION_FAIL,
         UNKNOWN,
 
-        RADIO_NOT_AVAILABLE,
-        RADIO_ERROR_RETRY;
+        RADIO_NOT_AVAILABLE;
 
         public boolean isPermanentFail() {
             return (this == OPERATOR_BARRED) || (this == MISSING_UKNOWN_APN) ||
@@ -128,117 +221,139 @@
                 return "Data Network Registration Failure";
             case RADIO_NOT_AVAILABLE:
                 return "Radio Not Available";
-            case RADIO_ERROR_RETRY:
-                return "Transient Radio Rrror";
             default:
                 return "Unknown Data Error";
             }
         }
     }
 
-    // ***** Event codes
-    protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1;
-    protected static final int EVENT_GET_LAST_FAIL_DONE = 2;
-    protected static final int EVENT_LINK_STATE_CHANGED = 3;
-    protected static final int EVENT_DEACTIVATE_DONE = 4;
-    protected static final int EVENT_FORCE_RETRY = 5;
+    // ***** Event codes for driving the state machine
+    protected static final int EVENT_RESET = 1;
+    protected static final int EVENT_CONNECT = 2;
+    protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 3;
+    protected static final int EVENT_GET_LAST_FAIL_DONE = 4;
+    protected static final int EVENT_DEACTIVATE_DONE = 5;
+    protected static final int EVENT_DISCONNECT = 6;
 
     //***** Tag IDs for EventLog
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
 
-
     //***** Member Variables
+    protected int mTag;
     protected PhoneBase phone;
-    protected Message onConnectCompleted;
-    protected Message onDisconnect;
     protected int cid;
     protected String interfaceName;
     protected String ipAddress;
     protected String gatewayAddress;
     protected String[] dnsServers;
-    protected State state;
     protected long createTime;
     protected long lastFailTime;
     protected FailCause lastFailCause;
     protected static final String NULL_IP = "0.0.0.0";
     Object userData;
 
-    // receivedDisconnectReq is set when disconnect during activation
-    protected boolean receivedDisconnectReq;
+    //***** Abstract methods
+    public abstract String toString();
 
-    /* Instance Methods */
-    protected abstract void onSetupConnectionCompleted(AsyncResult ar);
-
-    protected abstract void onDeactivated(AsyncResult ar);
-
-    protected abstract void disconnect(Message msg);
-
-    protected abstract void notifyFail(FailCause cause, Message onCompleted);
-
-    protected abstract void notifyDisconnect(Message msg);
-
-    protected abstract void onLinkStateChanged(DataLink.LinkState linkState);
+    protected abstract void onConnect(ConnectionParams cp);
 
     protected abstract FailCause getFailCauseFromRequest(int rilCause);
 
-    public abstract String toString();
+    protected abstract boolean isDnsOk(String[] domainNameServers);
 
     protected abstract void log(String s);
 
 
    //***** Constructor
-    protected DataConnection(PhoneBase phone) {
-        super();
+    protected DataConnection(PhoneBase phone, String name) {
+        super(name);
+        if (DBG) log("DataConnection constructor E");
         this.phone = phone;
-        onConnectCompleted = null;
-        onDisconnect = null;
         this.cid = -1;
-        receivedDisconnectReq = false;
         this.dnsServers = new String[2];
 
         clearSettings();
+
+        setDbg(true);
+        addState(mDefaultState);
+            addState(mInactiveState, mDefaultState);
+            addState(mActivatingState, mDefaultState);
+            addState(mActiveState, mDefaultState);
+            addState(mDisconnectingState, mDefaultState);
+            addState(mDisconnectingBadDnsState, mDefaultState);
+        setInitialState(mInactiveState);
+        if (DBG) log("DataConnection constructor X");
+    }
+
+    /**
+     * TearDown the data connection.
+     *
+     * @param o will be returned in AsyncResult.userObj
+     *          and is either a DisconnectParams or ConnectionParams.
+     */
+    private void tearDownData(Object o) {
+        if (phone.mCM.getRadioState().isOn()) {
+            if (DBG) log("tearDownData radio is on, call deactivateDataCall");
+            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, o));
+        } else {
+            if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
+            sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, o));
+        }
+    }
+
+    /**
+     * Send the connectionCompletedMsg.
+     *
+     * @param cp is the ConnectionParams
+     * @param cause
+     */
+    private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {
+        Message connectionCompletedMsg = cp.onCompletedMsg;
+        if (connectionCompletedMsg == null) {
+            return;
+        }
+
+        long timeStamp = System.currentTimeMillis();
+        connectionCompletedMsg.arg1 = cid;
+
+        if (cause == FailCause.NONE) {
+            createTime = timeStamp;
+            AsyncResult.forMessage(connectionCompletedMsg);
+        } else {
+            lastFailCause = cause;
+            lastFailTime = timeStamp;
+            AsyncResult.forMessage(connectionCompletedMsg, cause, new Exception());
+        }
+        if (DBG) log("notifyConnection at " + timeStamp + " cause=" + cause);
+
+        connectionCompletedMsg.sendToTarget();
+    }
+
+    /**
+     * Send ar.userObj if its a message, which is should be back to originator.
+     *
+     * @param dp is the DisconnectParams.
+     */
+    private void notifyDisconnectCompleted(DisconnectParams dp) {
+        if (DBG) log("NotifyDisconnectCompleted");
+
+        Message msg = dp.onCompletedMsg;
+        AsyncResult.forMessage(msg);
+        msg.sendToTarget();
+
+        clearSettings();
     }
 
-    protected void setHttpProxy(String httpProxy, String httpPort) {
-        if (httpProxy == null || httpProxy.length() == 0) {
-            phone.setSystemProperty("net.gprs.http-proxy", null);
-            return;
-        }
+    /**
+     * Clear all settings called when entering mInactiveState.
+     */
+    protected void clearSettings() {
+        if (DBG) log("clearSettings");
 
-        if (httpPort == null || httpPort.length() == 0) {
-            httpPort = "8080";     // Default to port 8080
-        }
-
-        phone.setSystemProperty("net.gprs.http-proxy",
-                "http://" + httpProxy + ":" + httpPort + "/");
-    }
-
-    public String getInterface() {
-        return interfaceName;
-    }
-
-    public String getIpAddress() {
-        return ipAddress;
-    }
-
-    public String getGatewayAddress() {
-        return gatewayAddress;
-    }
-
-    public String[] getDnsServers() {
-        return dnsServers;
-    }
-
-    public void clearSettings() {
-        log("DataConnection.clearSettings()");
-
-        this.state = State.INACTIVE;
         this.createTime = -1;
         this.lastFailTime = -1;
         this.lastFailCause = FailCause.NONE;
 
-        receivedDisconnectReq = false;
-        onConnectCompleted = null;
         interfaceName = null;
         ipAddress = null;
         gatewayAddress = null;
@@ -246,80 +361,433 @@
         dnsServers[1] = null;
     }
 
-    protected void onGetLastFailCompleted(AsyncResult ar) {
-        if (receivedDisconnectReq) {
-            // Don't bother reporting the error if there's already a
-            // pending disconnect request, since DataConnectionTracker
-            // has already updated its state.
-            notifyDisconnect(onDisconnect);
-        } else {
-            FailCause cause = FailCause.UNKNOWN;
+    /**
+     * Process setup completion.
+     *
+     * @param ar is the result
+     * @return SetupResult.
+     */
+    private SetupResult onSetupConnectionCompleted(AsyncResult ar) {
+        SetupResult result;
+        String[] response = ((String[]) ar.result);
+        ConnectionParams cp = (ConnectionParams) ar.userObj;
 
-            if (ar.exception == null) {
-                int rilFailCause = ((int[]) (ar.result))[0];
-                cause = getFailCauseFromRequest(rilFailCause);
+        if (ar.exception != null) {
+            if (DBG) log("DataConnection Init failed " + ar.exception);
+
+            if (ar.exception instanceof CommandException
+                    && ((CommandException) (ar.exception)).getCommandError()
+                    == CommandException.Error.RADIO_NOT_AVAILABLE) {
+                result = SetupResult.ERR_BadCommand;
+                result.mFailCause = FailCause.RADIO_NOT_AVAILABLE;
+            } else {
+                result = SetupResult.ERR_Other;
             }
-            notifyFail(cause, onConnectCompleted);
-        }
-    }
-
-    protected void onForceRetry() {
-        if (receivedDisconnectReq) {
-            notifyDisconnect(onDisconnect);
+        } else if (cp.tag != mTag) {
+            if (DBG) {
+                log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag);
+            }
+            result = SetupResult.ERR_Stale;
         } else {
-            notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted);
+            cid = Integer.parseInt(response[0]);
+            if (response.length > 2) {
+                interfaceName = response[1];
+                ipAddress = response[2];
+                String prefix = "net." + interfaceName + ".";
+                gatewayAddress = SystemProperties.get(prefix + "gw");
+                dnsServers[0] = SystemProperties.get(prefix + "dns1");
+                dnsServers[1] = SystemProperties.get(prefix + "dns2");
+                if (DBG) {
+                    log("interface=" + interfaceName + " ipAddress=" + ipAddress
+                        + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
+                        + " DNS2=" + dnsServers[1]);
+                }
+
+                if (isDnsOk(dnsServers)) {
+                    result = SetupResult.SUCCESS;
+                } else {
+                    result = SetupResult.ERR_BadDns;
+                }
+            } else {
+                result = SetupResult.ERR_Other;
+            }
+        }
+
+        if (DBG) log("DataConnection setup result=" + result + " on cid = " + cid);
+        return result;
+    }
+
+    /**
+     * The parent state for all other states.
+     */
+    private class DcDefaultState extends HierarchicalState {
+        @Override
+        protected boolean processMessage(Message msg) {
+            AsyncResult ar;
+
+            switch (msg.what) {
+                case EVENT_RESET:
+                    if (DBG) log("DcDefaultState: msg.what=EVENT_RESET");
+                    clearSettings();
+                    transitionTo(mInactiveState);
+                    break;
+
+                case EVENT_CONNECT:
+                    if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
+                    ConnectionParams cp = (ConnectionParams) msg.obj;
+                    notifyConnectCompleted(cp, FailCause.UNKNOWN);
+                    break;
+
+                case EVENT_DISCONNECT:
+                    if (DBG) log("DcDefaultState: msg.what=EVENT_DISCONNECT");
+                    notifyDisconnectCompleted((DisconnectParams) msg.obj);
+                    break;
+
+                default:
+                    if (DBG) {
+                        log("DcDefaultState: shouldn't happen but ignore msg.what=" + msg.what);
+                    }
+                    break;
+            }
+
+            return true;
         }
     }
+    private DcDefaultState mDefaultState = new DcDefaultState();
 
-    @Override
-    public void handleMessage(Message msg) {
-        AsyncResult ar;
+    /**
+     * The state machine is inactive and expects a EVENT_CONNECT.
+     */
+    private class DcInactiveState extends HierarchicalState {
+        @Override protected void enter() {
+            mTag += 1;
+        }
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
 
-        log("DataConnection.handleMessage()");
+            switch (msg.what) {
+                case EVENT_RESET:
+                    if (DBG) {
+                        log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset");
+                    }
+                    retVal = true;
+                    break;
 
-        switch (msg.what) {
+                case EVENT_CONNECT:
+                    if (DBG) log("DcInactiveState msg.what=EVENT_CONNECT");
+                    ConnectionParams cp = (ConnectionParams) msg.obj;
+                    cp.tag = mTag;
+                    onConnect(cp);
+                    transitionTo(mActivatingState);
+                    retVal = true;
+                    break;
 
-        case EVENT_SETUP_DATA_CONNECTION_DONE:
-            onSetupConnectionCompleted((AsyncResult) msg.obj);
-            break;
-
-        case EVENT_FORCE_RETRY:
-            onForceRetry();
-            break;
-
-        case EVENT_GET_LAST_FAIL_DONE:
-            onGetLastFailCompleted((AsyncResult) msg.obj);
-            break;
-
-        case EVENT_LINK_STATE_CHANGED:
-            ar = (AsyncResult) msg.obj;
-            DataLink.LinkState ls  = (DataLink.LinkState) ar.result;
-            onLinkStateChanged(ls);
-            break;
-
-        case EVENT_DEACTIVATE_DONE:
-            onDeactivated((AsyncResult) msg.obj);
-            break;
+                default:
+                    if (DBG) log("DcInactiveState nothandled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
         }
     }
+    private DcInactiveState mInactiveState = new DcInactiveState();
 
-    public State getState() {
-        log("DataConnection.getState()");
-        return state;
+    /**
+     * The state machine is activating a connection.
+     */
+    private class DcActivatingState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+            AsyncResult ar;
+            ConnectionParams cp;
+
+            switch (msg.what) {
+                case EVENT_DISCONNECT:
+                    if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
+                    deferMessage(msg);
+                    retVal = true;
+                    break;
+
+                case EVENT_SETUP_DATA_CONNECTION_DONE:
+                    if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");
+
+                    ar = (AsyncResult) msg.obj;
+                    cp = (ConnectionParams) ar.userObj;
+
+                    SetupResult result = onSetupConnectionCompleted(ar);
+                    switch (result) {
+                        case SUCCESS:
+                            // All is well
+                            notifyConnectCompleted(cp, FailCause.NONE);
+                            transitionTo(mActiveState);
+                            break;
+                        case ERR_BadCommand:
+                            // Vendor ril rejected the command and didn't connect.
+                            notifyConnectCompleted(cp, result.mFailCause);
+                            transitionTo(mInactiveState);
+                            break;
+                        case ERR_BadDns:
+                            // Connection succeeded but DNS info is bad so disconnect
+                            EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
+                                    dnsServers[0]);
+                            tearDownData(cp);
+                            transitionTo(mDisconnectingBadDnsState);
+                            break;
+                        case ERR_Other:
+                            // Request the failure cause and process in this state
+                            phone.mCM.getLastDataCallFailCause(
+                                    obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
+                            break;
+                        case ERR_Stale:
+                            // Request is stale, ignore.
+                            break;
+                        default:
+                            throw new RuntimeException("Unkown SetupResult, should not happen");
+                    }
+                    retVal = true;
+                    break;
+
+                case EVENT_GET_LAST_FAIL_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    cp = (ConnectionParams) ar.userObj;
+                    FailCause cause = FailCause.UNKNOWN;
+
+                    if (cp.tag == mTag) {
+                        if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE");
+                        if (ar.exception == null) {
+                            int rilFailCause = ((int[]) (ar.result))[0];
+                            cause = getFailCauseFromRequest(rilFailCause);
+                        }
+                         notifyConnectCompleted(cp, cause);
+                         transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) {
+                            log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="
+                                + cp.tag + ", mTag=" + mTag);
+                        }
+                    }
+
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcActivatingState not handled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcActivatingState mActivatingState = new DcActivatingState();
+
+    /**
+     * The state machine is connected, expecting an EVENT_DISCONNECT.
+     */
+    private class DcActiveState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_DISCONNECT:
+                    if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT");
+                    DisconnectParams dp = (DisconnectParams) msg.obj;
+                    dp.tag = mTag;
+                    tearDownData(dp);
+                    transitionTo(mDisconnectingState);
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcActiveState nothandled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcActiveState mActiveState = new DcActiveState();
+
+    /**
+     * The state machine is disconnecting.
+     */
+    private class DcDisconnectingState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_DEACTIVATE_DONE:
+                    if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE");
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    DisconnectParams dp = (DisconnectParams) ar.userObj;
+                    if (dp.tag == mTag) {
+                        notifyDisconnectCompleted((DisconnectParams) ar.userObj);
+                        transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
+                                + dp.tag + " mTag=" + mTag);
+                    }
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcDisconnectingState not handled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
+
+    /**
+     * The state machine is disconnecting after a bad dns setup
+     * was found in mInactivatingState.
+     */
+    private class DcDisconnectingBadDnsState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_DEACTIVATE_DONE:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    ConnectionParams cp = (ConnectionParams) ar.userObj;
+                    if (cp.tag == mTag) {
+                        if (DBG) log("DcDisconnectingBadDnsState msg.what=EVENT_DEACTIVATE_DONE");
+                        notifyConnectCompleted(cp, FailCause.UNKNOWN);
+                        transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) log("DcDisconnectingBadDnsState EVENT_DEACTIVE_DONE stale dp.tag="
+                                + cp.tag + ", mTag=" + mTag);
+                    }
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcDisconnectingBadDnsState not handled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcDisconnectingBadDnsState mDisconnectingBadDnsState = new DcDisconnectingBadDnsState();
+
+    // ******* public interface
+
+    /**
+     * Disconnect from the network.
+     */
+    public void reset() {
+        sendMessage(obtainMessage(EVENT_RESET));
     }
 
+    /**
+     * Connect to the apn and return an AsyncResult in onCompletedMsg.
+     * Used for cellular networks that use Acess Point Names (APN) such
+     * as GSM networks.
+     *
+     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+     *        With AsyncResult.userObj set to the original msg.obj,
+     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
+     * @param apn is the Acces Point Name to connect to
+     */
+    public void connect(Message onCompletedMsg, ApnSetting apn) {
+        sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
+    }
+
+    /**
+     * Connect to the apn and return an AsyncResult in onCompletedMsg.
+     *
+     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+     *        With AsyncResult.userObj set to the original msg.obj,
+     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
+     */
+    public void connect(Message onCompletedMsg) {
+        sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(null, onCompletedMsg)));
+    }
+
+    /**
+     * Disconnect from the network.
+     *
+     * @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)));
+    }
+
+    // ****** The following are used for debugging.
+
+    /**
+     * @return true if the state machine is in the inactive state.
+     */
+    public boolean isInactive() {
+        boolean retVal = getCurrentState() == mInactiveState;
+        return retVal;
+    }
+
+    /**
+     * @return true if the state machine is in the inactive state.
+     */
+    public boolean isActive() {
+        boolean retVal = getCurrentState() == mActiveState;
+        return retVal;
+    }
+
+    /**
+     * @return the interface name as a string.
+     */
+    public String getInterface() {
+        return interfaceName;
+    }
+
+    /**
+     * @return the ip address as a string.
+     */
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    /**
+     * @return the gateway address as a string.
+     */
+    public String getGatewayAddress() {
+        return gatewayAddress;
+    }
+
+    /**
+     * @return an array of associated DNS addresses.
+     */
+    public String[] getDnsServers() {
+        return dnsServers;
+    }
+
+    /**
+     * @return the current state as a string.
+     */
+    public String getStateAsString() {
+        String retVal = getCurrentState().getName();
+        return retVal;
+    }
+
+    /**
+     * @return the time of when this connection was created.
+     */
     public long getConnectionTime() {
-        log("DataConnection.getConnectionTime()");
         return createTime;
     }
 
+    /**
+     * @return the time of the last failure.
+     */
     public long getLastFailTime() {
-        log("DataConnection.getLastFailTime()");
         return lastFailTime;
     }
 
+    /**
+     * @return the last cause of failure.
+     */
     public FailCause getLastFailCause() {
-        log("DataConnection.getLastFailCause()");
         return lastFailCause;
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataLink.java b/telephony/java/com/android/internal/telephony/DataLink.java
deleted file mode 100644
index 8132d91..0000000
--- a/telephony/java/com/android/internal/telephony/DataLink.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.os.Handler;
-import android.os.Registrant;
-
-/**
- * Base class representing the data link layer (eg, PPP).
- *
- * {@hide}
- */
-public abstract class DataLink extends Handler implements DataLinkInterface {
-
-    /** Registrant for link status change notifications. */
-    protected Registrant mLinkChangeRegistrant;
-    protected DataConnectionTracker dataConnection;
-
-    protected DataLink(DataConnectionTracker dc) {
-        dataConnection = dc;
-    }
-
-    public void setOnLinkChange(Handler h, int what, Object obj) {
-        mLinkChangeRegistrant = new Registrant(h, what, obj);
-    }
-}
diff --git a/telephony/java/com/android/internal/telephony/DataLinkInterface.java b/telephony/java/com/android/internal/telephony/DataLinkInterface.java
deleted file mode 100644
index e8148a8..0000000
--- a/telephony/java/com/android/internal/telephony/DataLinkInterface.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.database.Cursor;
-import android.os.Handler;
-
-/**
- * Data link interface.
- *
- * {@hide}
- */
-public interface DataLinkInterface {
-    /**
-     * Link state enumeration.
-     *
-     */
-    enum LinkState {
-        LINK_UNKNOWN,
-        LINK_UP,
-        LINK_DOWN,
-        LINK_EXITED
-    }
-
-    /** Normal exit */
-    final static int EXIT_OK = 0;
-    /** Open failed */
-    final static int EXIT_OPEN_FAILED = 7;
-
-    /**
-     * Sets the handler for link state change events.
-     *
-     * @param h Handler
-     * @param what User-defined message code
-     * @param obj User object
-     */
-    void setOnLinkChange(Handler h, int what, Object obj);
-
-    /**
-     * Sets up the data link.
-     */
-    void connect();
-
-    /**
-     * Tears down the data link.
-     */
-    void disconnect();
-
-    /**
-     * Returns the exit code for a data link failure.
-     *
-     * @return exit code
-     */
-    int getLastLinkExitCode();
-
-    /**
-     * Sets password information that may be required by the data link
-     * (eg, PAP secrets).
-     *
-     * @param cursor cursor to carriers table
-     */
-    void setPasswordInfo(Cursor cursor);
-}
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index c113581..a8ad80e 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -28,7 +28,7 @@
 
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.gsm.NetworkInfo;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -1176,21 +1176,7 @@
     void invokeOemRilRequestStrings(String[] strings, Message response);
 
     /**
-     * Get the current active PDP context list
-     *
-     * @deprecated
-     * @param response <strong>On success</strong>, "response" bytes is
-     * made available as:
-     * (String[])(((AsyncResult)response.obj).result).
-     * <strong>On failure</strong>,
-     * (((AsyncResult)response.obj).result) == null and
-     * (((AsyncResult)response.obj).exception) being an instance of
-     * com.android.internal.telephony.gsm.CommandException
-     */
-    void getPdpContextList(Message response);
-
-    /**
-     * Get the current active Data Call list, substitutes getPdpContextList
+     * Get the current active Data Call list
      *
      * @param response <strong>On success</strong>, "response" bytes is
      * made available as:
@@ -1203,19 +1189,11 @@
     void getDataCallList(Message response);
 
     /**
-     * Get current mutiple PDP link status
-     *
-     * @deprecated
-     * @return list of pdp link connections
-     */
-    List<PdpConnection> getCurrentPdpList ();
-
-    /**
      * Get current mutiple data connection status
      *
      * @return list of data connections
      */
-    List<DataConnection> getCurrentDataConnectionList ();
+    List<DataConnection> getCurrentDataConnectionList();
 
     /**
      * Update the ServiceState CellLocation for current network registration.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 50dd76a..bad9ab3 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -35,7 +35,7 @@
 import android.util.Log;
 
 import com.android.internal.R;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -692,16 +692,6 @@
         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
     }
 
-    /**
-     * This should only be called in GSM mode.
-     * Only here for some backward compatibility
-     * issues concerning the GSMPhone class.
-     * @deprecated Always returns null.
-     */
-    public List<PdpConnection> getCurrentPdpList() {
-        return null;
-    }
-
     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 3eadd81..d56d99f 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -34,7 +34,7 @@
 import com.android.internal.telephony.cdma.CDMAPhone;
 import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.gsm.NetworkInfo;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -564,24 +564,10 @@
         mActivePhone.invokeOemRilRequestStrings(strings, response);
     }
 
-    /**
-     * @deprecated
-     */
-    public void getPdpContextList(Message response) {
-        mActivePhone.getPdpContextList(response);
-    }
-
     public void getDataCallList(Message response) {
         mActivePhone.getDataCallList(response);
     }
 
-    /**
-     * @deprecated
-     */
-    public List<PdpConnection> getCurrentPdpList() {
-        return mActivePhone.getCurrentPdpList();
-    }
-
     public List<DataConnection> getCurrentDataConnectionList() {
         return mActivePhone.getCurrentDataConnectionList();
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 75e8b65..d4b1652 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -657,13 +657,6 @@
         mSST.disableLocationUpdates();
     }
 
-    /**
-     * @deprecated
-     */
-    public void getPdpContextList(Message response) {
-        getDataCallList(response);
-    }
-
     public void getDataCallList(Message response) {
         mCM.getDataCallList(response);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 4588f36..6c20204 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -16,221 +16,77 @@
 
 package com.android.internal.telephony.cdma;
 
-import android.os.*;
-import android.util.EventLog;
+import android.os.Message;
 import android.util.Log;
 
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataConnection;
-import com.android.internal.telephony.DataLink;
 import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.TelephonyEventLog;
 
 /**
  * {@hide}
- *
  */
 public class CdmaDataConnection extends DataConnection {
 
     private static final String LOG_TAG = "CDMA";
-    private static final boolean DBG = true;
 
     /** Fail cause of last Data Call activate from RIL_LastDataCallActivateFailCause */
     private final static int PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING         = 8;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_APN                         = 27;
     private final static int PS_NET_DOWN_REASON_AUTH_FAILED                         = 29;
     private final static int PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED                = 32;
     private final static int PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED                 = 33;
 
-/** It is likely that the number of error codes listed below will be removed
- * in the foreseeable future.  They have been added, but not agreed upon.
- *
- */
-    private final static int PS_NET_DOWN_REASON_NOT_SPECIFIED                       = 0;
-    private final static int PS_NET_DOWN_REASON_CLOSE_IN_PROGRESS                   = 1;
-    private final static int PS_NET_DOWN_REASON_NW_INITIATED_TERMINATION            = 2;
-    private final static int PS_NET_DOWN_REASON_APP_PREEMPTED                       = 3;
-    private final static int PS_NET_DOWN_REASON_LLC_SNDCP_FAILURE                   = 25;
-    private final static int PS_NET_DOWN_REASON_INSUFFICIENT_RESOURCES              = 26;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP                         = 28;
-    private final static int PS_NET_DOWN_REASON_GGSN_REJECT                         = 30;
-    private final static int PS_NET_DOWN_REASON_ACTIVATION_REJECT                   = 31;
-    private final static int PS_NET_DOWN_REASON_OPTION_TEMP_OOO                     = 34;
-    private final static int PS_NET_DOWN_REASON_NSAPI_ALREADY_USED                  = 35;
-    private final static int PS_NET_DOWN_REASON_REGULAR_DEACTIVATION                = 36;
-    private final static int PS_NET_DOWN_REASON_QOS_NOT_ACCEPTED                    = 37;
-    private final static int PS_NET_DOWN_REASON_NETWORK_FAILURE                     = 38;
-    private final static int PS_NET_DOWN_REASON_UMTS_REATTACH_REQ                   = 39;
-    private final static int PS_NET_DOWN_REASON_TFT_SEMANTIC_ERROR                  = 41;
-    private final static int PS_NET_DOWN_REASON_TFT_SYNTAX_ERROR                    = 42;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP_CONTEXT                 = 43;
-    private final static int PS_NET_DOWN_REASON_FILTER_SEMANTIC_ERROR               = 44;
-    private final static int PS_NET_DOWN_REASON_FILTER_SYNTAX_ERROR                 = 45;
-    private final static int PS_NET_DOWN_REASON_PDP_WITHOUT_ACTIVE_TFT              = 46;
-    private final static int PS_NET_DOWN_REASON_INVALID_TRANSACTION_ID              = 81;
-    private final static int PS_NET_DOWN_REASON_MESSAGE_INCORRECT_SEMANTIC          = 95;
-    private final static int PS_NET_DOWN_REASON_INVALID_MANDATORY_INFO              = 96;
-    private final static int PS_NET_DOWN_REASON_MESSAGE_TYPE_UNSUPPORTED            = 97;
-    private final static int PS_NET_DOWN_REASON_MSG_TYPE_NONCOMPATIBLE_STATE        = 98;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_INFO_ELEMENT                = 99;
-    private final static int PS_NET_DOWN_REASON_CONDITIONAL_IE_ERROR                = 100;
-    private final static int PS_NET_DOWN_REASON_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101;
-    private final static int PS_NET_DOWN_REASON_PROTOCOL_ERROR                      = 111;
-    private final static int PS_NET_DOWN_REASON_APN_TYPE_CONFLICT                   = 112;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_CAUSE_CODE                  = 113;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_MIN                        = 200;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_ERROR                      = 201;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_CALL_ENDED                 = 202;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_UNKNOWN_CAUSE_CODE         = 203;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_MAX                        = 204;
-    private final static int PS_NET_DOWN_REASON_CDMA_LOCK                           = 500;
-    private final static int PS_NET_DOWN_REASON_INTERCEPT                           = 501;
-    private final static int PS_NET_DOWN_REASON_REORDER                             = 502;
-    private final static int PS_NET_DOWN_REASON_REL_SO_REJ                          = 503;
-    private final static int PS_NET_DOWN_REASON_INCOM_CALL                          = 504;
-    private final static int PS_NET_DOWN_REASON_ALERT_STOP                          = 505;
-    private final static int PS_NET_DOWN_REASON_ACTIVATION                          = 506;
-    private final static int PS_NET_DOWN_REASON_MAX_ACCESS_PROBE                    = 507;
-    private final static int PS_NET_DOWN_REASON_CCS_NOT_SUPPORTED_BY_BS             = 508;
-    private final static int PS_NET_DOWN_REASON_NO_RESPONSE_FROM_BS                 = 509;
-    private final static int PS_NET_DOWN_REASON_REJECTED_BY_BS                      = 510;
-    private final static int PS_NET_DOWN_REASON_INCOMPATIBLE                        = 511;
-    private final static int PS_NET_DOWN_REASON_ALREADY_IN_TC                       = 512;
-    private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_GPS           = 513;
-    private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_SMS           = 514;
-    private final static int PS_NET_DOWN_REASON_NO_CDMA_SRV                         = 515;
-    private final static int PS_NET_DOWN_REASON_CONF_FAILED                         = 1000;
-    private final static int PS_NET_DOWN_REASON_INCOM_REJ                           = 1001;
-    private final static int PS_NET_DOWN_REASON_NO_GW_SRV                           = 1002;
-    private final static int PS_NET_DOWN_REASON_CD_GEN_OR_BUSY                      = 1500;
-    private final static int PS_NET_DOWN_REASON_CD_BILL_OR_AUTH                     = 1501;
-    private final static int PS_NET_DOWN_REASON_CHG_HDR                             = 1502;
-    private final static int PS_NET_DOWN_REASON_EXIT_HDR                            = 1503;
-    private final static int PS_NET_DOWN_REASON_HDR_NO_SESSION                      = 1504;
-    private final static int PS_NET_DOWN_REASON_HDR_ORIG_DURING_GPS_FIX             = 1505;
-    private final static int PS_NET_DOWN_REASON_HDR_CS_TIMEOUT                      = 1506;
-    private final static int PS_NET_DOWN_REASON_HDR_RELEASED_BY_CM                  = 1507;
-    private final static int PS_NET_DOWN_REASON_CLIENT_END                          = 2000;
-    private final static int PS_NET_DOWN_REASON_NO_SRV                              = 2001;
-    private final static int PS_NET_DOWN_REASON_FADE                                = 2002;
-    private final static int PS_NET_DOWN_REASON_REL_NORMAL                          = 2003;
-    private final static int PS_NET_DOWN_REASON_ACC_IN_PROG                         = 2004;
-    private final static int PS_NET_DOWN_REASON_ACC_FAIL                            = 2005;
-    private final static int PS_NET_DOWN_REASON_REDIR_OR_HANDOFF                    = 2006;
-
-    // ***** Instance Variables
 
     // ***** Constructor
-    CdmaDataConnection(CDMAPhone phone) {
-        super(phone);
-
-        if (DBG) log("CdmaDataConnection <constructor>");
+    private CdmaDataConnection(CDMAPhone phone, String name) {
+        super(phone, name);
     }
 
     /**
-     * Setup a data connection
+     * Create the connection object
      *
-     * @param onCompleted
-     *            notify success or not after down
+     * @param phone
+     * @return CdmaDataConnection that was created.
      */
-    void connect(Message onCompleted) {
+    static CdmaDataConnection makeDataConnection(CDMAPhone phone) {
+        synchronized (mCountLock) {
+            mCount += 1;
+        }
+        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount);
+        cdmaDc.start();
+        if (DBG) cdmaDc.log("Made " + cdmaDc.getName());
+        return cdmaDc;
+    }
+
+    /**
+     * Begin setting up a data connection, calls setupDataCall
+     * and the ConnectionParams will be returned with the
+     * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
+     *
+     * @param cp is the connection parameters
+     */
+    @Override
+    protected void onConnect(ConnectionParams cp) {
         if (DBG) log("CdmaDataConnection Connecting...");
 
-        state = State.ACTIVATING;
-        onConnectCompleted = onCompleted;
         createTime = -1;
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
-        receivedDisconnectReq = false;
+
+        // msg.obj will be returned in AsyncResult.userObj;
+        Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
+        msg.obj = cp;
         phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
                 Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null,
-                null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP),
-                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+                null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), msg);
     }
 
-    private void tearDownData(Message msg) {
-        if (phone.mCM.getRadioState().isOn()) {
-            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
-        }
-    }
-
-    protected void disconnect(Message msg) {
-        onDisconnect = msg;
-        if (state == State.ACTIVE) {
-            tearDownData(msg);
-        } else if (state == State.ACTIVATING) {
-            receivedDisconnectReq = true;
-        } else {
-            // state == INACTIVE.  Nothing to do, so notify immediately.
-            notifyDisconnect(msg);
-        }
-    }
-
-
+    @Override
     public String toString() {
-        return "State=" + state + " create=" + createTime + " lastFail="
-                + lastFailTime + " lastFailCause=" + lastFailCause;
+        return "State=" + getCurrentState().getName() + " create=" + createTime + " lastFail="
+                + lastFailTime + " lastFasilCause=" + lastFailCause;
     }
 
-
-    protected void notifyFail(FailCause cause, Message onCompleted) {
-        if (onCompleted == null) {
-            return;
-        }
-        state = State.INACTIVE;
-        lastFailCause = cause;
-        lastFailTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-
-        if(DBG) {
-            log("Notify data connection fail at " + lastFailTime +
-                    " due to " + lastFailCause);
-        }
-
-        AsyncResult.forMessage(onCompleted, cause, new Exception());
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifySuccess(Message onCompleted) {
-        if (onCompleted == null) {
-            return;
-        }
-
-        state = State.ACTIVE;
-        createTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-        onCompleted.arg1 = cid;
-
-        if (DBG) log("Notify data connection success at " + createTime);
-
-        AsyncResult.forMessage(onCompleted);
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifyDisconnect(Message msg) {
-        if (DBG) log("Notify data connection disconnect");
-
-        if (msg != null) {
-            AsyncResult.forMessage(msg);
-            msg.sendToTarget();
-        }
-        clearSettings();
-    }
-
-    protected void onLinkStateChanged(DataLink.LinkState linkState) {
-        switch (linkState) {
-            case LINK_UP:
-                notifySuccess(onConnectCompleted);
-                break;
-
-            case LINK_DOWN:
-            case LINK_EXITED:
-                phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
-                break;
-        }
-    }
-
+    @Override
     protected FailCause getFailCauseFromRequest(int rilCause) {
         FailCause cause;
 
@@ -253,73 +109,19 @@
         return cause;
     }
 
-    protected void log(String s) {
-        Log.d(LOG_TAG, "[CdmaDataConnection] " + s);
-    }
-
     @Override
-    protected void onDeactivated(AsyncResult ar) {
-        notifyDisconnect((Message) ar.userObj);
-        if (DBG) log("CDMA Connection Deactivated");
-    }
-
-    @Override
-    protected void onSetupConnectionCompleted(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception);
-
-            if (receivedDisconnectReq) {
-                // Don't bother reporting the error if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                notifyDisconnect(onDisconnect);
-            } else {
-                if (ar.exception instanceof CommandException
-                        && ((CommandException) (ar.exception)).getCommandError()
-                        == CommandException.Error.RADIO_NOT_AVAILABLE) {
-                    notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted);
-                } else {
-                    phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
-                }
-            }
+    protected boolean isDnsOk(String[] domainNameServers) {
+        if ((NULL_IP.equals(domainNameServers[0])
+                && NULL_IP.equals(domainNameServers[1])
+                && !((CDMAPhone) phone).isDnsCheckDisabled())) {
+            return false;
         } else {
-            if (receivedDisconnectReq) {
-                // Don't bother reporting success if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                tearDownData(onDisconnect);
-            } else {
-                String[] response = ((String[]) ar.result);
-                cid = Integer.parseInt(response[0]);
-
-                if (response.length > 2) {
-                    interfaceName = response[1];
-                    ipAddress = response[2];
-                    String prefix = "net." + interfaceName + ".";
-                    gatewayAddress = SystemProperties.get(prefix + "gw");
-                    dnsServers[0] = SystemProperties.get(prefix + "dns1");
-                    dnsServers[1] = SystemProperties.get(prefix + "dns2");
-                    if (DBG) {
-                        log("interface=" + interfaceName + " ipAddress=" + ipAddress
-                            + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
-                            + " DNS2=" + dnsServers[1]);
-                    }
-
-                    if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
-                                        && !((CDMAPhone) phone).isDnsCheckDisabled()) {
-                        // Work around a race condition where QMI does not fill in DNS:
-                        // Deactivate PDP and let DataConnectionTracker retry.
-                        EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
-                                    dnsServers[0]);
-                        phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
-                        return;
-                    }
-                }
-
-                onLinkStateChanged(DataLink.LinkState.LINK_UP);
-
-                if (DBG) log("CdmaDataConnection setup on cid = " + cid);
-            }
+            return true;
         }
     }
+
+    @Override
+    protected void log(String s) {
+        Log.d(LOG_TAG, "[" + getName() + "] " + s);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index b63b0c4..ecd3380 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -386,7 +386,7 @@
                     Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
                     conn.disconnect(msg);
                 } else {
-                    conn.clearSettings();
+                    conn.reset();
                 }
             }
         }
@@ -403,7 +403,7 @@
     private CdmaDataConnection findFreeDataConnection() {
         for (DataConnection connBase : dataConnectionList) {
             CdmaDataConnection conn = (CdmaDataConnection) connBase;
-            if (conn.getState() == DataConnection.State.INACTIVE) {
+            if (conn.isInactive()) {
                 return conn;
             }
         }
@@ -801,7 +801,7 @@
         CdmaDataConnection dataConn;
 
        for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
-            dataConn = new CdmaDataConnection(mCdmaPhone);
+            dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone);
             dataConnectionList.add(dataConn);
        }
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 33d150a..2bb7968 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1050,33 +1050,10 @@
         return mCT.getMute();
     }
 
-    /**
-     * @deprecated Do not use.
-     */
-    @Deprecated
-    public void getPdpContextList(Message response) {
-        getDataCallList(response);
-    }
-
     public void getDataCallList(Message response) {
         mCM.getDataCallList(response);
     }
 
-    /**
-     * @deprecated Do not use.
-     */
-    @Deprecated
-    public List<PdpConnection> getCurrentPdpList() {
-        ArrayList<DataConnection> connections = new ArrayList<DataConnection>();
-        ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>();
-
-        for(int n = 0; n < connections.size(); n++) {
-            pdp_list.add((PdpConnection) connections.get(n));
-        }
-
-        return pdp_list;
-    }
-
     public List<DataConnection> getCurrentDataConnectionList () {
         return mDataConnection.getAllDataConnections();
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
new file mode 100644
index 0000000..905d5e3
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -0,0 +1,226 @@
+/*
+ * 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.gsm;
+
+import android.os.Message;
+import android.util.Log;
+
+import com.android.common.Patterns;
+import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RILConstants;
+
+/**
+ * {@hide}
+ */
+public class GsmDataConnection extends DataConnection {
+
+    private static final String LOG_TAG = "GSM";
+
+    /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
+    private static final int PDP_FAIL_OPERATOR_BARRED = 0x08;
+    private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
+    private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B;
+    private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
+    private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D;
+    private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
+    private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
+    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
+    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
+    private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
+    private static final int PDP_FAIL_NSAPI_IN_USE      = 0x23;
+    private static final int PDP_FAIL_PROTOCOL_ERRORS   = 0x6F;
+    private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff;
+
+    private static final int PDP_FAIL_REGISTRATION_FAIL = -1;
+    private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2;
+
+    //***** Instance Variables
+    private ApnSetting apn;
+
+    //***** Constructor
+    private GsmDataConnection(GSMPhone phone, String name) {
+        super(phone, name);
+    }
+
+    /**
+     * Create the connection object
+     *
+     * @param phone
+     * @return GsmDataConnection that was created.
+     */
+    static GsmDataConnection makeDataConnection(GSMPhone phone) {
+        synchronized (mCountLock) {
+            mCount += 1;
+        }
+        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount);
+        gsmDc.start();
+        if (DBG) gsmDc.log("Made " + gsmDc.getName());
+        return gsmDc;
+    }
+
+    /**
+     * Begin setting up a data connection, calls setupDataCall
+     * and the ConnectionParams will be returned with the
+     * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
+     *
+     * @param cp is the connection parameters
+     */
+    @Override
+    protected
+    void onConnect(ConnectionParams cp) {
+        apn = cp.apn;
+
+        if (DBG) log("Connecting to carrier: '" + apn.carrier
+                + "' APN: '" + apn.apn
+                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+
+        setHttpProxy (apn.proxy, apn.port);
+
+        createTime = -1;
+        lastFailTime = -1;
+        lastFailCause = FailCause.NONE;
+
+        // msg.obj will be returned in AsyncResult.userObj;
+        Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
+        msg.obj = cp;
+
+        int authType = apn.authType;
+        if (authType == -1) {
+            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+                RILConstants.SETUP_DATA_AUTH_NONE;
+        }
+        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), msg);
+    }
+
+    @Override
+    protected void clearSettings() {
+        super.clearSettings();
+        apn = null;
+    }
+
+    @Override
+    public String toString() {
+        return "State=" + getCurrentState().getName() + " Apn=" + apn +
+               " create=" + createTime + " lastFail=" + lastFailTime +
+               " lastFailCause=" + lastFailCause;
+    }
+
+    @Override
+    protected FailCause getFailCauseFromRequest(int rilCause) {
+        FailCause cause;
+
+        switch (rilCause) {
+            case PDP_FAIL_OPERATOR_BARRED:
+                cause = FailCause.OPERATOR_BARRED;
+                break;
+            case PDP_FAIL_INSUFFICIENT_RESOURCES:
+                cause = FailCause.INSUFFICIENT_RESOURCES;
+                break;
+            case PDP_FAIL_MISSING_UKNOWN_APN:
+                cause = FailCause.MISSING_UKNOWN_APN;
+                break;
+            case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
+                cause = FailCause.UNKNOWN_PDP_ADDRESS;
+                break;
+            case PDP_FAIL_USER_AUTHENTICATION:
+                cause = FailCause.USER_AUTHENTICATION;
+                break;
+            case PDP_FAIL_ACTIVATION_REJECT_GGSN:
+                cause = FailCause.ACTIVATION_REJECT_GGSN;
+                break;
+            case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
+                cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED;
+                break;
+            case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
+                cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER;
+                break;
+            case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
+                cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
+                break;
+            case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
+                cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
+                break;
+            case PDP_FAIL_NSAPI_IN_USE:
+                cause = FailCause.NSAPI_IN_USE;
+                break;
+            case PDP_FAIL_PROTOCOL_ERRORS:
+                cause = FailCause.PROTOCOL_ERRORS;
+                break;
+            case PDP_FAIL_ERROR_UNSPECIFIED:
+                cause = FailCause.UNKNOWN;
+                break;
+            case PDP_FAIL_REGISTRATION_FAIL:
+                cause = FailCause.REGISTRATION_FAIL;
+                break;
+            case PDP_FAIL_GPRS_REGISTRATION_FAIL:
+                cause = FailCause.GPRS_REGISTRATION_FAIL;
+                break;
+            default:
+                cause = FailCause.UNKNOWN;
+        }
+        return cause;
+    }
+
+    @Override
+    protected boolean isDnsOk(String[] domainNameServers) {
+        if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
+                    && !((GSMPhone) phone).isDnsCheckDisabled()) {
+            // Work around a race condition where QMI does not fill in DNS:
+            // Deactivate PDP and let DataConnectionTracker retry.
+            // 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)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    protected void log(String s) {
+        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
+        }
+
+        phone.setSystemProperty("net.gprs.http-proxy",
+                "http://" + httpProxy + ":" + httpPort + "/");
+    }
+
+    private boolean isIpAddress(String address) {
+        if (address == null) return false;
+
+        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index fb7aa3d..5c97925 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -126,8 +126,8 @@
      */
     private ArrayList<DataConnection> pdpList;
 
-    /** Currently active PdpConnection */
-    private PdpConnection mActivePdp;
+    /** Currently active DataConnection */
+    private GsmDataConnection mActivePdp;
 
     /** Is packet service restricted by network */
     private boolean mIsPsRestricted = false;
@@ -137,7 +137,7 @@
     // TODO: Increase this to match the max number of simultaneous
     // PDP contexts we plan to support.
     /**
-     * Pool size of PdpConnection objects.
+     * Pool size of DataConnection objects.
      */
     private static final int PDP_CONNECTION_POOL_SIZE = 1;
 
@@ -382,7 +382,7 @@
     }
 
     /**
-     * Formerly this method was ArrayList<PdpConnection> getAllPdps()
+     * Formerly this method was ArrayList<GsmDataConnection> getAllPdps()
      */
     public ArrayList<DataConnection> getAllDataConnections() {
         ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone();
@@ -452,7 +452,7 @@
                 waitingApns = buildWaitingApns();
                 if (waitingApns.isEmpty()) {
                     if (DBG) log("No APN found");
-                    notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN);
+                    notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
                     return false;
                 } else {
                     log ("Create from allApns : " + apnListToString(allApns));
@@ -487,7 +487,7 @@
      * 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 PdpConnection should be
+     * @param tearDown true if the underlying GsmDataConnection should be
      * disconnected.
      * @param reason reason for the clean up.
      */
@@ -505,12 +505,11 @@
         setState(State.DISCONNECTING);
 
         for (DataConnection conn : pdpList) {
-            PdpConnection pdp = (PdpConnection) conn;
             if (tearDown) {
                 Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
-                pdp.disconnect(msg);
+                conn.disconnect(msg);
             } else {
-                pdp.clearSettings();
+                conn.reset();
             }
         }
         stopNetStatPoll();
@@ -564,10 +563,10 @@
         return result;
     }
 
-    private PdpConnection findFreePdp() {
+    private GsmDataConnection findFreePdp() {
         for (DataConnection conn : pdpList) {
-            PdpConnection pdp = (PdpConnection) conn;
-            if (pdp.getState() == DataConnection.State.INACTIVE) {
+            GsmDataConnection pdp = (GsmDataConnection) conn;
+            if (pdp.isInactive()) {
                 return pdp;
             }
         }
@@ -576,13 +575,13 @@
 
     private boolean setupData(String reason) {
         ApnSetting apn;
-        PdpConnection pdp;
+        GsmDataConnection pdp;
 
         apn = getNextApn();
         if (apn == null) return false;
         pdp = findFreePdp();
         if (pdp == null) {
-            if (DBG) log("setupData: No free PdpConnection found!");
+            if (DBG) log("setupData: No free GsmDataConnection found!");
             return false;
         }
         mActiveApn = apn;
@@ -591,7 +590,7 @@
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
         msg.obj = reason;
-        pdp.connect(apn, msg);
+        pdp.connect(msg, apn);
 
         setState(State.INITING);
         phone.notifyDataConnection(reason);
@@ -974,13 +973,8 @@
      * seems like it deserves an error notification.
      * Transient errors are ignored
      */
-    private boolean shouldPostNotification(PdpConnection.FailCause  cause) {
-        boolean shouldPost = true;
-        // TODO CHECK
-        // if (dataLink != null) {
-        //    shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED;
-        //}
-        return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN);
+    private boolean shouldPostNotification(GsmDataConnection.FailCause  cause) {
+        return (cause != GsmDataConnection.FailCause.UNKNOWN);
     }
 
     /**
@@ -1046,7 +1040,7 @@
         }
     }
 
-    private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) {
+    private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode) {
         setState(State.FAILED);
     }
 
@@ -1069,7 +1063,7 @@
         mRetryMgr.resetRetryCount();
 
         // TODO:  To support simultaneous PDP contexts, this should really only call
-        // cleanUpConnection if it needs to free up a PdpConnection.
+        // cleanUpConnection if it needs to free up a GsmDataConnection.
         cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
     }
 
@@ -1149,8 +1143,8 @@
             // that the existing connection may service that type, in which
             // case we should try the next type, etc.
         } else {
-            PdpConnection.FailCause cause;
-            cause = (PdpConnection.FailCause) (ar.result);
+            GsmDataConnection.FailCause cause;
+            cause = (GsmDataConnection.FailCause) (ar.result);
             if(DBG) log("PDP setup failed " + cause);
                     // Log this failure to the Event Logs.
             if (cause.isEventLoggable()) {
@@ -1259,9 +1253,9 @@
                 if (cursor.getCount() > 0) {
                     allApns = createApnList(cursor);
                     // TODO: Figure out where this fits in.  This basically just
-                    // writes the pap-secrets file.  No longer tied to PdpConnection
+                    // writes the pap-secrets file.  No longer tied to GsmDataConnection
                     // object.  Not used on current platform (no ppp).
-                    //PdpConnection pdp = pdpList.get(pdp_name);
+                    //GsmDataConnection pdp = pdpList.get(pdp_name);
                     //if (pdp != null && pdp.dataLink != null) {
                     //    pdp.dataLink.setPasswordInfo(cursor);
                     //}
@@ -1273,7 +1267,7 @@
         if (allApns.isEmpty()) {
             if (DBG) log("No APN found for carrier: " + operator);
             preferredApn = null;
-            notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN);
+            notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
         } else {
             preferredApn = getPreferredApn();
             Log.d(LOG_TAG, "Get PreferredAPN");
@@ -1289,14 +1283,14 @@
         DataConnection pdp;
 
         for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {
-            pdp = new PdpConnection(mGsmPhone);
+            pdp = GsmDataConnection.makeDataConnection(mGsmPhone);
             pdpList.add(pdp);
          }
     }
 
     private void destroyAllPdpList() {
         if(pdpList != null) {
-            PdpConnection pdp;
+            GsmDataConnection pdp;
             pdpList.removeAll(pdpList);
         }
     }
@@ -1361,7 +1355,7 @@
         return result.toString();
     }
 
-    private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
+    private void startDelayedRetry(GsmDataConnection.FailCause cause, String reason) {
         notifyNoData(cause);
         reconnectAfterFail(cause, reason);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
deleted file mode 100644
index 02b061c..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * 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.gsm;
-
-import android.os.*;
-import android.util.EventLog;
-import android.util.Log;
-
-import com.android.common.Patterns;
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.DataConnection;
-import com.android.internal.telephony.DataLink;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.TelephonyEventLog;
-
-/**
- * {@hide}
- */
-public class PdpConnection extends DataConnection {
-
-    private static final String LOG_TAG = "GSM";
-    private static final boolean DBG  = true;
-
-    /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
-    private static final int PDP_FAIL_OPERATOR_BARRED = 0x08;
-    private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
-    private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B;
-    private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
-    private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D;
-    private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
-    private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
-    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
-    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
-    private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
-    private static final int PDP_FAIL_NSAPI_IN_USE      = 0x23;
-    private static final int PDP_FAIL_PROTOCOL_ERRORS   = 0x6F;
-    private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff;
-
-    private static final int PDP_FAIL_REGISTRATION_FAIL = -1;
-    private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2;
-
-    //***** Instance Variables
-    private String pdp_name;
-    private ApnSetting apn;
-
-    //***** Constructor
-    PdpConnection(GSMPhone phone) {
-        super(phone);
-    }
-
-    /**
-     * Setup PDP connection for provided apn
-     * @param apn for this connection
-     * @param onCompleted notify success or not after down
-     */
-    void connect(ApnSetting apn, Message onCompleted) {
-        if (DBG) log("Connecting to carrier: '" + apn.carrier
-                + "' APN: '" + apn.apn
-                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
-
-        setHttpProxy (apn.proxy, apn.port);
-
-        state = State.ACTIVATING;
-        this.apn = apn;
-        onConnectCompleted = onCompleted;
-        createTime = -1;
-        lastFailTime = -1;
-        lastFailCause = FailCause.NONE;
-        receivedDisconnectReq = false;
-
-        int authType = apn.authType;
-        if (authType == -1) {
-            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
-                RILConstants.SETUP_DATA_AUTH_NONE;
-        }
-        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),
-                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
-    }
-
-    private void tearDownData(Message msg) {
-        if (phone.mCM.getRadioState().isOn()) {
-            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
-        }
-    }
-
-    protected void disconnect(Message msg) {
-        onDisconnect = msg;
-        if (state == State.ACTIVE) {
-            tearDownData(msg);
-        } else if (state == State.ACTIVATING) {
-            receivedDisconnectReq = true;
-        } else {
-            // state == INACTIVE.  Nothing to do, so notify immediately.
-            notifyDisconnect(msg);
-        }
-    }
-
-    public void clearSettings() {
-        super.clearSettings();
-        apn = null;
-    }
-
-    public String toString() {
-        return "State=" + state + " Apn=" + apn +
-               " create=" + createTime + " lastFail=" + lastFailTime +
-               " lastFailCause=" + lastFailCause;
-    }
-
-
-    protected void notifyFail(FailCause cause, Message onCompleted) {
-        if (onCompleted == null) return;
-
-        state = State.INACTIVE;
-        lastFailCause = cause;
-        lastFailTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-
-        if (DBG) {
-            log("Notify PDP fail at " + lastFailTime +
-                    " due to " + lastFailCause);
-        }
-
-        AsyncResult.forMessage(onCompleted, cause, new Exception());
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifySuccess(Message onCompleted) {
-        if (onCompleted == null) {
-            return;
-        }
-
-        state = State.ACTIVE;
-        createTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-        onCompleted.arg1 = cid;
-
-        if (DBG) log("Notify PDP success at " + createTime);
-
-        AsyncResult.forMessage(onCompleted);
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifyDisconnect(Message msg) {
-        if (DBG) log("Notify PDP disconnect");
-
-        if (msg != null) {
-            AsyncResult.forMessage(msg);
-            msg.sendToTarget();
-        }
-        clearSettings();
-    }
-
-    protected void onLinkStateChanged(DataLink.LinkState linkState) {
-        switch (linkState) {
-            case LINK_UP:
-                notifySuccess(onConnectCompleted);
-                break;
-
-            case LINK_DOWN:
-            case LINK_EXITED:
-                phone.mCM.getLastPdpFailCause(
-                        obtainMessage (EVENT_GET_LAST_FAIL_DONE));
-                break;
-        }
-    }
-
-    protected FailCause getFailCauseFromRequest(int rilCause) {
-        FailCause cause;
-
-        switch (rilCause) {
-            case PDP_FAIL_OPERATOR_BARRED:
-                cause = FailCause.OPERATOR_BARRED;
-                break;
-            case PDP_FAIL_INSUFFICIENT_RESOURCES:
-                cause = FailCause.INSUFFICIENT_RESOURCES;
-                break;
-            case PDP_FAIL_MISSING_UKNOWN_APN:
-                cause = FailCause.MISSING_UKNOWN_APN;
-                break;
-            case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
-                cause = FailCause.UNKNOWN_PDP_ADDRESS;
-                break;
-            case PDP_FAIL_USER_AUTHENTICATION:
-                cause = FailCause.USER_AUTHENTICATION;
-                break;
-            case PDP_FAIL_ACTIVATION_REJECT_GGSN:
-                cause = FailCause.ACTIVATION_REJECT_GGSN;
-                break;
-            case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
-                cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED;
-                break;
-            case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
-                cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER;
-                break;
-            case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
-                cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
-                break;
-            case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
-                cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
-                break;
-            case PDP_FAIL_NSAPI_IN_USE:
-                cause = FailCause.NSAPI_IN_USE;
-                break;
-            case PDP_FAIL_PROTOCOL_ERRORS:
-                cause = FailCause.PROTOCOL_ERRORS;
-                break;
-            case PDP_FAIL_ERROR_UNSPECIFIED:
-                cause = FailCause.UNKNOWN;
-                break;
-            case PDP_FAIL_REGISTRATION_FAIL:
-                cause = FailCause.REGISTRATION_FAIL;
-                break;
-            case PDP_FAIL_GPRS_REGISTRATION_FAIL:
-                cause = FailCause.GPRS_REGISTRATION_FAIL;
-                break;
-            default:
-                cause = FailCause.UNKNOWN;
-        }
-        return cause;
-    }
-
-    protected void log(String s) {
-        Log.d(LOG_TAG, "[PdpConnection] " + s);
-    }
-
-    @Override
-    protected void onDeactivated(AsyncResult ar) {
-        notifyDisconnect((Message) ar.userObj);
-        if (DBG) log("PDP Connection Deactivated");
-    }
-
-    @Override
-    protected void onSetupConnectionCompleted(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception);
-
-            if (receivedDisconnectReq) {
-                // Don't bother reporting the error if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                notifyDisconnect(onDisconnect);
-            } else {
-                if ( ar.exception instanceof CommandException &&
-                        ((CommandException) (ar.exception)).getCommandError()
-                        == CommandException.Error.RADIO_NOT_AVAILABLE) {
-                    notifyFail(FailCause.RADIO_NOT_AVAILABLE,
-                            onConnectCompleted);
-                } else {
-                    phone.mCM.getLastPdpFailCause(
-                            obtainMessage(EVENT_GET_LAST_FAIL_DONE));
-                }
-            }
-        } else {
-            if (receivedDisconnectReq) {
-                // Don't bother reporting success if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                tearDownData(onDisconnect);
-            } else {
-                String[] response = ((String[]) ar.result);
-                cid = Integer.parseInt(response[0]);
-
-                if (response.length > 2) {
-                    interfaceName = response[1];
-                    ipAddress = response[2];
-                    String prefix = "net." + interfaceName + ".";
-                    gatewayAddress = SystemProperties.get(prefix + "gw");
-                    dnsServers[0] = SystemProperties.get(prefix + "dns1");
-                    dnsServers[1] = SystemProperties.get(prefix + "dns2");
-                    if (DBG) {
-                        log("interface=" + interfaceName + " ipAddress=" + ipAddress
-                            + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
-                            + " DNS2=" + dnsServers[1]);
-                    }
-
-                    if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
-                                        && !((GSMPhone) phone).isDnsCheckDisabled()) {
-                        // Work around a race condition where QMI does not fill in DNS:
-                        // Deactivate PDP and let DataConnectionTracker retry.
-                        // 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)) {
-                            EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
-                                    dnsServers[0]);
-                            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
-                            return;
-                        }
-                    }
-                }
-
-                onLinkStateChanged(DataLink.LinkState.LINK_UP);
-
-                if (DBG) log("PDP setup on cid = " + cid);
-            }
-        }
-    }
-
-    private boolean isIpAddress(String address) {
-        if (address == null) return false;
-
-        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
-    }
-
-    public ApnSetting getApn() {
-        return this.apn;
-    }
-}