Merge "Update ScriptC constructor to remove depricated param."
diff --git a/api/current.xml b/api/current.xml
index d682155..0cf46eb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1905,7 +1905,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843550"
+ value="16843552"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1916,7 +1916,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843549"
+ value="16843551"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1927,7 +1927,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843551"
+ value="16843553"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3804,6 +3804,17 @@
  visibility="public"
 >
 </field>
+<field name="enterFadeDuration"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843549"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="entries"
  type="int"
  transient="false"
@@ -3848,6 +3859,17 @@
  visibility="public"
 >
 </field>
+<field name="exitFadeDuration"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843550"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="expandableListPreferredChildIndicatorLeft"
  type="int"
  transient="false"
@@ -9308,7 +9330,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843553"
+ value="16843555"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9319,7 +9341,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843552"
+ value="16843554"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -19503,6 +19525,17 @@
 <parameter name="index" type="int">
 </parameter>
 </method>
+<method name="getTabCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getTitle"
  return="java.lang.CharSequence"
  abstract="true"
@@ -28300,6 +28333,17 @@
  visibility="public"
 >
 </method>
+<method name="disallowAddToBackStack"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="hide"
  return="android.app.FragmentTransaction"
  abstract="true"
@@ -28313,6 +28357,17 @@
 <parameter name="fragment" type="android.app.Fragment">
 </parameter>
 </method>
+<method name="isAddToBackStackAllowed"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isEmpty"
  return="boolean"
  abstract="true"
@@ -83932,6 +83987,17 @@
  visibility="public"
 >
 </method>
+<method name="jumpToCurrentState"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="mutate"
  return="android.graphics.drawable.Drawable"
  abstract="false"
@@ -84421,6 +84487,32 @@
 <parameter name="state" type="android.graphics.drawable.DrawableContainer.DrawableContainerState">
 </parameter>
 </method>
+<method name="setEnterFadeDuration"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ms" type="int">
+</parameter>
+</method>
+<method name="setExitFadeDuration"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ms" type="int">
+</parameter>
+</method>
 <method name="unscheduleDrawable"
  return="void"
  abstract="false"
@@ -84568,6 +84660,28 @@
  visibility="public"
 >
 </method>
+<method name="getEnterFadeDuration"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getExitFadeDuration"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getOpacity"
  return="int"
  abstract="false"
@@ -84629,6 +84743,32 @@
 <parameter name="constant" type="boolean">
 </parameter>
 </method>
+<method name="setEnterFadeDuration"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="int">
+</parameter>
+</method>
+<method name="setExitFadeDuration"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="int">
+</parameter>
+</method>
 <method name="setVariablePadding"
  return="void"
  abstract="false"
@@ -190423,6 +190563,17 @@
 <parameter name="newSize" type="int">
 </parameter>
 </method>
+<field name="NOTHING"
+ type="int[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="WILD_CARD"
  type="int[]"
  transient="false"
@@ -203765,6 +203916,17 @@
  visibility="public"
 >
 </method>
+<method name="jumpDrawablesToCurrentState"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="layout"
  return="void"
  abstract="false"
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 39754b0..1945b05 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -665,6 +665,11 @@
         public IntPropertyValuesHolder(String propertyName, int... values) {
             super(propertyName);
             setIntValues(values);
+        }
+
+        @Override
+        public void setIntValues(int... values) {
+            super.setIntValues(values);
             mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
         }
 
@@ -722,6 +727,11 @@
         public FloatPropertyValuesHolder(String propertyName, float... values) {
             super(propertyName);
             setFloatValues(values);
+        }
+
+        @Override
+        public void setFloatValues(float... values) {
+            super.setFloatValues(values);
             mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
         }
 
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index e185624..a57b54a 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -478,6 +478,12 @@
     public abstract Tab getTabAt(int index);
 
     /**
+     * Returns the number of tabs currently registered with the action bar.
+     * @return Tab count
+     */
+    public abstract int getTabCount();
+
+    /**
      * Retrieve the current height of the ActionBar.
      *
      * @return The ActionBar's height
@@ -626,7 +632,8 @@
          * @param tab The tab that was selected
          * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
          *        during a tab switch. The previous tab's unselect and this tab's select will be
-         *        executed in a single transaction.
+         *        executed in a single transaction. This FragmentTransaction does not support
+         *        being added to the back stack.
          */
         public void onTabSelected(Tab tab, FragmentTransaction ft);
 
@@ -636,7 +643,8 @@
          * @param tab The tab that was unselected
          * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
          *        during a tab switch. This tab's unselect and the newly selected tab's select
-         *        will be executed in a single transaction.
+         *        will be executed in a single transaction. This FragmentTransaction does not
+         *        support being added to the back stack.
          */
         public void onTabUnselected(Tab tab, FragmentTransaction ft);
 
@@ -646,7 +654,8 @@
          *
          * @param tab The tab that was reselected.
          * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
-         *        once this method returns.
+         *        once this method returns. This FragmentTransaction does not support
+         *        being added to the back stack.
          */
         public void onTabReselected(Tab tab, FragmentTransaction ft);
     }
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index e6cc0f9..c75777d 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -186,6 +186,7 @@
     int mTransition;
     int mTransitionStyle;
     boolean mAddToBackStack;
+    boolean mAllowAddToBackStack = true;
     String mName;
     boolean mCommitted;
     int mIndex;
@@ -346,11 +347,28 @@
     }
 
     public FragmentTransaction addToBackStack(String name) {
+        if (!mAllowAddToBackStack) {
+            throw new IllegalStateException(
+                    "This FragmentTransaction is not allowed to be added to the back stack.");
+        }
         mAddToBackStack = true;
         mName = name;
         return this;
     }
 
+    public boolean isAddToBackStackAllowed() {
+        return mAllowAddToBackStack;
+    }
+
+    public FragmentTransaction disallowAddToBackStack() {
+        if (mAddToBackStack) {
+            throw new IllegalStateException(
+                    "This transaction is already being added to the back stack");
+        }
+        mAllowAddToBackStack = false;
+        return this;
+    }
+
     public FragmentTransaction setBreadCrumbTitle(int res) {
         mBreadCrumbTitleRes = res;
         mBreadCrumbTitleText = null;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index b00476bb..19da763 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -144,6 +144,22 @@
     public FragmentTransaction addToBackStack(String name);
 
     /**
+     * Returns true if this FragmentTransaction is allowed to be added to the back
+     * stack. If this method would return false, {@link #addToBackStack(String)}
+     * will throw {@link IllegalStateException}.
+     *
+     * @return True if {@link #addToBackStack(String)} is permitted on this transaction.
+     */
+    public boolean isAddToBackStackAllowed();
+
+    /**
+     * Disallow calls to {@link #addToBackStack(String)}. Any future calls to
+     * addToBackStack will throw {@link IllegalStateException}. If addToBackStack
+     * has already been called, this method will throw IllegalStateException.
+     */
+    public FragmentTransaction disallowAddToBackStack();
+
+    /**
      * Set the full title to show as a bread crumb when this transaction
      * is on the back stack, as used by {@link FragmentBreadCrumbs}.
      *
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 7743ceb..cd08e33 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -39,8 +39,6 @@
 
     // NfcAdapter-class related methods
     boolean isEnabled();
-    NdefMessage localGet();
-    void localSet(in NdefMessage message);
     void openTagConnection(in Tag tag);
 
     // Non-public methods
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index cf80faf..88b6ea4 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -301,48 +301,6 @@
     }
 
     /**
-     * Set the NDEF Message that this NFC adapter should appear as to Tag
-     * readers.
-     * <p>
-     * Any Tag reader can read the contents of the local tag when it is in
-     * proximity, without any further user confirmation.
-     * <p>
-     * The implementation of this method must either
-     * <ul>
-     * <li>act as a passive tag containing this NDEF message
-     * <li>provide the NDEF message on over LLCP to peer NFC adapters
-     * </ul>
-     * The NDEF message is preserved across reboot.
-     * <p>Requires {@link android.Manifest.permission#NFC} permission.
-     *
-     * @param message NDEF message to make public
-     * @hide
-     */
-    public void setLocalNdefMessage(NdefMessage message) {
-        try {
-            mService.localSet(message);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-        }
-    }
-
-    /**
-     * Get the NDEF Message that this adapter appears as to Tag readers.
-     * <p>Requires {@link android.Manifest.permission#NFC} permission.
-     *
-     * @return NDEF Message that is publicly readable
-     * @hide
-     */
-    public NdefMessage getLocalNdefMessage() {
-        try {
-            return mService.localGet();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            return null;
-        }
-    }
-
-    /**
      * Create a raw tag connection to the default Target
      * <p>Requires {@link android.Manifest.permission#NFC} permission.
      * @hide
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index f3d8159..21d8e45 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -38,6 +38,7 @@
 public class StateSet {
 
     public static final int[] WILD_CARD = new int[0];
+    public static final int[] NOTHING = new int[] { 0 };
 
     /**
      * Return whether the stateSetOrSpec is matched by all StateSets.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7276044..340678d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8620,6 +8620,16 @@
     }
 
     /**
+     * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
+     * on all Drawable objects associated with this view.
+     */
+    public void jumpDrawablesToCurrentState() {
+        if (mBGDrawable != null) {
+            mBGDrawable.jumpToCurrentState();
+        }
+    }
+
+    /**
      * Sets the background color for this view.
      * @param color the color of the background
      */
@@ -8627,6 +8637,7 @@
     public void setBackgroundColor(int color) {
         if (mBGDrawable instanceof ColorDrawable) {
             ((ColorDrawable) mBGDrawable).setColor(color);
+            invalidate();
         } else {
             setBackgroundDrawable(new ColorDrawable(color));
         }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4e90ecd..7629673 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.SparseBooleanArray;
+import android.util.StateSet;
 import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -254,6 +255,17 @@
     Drawable mSelector;
 
     /**
+     * Set to true if we would like to have the selector showing itself.
+     * We still need to draw and position it even if this is false.
+     */
+    boolean mSelectorShowing;
+
+    /**
+     * The current position of the selector in the list.
+     */
+    int mSelectorPosition = INVALID_POSITION;
+
+    /**
      * Defines the selector's location and dimension at drawing time
      */
     Rect mSelectorRect = new Rect();
@@ -1324,6 +1336,7 @@
             setSelectedPositionInt(INVALID_POSITION);
             // Do this before setting mNeedSync since setNextSelectedPosition looks at mNeedSync
             setNextSelectedPositionInt(INVALID_POSITION);
+            mSelectorPosition = INVALID_POSITION;
             mNeedSync = true;
             mSyncRowId = ss.firstId;
             mSyncPosition = ss.position;
@@ -1416,6 +1429,8 @@
         setSelectedPositionInt(INVALID_POSITION);
         setNextSelectedPositionInt(INVALID_POSITION);
         mSelectedTop = 0;
+        mSelectorShowing = false;
+        mSelectorPosition = INVALID_POSITION;
         mSelectorRect.setEmpty();
         invalidate();
     }
@@ -1708,7 +1723,7 @@
             }
 
             if (child != scrapView) {
-                mRecycler.addScrapView(scrapView);
+                mRecycler.addScrapView(scrapView, position);
                 if (mCacheColorHint != 0) {
                     child.setDrawingCacheBackgroundColor(mCacheColorHint);
                 }
@@ -1734,7 +1749,11 @@
         return child;
     }
 
-    void positionSelector(View sel) {
+    void positionSelector(int position, View sel) {
+        if (position != INVALID_POSITION) {
+            mSelectorPosition = position;
+        }
+
         final Rect selectorRect = mSelectorRect;
         selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom());
         positionSelector(selectorRect.left, selectorRect.top, selectorRect.right,
@@ -1743,7 +1762,9 @@
         final boolean isChildViewEnabled = mIsChildViewEnabled;
         if (sel.isEnabled() != isChildViewEnabled) {
             mIsChildViewEnabled = !isChildViewEnabled;
-            refreshDrawableState();
+            if (mSelectorShowing) {
+                refreshDrawableState();
+            }
         }
     }
 
@@ -1822,7 +1843,7 @@
     }
 
     private void drawSelector(Canvas canvas) {
-        if (shouldShowSelector() && mSelectorRect != null && !mSelectorRect.isEmpty()) {
+        if (!mSelectorRect.isEmpty()) {
             final Drawable selector = mSelector;
             selector.setBounds(mSelectorRect);
             selector.draw(canvas);
@@ -1866,7 +1887,7 @@
         mSelectionRightPadding = padding.right;
         mSelectionBottomPadding = padding.bottom;
         sel.setCallback(this);
-        sel.setState(getDrawableState());
+        updateSelectorState();
     }
 
     /**
@@ -1891,7 +1912,7 @@
         Drawable selector = mSelector;
         Rect selectorRect = mSelectorRect;
         if (selector != null && (isFocused() || touchModeDrawsInPressedState())
-                && selectorRect != null && !selectorRect.isEmpty()) {
+                && !selectorRect.isEmpty()) {
 
             final View v = getChildAt(mSelectedPosition - mFirstPosition);
 
@@ -1926,12 +1947,20 @@
         mScrollDown = down;
     }
 
+    void updateSelectorState() {
+        if (mSelector != null) {
+            if (shouldShowSelector()) {
+                mSelector.setState(getDrawableState());
+            } else {
+                mSelector.setState(StateSet.NOTHING);
+            }
+        }
+    }
+
     @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
-        if (mSelector != null) {
-            mSelector.setState(getDrawableState());
-        }
+        updateSelectorState();
     }
 
     @Override
@@ -2141,7 +2170,6 @@
                 } else {
                     mTouchMode = TOUCH_MODE_DONE_WAITING;
                 }
-
             }
         }
     }
@@ -2316,10 +2344,10 @@
                     mLayoutMode = LAYOUT_NORMAL;
 
                     if (!mDataChanged) {
-                        layoutChildren();
                         child.setPressed(true);
-                        positionSelector(child);
                         setPressed(true);
+                        layoutChildren();
+                        positionSelector(mMotionPosition, child);
 
                         final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
                         final boolean longClickable = isLongClickable();
@@ -2566,7 +2594,7 @@
                             setSelectedPositionInt(mMotionPosition);
                             layoutChildren();
                             child.setPressed(true);
-                            positionSelector(child);
+                            positionSelector(mMotionPosition, child);
                             setPressed(true);
                             if (mSelector != null) {
                                 Drawable d = mSelector.getCurrent();
@@ -2576,16 +2604,17 @@
                             }
                             postDelayed(new Runnable() {
                                 public void run() {
+                                    mTouchMode = TOUCH_MODE_REST;
                                     child.setPressed(false);
                                     setPressed(false);
                                     if (!mDataChanged) {
                                         post(performClick);
                                     }
-                                    mTouchMode = TOUCH_MODE_REST;
                                 }
                             }, ViewConfiguration.getPressedStateDuration());
                         } else {
                             mTouchMode = TOUCH_MODE_REST;
+                            updateSelectorState();
                         }
                         return true;
                     } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
@@ -2593,6 +2622,7 @@
                     }
                 }
                 mTouchMode = TOUCH_MODE_REST;
+                updateSelectorState();
                 break;
             case TOUCH_MODE_SCROLL:
                 final int childCount = getChildCount();
@@ -3507,7 +3537,7 @@
                     count++;
                     int position = firstPosition + i;
                     if (position >= headerViewsCount && position < footerViewsStart) {
-                        mRecycler.addScrapView(child);
+                        mRecycler.addScrapView(child, position);
 
                         if (ViewDebug.TRACE_RECYCLER) {
                             ViewDebug.trace(child,
@@ -3528,7 +3558,7 @@
                     count++;
                     int position = firstPosition + i;
                     if (position >= headerViewsCount && position < footerViewsStart) {
-                        mRecycler.addScrapView(child);
+                        mRecycler.addScrapView(child, position);
 
                         if (ViewDebug.TRACE_RECYCLER) {
                             ViewDebug.trace(child,
@@ -3563,8 +3593,15 @@
         if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
             final int childIndex = mSelectedPosition - mFirstPosition;
             if (childIndex >= 0 && childIndex < getChildCount()) {
-                positionSelector(getChildAt(childIndex));
+                positionSelector(mSelectedPosition, getChildAt(childIndex));
             }
+        } else if (mSelectorPosition != INVALID_POSITION) {
+            final int childIndex = mSelectorPosition - mFirstPosition;
+            if (childIndex >= 0 && childIndex < getChildCount()) {
+                positionSelector(INVALID_POSITION, getChildAt(childIndex));
+            }
+        } else {
+            mSelectorRect.setEmpty();
         }
 
         mBlockLayoutRequests = false;
@@ -3616,7 +3653,7 @@
             setSelectedPositionInt(INVALID_POSITION);
             setNextSelectedPositionInt(INVALID_POSITION);
             mSelectedTop = 0;
-            mSelectorRect.setEmpty();
+            mSelectorShowing = false;
         }
     }
 
@@ -3876,6 +3913,7 @@
         mNextSelectedPosition = INVALID_POSITION;
         mNextSelectedRowId = INVALID_ROW_ID;
         mNeedSync = false;
+        mSelectorPosition = INVALID_POSITION;
         checkSelectionChanged();
     }
 
@@ -4562,6 +4600,13 @@
         @ViewDebug.ExportedProperty(category = "list")
         boolean forceAdd;
 
+        /**
+         * The position the view was removed from when pulled out of the
+         * scrap heap.
+         * @hide
+         */
+        int scrappedFromPosition;
+
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
         }
@@ -4741,23 +4786,12 @@
          * @return A view from the ScrapViews collection. These are unordered.
          */
         View getScrapView(int position) {
-            ArrayList<View> scrapViews;
             if (mViewTypeCount == 1) {
-                scrapViews = mCurrentScrap;
-                int size = scrapViews.size();
-                if (size > 0) {
-                    return scrapViews.remove(size - 1);
-                } else {
-                    return null;
-                }
+                return retrieveFromScrap(mCurrentScrap, position);
             } else {
                 int whichScrap = mAdapter.getItemViewType(position);
                 if (whichScrap >= 0 && whichScrap < mScrapViews.length) {
-                    scrapViews = mScrapViews[whichScrap];
-                    int size = scrapViews.size();
-                    if (size > 0) {
-                        return scrapViews.remove(size - 1);
-                    }
+                    return retrieveFromScrap(mScrapViews[whichScrap], position);
                 }
             }
             return null;
@@ -4768,7 +4802,7 @@
          *
          * @param scrap The view to add
          */
-        void addScrapView(View scrap) {
+        void addScrapView(View scrap, int position) {
             AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
             if (lp == null) {
                 return;
@@ -4784,6 +4818,8 @@
                 return;
             }
 
+            lp.scrappedFromPosition = position;
+
             if (mViewTypeCount == 1) {
                 scrap.dispatchStartTemporaryDetach();
                 mCurrentScrap.add(scrap);
@@ -4810,7 +4846,9 @@
             for (int i = count - 1; i >= 0; i--) {
                 final View victim = activeViews[i];
                 if (victim != null) {
-                    int whichScrap = ((AbsListView.LayoutParams) victim.getLayoutParams()).viewType;
+                    final AbsListView.LayoutParams lp
+                            = (AbsListView.LayoutParams) victim.getLayoutParams();
+                    int whichScrap = lp.viewType;
 
                     activeViews[i] = null;
 
@@ -4826,6 +4864,7 @@
                         scrapViews = mScrapViews[whichScrap];
                     }
                     victim.dispatchStartTemporaryDetach();
+                    lp.scrappedFromPosition = mFirstActivePosition + i;
                     scrapViews.add(victim);
 
                     if (hasListener) {
@@ -4911,4 +4950,22 @@
             }
         }
     }
+
+    static View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
+        int size = scrapViews.size();
+        if (size > 0) {
+            // See if we still have a view for this position.
+            for (int i=0; i<size; i++) {
+                View view = scrapViews.get(i);
+                if (((AbsListView.LayoutParams)view.getLayoutParams())
+                        .scrappedFromPosition == position) {
+                    scrapViews.remove(i);
+                    return view;
+                }
+            }
+            return scrapViews.remove(size - 1);
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index f5afb94..f16efbd 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.database.DataSetObserver;
-import android.os.Handler;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.util.AttributeSet;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 46c7d33..936a97d 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1009,7 +1009,7 @@
             childHeight = child.getMeasuredHeight();
 
             if (mRecycler.shouldRecycleViewType(p.viewType)) {
-                mRecycler.addScrapView(child);
+                mRecycler.addScrapView(child, -1);
             }
         }
         
@@ -1148,7 +1148,7 @@
 
             if (dataChanged) {
                 for (int i = 0; i < childCount; i++) {
-                    recycleBin.addScrapView(getChildAt(i));
+                    recycleBin.addScrapView(getChildAt(i), firstPosition+i);
                 }
             } else {
                 recycleBin.fillActiveViews(childCount, firstPosition);
@@ -1215,11 +1215,11 @@
             recycleBin.scrapActiveViews();
 
             if (sel != null) {
-               positionSelector(sel);
+               positionSelector(INVALID_POSITION, sel);
                mSelectedTop = sel.getTop();
             } else if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
                 View child = getChildAt(mMotionPosition - mFirstPosition);
-                if (child != null) positionSelector(child);                
+                if (child != null) positionSelector(mMotionPosition, child);
             } else {
                 mSelectedTop = 0;
                 mSelectorRect.setEmpty();
@@ -1391,6 +1391,11 @@
         if (mCachingStarted) {
             child.setDrawingCacheEnabled(true);
         }
+
+        if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition)
+                != position) {
+            child.jumpDrawablesToCurrentState();
+        }
     }
 
     /**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b5e103f..e0119e9 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -581,7 +581,7 @@
         final boolean scroll = scrollYDelta != 0;
         if (scroll) {
             scrollListItemsBy(-scrollYDelta);
-            positionSelector(child);
+            positionSelector(INVALID_POSITION, child);
             mSelectedTop = child.getTop();
             invalidate();
         }
@@ -1086,7 +1086,7 @@
 
             if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
                     ((LayoutParams) child.getLayoutParams()).viewType)) {
-                mRecycler.addScrapView(child);
+                mRecycler.addScrapView(child, -1);
             }
         }
 
@@ -1203,7 +1203,7 @@
             // Recycle the view before we possibly return from the method
             if (recyle && recycleBin.shouldRecycleViewType(
                     ((LayoutParams) child.getLayoutParams()).viewType)) {
-                recycleBin.addScrapView(child);
+                recycleBin.addScrapView(child, -1);
             }
 
             returnedHeight += child.getMeasuredHeight();
@@ -1507,7 +1507,7 @@
             // already cached in mHeaderViews;
             if (dataChanged) {
                 for (int i = 0; i < childCount; i++) {
-                    recycleBin.addScrapView(getChildAt(i));
+                    recycleBin.addScrapView(getChildAt(i), firstPosition+i);
                     if (ViewDebug.TRACE_RECYCLER) {
                         ViewDebug.trace(getChildAt(i),
                                 ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i);
@@ -1610,19 +1610,19 @@
                         if (focused != null) {
                             focused.clearFocus();
                         }
-                        positionSelector(sel);
+                        positionSelector(INVALID_POSITION, sel);
                     } else {
                         sel.setSelected(false);
                         mSelectorRect.setEmpty();
                     }
                 } else {
-                    positionSelector(sel);
+                    positionSelector(INVALID_POSITION, sel);
                 }
                 mSelectedTop = sel.getTop();
             } else {
                 if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
                     View child = getChildAt(mMotionPosition - mFirstPosition);
-                    if (child != null) positionSelector(child);
+                    if (child != null) positionSelector(mMotionPosition, child);
                 } else {
                     mSelectedTop = 0;
                     mSelectorRect.setEmpty();
@@ -1703,7 +1703,7 @@
 
 
         if (!mDataChanged) {
-            // Try to use an exsiting view for this position
+            // Try to use an existing view for this position
             child = mRecycler.getActiveView(position);
             if (child != null) {
                 if (ViewDebug.TRACE_RECYCLER) {
@@ -1820,6 +1820,11 @@
         if (mCachingStarted && !child.isDrawingCacheEnabled()) {
             child.setDrawingCacheEnabled(true);
         }
+
+        if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition)
+                != position) {
+            child.jumpDrawablesToCurrentState();
+        }
     }
 
     @Override
@@ -2288,6 +2293,7 @@
         }
 
         View selectedView = getSelectedView();
+        int selectedPos = mSelectedPosition;
 
         int nextSelectedPosition = lookForSelectablePositionOnScreen(direction);
         int amountToScroll = amountToScroll(direction, nextSelectedPosition);
@@ -2305,6 +2311,7 @@
             setSelectedPositionInt(nextSelectedPosition);
             setNextSelectedPositionInt(nextSelectedPosition);
             selectedView = getSelectedView();
+            selectedPos = nextSelectedPosition;
             if (mItemsCanFocus && focusResult == null) {
                 // there was no new view found to take focus, make sure we
                 // don't leave focus with the old selection
@@ -2345,7 +2352,7 @@
 
         if (needToRedraw) {
             if (selectedView != null) {
-                positionSelector(selectedView);
+                positionSelector(selectedPos, selectedView);
                 mSelectedTop = selectedView.getTop();
             }
             if (!awakenScrollBars()) {
@@ -2841,7 +2848,7 @@
                 AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams();
                 if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
                     detachViewFromParent(first);
-                    recycleBin.addScrapView(first);
+                    recycleBin.addScrapView(first, mFirstPosition);
                 } else {
                     removeViewInLayout(first);
                 }
@@ -2872,7 +2879,7 @@
                 AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams();
                 if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
                     detachViewFromParent(last);
-                    recycleBin.addScrapView(last);
+                    recycleBin.addScrapView(last, mFirstPosition+lastIndex);
                 } else {
                     removeViewInLayout(last);
                 }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 1d612e2..7cf369f 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -65,12 +65,15 @@
     private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
 
     private TabImpl mSelectedTab;
+    private int mSavedTabPosition = INVALID_POSITION;
     
     private ActionMode mActionMode;
     
     private static final int CONTEXT_DISPLAY_NORMAL = 0;
     private static final int CONTEXT_DISPLAY_SPLIT = 1;
     
+    private static final int INVALID_POSITION = -1;
+
     private int mContextDisplayMode;
 
     private boolean mClosingContext;
@@ -183,6 +186,8 @@
             selectTab(null);
         }
         mTabs.clear();
+        mActionView.removeAllTabs();
+        mSavedTabPosition = INVALID_POSITION;
     }
 
     public void setTitle(CharSequence title) {
@@ -310,6 +315,8 @@
 
     @Override
     public void removeTabAt(int position) {
+        int selectedTabPosition = mSelectedTab != null
+                ? mSelectedTab.getPosition() : mSavedTabPosition;
         mActionView.removeTabAt(position);
         mTabs.remove(position);
 
@@ -318,7 +325,9 @@
             mTabs.get(i).setPosition(i);
         }
 
-        selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
+        if (selectedTabPosition == position) {
+            selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
+        }
     }
 
     @Override
@@ -333,7 +342,13 @@
 
     @Override
     public void selectTab(Tab tab) {
-        final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction();
+        if (getNavigationMode() != NAVIGATION_MODE_TABS) {
+            mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
+            return;
+        }
+
+        final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction()
+                .disallowAddToBackStack();
 
         if (mSelectedTab == tab) {
             if (mSelectedTab != null) {
@@ -623,12 +638,52 @@
     }
 
     @Override
+    public int getTabCount() {
+        return mTabs.size();
+    }
+
+    @Override
     public void setNavigationMode(int mode) {
+        final int oldMode = mActionView.getNavigationMode();
+        switch (oldMode) {
+            case NAVIGATION_MODE_TABS:
+                mSavedTabPosition = getSelectedNavigationIndex();
+                selectTab(null);
+                break;
+        }
         mActionView.setNavigationMode(mode);
+        switch (mode) {
+            case NAVIGATION_MODE_TABS:
+                if (mSavedTabPosition != INVALID_POSITION) {
+                    setSelectedNavigationItem(mSavedTabPosition);
+                    mSavedTabPosition = INVALID_POSITION;
+                }
+                break;
+        }
     }
 
     @Override
     public Tab getTabAt(int index) {
         return mTabs.get(index);
     }
+
+    /**
+     * This fragment is added when we're keeping a back stack in a tab switch
+     * transaction. We use it to change the selected tab in the action bar view
+     * when we back out.
+     */
+    private class SwitchSelectedTabViewFragment extends Fragment {
+        private int mSelectedTabIndex;
+
+        public SwitchSelectedTabViewFragment(int oldSelectedTab) {
+            mSelectedTabIndex = oldSelectedTab;
+        }
+
+        @Override
+        public void onDetach() {
+            if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) {
+                mActionView.setTabSelected(mSelectedTabIndex);
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 95d6dd3..8ead9c8 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -487,6 +487,12 @@
         }
     }
 
+    public void removeAllTabs() {
+        if (mTabLayout != null) {
+            mTabLayout.removeAllViews();
+        }
+    }
+
     @Override
     protected LayoutParams generateDefaultLayoutParams() {
         // Used by custom nav views if they don't supply layout params. Everything else
diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java
index f4ee7ee..f91d3d6 100644
--- a/core/java/com/android/internal/widget/WaveView.java
+++ b/core/java/com/android/internal/widget/WaveView.java
@@ -53,8 +53,10 @@
     private static final int STATE_UNLOCK_SUCCESS = 5;
 
     // Animation properties.
-    private static final long DURATION = 500; // duration of transitional animations
-    private static final long FINAL_DELAY = 1300; // delay for final animations
+    private static final long DURATION = 300; // duration of transitional animations
+    private static final long FINAL_DURATION = 200; // duration of final animations when unlocking
+    private static final long RING_DELAY = 1300; // when to start fading animated rings
+    private static final long FINAL_DELAY = 200; // delay for unlock success animation
     private static final long SHORT_DELAY = 100; // for starting one animation after another.
     private static final long WAVE_DURATION = 2000; // amount of time for way to expand/decay
     private static final long RESET_TIMEOUT = 3000; // elapsed time of inactivity before we reset
@@ -299,11 +301,11 @@
                         // x:ringX, y:ringY, scaleX: .1, scaleY: .1, ease:Quint.easeOut});
                         DrawableHolder wave = mLightWaves.get(n);
                         long delay = 1000L*(6 + n - mCurrentWave)/10L;
-                        wave.addAnimTo(DURATION, delay, "x", ringX, true);
-                        wave.addAnimTo(DURATION, delay, "y", ringY, true);
-                        wave.addAnimTo(DURATION, delay, "scaleX", 0.1f, true);
-                        wave.addAnimTo(DURATION, delay, "scaleY", 0.1f, true);
-                        wave.addAnimTo(DURATION, delay, "alpha", 0.0f, true);
+                        wave.addAnimTo(FINAL_DURATION, delay, "x", ringX, true);
+                        wave.addAnimTo(FINAL_DURATION, delay, "y", ringY, true);
+                        wave.addAnimTo(FINAL_DURATION, delay, "scaleX", 0.1f, true);
+                        wave.addAnimTo(FINAL_DURATION, delay, "scaleY", 0.1f, true);
+                        wave.addAnimTo(FINAL_DURATION, delay, "alpha", 0.0f, true);
                     }
                     for (int i = 0; i < mLightWaves.size(); i++) {
                         mLightWaves.get(i).startAnimations(this);
@@ -311,14 +313,14 @@
 
                     //TweenMax.to(unlockRing, .5, {x:ringX, y: ringY, scaleX: .1, scaleY: .1,
                     // alpha: 0, ease: Quint.easeOut   });
-                    mUnlockRing.addAnimTo(DURATION, 0, "x", ringX, false);
-                    mUnlockRing.addAnimTo(DURATION, 0, "y", ringY, false);
-                    mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, false);
-                    mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, false);
-                    mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, false);
+                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
+                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
+                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleX", 0.1f, false);
+                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleY", 0.1f, false);
+                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "alpha", 0.0f, false);
 
                     //TweenMax.to(unlockRing, .5, { delay: 1.3, alpha: 0  , ease: Quint.easeOut });
-                    mUnlockRing.addAnimTo(DURATION, FINAL_DELAY, "alpha", 0.0f, false);
+                    mUnlockRing.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
 
                     //TweenMax.to(unlockDefault, 0, { x:ringX, y: ringY, scaleX: .1, scaleY: .1,
                     // alpha: 0  , overwrite: true });
@@ -332,27 +334,27 @@
 
                     //TweenMax.to(unlockDefault, .5, { x:ringX, y: ringY, scaleX: 1, scaleY: 1,
                     // alpha: 1  , ease: Quint.easeOut  , overwrite: true });
-                    mUnlockDefault.addAnimTo(DURATION, 0, "x", ringX, true);
-                    mUnlockDefault.addAnimTo(DURATION, 0, "y", ringY, true);
-                    mUnlockDefault.addAnimTo(DURATION, 0, "scaleX", 1.0f, true);
-                    mUnlockDefault.addAnimTo(DURATION, 0, "scaleY", 1.0f, true);
-                    mUnlockDefault.addAnimTo(DURATION, 0, "alpha", 1.0f, true);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "x", ringX, true);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "y", ringY, true);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleX", 1.0f, true);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleY", 1.0f, true);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "alpha", 1.0f, true);
 
                     //TweenMax.to(unlockDefault, .5, { delay: 1.3, scaleX: 3, scaleY: 3,
                     // alpha: 1, ease: Quint.easeOut });
-                    mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
-                    mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
-                    mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "alpha", 1.0f, false);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
+                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
 
                     //TweenMax.to(unlockHalo, .5, { x:ringX, y: ringY , ease: Back.easeOut    });
-                    mUnlockHalo.addAnimTo(DURATION, 0, "x", ringX, false);
-                    mUnlockHalo.addAnimTo(DURATION, 0, "y", ringY, false);
+                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
+                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
 
                     //TweenMax.to(unlockHalo, .5, { delay: 1.3, scaleX: 3, scaleY: 3,
                     // alpha: 1, ease: Quint.easeOut   });
-                    mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
-                    mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
-                    mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "alpha", 1.0f, false);
+                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
+                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
+                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
 
                     removeCallbacks(mLockTimerActions);
 
@@ -437,7 +439,7 @@
 
                 //TweenMax.to(this["lightWave"+currentWave], 1, { delay: 1.3
                 // , alpha: 0  , ease:Quint.easeOut});
-                wave.addAnimTo(1000, FINAL_DELAY, "alpha", 0.0f, false);
+                wave.addAnimTo(1000, RING_DELAY, "alpha", 0.0f, false);
                 wave.startAnimations(WaveView.this);
 
                 mCurrentWave = (mCurrentWave+1) % mWaveCount;
diff --git a/core/res/res/drawable/activated_background.xml b/core/res/res/drawable/activated_background.xml
index d92fba1..1047e5b 100644
--- a/core/res/res/drawable/activated_background.xml
+++ b/core/res/res/drawable/activated_background.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
     <item android:state_activated="true" android:drawable="@android:drawable/list_selector_background_selected" />
     <item android:drawable="@color/transparent" />
 </selector>
diff --git a/core/res/res/drawable/activated_background_holo_dark.xml b/core/res/res/drawable/activated_background_holo_dark.xml
index febf2c4..a29bcb9 100644
--- a/core/res/res/drawable/activated_background_holo_dark.xml
+++ b/core/res/res/drawable/activated_background_holo_dark.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
     <item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" />
     <item android:drawable="@color/transparent" />
 </selector>
diff --git a/core/res/res/drawable/activated_background_holo_light.xml b/core/res/res/drawable/activated_background_holo_light.xml
index febf2c4..a29bcb9 100644
--- a/core/res/res/drawable/activated_background_holo_light.xml
+++ b/core/res/res/drawable/activated_background_holo_light.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
     <item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" />
     <item android:drawable="@color/transparent" />
 </selector>
diff --git a/core/res/res/drawable/activated_background_light.xml b/core/res/res/drawable/activated_background_light.xml
index 5d5681d..7d737db 100644
--- a/core/res/res/drawable/activated_background_light.xml
+++ b/core/res/res/drawable/activated_background_light.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
     <item android:state_activated="true" android:drawable="@drawable/list_selector_background_selected_light" />
     <item android:drawable="@color/transparent" />
 </selector>
diff --git a/core/res/res/drawable/list_selector_background.xml b/core/res/res/drawable/list_selector_background.xml
index 6fb0661..f5eb12d 100644
--- a/core/res/res/drawable/list_selector_background.xml
+++ b/core/res/res/drawable/list_selector_background.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_window_focused="false" android:drawable="@color/transparent" />
 
diff --git a/core/res/res/drawable/list_selector_background_light.xml b/core/res/res/drawable/list_selector_background_light.xml
index 4da7e21..50a821b 100644
--- a/core/res/res/drawable/list_selector_background_light.xml
+++ b/core/res/res/drawable/list_selector_background_light.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_window_focused="false" android:drawable="@color/transparent" />
 
diff --git a/core/res/res/drawable/list_selector_holo_dark.xml b/core/res/res/drawable/list_selector_holo_dark.xml
index e4c5c52..9a6cb89 100644
--- a/core/res/res/drawable/list_selector_holo_dark.xml
+++ b/core/res/res/drawable/list_selector_holo_dark.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_window_focused="false" android:drawable="@color/transparent" />
 
diff --git a/core/res/res/drawable/list_selector_holo_light.xml b/core/res/res/drawable/list_selector_holo_light.xml
index 17631bd..844259e 100644
--- a/core/res/res/drawable/list_selector_holo_light.xml
+++ b/core/res/res/drawable/list_selector_holo_light.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_window_focused="false" android:drawable="@color/transparent" />
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a2fa1a3..1083452 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2786,6 +2786,10 @@
              same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
              an RGB 565 screen). -->
         <attr name="dither" format="boolean" />
+        <!-- Amount of time (in milliseconds) to fade in a new state drawable. -->
+        <attr name="enterFadeDuration" format="integer" />
+        <!-- Amount of time (in milliseconds) to fade out an old state drawable. -->
+        <attr name="exitFadeDuration" format="integer" />
     </declare-styleable>
 
     <declare-styleable name="AnimationDrawable">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fd7e984..f8752d3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1358,6 +1358,8 @@
   <public type="attr" name="buttonGroupStyle" />
   <public type="attr" name="alertDialogButtonGroupStyle" />
   <public type="attr" name="homeAsUpIndicator" />
+  <public type="attr" name="enterFadeDuration" />
+  <public type="attr" name="exitFadeDuration" />
 
   <public type="anim" name="animator_fade_in" />
   <public type="anim" name="animator_fade_out" />
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 7b2d9d7..baa9d62 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -423,6 +423,13 @@
     }
 
     /**
+     * If this Drawable does transition animations between states, ask that
+     * it immediately jump to the current state and skip any active animations.
+     */
+    public void jumpToCurrentState() {
+    }
+
+    /**
      * @return The current drawable that will be used by this drawable. For simple drawables, this
      *         is just the drawable itself. For drawables that change state like
      *         {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 124d907..e55a746 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -21,6 +21,7 @@
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.os.SystemClock;
 
 /**
  * A helper class that contains several {@link Drawable}s and selects which one to use.
@@ -28,6 +29,8 @@
  * You can subclass it to create your own DrawableContainers or directly use one its child classes.
  */
 public class DrawableContainer extends Drawable implements Drawable.Callback {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "DrawableContainer";
 
     /**
      * To be proper, we should have a getter for dither (and alpha, etc.)
@@ -48,6 +51,12 @@
     private int mCurIndex = -1;
     private boolean mMutated;
 
+    // Animations.
+    private Runnable mAnimationRunnable;
+    private long mEnterAnimationEnd;
+    private long mExitAnimationEnd;
+    private Drawable mLastDrawable;
+
     // overrides from Drawable
 
     @Override
@@ -55,6 +64,9 @@
         if (mCurrDrawable != null) {
             mCurrDrawable.draw(canvas);
         }
+        if (mLastDrawable != null) {
+            mLastDrawable.draw(canvas);
+        }
     }
 
     @Override
@@ -83,7 +95,11 @@
         if (mAlpha != alpha) {
             mAlpha = alpha;
             if (mCurrDrawable != null) {
-                mCurrDrawable.setAlpha(alpha);
+                if (mEnterAnimationEnd == 0) {
+                    mCurrDrawable.setAlpha(alpha);
+                } else {
+                    animate(false);
+                }
             }
         }
     }
@@ -108,8 +124,29 @@
         }
     }
     
+    /**
+     * Change the global fade duration when a new drawable is entering
+     * the scene.
+     * @param ms The amount of time to fade in milliseconds.
+     */
+    public void setEnterFadeDuration(int ms) {
+        mDrawableContainerState.mEnterFadeDuration = ms;
+    }
+    
+    /**
+     * Change the global fade duration when a new drawable is leaving
+     * the scene.
+     * @param ms The amount of time to fade in milliseconds.
+     */
+    public void setExitFadeDuration(int ms) {
+        mDrawableContainerState.mExitFadeDuration = ms;
+    }
+    
     @Override
     protected void onBoundsChange(Rect bounds) {
+        if (mLastDrawable != null) {
+            mLastDrawable.setBounds(bounds);
+        }
         if (mCurrDrawable != null) {
             mCurrDrawable.setBounds(bounds);
         }
@@ -121,7 +158,34 @@
     }
     
     @Override
+    public void jumpToCurrentState() {
+        boolean changed = false;
+        if (mLastDrawable != null) {
+            mLastDrawable.jumpToCurrentState();
+            mLastDrawable = null;
+            changed = true;
+        }
+        if (mCurrDrawable != null) {
+            mCurrDrawable.jumpToCurrentState();
+        }
+        if (mExitAnimationEnd != 0) {
+            mExitAnimationEnd = 0;
+            changed = true;
+        }
+        if (mEnterAnimationEnd != 0) {
+            mEnterAnimationEnd = 0;
+            changed = true;
+        }
+        if (changed) {
+            invalidateSelf();
+        }
+    }
+
+    @Override
     protected boolean onStateChange(int[] state) {
+        if (mLastDrawable != null) {
+            return mLastDrawable.setState(state);
+        }
         if (mCurrDrawable != null) {
             return mCurrDrawable.setState(state);
         }
@@ -130,6 +194,9 @@
 
     @Override
     protected boolean onLevelChange(int level) {
+        if (mLastDrawable != null) {
+            return mLastDrawable.setLevel(level);
+        }
         if (mCurrDrawable != null) {
             return mCurrDrawable.setLevel(level);
         }
@@ -168,22 +235,19 @@
         return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0;
     }
 
-    public void invalidateDrawable(Drawable who)
-    {
+    public void invalidateDrawable(Drawable who) {
         if (who == mCurrDrawable && mCallback != null) {
             mCallback.invalidateDrawable(this);
         }
     }
 
-    public void scheduleDrawable(Drawable who, Runnable what, long when)
-    {
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
         if (who == mCurrDrawable && mCallback != null) {
             mCallback.scheduleDrawable(this, what, when);
         }
     }
 
-    public void unscheduleDrawable(Drawable who, Runnable what)
-    {
+    public void unscheduleDrawable(Drawable who, Runnable what) {
         if (who == mCurrDrawable && mCallback != null) {
             mCallback.unscheduleDrawable(this, what);
         }
@@ -192,6 +256,9 @@
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
         boolean changed = super.setVisible(visible, restart);
+        if (mLastDrawable != null) {
+            mLastDrawable.setVisible(visible, restart);
+        }
         if (mCurrDrawable != null) {
             mCurrDrawable.setVisible(visible, restart);
         }
@@ -208,16 +275,39 @@
         if (idx == mCurIndex) {
             return false;
         }
+
+        final long now = SystemClock.uptimeMillis();
+
+        if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + idx
+                + ": exit=" + mDrawableContainerState.mExitFadeDuration
+                + " enter=" + mDrawableContainerState.mEnterFadeDuration);
+
+        if (mDrawableContainerState.mExitFadeDuration > 0) {
+            if (mLastDrawable != null) {
+                mLastDrawable.setVisible(false, false);
+            }
+            if (mCurrDrawable != null) {
+                mLastDrawable = mCurrDrawable;
+                mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration;
+            } else {
+                mLastDrawable = null;
+                mExitAnimationEnd = 0;
+            }
+        } else if (mCurrDrawable != null) {
+            mCurrDrawable.setVisible(false, false);
+        }
+
         if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
             Drawable d = mDrawableContainerState.mDrawables[idx];
-            if (mCurrDrawable != null) {
-                mCurrDrawable.setVisible(false, false);
-            }
             mCurrDrawable = d;
             mCurIndex = idx;
             if (d != null) {
+                if (mDrawableContainerState.mEnterFadeDuration > 0) {
+                    mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
+                } else {
+                    d.setAlpha(mAlpha);
+                }
                 d.setVisible(isVisible(), true);
-                d.setAlpha(mAlpha);
                 d.setDither(mDrawableContainerState.mDither);
                 d.setColorFilter(mColorFilter);
                 d.setState(getState());
@@ -225,16 +315,72 @@
                 d.setBounds(getBounds());
             }
         } else {
-            if (mCurrDrawable != null) {
-                mCurrDrawable.setVisible(false, false);
-            }
             mCurrDrawable = null;
             mCurIndex = -1;
         }
+
+        if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) {
+            if (mAnimationRunnable == null) {
+                mAnimationRunnable = new Runnable() {
+                    @Override public void run() {
+                        animate(true);
+                        invalidateSelf();
+                    }
+                };
+            } else {
+                unscheduleSelf(mAnimationRunnable);
+            }
+            // Compute first frame and schedule next animation.
+            animate(true);
+        }
+
         invalidateSelf();
+
         return true;
     }
     
+    void animate(boolean schedule) {
+        final long now = SystemClock.uptimeMillis();
+        boolean animating = false;
+        if (mCurrDrawable != null) {
+            if (mEnterAnimationEnd != 0) {
+                if (mEnterAnimationEnd <= now) {
+                    mCurrDrawable.setAlpha(mAlpha);
+                    mEnterAnimationEnd = 0;
+                } else {
+                    int animAlpha = (int)((mEnterAnimationEnd-now)*255)
+                            / mDrawableContainerState.mEnterFadeDuration;
+                    if (DEBUG) android.util.Log.i(TAG, toString() + " cur alpha " + animAlpha);
+                    mCurrDrawable.setAlpha(((255-animAlpha)*mAlpha)/255);
+                    animating = true;
+                }
+            }
+        } else {
+            mEnterAnimationEnd = 0;
+        }
+        if (mLastDrawable != null) {
+            if (mExitAnimationEnd != 0) {
+                if (mExitAnimationEnd <= now) {
+                    mLastDrawable.setVisible(false, false);
+                    mLastDrawable = null;
+                    mExitAnimationEnd = 0;
+                } else {
+                    int animAlpha = (int)((mExitAnimationEnd-now)*255)
+                            / mDrawableContainerState.mExitFadeDuration;
+                    if (DEBUG) android.util.Log.i(TAG, toString() + " last alpha " + animAlpha);
+                    mLastDrawable.setAlpha((animAlpha*mAlpha)/255);
+                    animating = true;
+                }
+            }
+        } else {
+            mExitAnimationEnd = 0;
+        }
+
+        if (schedule && animating) {
+            scheduleSelf(mAnimationRunnable, now + 1000/60);
+        }
+    }
+
     @Override
     public Drawable getCurrent() {
         return mCurrDrawable;
@@ -300,6 +446,9 @@
         
         boolean     mDither = DEFAULT_DITHER;        
 
+        int         mEnterFadeDuration;
+        int         mExitFadeDuration;
+
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
@@ -340,6 +489,9 @@
                 
                 mDither = orig.mDither;
 
+                mEnterFadeDuration = orig.mEnterFadeDuration;
+                mExitFadeDuration = orig.mExitFadeDuration;
+
             } else {
                 mDrawables = new Drawable[10];
                 mNumChildren = 0;
@@ -476,6 +628,22 @@
             }
         }
 
+        public final void setEnterFadeDuration(int duration) {
+            mEnterFadeDuration = duration;
+        }
+
+        public final int getEnterFadeDuration() {
+            return mEnterFadeDuration;
+        }
+
+        public final void setExitFadeDuration(int duration) {
+            mExitFadeDuration = duration;
+        }
+
+        public final int getExitFadeDuration() {
+            return mExitFadeDuration;
+        }
+
         public final int getOpacity() {
             if (mHaveOpacity) {
                 return mOpacity;
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 239be40..384ca81 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -20,6 +20,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -44,6 +45,7 @@
  * @attr ref android.R.styleable#DrawableStates_state_checkable
  * @attr ref android.R.styleable#DrawableStates_state_checked
  * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
  * @attr ref android.R.styleable#DrawableStates_state_active
  * @attr ref android.R.styleable#DrawableStates_state_single
  * @attr ref android.R.styleable#DrawableStates_state_first
@@ -52,6 +54,9 @@
  * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class StateListDrawable extends DrawableContainer {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "StateListDrawable";
+
     /**
      * To be proper, we should have a getter for dither (and alpha, etc.)
      * so that proxy classes like this can save/restore their delegates'
@@ -93,6 +98,8 @@
     @Override
     protected boolean onStateChange(int[] stateSet) {
         int idx = mStateListState.indexOfStateSet(stateSet);
+        if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states "
+                + Arrays.toString(stateSet) + " found " + idx);
         if (idx < 0) {
             idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);
         }
@@ -117,6 +124,10 @@
                 com.android.internal.R.styleable.StateListDrawable_variablePadding, false));
         mStateListState.setConstantSize(a.getBoolean(
                 com.android.internal.R.styleable.StateListDrawable_constantSize, false));
+        mStateListState.setEnterFadeDuration(a.getInt(
+                com.android.internal.R.styleable.StateListDrawable_enterFadeDuration, 0));
+        mStateListState.setExitFadeDuration(a.getInt(
+                com.android.internal.R.styleable.StateListDrawable_exitFadeDuration, 0));
 
         setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither,
                                DEFAULT_DITHER));
@@ -251,7 +262,7 @@
     }
 
     static final class StateListState extends DrawableContainerState {
-        private int[][] mStateSets;
+        int[][] mStateSets;
 
         StateListState(StateListState orig, StateListDrawable owner, Resources res) {
             super(orig, owner, res);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 855a4e0..09e01f6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -260,25 +260,25 @@
     const GLuint previousFbo = mSnapshot->fbo;
     const int count = saveSnapshot(flags);
 
-    int alpha = 255;
-    SkXfermode::Mode mode;
+    if (!mSnapshot->invisible) {
+        int alpha = 255;
+        SkXfermode::Mode mode;
 
-    if (p) {
-        alpha = p->getAlpha();
-        if (!mCaches.extensions.hasFramebufferFetch()) {
-            const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
-            if (!isMode) {
-                // Assume SRC_OVER
-                mode = SkXfermode::kSrcOver_Mode;
+        if (p) {
+            alpha = p->getAlpha();
+            if (!mCaches.extensions.hasFramebufferFetch()) {
+                const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
+                if (!isMode) {
+                    // Assume SRC_OVER
+                    mode = SkXfermode::kSrcOver_Mode;
+                }
+            } else {
+                mode = getXfermode(p->getXfermode());
             }
         } else {
-            mode = getXfermode(p->getXfermode());
+            mode = SkXfermode::kSrcOver_Mode;
         }
-    } else {
-        mode = SkXfermode::kSrcOver_Mode;
-    }
 
-    if (!mSnapshot->previous->invisible) {
         createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo);
     }
 
@@ -379,8 +379,7 @@
             bounds.getHeight() > mCaches.maxTextureSize) {
         snapshot->invisible = true;
     } else {
-        snapshot->invisible = snapshot->previous->invisible ||
-                (alpha <= ALPHA_THRESHOLD && fboLayer);
+        snapshot->invisible = snapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
     }
 
     // Bail out if we won't draw in this snapshot
@@ -1011,6 +1010,9 @@
 }
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
+    // No need to check against the clip, we fill the clip region
+    if (mSnapshot->invisible) return;
+
     Rect& clip(*mSnapshot->clipRect);
     clip.snapToPixelBoundaries();
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 4644a7c..50d10bf 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -219,7 +219,7 @@
     }
 
     class WaveViewMethods implements WaveView.OnTriggerListener {
-        private static final int WAIT_FOR_ANIMATION_TIMEOUT = 500;
+        private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0;
         private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
 
         /** {@inheritDoc} */
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 185d413..c3ad9e6 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -261,8 +261,10 @@
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
 
     //***** Member Variables
+    protected int mId;
     protected int mTag;
     protected PhoneBase phone;
+    protected RetryManager mRetryMgr;
     protected int cid;
     protected LinkProperties mLinkProperties = new LinkProperties();
     protected LinkCapabilities mCapabilities = new LinkCapabilities();
@@ -285,10 +287,11 @@
 
 
    //***** Constructor
-    protected DataConnection(PhoneBase phone, String name) {
+    protected DataConnection(PhoneBase phone, String name, RetryManager rm) {
         super(name);
         if (DBG) log("DataConnection constructor E");
         this.phone = phone;
+        mRetryMgr = rm;
         this.cid = -1;
         clearSettings();
 
@@ -358,8 +361,8 @@
 
         if (dp.onCompletedMsg != null) {
             Message msg = dp.onCompletedMsg;
-            log(String.format("msg.what=%d msg.obj=%s",
-                    msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
+            log(String.format("msg=%s msg.obj=%s", msg.toString(),
+                    ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
             AsyncResult.forMessage(msg);
             msg.sendToTarget();
         }
@@ -372,6 +375,10 @@
         clearSettings();
     }
 
+    public RetryManager getRetryMgr() {
+        return mRetryMgr;
+    }
+
     /**
      * Clear all settings called when entering mInactiveState.
      */
@@ -857,13 +864,13 @@
 
     /**
      * Connect to the apn and return an AsyncResult in onCompletedMsg.
-     * Used for cellular networks that use Acess Point Names (APN) such
+     * Used for cellular networks that use Acesss 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
+     * @param apn is the Access Point Name to connect to
      */
     public void connect(Message onCompletedMsg, ApnSetting apn) {
         sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
@@ -915,6 +922,13 @@
     }
 
     /**
+     * Get the DataConnection ID
+     */
+    public int getDataConnectionId() {
+        return mId;
+    }
+
+    /**
      * Return the LinkProperties for the connection.
      *
      * @return a copy of the LinkProperties, is never null.
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 52839be..f8812ec 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -16,27 +16,38 @@
 
 package com.android.internal.telephony;
 
+import com.android.internal.telephony.cdma.CDMAPhone;
+
 import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.net.IConnectivityManager;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.ServiceManager;
+import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.ArrayList;
-
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * {@hide}
- *
  */
 public abstract class DataConnectionTracker extends Handler {
-    protected static final boolean DBG = false;
-    protected final String LOG_TAG = "DataConnectionTracker";
+    protected static final boolean DBG = true;
 
     /**
      * IDLE: ready to start data connection setup, default state
@@ -121,9 +132,10 @@
     protected boolean mMasterDataEnabled = true;
 
     protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
+
     protected int enabledCount = 0;
 
-    /* Currently requested APN type */
+    /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
     protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
 
     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
@@ -165,20 +177,27 @@
     // represents an invalid IP address
     protected static final String NULL_IP = "0.0.0.0";
 
+    // TODO: See if we can remove INTENT_RECONNECT_ALARM
+    //       having to have different values for GSM and
+    //       CDMA. If so we can then remove the need for
+    //       getActionIntentReconnectAlarm.
+    protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
 
     // member variables
-    protected PhoneBase phone;
-    protected Activity activity = Activity.NONE;
-    protected State state = State.IDLE;
+    protected PhoneBase mPhone;
+    protected Activity mActivity = Activity.NONE;
+    protected State mState = State.IDLE;
     protected Handler mDataConnectionTracker = null;
 
 
-    protected long txPkts, rxPkts, sentSinceLastRecv;
-    protected int netStatPollPeriod;
+    protected long mTxPkts;
+    protected long mRxPkts;
+    protected long mSentSinceLastRecv;
+    protected int mNetStatPollPeriod;
     protected int mNoRecvPollCount = 0;
-    protected boolean netStatPollEnabled = false;
+    protected boolean mNetStatPollEnabled = false;
 
-    /** Manage the behavior of data retry after failure */
+    /** 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
@@ -188,37 +207,125 @@
     protected PendingIntent mReconnectIntent = null;
 
     /** CID of active data connection */
-    protected int cidActive;
+    protected int mCidActive;
 
     /** indication of our availability (preconditions to trysetupData are met) **/
     protected boolean mAvailability = false;
 
+    // When false we will not auto attach and manully attaching is required.
+    protected boolean mAutoAttachOnCreation = false;
+
+    // State of screen
+    // (TODO: Reconsider tying directly to screen, maybe this is
+    //        really a lower power mode")
+    protected boolean mIsScreenOn = true;
+
     /** The link properties (dns, gateway, ip, etc) */
     protected LinkProperties mLinkProperties = new LinkProperties();
 
     /** The link capabilities */
     protected LinkCapabilities mLinkCapabilities = new LinkCapabilities();
 
+    /** Allows the generation of unique Id's for DataConnection objects */
+    protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
+
+    /** The data connections. */
+    protected HashMap<Integer, DataConnection> mDataConnections =
+        new HashMap<Integer, DataConnection>();
+
+    protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
+    {
+        @Override
+        public void onReceive(Context context, Intent intent)
+        {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_SCREEN_ON)) {
+                mIsScreenOn = true;
+                stopNetStatPoll();
+                startNetStatPoll();
+            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+                mIsScreenOn = false;
+                stopNetStatPoll();
+                startNetStatPoll();
+            } else if (action.equals(getActionIntentReconnectAlarm())) {
+                log("Reconnect alarm. Previous state was " + mState);
+
+                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);
+                mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
+            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+                final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+
+                if (!enabled) {
+                    // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
+                    // quit and won't report disconnected until next enabling.
+                    mIsWifiConnected = false;
+                }
+            }
+        }
+    };
+
     /**
      * Default constructor
      */
     protected DataConnectionTracker(PhoneBase phone) {
         super();
-        this.phone = phone;
+        mPhone = phone;
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(getActionIntentReconnectAlarm());
+        filter.addAction(Intent.ACTION_SCREEN_ON);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+
+        // TODO: Why is this registering the phone as the receiver of the intent
+        //       and not its own handler?
+        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
+
+        // This preference tells us 1) initial condition for "dataEnabled",
+        // and 2) whether the RIL will setup the baseband to auto-PS attach.
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
+        boolean dataEnabledSetting = true;
+        try {
+            dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager.
+                    getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled();
+        } catch (Exception e) {
+            // nothing to do - use the old behavior and leave data on
+        }
+        dataEnabled[APN_DEFAULT_ID] =
+                !sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false) &&
+                dataEnabledSetting;
+        if (dataEnabled[APN_DEFAULT_ID]) {
+            enabledCount++;
+        }
+        mAutoAttachOnCreation = dataEnabled[APN_DEFAULT_ID];
     }
 
-    public abstract void dispose();
+    public void dispose() {
+        mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
+    }
 
     public Activity getActivity() {
-        return activity;
+        return mActivity;
     }
 
     public State getState() {
-        return state;
+        return mState;
     }
 
     public String getStateInString() {
-        switch (state) {
+        switch (mState) {
             case IDLE:          return "IDLE";
             case INITING:       return "INIT";
             case CONNECTING:    return "CING";
@@ -231,6 +338,14 @@
     }
 
     /**
+     * @return the data connections
+     */
+    public ArrayList<DataConnection> getAllDataConnections() {
+        /** TODO: change return type to Collection? */
+        return new ArrayList<DataConnection>(mDataConnections.values());
+    }
+
+    /**
      * The data connection is expected to be setup while device
      *  1. has Icc card
      *  2. registered for data service
@@ -246,9 +361,9 @@
     //  the shared values.  If it is not, then update it.
     public void setDataOnRoamingEnabled(boolean enabled) {
         if (getDataOnRoamingEnabled() != enabled) {
-            Settings.Secure.putInt(phone.getContext().getContentResolver(),
+            Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
                 Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
-            if (phone.getServiceState().getRoaming()) {
+            if (mPhone.getServiceState().getRoaming()) {
                 if (enabled) {
                     mRetryMgr.resetRetryCount();
                 }
@@ -257,16 +372,19 @@
         }
     }
 
-    //Retrieve the data roaming setting from the shared preferences.
+    // Retrieve the data roaming setting from the shared preferences.
     public boolean getDataOnRoamingEnabled() {
         try {
-            return Settings.Secure.getInt(phone.getContext().getContentResolver(),
-                Settings.Secure.DATA_ROAMING) > 0;
+            return Settings.Secure.getInt(
+                    mPhone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING) > 0;
         } catch (SettingNotFoundException snfe) {
             return false;
         }
     }
 
+
+    protected abstract String getActionIntentReconnectAlarm();
+
     // abstract handler methods
     protected abstract boolean onTrySetupData(String reason);
     protected abstract void onRoamingOff();
@@ -274,14 +392,14 @@
     protected abstract void onRadioAvailable();
     protected abstract void onRadioOffOrNotAvailable();
     protected abstract void onDataSetupComplete(AsyncResult ar);
-    protected abstract void onDisconnectDone(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);
 
     @Override
-    public void handleMessage (Message msg) {
+    public void handleMessage(Message msg) {
         switch (msg.what) {
 
             case EVENT_ENABLE_NEW_APN:
@@ -291,7 +409,7 @@
             case EVENT_TRY_SETUP_DATA:
                 String reason = null;
                 if (msg.obj instanceof String) {
-                    reason = (String)msg.obj;
+                    reason = (String) msg.obj;
                 }
                 onTrySetupData(reason);
                 break;
@@ -316,12 +434,13 @@
                 break;
 
             case EVENT_DATA_SETUP_COMPLETE:
-                cidActive = msg.arg1;
+                mCidActive = msg.arg1;
                 onDataSetupComplete((AsyncResult) msg.obj);
                 break;
 
             case EVENT_DISCONNECT_DONE:
-                onDisconnectDone((AsyncResult) msg.obj);
+                log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
+                onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
                 break;
 
             case EVENT_VOICE_CALL_STARTED:
@@ -334,7 +453,7 @@
 
             case EVENT_CLEAN_UP_CONNECTION:
                 boolean tearDown = (msg.arg1 == 0) ? false : true;
-                onCleanUpConnection(tearDown, (String)msg.obj);
+                onCleanUpConnection(tearDown, (String) msg.obj);
                 break;
 
             case EVENT_SET_MASTER_DATA_ENABLE:
@@ -354,8 +473,9 @@
 
     /**
      * Report the current state of data connectivity (enabled or disabled)
+     *
      * @return {@code false} if data connectivity has been explicitly disabled,
-     * {@code true} otherwise.
+     *         {@code true} otherwise.
      */
     public synchronized boolean getDataEnabled() {
         return dataEnabled[APN_DEFAULT_ID];
@@ -363,8 +483,9 @@
 
     /**
      * Report on whether data connectivity is enabled
+     *
      * @return {@code false} if data connectivity has been explicitly disabled,
-     * {@code true} otherwise.
+     *         {@code true} otherwise.
      */
     public boolean getAnyDataEnabled() {
         return (enabledCount != 0);
@@ -378,6 +499,8 @@
 
     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;
@@ -407,7 +530,7 @@
         case APN_HIPRI_ID:
             return Phone.APN_TYPE_HIPRI;
         default:
-            Log.e(LOG_TAG, "Unknown id (" + id + ") in apnIdToType");
+            log("Unknown id (" + id + ") in apnIdToType");
             return Phone.APN_TYPE_DEFAULT;
         }
     }
@@ -420,8 +543,6 @@
 
     protected abstract String getActiveApnString();
 
-    public abstract ArrayList<DataConnection> getAllDataConnections();
-
     protected abstract void setState(State s);
 
     protected LinkProperties getLinkProperties(String apnType) {
@@ -467,33 +588,34 @@
     protected void notifyDataConnection(String reason) {
         for (int id = 0; id < APN_NUM_TYPES; id++) {
             if (dataEnabled[id]) {
-                phone.notifyDataConnection(reason, apnIdToType(id));
+                mPhone.notifyDataConnection(reason, apnIdToType(id));
             }
         }
         notifyDataAvailability(reason);
     }
 
-    // a new APN has gone active and needs to send events to catch up with the current condition
+    // a new APN has gone active and needs to send events to catch up with the
+    // current condition
     private void notifyApnIdUpToCurrent(String reason, int apnId) {
-        switch (state) {
+        switch (mState) {
             case IDLE:
             case INITING:
                 break;
             case CONNECTING:
             case SCANNING:
-                phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
+                mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
                 break;
             case CONNECTED:
             case DISCONNECTING:
-                phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
-                phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED);
+                mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
+                mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED);
                 break;
         }
     }
 
     // since we normally don't send info to a disconnected APN, we need to do this specially
     private void notifyApnIdDisconnected(String reason, int apnId) {
-        phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED);
+        mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED);
     }
 
     // disabled apn's still need avail/unavail notificiations - send them out
@@ -526,10 +648,10 @@
      * @return {@code true} if data connectivity is possible, {@code false} otherwise.
      */
     protected boolean isDataPossible() {
-        boolean possible = (isDataAllowed() &&
-            !(getDataEnabled() && (state == State.FAILED || state == State.IDLE)));
+        boolean possible = (isDataAllowed()
+                && !(getDataEnabled() && (mState == State.FAILED || mState == State.IDLE)));
         if (!possible && DBG && isDataAllowed()) {
-            log("Data not possible.  No coverage: dataState = " + state);
+            log("Data not possible.  No coverage: dataState = " + mState);
         }
         return possible;
     }
@@ -549,13 +671,13 @@
 
     /**
      * Ensure that we are connected to an APN of the specified type.
-     * @param type the APN type (currently the only valid values
-     * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
-     * @return the result of the operation. Success is indicated by
-     * a return value of either {@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.
+     *
+     * @param type the APN type (currently the only valid values are
+     *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
+     * @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.
      */
     public synchronized int enableApnType(String type) {
         int id = apnTypeToId(type);
@@ -564,13 +686,12 @@
         }
 
         if (DBG) {
-            Log.d(LOG_TAG, "enableApnType(" + type + "), isApnTypeActive = "
-                    + isApnTypeActive(type) + ", isApnIdEnabled =" + isApnIdEnabled(id) +
-                    " and state = " + state);
+            log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type)
+                    + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState);
         }
 
         if (!isApnTypeAvailable(type)) {
-            if (DBG) Log.d(LOG_TAG, "type not available");
+            if (DBG) log("type not available");
             return Phone.APN_TYPE_NOT_AVAILABLE;
         }
 
@@ -583,15 +704,21 @@
     }
 
     /**
-     * The APN of the specified type is no longer needed. Ensure that if
-     * use of the default APN has not been explicitly disabled, we are connected
-     * to the default APN.
+     * The APN of the specified type is no longer needed. Ensure that if use of
+     * the default APN has not been explicitly disabled, we are connected to the
+     * default APN.
+     *
      * @param type the APN type. The only valid values are currently
-     * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
-     * @return
+     *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
+     * @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 disconnected. A {@code
+     *         Phone.APN_REQUEST_FAILED} is returned if the type parameter is
+     *         invalid or if the apn wasn't enabled.
      */
     public synchronized int disableApnType(String type) {
-        if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
+        if (DBG) log("disableApnType(" + type + ")");
         int id = apnTypeToId(type);
         if (id == APN_INVALID_ID) {
             return Phone.APN_REQUEST_FAILED;
@@ -614,8 +741,8 @@
 
     private void setEnabled(int id, boolean enable) {
         if (DBG) {
-            Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = "
-                    + dataEnabled[id] + " and enabledCount = " + enabledCount);
+            log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id]
+                    + " and enabledCount = " + enabledCount);
         }
         Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
         msg.arg1 = id;
@@ -625,9 +752,10 @@
 
     protected synchronized void onEnableApn(int apnId, int enabled) {
         if (DBG) {
-            Log.d(LOG_TAG, "EVENT_APN_ENABLE_REQUEST " + apnId + ", " + enabled);
-            Log.d(LOG_TAG, " dataEnabled = " + dataEnabled[apnId] + ", enabledCount = "
-                    + enabledCount + ", isApnTypeActive = " + isApnTypeActive(apnIdToType(apnId)));
+            log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
+                    ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] +
+                    ", enabledCount = " + enabledCount + ", isApnTypeActive = " +
+                    isApnTypeActive(apnIdToType(apnId)));
         }
         if (enabled == ENABLED) {
             if (!dataEnabled[apnId]) {
@@ -676,18 +804,22 @@
     }
 
     /**
-     * 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.
-     * <p>This operation only affects the default APN, and if the same APN is
-     * currently being used for MMS traffic, the teardown will not happen
-     * even when {@code enable} is {@code false}.</p>
-     * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
+     * 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.
+     * <p>
+     * This operation only affects the default APN, and if the same APN is
+     * currently being used for MMS traffic, the teardown will not happen even
+     * when {@code enable} is {@code false}.
+     * </p>
+     *
+     * @param enable indicates whether to enable ({@code true}) or disable (
+     *            {@code false}) data
      * @return {@code true} if the operation succeeded
      */
     public boolean setDataEnabled(boolean enable) {
-        if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")");
+        if (DBG)
+            log("setDataEnabled(" + enable + ")");
 
         Message msg = obtainMessage(EVENT_SET_MASTER_DATA_ENABLE);
         msg.arg1 = (enable ? ENABLED : DISABLED);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 95cb1c6..8072c44 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -23,6 +23,7 @@
 import com.android.internal.telephony.gsm.ApnSetting;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.RetryManager;
 
 /**
  * {@hide}
@@ -39,23 +40,27 @@
 
 
     // ***** Constructor
-    private CdmaDataConnection(CDMAPhone phone, String name) {
-        super(phone, name);
+    private CdmaDataConnection(CDMAPhone phone, String name, RetryManager rm) {
+        super(phone, name, rm);
     }
 
     /**
      * Create the connection object
      *
-     * @param phone
+     * @param phone the Phone
+     * @param id the connection id
+     * @param rm the RetryManager
      * @return CdmaDataConnection that was created.
      */
-    static CdmaDataConnection makeDataConnection(CDMAPhone phone) {
+    static CdmaDataConnection makeDataConnection(CDMAPhone phone, int id, RetryManager rm) {
         synchronized (mCountLock) {
             mCount += 1;
         }
-        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount);
+        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone,
+                "CdmaDataConnection-" + mCount, rm);
         cdmaDc.start();
         if (DBG) cdmaDc.log("Made " + cdmaDc.getName());
+        cdmaDc.mId = id;
         return cdmaDc;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index e499e95..7c652c5 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -18,21 +18,13 @@
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.net.IConnectivityManager;
-import android.net.NetworkInfo;
 import android.net.TrafficStats;
-import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
 import android.os.Message;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.preference.PreferenceManager;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.cdma.CdmaCellLocation;
@@ -46,6 +38,7 @@
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.gsm.ApnSetting;
 import com.android.internal.telephony.Phone;
 
@@ -59,20 +52,11 @@
 
     private CDMAPhone mCdmaPhone;
 
-    // Indicates baseband will not auto-attach
-    private boolean noAutoAttach = false;
-    private boolean mIsScreenOn = true;
-
     //useful for debugging
-    boolean failNextConnect = false;
+    boolean mFailNextConnect = false;
 
-    /**
-     * dataConnectionList holds all the Data connection
-     */
-    private ArrayList<DataConnection> dataConnectionList;
-
-    /** Currently active CdmaDataConnection */
-    private CdmaDataConnection mActiveDataConnection;
+    /** The DataConnection being setup */
+    private CdmaDataConnection mPendingDataConnection;
 
     private boolean mPendingRestartRadio = false;
     private static final int TIME_DELAYED_TO_RESTART_RADIO =
@@ -83,10 +67,8 @@
      */
     private static final int DATA_CONNECTION_POOL_SIZE = 1;
 
-    private static final int POLL_CONNECTION_MILLIS = 5 * 1000;
     private static final String INTENT_RECONNECT_ALARM =
-            "com.android.internal.telephony.cdma-reconnect";
-    private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
+        "com.android.internal.telephony.cdma-reconnect";
 
     /**
      * Constants for the data connection activity:
@@ -110,49 +92,6 @@
     // if we have no active Apn this is null
     protected ApnSetting mActiveApn;
 
-    // Possibly promote to base class, the only difference is
-    // the INTENT_RECONNECT_ALARM action is a different string.
-    // Do consider technology changes if it is promoted.
-    BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
-    {
-        @Override
-        public void onReceive(Context context, Intent intent)
-        {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_SCREEN_ON)) {
-                mIsScreenOn = true;
-                stopNetStatPoll();
-                startNetStatPoll();
-            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
-                mIsScreenOn = false;
-                stopNetStatPoll();
-                startNetStatPoll();
-            } else if (action.equals((INTENT_RECONNECT_ALARM))) {
-                Log.d(LOG_TAG, "Data reconnect alarm. Previous state was " + state);
-
-                String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-                if (state == State.FAILED) {
-                    cleanUpConnection(false, reason);
-                }
-                trySetupData(reason);
-            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                final android.net.NetworkInfo networkInfo = (NetworkInfo)
-                        intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-                mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
-            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
-                if (!enabled) {
-                    // when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION
-                    // quit and wont report disconnected til next enalbing.
-                    mIsWifiConnected = false;
-                }
-            }
-        }
-    };
-
-
     /* Constructor */
 
     CdmaDataConnectionTracker(CDMAPhone p) {
@@ -172,79 +111,49 @@
         p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
         p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null);
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(INTENT_RECONNECT_ALARM);
-        filter.addAction(Intent.ACTION_SCREEN_ON);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-
-        // TODO: Why is this registering the phone as the receiver of the intent
-        //       and not its own handler?
-        p.getContext().registerReceiver(mIntentReceiver, filter, null, p);
-
         mDataConnectionTracker = this;
 
         createAllDataConnectionList();
-
-        // This preference tells us 1) initial condition for "dataEnabled",
-        // and 2) whether the RIL will setup the baseband to auto-PS attach.
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
-
-        boolean dataEnabledSetting = true;
-        try {
-            dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager.
-                    getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled();
-        } catch (Exception e) {
-            // nothing to do - use the old behavior and leave data on
-        }
-        dataEnabled[APN_DEFAULT_ID] =
-                !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false) &&
-                dataEnabledSetting;
-        if (dataEnabled[APN_DEFAULT_ID]) {
-            enabledCount++;
-        }
-        noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
-
-        if (!mRetryMgr.configure(SystemProperties.get("ro.cdma.data_retry_config"))) {
-            if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
-                // Should never happen, log an error and default to a simple linear sequence.
-                Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
-                        + DEFAULT_DATA_RETRY_CONFIG);
-                mRetryMgr.configure(20, 2000, 1000);
-            }
-        }
     }
 
+    @Override
     public void dispose() {
+        super.dispose();
+
         // Unregister from all events
-        phone.mCM.unregisterForAvailable(this);
-        phone.mCM.unregisterForOffOrNotAvailable(this);
+        mPhone.mCM.unregisterForAvailable(this);
+        mPhone.mCM.unregisterForOffOrNotAvailable(this);
         mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this);
-        phone.mCM.unregisterForNVReady(this);
-        phone.mCM.unregisterForDataStateChanged(this);
+        mPhone.mCM.unregisterForNVReady(this);
+        mPhone.mCM.unregisterForDataStateChanged(this);
         mCdmaPhone.mCT.unregisterForVoiceCallEnded(this);
         mCdmaPhone.mCT.unregisterForVoiceCallStarted(this);
         mCdmaPhone.mSST.unregisterForCdmaDataConnectionAttached(this);
         mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this);
         mCdmaPhone.mSST.unregisterForRoamingOn(this);
         mCdmaPhone.mSST.unregisterForRoamingOff(this);
-        phone.mCM.unregisterForCdmaOtaProvision(this);
+        mPhone.mCM.unregisterForCdmaOtaProvision(this);
 
-        phone.getContext().unregisterReceiver(this.mIntentReceiver);
         destroyAllDataConnectionList();
     }
 
+    @Override
     protected void finalize() {
-        if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized");
+        if(DBG) log("CdmaDataConnectionTracker finalized");
     }
 
+    @Override
+    protected String getActionIntentReconnectAlarm() {
+        return INTENT_RECONNECT_ALARM;
+    }
+
+    @Override
     protected void setState(State s) {
         if (DBG) log ("setState: " + s);
-        if (state != s) {
+        if (mState != s) {
             EventLog.writeEvent(EventLogTags.CDMA_DATA_STATE_CHANGE,
-                    state.toString(), s.toString());
-            state = s;
+                    mState.toString(), s.toString());
+            mState = s;
         }
     }
 
@@ -263,6 +172,7 @@
         return false;
     }
 
+    @Override
     protected String[] getActiveApnTypes() {
         String[] result;
         if (mActiveApn != null) {
@@ -274,6 +184,7 @@
         return result;
     }
 
+    @Override
     protected String getActiveApnString() {
         return null;
     }
@@ -287,45 +198,51 @@
      *
      * @return false while no data connection if all above requirements are met.
      */
+    @Override
     public boolean isDataConnectionAsDesired() {
-        boolean roaming = phone.getServiceState().getRoaming();
+        boolean roaming = mPhone.getServiceState().getRoaming();
 
-        if (((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) ||
+        if (((mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) ||
                  mCdmaPhone.mRuimRecords.getRecordsLoaded()) &&
                 (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() ==
                  ServiceState.STATE_IN_SERVICE) &&
                 (!roaming || getDataOnRoamingEnabled()) &&
                 !mIsWifiConnected ) {
-            return (state == State.CONNECTED);
+            return (mState == State.CONNECTED);
         }
         return true;
     }
 
+    @Override
     protected boolean isDataAllowed() {
         int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState();
-        boolean roaming = (phone.getServiceState().getRoaming() && !getDataOnRoamingEnabled());
+        boolean roaming = (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled());
         boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState();
 
-        boolean allowed = (psState == ServiceState.STATE_IN_SERVICE &&
-                (phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY ||
-                 mCdmaPhone.mRuimRecords.getRecordsLoaded()) &&
-                (mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
-                 phone.getState() == Phone.State.IDLE) &&
-                !roaming &&
-                mMasterDataEnabled &&
-                desiredPowerState &&
-                !mPendingRestartRadio &&
-                !mCdmaPhone.needsOtaServiceProvisioning());
+        boolean allowed =
+                    (psState == ServiceState.STATE_IN_SERVICE ||
+                            mAutoAttachOnCreation) &&
+                    (mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY ||
+                            mCdmaPhone.mRuimRecords.getRecordsLoaded()) &&
+                    (mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
+                            mPhone.getState() == Phone.State.IDLE) &&
+                    !roaming &&
+                    mMasterDataEnabled &&
+                    desiredPowerState &&
+                    !mPendingRestartRadio &&
+                    !mCdmaPhone.needsOtaServiceProvisioning();
         if (!allowed && DBG) {
             String reason = "";
-            if (psState != ServiceState.STATE_IN_SERVICE) reason += " - psState= " + psState;
-            if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY &&
-                    !mCdmaPhone.mRuimRecords.getRecordsLoaded()) {
-                reason += " - radioState= " + phone.mCM.getRadioState() + " - RUIM not loaded";
+            if (!((psState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
+                reason += " - psState= " + psState;
             }
-            if (phone.getState() != Phone.State.IDLE &&
+            if (!(mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY ||
+                    mCdmaPhone.mRuimRecords.getRecordsLoaded())) {
+                reason += " - radioState= " + mPhone.mCM.getRadioState() + " - RUIM not loaded";
+            }
+            if (mPhone.getState() != Phone.State.IDLE &&
                     mCdmaPhone.mSST.isConcurrentVoiceAndData()) {
-                reason += " - concurrentVoiceAndData not allowed and state= " + phone.getState();
+                reason += " - concurrentVoiceAndData not allowed and state= " + mPhone.getState();
             }
             if (roaming) reason += " - Roaming";
             if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false";
@@ -340,22 +257,22 @@
     private boolean trySetupData(String reason) {
         if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
 
-        if (phone.getSimulatedRadioControl() != null) {
+        if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
             setState(State.CONNECTED);
             notifyDataConnection(reason);
             notifyOffApnsOfAvailability(reason, true);
 
-            Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected");
+            log("(fix?) We're on the simulator; assuming data is connected");
             return true;
         }
 
         int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState();
-        boolean roaming = phone.getServiceState().getRoaming();
+        boolean roaming = mPhone.getServiceState().getRoaming();
         boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState();
 
-        if ((state == State.IDLE || state == State.SCANNING) &&
+        if ((mState == State.IDLE || mState == State.SCANNING) &&
                 isDataAllowed() && getAnyDataEnabled()) {
             boolean retValue = setupData(reason);
             notifyOffApnsOfAvailability(reason, retValue);
@@ -367,13 +284,12 @@
     }
 
     /**
-     * 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 DataConnection should be
-     * disconnected.
-     * @param reason reason for the clean up.
+     * Cleanup all connections.
+     *
+     * TODO: Cleanup only a specified connection passed as a parameter.
+     *
+     * @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("cleanUpConnection: reason: " + reason);
@@ -381,7 +297,7 @@
         // Clear the reconnect alarm, if set.
         if (mReconnectIntent != null) {
             AlarmManager am =
-                (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
+                (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
             am.cancel(mReconnectIntent);
             mReconnectIntent = null;
         }
@@ -390,11 +306,12 @@
         notifyDataAvailability(reason);
 
         boolean notificationDeferred = false;
-        for (DataConnection conn : dataConnectionList) {
+        for (DataConnection conn : mDataConnections.values()) {
             if(conn != null) {
                 if (tearDown) {
                     if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
-                    conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
+                    conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE,
+                            conn.getDataConnectionId(), 0, reason));
                     notificationDeferred = true;
                 } else {
                     if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
@@ -413,10 +330,9 @@
     }
 
     private CdmaDataConnection findFreeDataConnection() {
-        for (DataConnection connBase : dataConnectionList) {
-            CdmaDataConnection conn = (CdmaDataConnection) connBase;
-            if (conn.isInactive()) {
-                return conn;
+        for (DataConnection dc : mDataConnections.values()) {
+            if (dc.isInactive()) {
+                return (CdmaDataConnection) dc;
             }
         }
         return null;
@@ -430,7 +346,8 @@
             return false;
         }
 
-        mActiveDataConnection = conn;
+        /** TODO: We probably want the connection being setup to a parameter passed around */
+        mPendingDataConnection = conn;
         String[] types;
         if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) {
             types = new String[1];
@@ -458,28 +375,31 @@
     }
 
     private void resetPollStats() {
-        txPkts = -1;
-        rxPkts = -1;
-        sentSinceLastRecv = 0;
-        netStatPollPeriod = POLL_NETSTAT_MILLIS;
+        mTxPkts = -1;
+        mRxPkts = -1;
+        mSentSinceLastRecv = 0;
+        mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
         mNoRecvPollCount = 0;
     }
 
+    @Override
     protected void startNetStatPoll() {
-        if (state == State.CONNECTED && netStatPollEnabled == false) {
-            Log.d(LOG_TAG, "[DataConnection] Start poll NetStat");
+        if (mState == State.CONNECTED && mNetStatPollEnabled == false) {
+            log("[DataConnection] Start poll NetStat");
             resetPollStats();
-            netStatPollEnabled = true;
+            mNetStatPollEnabled = true;
             mPollNetStat.run();
         }
     }
 
+    @Override
     protected void stopNetStatPoll() {
-        netStatPollEnabled = false;
+        mNetStatPollEnabled = false;
         removeCallbacks(mPollNetStat);
-        Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat");
+        log("[DataConnection] Stop poll NetStat");
     }
 
+    @Override
     protected void restartRadio() {
         if (DBG) log("Cleanup connection and wait " +
                 (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio");
@@ -496,73 +416,73 @@
 
             Activity newActivity;
 
-            preTxPkts = txPkts;
-            preRxPkts = rxPkts;
+            preTxPkts = mTxPkts;
+            preRxPkts = mRxPkts;
 
-            txPkts = TrafficStats.getMobileTxPackets();
-            rxPkts = TrafficStats.getMobileRxPackets();
+            mTxPkts = TrafficStats.getMobileTxPackets();
+            mRxPkts = TrafficStats.getMobileRxPackets();
 
-            //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts));
+            //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts));
 
-            if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
-                sent = txPkts - preTxPkts;
-                received = rxPkts - preRxPkts;
+            if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
+                sent = mTxPkts - preTxPkts;
+                received = mRxPkts - preRxPkts;
 
                 if ( sent > 0 && received > 0 ) {
-                    sentSinceLastRecv = 0;
+                    mSentSinceLastRecv = 0;
                     newActivity = Activity.DATAINANDOUT;
                 } else if (sent > 0 && received == 0) {
-                    if (phone.getState()  == Phone.State.IDLE) {
-                        sentSinceLastRecv += sent;
+                    if (mPhone.getState()  == Phone.State.IDLE) {
+                        mSentSinceLastRecv += sent;
                     } else {
-                        sentSinceLastRecv = 0;
+                        mSentSinceLastRecv = 0;
                     }
                     newActivity = Activity.DATAOUT;
                 } else if (sent == 0 && received > 0) {
-                    sentSinceLastRecv = 0;
+                    mSentSinceLastRecv = 0;
                     newActivity = Activity.DATAIN;
                 } else if (sent == 0 && received == 0) {
-                    newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE;
+                    newActivity = (mActivity == Activity.DORMANT) ? mActivity : Activity.NONE;
                 } else {
-                    sentSinceLastRecv = 0;
-                    newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE;
+                    mSentSinceLastRecv = 0;
+                    newActivity = (mActivity == Activity.DORMANT) ? mActivity : Activity.NONE;
                 }
 
-                if (activity != newActivity) {
-                    activity = newActivity;
-                    phone.notifyDataActivity();
+                if (mActivity != newActivity && mIsScreenOn) {
+                    mActivity = newActivity;
+                    mPhone.notifyDataActivity();
                 }
             }
 
-            if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) {
+            if (mSentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) {
                 // Packets sent without ack exceeded threshold.
 
                 if (mNoRecvPollCount == 0) {
                     EventLog.writeEvent(
                             EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED,
-                            sentSinceLastRecv);
+                            mSentSinceLastRecv);
                 }
 
                 if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) {
                     mNoRecvPollCount++;
                     // Slow down the poll interval to let things happen
-                    netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS;
+                    mNetStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS;
                 } else {
-                    if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) +
+                    if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) +
                                         " pkts since last received");
                     // We've exceeded the threshold.  Restart the radio.
-                    netStatPollEnabled = false;
+                    mNetStatPollEnabled = false;
                     stopNetStatPoll();
                     restartRadio();
                     EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, NO_RECV_POLL_LIMIT);
                 }
             } else {
                 mNoRecvPollCount = 0;
-                netStatPollPeriod = POLL_NETSTAT_MILLIS;
+                mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
             }
 
-            if (netStatPollEnabled) {
-                mDataConnectionTracker.postDelayed(this, netStatPollPeriod);
+            if (mNetStatPollEnabled) {
+                mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
             }
         }
     };
@@ -594,7 +514,7 @@
     }
 
     private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
-        if (state == State.FAILED) {
+        if (mState == State.FAILED) {
             /**
              * For now With CDMA we never try to reconnect on
              * error and instead just continue to retry
@@ -602,15 +522,15 @@
              * TODO: Make this configurable?
              */
             int nextReconnectDelay = mRetryMgr.getRetryTimer();
-            Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for "
+            log("Data Connection activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
             AlarmManager am =
-                (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
+                (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(
-                    phone.getContext(), 0, intent, 0);
+                    mPhone.getContext(), 0, intent, 0);
             am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
                     mReconnectIntent);
@@ -618,7 +538,7 @@
             mRetryMgr.increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
-                Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification "
+                log("NOT Posting Data Connection Unavailable notification "
                                 + "-- likely transient error");
             } else {
                 notifyNoData(lastFailCauseCode);
@@ -639,14 +559,14 @@
     }
 
     protected void onRecordsLoaded() {
-        if (state == State.FAILED) {
+        if (mState == State.FAILED) {
             cleanUpConnection(false, null);
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onNVReady() {
-        if (state == State.FAILED) {
+        if (mState == State.FAILED) {
             cleanUpConnection(false, null);
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
@@ -657,12 +577,13 @@
      */
     @Override
     protected void onEnableNewApn() {
-          cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
+        cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
     }
 
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected boolean onTrySetupData(String reason) {
         return trySetupData(reason);
     }
@@ -670,6 +591,7 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected void onRoamingOff() {
         trySetupData(Phone.REASON_ROAMING_OFF);
     }
@@ -677,6 +599,7 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected void onRoamingOn() {
         if (getDataOnRoamingEnabled()) {
             trySetupData(Phone.REASON_ROAMING_ON);
@@ -689,19 +612,20 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected void onRadioAvailable() {
-        if (phone.getSimulatedRadioControl() != null) {
+        if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
             setState(State.CONNECTED);
             notifyDataConnection(null);
 
-            Log.i(LOG_TAG, "We're on the simulator; assuming data is connected");
+            log("We're on the simulator; assuming data is connected");
         }
 
         notifyDataAvailability(null);
 
-        if (state != State.IDLE) {
+        if (mState != State.IDLE) {
             cleanUpConnection(true, null);
         }
     }
@@ -709,13 +633,14 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected void onRadioOffOrNotAvailable() {
         mRetryMgr.resetRetryCount();
 
-        if (phone.getSimulatedRadioControl() != null) {
+        if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
-            Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless");
+            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);
@@ -725,6 +650,7 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected void onDataSetupComplete(AsyncResult ar) {
         String reason = null;
         if (ar.userObj instanceof String) {
@@ -733,8 +659,8 @@
 
         if (ar.exception == null) {
             // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
-            mLinkProperties = getLinkProperties(mActiveDataConnection);
-            mLinkCapabilities = getLinkCapabilities(mActiveDataConnection);
+            mLinkProperties = getLinkProperties(mPendingDataConnection);
+            mLinkCapabilities = getLinkCapabilities(mPendingDataConnection);
 
             // everything is setup
             notifyDefaultData(reason);
@@ -754,8 +680,9 @@
     /**
      * Called when EVENT_DISCONNECT_DONE is received.
      */
-    protected void onDisconnectDone(AsyncResult ar) {
-        if(DBG) log("EVENT_DISCONNECT_DONE");
+    @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;
@@ -799,8 +726,9 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected void onVoiceCallStarted() {
-        if (state == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) {
+        if (mState == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) {
             stopNetStatPoll();
             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
             notifyDataAvailability(Phone.REASON_VOICE_CALL_STARTED);
@@ -810,8 +738,9 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
+    @Override
     protected void onVoiceCallEnded() {
-        if (state == State.CONNECTED) {
+        if (mState == State.CONNECTED) {
             if (!mCdmaPhone.mSST.isConcurrentVoiceAndData()) {
                 startNetStatPoll();
                 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
@@ -827,39 +756,49 @@
         }
     }
 
-    /**
-     * @override com.android.internal.telephony.DataConnectionTracker
-     */
+    @Override
     protected void onCleanUpConnection(boolean tearDown, String reason) {
         cleanUpConnection(tearDown, reason);
     }
 
     private void createAllDataConnectionList() {
-       dataConnectionList = new ArrayList<DataConnection>();
         CdmaDataConnection dataConn;
 
-       for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
-            dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone);
-            dataConnectionList.add(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);
+            }
+        }
+
+        for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
+            int id = mUniqueIdGenerator.getAndIncrement();
+
+            dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm);
+            mDataConnections.put(id, dataConn);
+        }
     }
 
     private void destroyAllDataConnectionList() {
-        if(dataConnectionList != null) {
-            dataConnectionList.removeAll(dataConnectionList);
+        if(mDataConnections != null) {
+            mDataConnections.clear();
         }
     }
 
     private void onCdmaDataDetached() {
-        if (state == State.CONNECTED) {
+        if (mState == State.CONNECTED) {
             startNetStatPoll();
             notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED);
         } else {
-            if (state == State.FAILED) {
+            if (mState == State.FAILED) {
                 cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
                 mRetryMgr.resetRetryCount();
 
-                CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
+                CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation());
                 EventLog.writeEvent(EventLogTags.CDMA_DATA_SETUP_FAILED,
                         loc != null ? loc.getBaseStationId() : -1,
                         TelephonyManager.getDefault().getNetworkType());
@@ -886,8 +825,8 @@
 
     private void onRestartRadio() {
         if (mPendingRestartRadio) {
-            Log.d(LOG_TAG, "************TURN OFF RADIO**************");
-            phone.mCM.setRadioPower(false, null);
+            log("************TURN OFF RADIO**************");
+            mPhone.mCM.setRadioPower(false, null);
             /* 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
@@ -900,7 +839,7 @@
     }
 
     private void writeEventLogCdmaDataDrop() {
-        CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
+        CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation());
         EventLog.writeEvent(EventLogTags.CDMA_DATA_DROP,
                 loc != null ? loc.getBaseStationId() : -1,
                 TelephonyManager.getDefault().getNetworkType());
@@ -916,7 +855,7 @@
             return;
         }
 
-        if (state == State.CONNECTED) {
+        if (mState == State.CONNECTED) {
             boolean isActiveOrDormantConnectionPresent = false;
             int connectionState = DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE;
 
@@ -932,7 +871,7 @@
 
             if (!isActiveOrDormantConnectionPresent) {
                 // No active or dormant connection
-                Log.i(LOG_TAG, "onDataStateChanged: No active connection"
+                log("onDataStateChanged: No active connection"
                         + "state is CONNECTED, disconnecting/cleanup");
                 writeEventLogCdmaDataDrop();
                 cleanUpConnection(true, null);
@@ -941,42 +880,39 @@
 
             switch (connectionState) {
                 case DATA_CONNECTION_ACTIVE_PH_LINK_UP:
-                    Log.v(LOG_TAG, "onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore");
-                    activity = Activity.NONE;
-                    phone.notifyDataActivity();
+                    log("onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore");
+                    mActivity = Activity.NONE;
+                    mPhone.notifyDataActivity();
                     startNetStatPoll();
                     break;
 
                 case DATA_CONNECTION_ACTIVE_PH_LINK_DOWN:
-                    Log.v(LOG_TAG, "onDataStateChanged active=LINK_DOWN && CONNECTED, dormant");
-                    activity = Activity.DORMANT;
-                    phone.notifyDataActivity();
+                    log("onDataStateChanged active=LINK_DOWN && CONNECTED, dormant");
+                    mActivity = Activity.DORMANT;
+                    mPhone.notifyDataActivity();
                     stopNetStatPoll();
                     break;
 
                 default:
-                    Log.v(LOG_TAG, "onDataStateChanged: IGNORE unexpected DataCallState.active="
+                    log("onDataStateChanged: IGNORE unexpected DataCallState.active="
                             + connectionState);
             }
         } else {
             // TODO: Do we need to do anything?
-            Log.i(LOG_TAG, "onDataStateChanged: not connected, state=" + state + " ignoring");
+            log("onDataStateChanged: not connected, state=" + mState + " ignoring");
         }
     }
 
-    public ArrayList<DataConnection> getAllDataConnections() {
-        return dataConnectionList;
-    }
-
     private void startDelayedRetry(FailCause cause, String reason) {
         notifyNoData(cause);
         reconnectAfterFail(cause, reason);
     }
 
+    @Override
     public void handleMessage (Message msg) {
 
-        if (!phone.mIsTheCurrentActivePhone) {
-            Log.d(LOG_TAG, "Ignore CDMA msgs since CDMA phone is inactive");
+        if (!mPhone.mIsTheCurrentActivePhone) {
+            log("Ignore CDMA msgs since CDMA phone is inactive");
             return;
         }
 
@@ -1013,7 +949,13 @@
         }
     }
 
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s);
     }
+
+    @Override
+    protected void loge(String s) {
+        Log.e(LOG_TAG, "[CdmaDataConnectionTracker] " + s);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 1572f09..d428099 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -23,6 +23,7 @@
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.RetryManager;
 
 /**
  * {@hide}
@@ -53,23 +54,27 @@
     private ApnSetting apn;
 
     //***** Constructor
-    private GsmDataConnection(GSMPhone phone, String name) {
-        super(phone, name);
+    private GsmDataConnection(GSMPhone phone, String name, RetryManager rm) {
+        super(phone, name, rm);
     }
 
     /**
      * Create the connection object
      *
-     * @param phone
+     * @param phone the Phone
+     * @param id the connection id
+     * @param rm the RetryManager
      * @return GsmDataConnection that was created.
      */
-    static GsmDataConnection makeDataConnection(GSMPhone phone) {
+    static GsmDataConnection makeDataConnection(GSMPhone phone, int id, RetryManager rm) {
         synchronized (mCountLock) {
             mCount += 1;
         }
-        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount);
+        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount, rm);
         gsmDc.start();
         if (DBG) gsmDc.log("Made " + gsmDc.getName());
+        gsmDc.mId = id;
+        gsmDc.mRetryMgr = rm;
         return gsmDc;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 66da6e8..2aca9ad 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -18,27 +18,19 @@
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
 import android.database.ContentObserver;
 import android.database.Cursor;
-import android.net.IConnectivityManager;
-import android.net.NetworkInfo;
 import android.net.ProxyProperties;
 import android.net.TrafficStats;
 import android.net.Uri;
-import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
 import android.os.Message;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Telephony;
 import android.telephony.ServiceState;
@@ -61,6 +53,7 @@
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.HashMap;
 
 /**
  * {@hide}
@@ -85,9 +78,6 @@
 
     //***** Instance Variables
 
-    // Indicates baseband will not auto-attach
-    private boolean noAutoAttach = false;
-
     private boolean mReregisterOnReconnectFailure = false;
     private ContentResolver mResolver;
 
@@ -95,13 +85,12 @@
     // Count of PDP reset attempts; reset when we see incoming,
     // call reRegisterNetwork, or pingTest succeeds.
     private int mPdpResetCount = 0;
-    private boolean mIsScreenOn = true;
 
     /** Delay between APN attempts */
     protected static final int APN_DELAY_MILLIS = 5000;
 
     //useful for debugging
-    boolean failNextConnect = false;
+    boolean mFailNextConnect = false;
 
     /**
      * allApns holds all apns for this sim spn, retrieved from
@@ -109,104 +98,49 @@
      *
      * Create once after simcard info is loaded
      */
-    private ArrayList<ApnSetting> allApns = null;
+    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> waitingApns = null;
+    private ArrayList<ApnSetting> mWaitingApns = null;
 
-    private ApnSetting preferredApn = null;
+    private ApnSetting mPreferredApn = null;
 
     /* Currently active APN */
     protected ApnSetting mActiveApn;
 
-    /**
-     * pdpList holds all the PDP connection, i.e. IP Link in GPRS
-     */
-    private ArrayList<DataConnection> pdpList;
+      /** The DataConnection being setup */
+    private GsmDataConnection mPendingDataConnection;
 
-    /** Currently active DataConnection */
-    private GsmDataConnection mActivePdp;
+    /** 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
 
-    // TODO: Increase this to match the max number of simultaneous
-    // PDP contexts we plan to support.
-    /**
-     * Pool size of DataConnection objects.
-     */
-    private static final int PDP_CONNECTION_POOL_SIZE = 1;
-
     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_REASON = "reason";
 
     static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
     static final String APN_ID = "apn_id";
     private boolean canSetPreferApn = false;
 
-    // for tracking retries on the default APN
-    private RetryManager mDefaultRetryManager;
-    // for tracking retries on a secondary APN
-    private RetryManager mSecondaryRetryManager;
-
-    BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
-    {
-        @Override
-        public void onReceive(Context context, Intent intent)
-        {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_SCREEN_ON)) {
-                mIsScreenOn = true;
-                stopNetStatPoll();
-                startNetStatPoll();
-            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
-                mIsScreenOn = false;
-                stopNetStatPoll();
-                startNetStatPoll();
-            } else if (action.equals((INTENT_RECONNECT_ALARM))) {
-                Log.d(LOG_TAG, "GPRS reconnect alarm. Previous state was " + state);
-
-                String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-                if (state == State.FAILED) {
-                    Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
-                    msg.arg1 = 0; // tearDown is false
-                    msg.obj = (String) 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);
-                mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
-            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
-                if (!enabled) {
-                    // when wifi got disabled, the NETWORK_STATE_CHANGED_ACTION
-                    // quit and won't report disconnected til next enabling.
-                    mIsWifiConnected = false;
-                }
-            }
-        }
-    };
-
     /** Watches for changes to the APN db. */
-    private ApnChangeObserver apnObserver;
+    private ApnChangeObserver mApnObserver;
 
     //***** Constructor
 
     GsmDataConnectionTracker(GSMPhone 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);
@@ -220,73 +154,26 @@
         p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null);
         p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null);
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(INTENT_RECONNECT_ALARM);
-        filter.addAction(Intent.ACTION_SCREEN_ON);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-
-        // TODO: Why is this registering the phone as the receiver of the intent
-        //       and not its own handler?
-        p.getContext().registerReceiver(mIntentReceiver, filter, null, p);
-
-
         mDataConnectionTracker = this;
-        mResolver = phone.getContext().getContentResolver();
+        mResolver = mPhone.getContext().getContentResolver();
 
-        apnObserver = new ApnChangeObserver();
+        mApnObserver = new ApnChangeObserver();
         p.getContext().getContentResolver().registerContentObserver(
-                Telephony.Carriers.CONTENT_URI, true, apnObserver);
+                Telephony.Carriers.CONTENT_URI, true, mApnObserver);
 
-        createAllPdpList();
-
-        // This preference tells us 1) initial condition for "dataEnabled",
-        // and 2) whether the RIL will setup the baseband to auto-PS attach.
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
-        boolean dataEnabledSetting = true;
-        try {
-            dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager.
-                getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled();
-        } catch (Exception e) {
-            // nothing to do - use the old behavior and leave data on
-        }
-        dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false) &&
-                dataEnabledSetting;
-        if (dataEnabled[APN_DEFAULT_ID]) {
-            enabledCount++;
-        }
-        noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
-
-        if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
-            if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
-                // Should never happen, log an error and default to a simple linear sequence.
-                Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
-                        + DEFAULT_DATA_RETRY_CONFIG);
-                mRetryMgr.configure(20, 2000, 1000);
-            }
-        }
-
-        mDefaultRetryManager = mRetryMgr;
-        mSecondaryRetryManager = new RetryManager();
-
-        if (!mSecondaryRetryManager.configure(SystemProperties.get(
-                "ro.gsm.2nd_data_retry_config"))) {
-            if (!mSecondaryRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) {
-                // Should never happen, log an error and default to a simple sequence.
-                Log.e(LOG_TAG, "Could note configure using SECONDARY_DATA_RETRY_CONFIG="
-                        + SECONDARY_DATA_RETRY_CONFIG);
-                mSecondaryRetryManager.configure("max_retries=3, 333, 333, 333");
-            }
-        }
+        /** Create the default connection */
+        createDataConnection(Phone.APN_TYPE_DEFAULT);
     }
 
+    @Override
     public void dispose() {
+        super.dispose();
+
         //Unregister for all events
-        phone.mCM.unregisterForAvailable(this);
-        phone.mCM.unregisterForOffOrNotAvailable(this);
+        mPhone.mCM.unregisterForAvailable(this);
+        mPhone.mCM.unregisterForOffOrNotAvailable(this);
         mGsmPhone.mSIMRecords.unregisterForRecordsLoaded(this);
-        phone.mCM.unregisterForDataStateChanged(this);
+        mPhone.mCM.unregisterForDataStateChanged(this);
         mGsmPhone.mCT.unregisterForVoiceCallEnded(this);
         mGsmPhone.mCT.unregisterForVoiceCallStarted(this);
         mGsmPhone.mSST.unregisterForGprsAttached(this);
@@ -296,29 +183,36 @@
         mGsmPhone.mSST.unregisterForPsRestrictedEnabled(this);
         mGsmPhone.mSST.unregisterForPsRestrictedDisabled(this);
 
-        phone.getContext().unregisterReceiver(this.mIntentReceiver);
-        phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver);
+        mPhone.getContext().getContentResolver().unregisterContentObserver(this.mApnObserver);
 
-        destroyAllPdpList();
+        destroyDataConnections();
     }
 
+    @Override
     protected void finalize() {
-        if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized");
+        if(DBG) log("finalize");
     }
 
+    @Override
+    protected String getActionIntentReconnectAlarm() {
+        return INTENT_RECONNECT_ALARM;
+    }
+
+    @Override
     protected void setState(State s) {
         if (DBG) log ("setState: " + s);
-        if (state != s) {
-            EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, state.toString(), s.toString());
-            state = s;
+        if (mState != s) {
+            EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, mState.toString(), s.toString());
+            mState = s;
         }
 
-        if (state == State.FAILED) {
-            if (waitingApns != null)
-                waitingApns.clear(); // when teardown the connection and set to IDLE
+        if (mState == State.FAILED) {
+            if (mWaitingApns != null)
+                mWaitingApns.clear(); // when tear down the connection and set to IDLE
         }
     }
 
+    @Override
     public String[] getActiveApnTypes() {
         String[] result;
         if (mActiveApn != null) {
@@ -330,6 +224,7 @@
         return result;
     }
 
+    @Override
     protected String getActiveApnString() {
         String result = null;
         if (mActiveApn != null) {
@@ -347,15 +242,16 @@
      *
      * @return false while no data connection if all above requirements are met.
      */
+    @Override
     public boolean isDataConnectionAsDesired() {
-        boolean roaming = phone.getServiceState().getRoaming();
+        boolean roaming = mPhone.getServiceState().getRoaming();
 
         if (mGsmPhone.mSIMRecords.getRecordsLoaded() &&
                 mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
                 (!roaming || getDataOnRoamingEnabled()) &&
             !mIsWifiConnected &&
             !mIsPsRestricted ) {
-            return (state == State.CONNECTED);
+            return (mState == State.CONNECTED);
         }
         return true;
     }
@@ -372,8 +268,8 @@
             return (fetchDunApn() != null);
         }
 
-        if (allApns != null) {
-            for (ApnSetting apn : allApns) {
+        if (mAllApns != null) {
+            for (ApnSetting apn : mAllApns) {
                 if (apn.canHandleType(type)) {
                     return true;
                 }
@@ -382,14 +278,6 @@
         return false;
     }
 
-    /**
-     * Formerly this method was ArrayList<GsmDataConnection> getAllPdps()
-     */
-    public ArrayList<DataConnection> getAllDataConnections() {
-        ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone();
-        return pdps;
-    }
-
     //****** Called from ServiceStateTracker
     /**
      * Invoked when ServiceStateTracker observes a transition from GPRS
@@ -405,11 +293,11 @@
     }
 
     private void onGprsAttached() {
-        if (state == State.CONNECTED) {
+        if (mState == State.CONNECTED) {
             startNetStatPoll();
             notifyDataConnection(Phone.REASON_GPRS_ATTACHED);
         } else {
-            if (state == State.FAILED) {
+            if (mState == State.FAILED) {
                 cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED);
                 mRetryMgr.resetRetryCount();
             }
@@ -417,26 +305,30 @@
         }
     }
 
+    @Override
     protected boolean isDataAllowed() {
         int gprsState = mGsmPhone.mSST.getCurrentGprsState();
         boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState();
 
-        boolean allowed = ((gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) &&
-                mGsmPhone.mSIMRecords.getRecordsLoaded() &&
-                phone.getState() == Phone.State.IDLE &&
-                mMasterDataEnabled &&
-                (!phone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
-                !mIsPsRestricted &&
-                desiredPowerState);
+        boolean allowed =
+                    (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
+                    mGsmPhone.mSIMRecords.getRecordsLoaded() &&
+                    mPhone.getState() == Phone.State.IDLE &&
+                    mMasterDataEnabled &&
+                    (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
+                    !mIsPsRestricted &&
+                    desiredPowerState;
         if (!allowed && DBG) {
             String reason = "";
-            if (gprsState != ServiceState.STATE_IN_SERVICE) reason += " - gprs= " + gprsState;
+            if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
+                reason += " - gprs= " + gprsState;
+            }
             if (!mGsmPhone.mSIMRecords.getRecordsLoaded()) reason += " - SIM not loaded";
-            if (phone.getState() != Phone.State.IDLE) {
-                reason += " - PhoneState= " + phone.getState();
+            if (mPhone.getState() != Phone.State.IDLE) {
+                reason += " - PhoneState= " + mPhone.getState();
             }
             if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false";
-            if (phone.getServiceState().getRoaming() && getDataOnRoamingEnabled()) {
+            if (mPhone.getServiceState().getRoaming() && getDataOnRoamingEnabled()) {
                 reason += " - Roaming";
             }
             if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
@@ -449,38 +341,38 @@
     private boolean trySetupData(String reason) {
         if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
 
-        Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
+        log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
 
-        if (phone.getSimulatedRadioControl() != null) {
+        if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
             setState(State.CONNECTED);
             notifyDataConnection(reason);
 
-            Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected");
+            log("(fix?) We're on the simulator; assuming data is connected");
             return true;
         }
 
         int gprsState = mGsmPhone.mSST.getCurrentGprsState();
         boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState();
 
-        if (((state == State.IDLE) || (state == State.SCANNING)) &&
+        if (((mState == State.IDLE) || (mState == State.SCANNING)) &&
                 isDataAllowed() && getAnyDataEnabled()) {
 
-            if (state == State.IDLE) {
-                waitingApns = buildWaitingApns();
-                if (waitingApns.isEmpty()) {
+            if (mState == State.IDLE) {
+                mWaitingApns = buildWaitingApns(mRequestedApnType);
+                if (mWaitingApns.isEmpty()) {
                     if (DBG) log("No APN found");
                     notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
                     notifyOffApnsOfAvailability(reason, false);
                     return false;
                 } else {
-                    log ("Create from allApns : " + apnListToString(allApns));
+                    log ("Create from allApns : " + apnListToString(mAllApns));
                 }
             }
 
             if (DBG) {
-                log ("Setup waitngApns : " + apnListToString(waitingApns));
+                log ("Setup waitngApns : " + apnListToString(mWaitingApns));
             }
             boolean retValue = setupData(reason);
             notifyOffApnsOfAvailability(reason, retValue);
@@ -492,13 +384,12 @@
     }
 
     /**
-     * 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.
+     * Cleanup all connections.
+     *
+     * TODO: Cleanup only a specified connection passed as a parameter.
+     *
+     * @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);
@@ -506,7 +397,7 @@
         // Clear the reconnect alarm, if set.
         if (mReconnectIntent != null) {
             AlarmManager am =
-                (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
+                (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
             am.cancel(mReconnectIntent);
             mReconnectIntent = null;
         }
@@ -514,10 +405,11 @@
         setState(State.DISCONNECTING);
 
         boolean notificationDeferred = false;
-        for (DataConnection conn : pdpList) {
+        for (DataConnection conn : mDataConnections.values()) {
             if (tearDown) {
                 if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
-                conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
+                conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE,
+                        conn.getDataConnectionId(), 0, reason));
                 notificationDeferred = true;
             } else {
                 if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
@@ -575,51 +467,49 @@
         return result;
     }
 
-    private GsmDataConnection findFreePdp() {
-        for (DataConnection conn : pdpList) {
-            GsmDataConnection pdp = (GsmDataConnection) conn;
-            if (pdp.isInactive()) {
-                return pdp;
+    private GsmDataConnection findFreeDataConnection() {
+        for (DataConnection dc : mDataConnections.values()) {
+            if (dc.isInactive()) {
+                log("found free GsmDataConnection");
+                return (GsmDataConnection) dc;
             }
         }
+        log("NO free GsmDataConnection");
         return null;
     }
 
     private boolean setupData(String reason) {
         ApnSetting apn;
-        GsmDataConnection pdp;
+        GsmDataConnection gdc;
 
         apn = getNextApn();
         if (apn == null) return false;
-        pdp = findFreePdp();
-        if (pdp == null) {
+        gdc = findFreeDataConnection();
+        if (gdc == null) {
             if (DBG) log("setupData: No free GsmDataConnection found!");
             return false;
         }
         mActiveApn = apn;
-        mActivePdp = pdp;
+        mPendingDataConnection = gdc;
 
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
         msg.obj = reason;
-        pdp.connect(msg, apn);
+        gdc.connect(msg, apn);
 
         setState(State.INITING);
         notifyDataConnection(reason);
         return true;
     }
 
-    private boolean
-    pdpStatesHasCID (ArrayList<DataCallState> states, int cid) {
+    private boolean dataCallStatesHasCID (ArrayList<DataCallState> states, int cid) {
         for (int i = 0, s = states.size() ; i < s ; i++) {
             if (states.get(i).cid == cid) return true;
         }
-
         return false;
     }
 
-    private boolean
-    pdpStatesHasActiveCID (ArrayList<DataCallState> states, int cid) {
+    private boolean dataCallStatesHasActiveCID (ArrayList<DataCallState> states, int cid) {
         for (int i = 0, s = states.size() ; i < s ; i++) {
             if ((states.get(i).cid == cid) && (states.get(i).active != 0)) {
                 return true;
@@ -635,7 +525,7 @@
     private void onApnChanged() {
         boolean isConnected;
 
-        isConnected = (state != State.IDLE && state != State.FAILED);
+        isConnected = (mState != State.IDLE && mState != State.FAILED);
 
         // The "current" may no longer be valid.  MMS depends on this to send properly.
         mGsmPhone.updateCurrentCarrierInProvider();
@@ -643,7 +533,7 @@
         // TODO: It'd be nice to only do this if the changed entrie(s)
         // match the current operator.
         createAllApnList();
-        if (state != State.DISCONNECTING) {
+        if (mState != State.DISCONNECTING) {
             cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
             if (!isConnected) {
                 // reset reconnect timer
@@ -660,10 +550,10 @@
      * via an unsolicited response (which could have happened at any
      * previous state
      */
-    protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) {
-        ArrayList<DataCallState> pdpStates;
+    private void onDataStateChanged (AsyncResult ar, boolean explicitPoll) {
+        ArrayList<DataCallState> dataCallStates;
 
-        pdpStates = (ArrayList<DataCallState>)(ar.result);
+        dataCallStates = (ArrayList<DataCallState>)(ar.result);
 
         if (ar.exception != null) {
             // This is probably "radio not available" or something
@@ -672,42 +562,42 @@
             return;
         }
 
-        if (state == State.CONNECTED) {
+        if (mState == 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 (!pdpStatesHasCID(pdpStates, cidActive)) {
+            if (!dataCallStatesHasCID(dataCallStates, mCidActive)) {
                 // It looks like the PDP context has deactivated.
                 // Tear everything down and try to reconnect.
 
-                Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
+                log("PDP connection has dropped. Reconnecting");
 
                 // Add an event log when the network drops PDP
-                GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+                GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
                 EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP,
                         loc != null ? loc.getCid() : -1,
                         TelephonyManager.getDefault().getNetworkType());
 
                 cleanUpConnection(true, null);
                 return;
-            } else if (!pdpStatesHasActiveCID(pdpStates, cidActive)) {
+            } else if (!dataCallStatesHasActiveCID(dataCallStates, mCidActive)) {
                 // 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.
 
                 if (!explicitPoll) {
                     // We think it disconnected but aren't sure...poll from our side
-                    phone.mCM.getPDPContextList(
+                    mPhone.mCM.getPDPContextList(
                             this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
                 } else {
-                    Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
+                    log("PDP connection has dropped (active=false case). "
                                     + " Reconnecting");
 
                     // Log the network drop on the event log.
-                    GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+                    GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
                     EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP,
                             loc != null ? loc.getCid() : -1,
                             TelephonyManager.getDefault().getNetworkType());
@@ -734,38 +624,26 @@
         mActiveApn = null;
     }
 
-    /**
-     * This is a kludge to deal with the fact that
-     * the PDP state change notification doesn't always work
-     * with certain RIL impl's/basebands
-     *
-     */
-    private void startPeriodicPdpPoll() {
-        removeMessages(EVENT_POLL_PDP);
-
-        sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
-    }
-
     private void resetPollStats() {
-        txPkts = -1;
-        rxPkts = -1;
-        sentSinceLastRecv = 0;
-        netStatPollPeriod = POLL_NETSTAT_MILLIS;
+        mTxPkts = -1;
+        mRxPkts = -1;
+        mSentSinceLastRecv = 0;
+        mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
         mNoRecvPollCount = 0;
     }
 
     private void doRecovery() {
-        if (state == State.CONNECTED) {
+        if (mState == 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, sentSinceLastRecv);
+                EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv);
                 cleanUpConnection(true, Phone.REASON_PDP_RESET);
             } else {
                 mPdpResetCount = 0;
-                EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, sentSinceLastRecv);
+                EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv);
                 mGsmPhone.mSST.reRegisterNetwork(null);
             }
             // TODO: Add increasingly drastic recovery steps, eg,
@@ -773,23 +651,26 @@
         }
     }
 
+    @Override
     protected void startNetStatPoll() {
-        if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) {
-            Log.d(LOG_TAG, "[DataConnection] Start poll NetStat");
+        if (mState == State.CONNECTED && mPingTestActive == false && mNetStatPollEnabled == false) {
+            log("[DataConnection] Start poll NetStat");
             resetPollStats();
-            netStatPollEnabled = true;
+            mNetStatPollEnabled = true;
             mPollNetStat.run();
         }
     }
 
+    @Override
     protected void stopNetStatPoll() {
-        netStatPollEnabled = false;
+        mNetStatPollEnabled = false;
         removeCallbacks(mPollNetStat);
-        Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat");
+        log("[DataConnection] Stop poll NetStat");
     }
 
+    @Override
     protected void restartRadio() {
-        Log.d(LOG_TAG, "************TURN OFF RADIO**************");
+        log("************TURN OFF RADIO**************");
         cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
         mGsmPhone.mSST.powerOffRadioSafely();
         /* Note: no need to call setRadioPower(true).  Assuming the desired
@@ -813,43 +694,43 @@
 
             Activity newActivity;
 
-            preTxPkts = txPkts;
-            preRxPkts = rxPkts;
+            preTxPkts = mTxPkts;
+            preRxPkts = mRxPkts;
 
-            txPkts = TrafficStats.getMobileTxPackets();
-            rxPkts = TrafficStats.getMobileRxPackets();
+            mTxPkts = TrafficStats.getMobileTxPackets();
+            mRxPkts = TrafficStats.getMobileRxPackets();
 
-            //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts));
+            //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts));
 
-            if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
-                sent = txPkts - preTxPkts;
-                received = rxPkts - preRxPkts;
+            if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
+                sent = mTxPkts - preTxPkts;
+                received = mRxPkts - preRxPkts;
 
                 if ( sent > 0 && received > 0 ) {
-                    sentSinceLastRecv = 0;
+                    mSentSinceLastRecv = 0;
                     newActivity = Activity.DATAINANDOUT;
                     mPdpResetCount = 0;
                 } else if (sent > 0 && received == 0) {
-                    if (phone.getState() == Phone.State.IDLE) {
-                        sentSinceLastRecv += sent;
+                    if (mPhone.getState() == Phone.State.IDLE) {
+                        mSentSinceLastRecv += sent;
                     } else {
-                        sentSinceLastRecv = 0;
+                        mSentSinceLastRecv = 0;
                     }
                     newActivity = Activity.DATAOUT;
                 } else if (sent == 0 && received > 0) {
-                    sentSinceLastRecv = 0;
+                    mSentSinceLastRecv = 0;
                     newActivity = Activity.DATAIN;
                     mPdpResetCount = 0;
                 } else if (sent == 0 && received == 0) {
                     newActivity = Activity.NONE;
                 } else {
-                    sentSinceLastRecv = 0;
+                    mSentSinceLastRecv = 0;
                     newActivity = Activity.NONE;
                 }
 
-                if (activity != newActivity && mIsScreenOn) {
-                    activity = newActivity;
-                    phone.notifyDataActivity();
+                if (mActivity != newActivity && mIsScreenOn) {
+                    mActivity = newActivity;
+                    mPhone.notifyDataActivity();
                 }
             }
 
@@ -857,11 +738,11 @@
                     Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
                     NUMBER_SENT_PACKETS_OF_HANG);
 
-            if (sentSinceLastRecv >= watchdogTrigger) {
+            if (mSentSinceLastRecv >= watchdogTrigger) {
                 // we already have NUMBER_SENT_PACKETS sent without ack
                 if (mNoRecvPollCount == 0) {
                     EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED,
-                            sentSinceLastRecv);
+                            mSentSinceLastRecv);
                 }
 
                 int noRecvPollLimit = Settings.Secure.getInt(mResolver,
@@ -871,21 +752,22 @@
                     // It's possible the PDP context went down and we weren't notified.
                     // Start polling the context list in an attempt to recover.
                     if (DBG) log("no DATAIN in a while; polling PDP");
-                    phone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
+                    mPhone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
 
                     mNoRecvPollCount++;
 
                     // Slow down the poll interval to let things happen
-                    netStatPollPeriod = Settings.Secure.getInt(mResolver,
+                    mNetStatPollPeriod = Settings.Secure.getInt(mResolver,
                             Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
                             POLL_NETSTAT_SLOW_MILLIS);
                 } else {
-                    if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) +
+                    if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) +
                                         " pkts since last received");
                     // We've exceeded the threshold.  Run ping test as a final check;
                     // it will proceed with recovery if ping fails.
                     stopNetStatPoll();
                     Thread pingTest = new Thread() {
+                        @Override
                         public void run() {
                             runPingTest();
                         }
@@ -896,17 +778,17 @@
             } else {
                 mNoRecvPollCount = 0;
                 if (mIsScreenOn) {
-                    netStatPollPeriod = Settings.Secure.getInt(mResolver,
+                    mNetStatPollPeriod = Settings.Secure.getInt(mResolver,
                             Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
                 } else {
-                    netStatPollPeriod = Settings.Secure.getInt(mResolver,
+                    mNetStatPollPeriod = Settings.Secure.getInt(mResolver,
                             Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
                             POLL_NETSTAT_SCREEN_OFF_MILLIS);
                 }
             }
 
-            if (netStatPollEnabled) {
-                mDataConnectionTracker.postDelayed(this, netStatPollPeriod);
+            if (mNetStatPollEnabled) {
+                mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
             }
         }
     };
@@ -925,9 +807,9 @@
                 status = p.waitFor();
             }
         } catch (IOException e) {
-            Log.w(LOG_TAG, "ping failed: IOException");
+            loge("ping failed: IOException");
         } catch (Exception e) {
-            Log.w(LOG_TAG, "exception trying to ping");
+            loge("exception trying to ping");
         }
 
         if (status == 0) {
@@ -968,7 +850,8 @@
     }
 
     private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
-        if (state == State.FAILED) {
+        if (mState == State.FAILED) {
+            /** TODO: Retrieve retry manager from connection itself */
             if (!mRetryMgr.isRetryNeeded()) {
                 if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
                     // if no more retries on a secondary APN attempt, tell the world and revert.
@@ -977,11 +860,11 @@
                     return;
                 }
                 if (mReregisterOnReconnectFailure) {
-                    // We've re-registerd once now just retry forever.
+                    // We've re-registered once now just retry forever.
                     mRetryMgr.retryForeverUsingLastTimeout();
                 } else {
                     // Try to re-register to the network.
-                    Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
+                    log("PDP activate failed, Reregistering to the network");
                     mReregisterOnReconnectFailure = true;
                     mGsmPhone.mSST.reRegisterNetwork(null);
                     mRetryMgr.resetRetryCount();
@@ -990,15 +873,15 @@
             }
 
             int nextReconnectDelay = mRetryMgr.getRetryTimer();
-            Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for "
+            log("PDP activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
             AlarmManager am =
-                (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
+                (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(
-                    phone.getContext(), 0, intent, 0);
+                    mPhone.getContext(), 0, intent, 0);
             am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
                     mReconnectIntent);
@@ -1006,7 +889,7 @@
             mRetryMgr.increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
-                Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification "
+                log("NOT Posting GPRS Unavailable notification "
                                 + "-- likely transient error");
             } else {
                 notifyNoData(lastFailCauseCode);
@@ -1018,9 +901,9 @@
         setState(State.FAILED);
     }
 
-    protected void onRecordsLoaded() {
+    private void onRecordsLoaded() {
         createAllApnList();
-        if (state == State.FAILED) {
+        if (mState == State.FAILED) {
             cleanUpConnection(false, null);
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
@@ -1028,19 +911,29 @@
 
     @Override
     protected void onEnableNewApn() {
+        log("onEnableNewApn E");
         // change our retry manager to use the appropriate numbers for the new APN
         if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
-            mRetryMgr = mDefaultRetryManager;
+            log("onEnableNewApn default type");
+            mRetryMgr = mPendingDataConnection.getRetryMgr();
+            mRetryMgr.resetRetryCount();
+        } else if (mApnToDataConnectionId.get(mRequestedApnType) == null) {
+            log("onEnableNewApn mRequestedApnType=" + mRequestedApnType +
+                    " missing, make a new connection");
+            int id = createDataConnection(mRequestedApnType);
+            mRetryMgr = mDataConnections.get(id).getRetryMgr();
+            mRetryMgr.resetRetryCount();
         } else {
-            mRetryMgr = mSecondaryRetryManager;
+            log("oneEnableNewApn connection already exists, nothing to setup");
         }
-        mRetryMgr.resetRetryCount();
 
         // 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");
     }
 
+    @Override
     protected boolean onTrySetupData(String reason) {
         return trySetupData(reason);
     }
@@ -1060,31 +953,33 @@
         }
     }
 
+    @Override
     protected void onRadioAvailable() {
-        if (phone.getSimulatedRadioControl() != null) {
+        if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
             setState(State.CONNECTED);
             notifyDataConnection(null);
 
-            Log.i(LOG_TAG, "We're on the simulator; assuming data is connected");
+            log("We're on the simulator; assuming data is connected");
         }
 
-        if (state != State.IDLE) {
+        if (mState != State.IDLE) {
             cleanUpConnection(true, null);
         }
     }
 
+    @Override
     protected void onRadioOffOrNotAvailable() {
         // Make sure our reconnect delay starts at the initial value
         // next time the radio comes on
         mRetryMgr.resetRetryCount();
         mReregisterOnReconnectFailure = false;
 
-        if (phone.getSimulatedRadioControl() != null) {
+        if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
-            Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless");
+            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"?
@@ -1092,7 +987,9 @@
         }
     }
 
+    @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;
@@ -1100,10 +997,10 @@
 
         if (ar.exception == null) {
             // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
-            mLinkProperties = getLinkProperties(mActivePdp);
-            mLinkCapabilities = getLinkCapabilities(mActivePdp);
+            mLinkProperties = getLinkProperties(mPendingDataConnection);
+            mLinkCapabilities = getLinkCapabilities(mPendingDataConnection);
 
-            ApnSetting apn = mActivePdp.getApn();
+            ApnSetting apn = mPendingDataConnection.getApn();
             if (apn.proxy != null && apn.proxy.length() != 0) {
                 try {
                     ProxyProperties proxy = new ProxyProperties();
@@ -1111,11 +1008,11 @@
                             Integer.parseInt(apn.port)));
                     mLinkProperties.setHttpProxy(proxy);
                 } catch (UnknownHostException e) {
-                    Log.e(LOG_TAG, "UnknownHostException making ProxyProperties: " + e);
+                    loge("UnknownHostException making ProxyProperties: " + e);
                 } catch (SecurityException e) {
-                    Log.e(LOG_TAG, "SecurityException making ProxyProperties: " + e);
+                    loge("SecurityException making ProxyProperties: " + e);
                 } catch (NumberFormatException e) {
-                    Log.e(LOG_TAG, "NumberFormatException making ProxyProperties (" + apn.port +
+                    loge("NumberFormatException making ProxyProperties (" + apn.port +
                             "): " + e);
                 }
             }
@@ -1123,10 +1020,10 @@
             // everything is setup
             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
                 SystemProperties.set("gsm.defaultpdpcontext.active", "true");
-                        if (canSetPreferApn && preferredApn == null) {
-                            Log.d(LOG_TAG, "PREFERRED APN is null");
-                            preferredApn = mActiveApn;
-                            setPreferredApn(preferredApn.id);
+                        if (canSetPreferApn && mPreferredApn == null) {
+                            log("PREFERRED APN is null");
+                            mPreferredApn = mActiveApn;
+                            setPreferredApn(mPreferredApn.id);
                         }
             } else {
                 SystemProperties.set("gsm.defaultpdpcontext.active", "false");
@@ -1143,13 +1040,14 @@
             if(DBG) log("PDP setup failed " + cause);
                     // Log this failure to the Event Logs.
             if (cause.isEventLoggable()) {
-                GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+                GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
                 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
                         cause.ordinal(), loc != null ? loc.getCid() : -1,
                         TelephonyManager.getDefault().getNetworkType());
             }
 
-            // No try for permanent failure
+            // Do not retry on permanent failure
+            // TODO: We should not fail permanently if more Apns to try!
             if (cause.isPermanentFail()) {
                 notifyNoData(cause);
                 notifyDataConnection(Phone.REASON_APN_FAILED);
@@ -1157,8 +1055,8 @@
                 return;
             }
 
-            waitingApns.remove(0);
-            if (waitingApns.isEmpty()) {
+            mWaitingApns.remove(0);
+            if (mWaitingApns.isEmpty()) {
                 // No more to try, start delayed retry
                 startDelayedRetry(cause, reason);
             } else {
@@ -1174,9 +1072,10 @@
     /**
      * Called when EVENT_DISCONNECT_DONE is received.
      */
-    protected void onDisconnectDone(AsyncResult ar) {
+    @Override
+    protected void onDisconnectDone(int connId, AsyncResult ar) {
+        if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId);
         String reason = null;
-        if(DBG) log("EVENT_DISCONNECT_DONE");
         if (ar.userObj instanceof String) {
            reason = (String) ar.userObj;
         }
@@ -1202,22 +1101,24 @@
     }
 
     protected void onPollPdp() {
-        if (state == State.CONNECTED) {
+        if (mState == State.CONNECTED) {
             // only poll when connected
-            phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
+            mPhone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
             sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
         }
     }
 
+    @Override
     protected void onVoiceCallStarted() {
-        if (state == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) {
+        if (mState == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) {
             stopNetStatPoll();
             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
         }
     }
 
+    @Override
     protected void onVoiceCallEnded() {
-        if (state == State.CONNECTED) {
+        if (mState == State.CONNECTED) {
             if (!mGsmPhone.mSST.isConcurrentVoiceAndData()) {
                 startNetStatPoll();
                 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
@@ -1234,74 +1135,92 @@
         }
     }
 
+    @Override
     protected void onCleanUpConnection(boolean tearDown, String reason) {
         cleanUpConnection(tearDown, reason);
     }
 
     /**
-     * Based on the sim operator numeric, create a list for all possible pdps
-     * with all apns associated with that pdp
-     *
-     *
+     * Based on the sim operator numeric, create a list for all possible
+     * Data Connections and setup the preferredApn.
      */
     private void createAllApnList() {
-        allApns = new ArrayList<ApnSetting>();
+        mAllApns = new ArrayList<ApnSetting>();
         String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (operator != null) {
             String selection = "numeric = '" + operator + "'";
 
-            Cursor cursor = phone.getContext().getContentResolver().query(
+            Cursor cursor = mPhone.getContext().getContentResolver().query(
                     Telephony.Carriers.CONTENT_URI, null, selection, null, null);
 
             if (cursor != null) {
                 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 GsmDataConnection
-                    // object.  Not used on current platform (no ppp).
-                    //GsmDataConnection pdp = pdpList.get(pdp_name);
-                    //if (pdp != null && pdp.dataLink != null) {
-                    //    pdp.dataLink.setPasswordInfo(cursor);
-                    //}
+                    mAllApns = createApnList(cursor);
                 }
                 cursor.close();
             }
         }
 
-        if (allApns.isEmpty()) {
+        if (mAllApns.isEmpty()) {
             if (DBG) log("No APN found for carrier: " + operator);
-            preferredApn = null;
+            mPreferredApn = null;
             notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
         } else {
-            preferredApn = getPreferredApn();
-            Log.d(LOG_TAG, "Get PreferredAPN");
-            if (preferredApn != null && !preferredApn.numeric.equals(operator)) {
-                preferredApn = null;
+            mPreferredApn = getPreferredApn();
+            log("Get PreferredAPN");
+            if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
+                mPreferredApn = null;
                 setPreferredApn(-1);
             }
         }
     }
 
-    private void createAllPdpList() {
-        pdpList = new ArrayList<DataConnection>();
-        DataConnection pdp;
+    /** Return the id for a new data connection */
+    private int createDataConnection(String apnType) {
+        log("createDataConnection(" + apnType + ") E");
+        RetryManager rm = new RetryManager();
 
-        for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {
-            pdp = GsmDataConnection.makeDataConnection(mGsmPhone);
-            pdpList.add(pdp);
-         }
+        if (apnType.equals(Phone.APN_TYPE_DEFAULT)) {
+            if (!rm.configure(SystemProperties.get("ro.gsm.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);
+                }
+            }
+        } else {
+            if (!rm.configure(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) {
+                if (!rm.configure(SECONDARY_DATA_RETRY_CONFIG)) {
+                    // Should never happen, log an error and default to a simple sequence.
+                    log("Could note configure using SECONDARY_DATA_RETRY_CONFIG="
+                            + SECONDARY_DATA_RETRY_CONFIG);
+                    rm.configure("max_retries=3, 333, 333, 333");
+                }
+            }
+        }
+
+        int id = mUniqueIdGenerator.getAndIncrement();
+        DataConnection conn = GsmDataConnection.makeDataConnection(mGsmPhone, id, rm);
+        mDataConnections.put(id, conn);
+        mApnToDataConnectionId.put(apnType, id);
+
+        log("createDataConnection(" + apnType + ") X id=" + id);
+        return id;
     }
 
-    private void destroyAllPdpList() {
-        if(pdpList != null) {
-            GsmDataConnection pdp;
-            pdpList.removeAll(pdpList);
+    private void destroyDataConnections() {
+        if(mDataConnections != null) {
+            log("destroyDataConnectionList clear mDataConnectionList");
+            mDataConnections.clear();
+        } else {
+            log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
         }
     }
 
     private ApnSetting fetchDunApn() {
-        Context c = phone.getContext();
+        Context c = mPhone.getContext();
         String apnData = Settings.Secure.getString(c.getContentResolver(),
                                     Settings.Secure.TETHER_DUN_APN);
         ApnSetting dunSetting = ApnSetting.fromString(apnData);
@@ -1312,14 +1231,16 @@
     }
 
     /**
+     * Build a list of APNs to be used to create PDP's.
      *
+     * @param requestedApnType
      * @return waitingApns list to be used to create PDP
      *          error when waitingApns.isEmpty()
      */
-    private ArrayList<ApnSetting> buildWaitingApns() {
+    private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType) {
         ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
 
-        if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) {
+        if (requestedApnType.equals(Phone.APN_TYPE_DUN)) {
             ApnSetting dun = fetchDunApn();
             if (dun != null) apnList.add(dun);
             return apnList;
@@ -1327,24 +1248,24 @@
 
         String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
 
-        if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
-            if (canSetPreferApn && preferredApn != null) {
-                Log.i(LOG_TAG, "Preferred APN:" + operator + ":"
-                        + preferredApn.numeric + ":" + preferredApn);
-                if (preferredApn.numeric.equals(operator)) {
-                    Log.i(LOG_TAG, "Waiting APN set to preferred APN");
-                    apnList.add(preferredApn);
+        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);
                     return apnList;
                 } else {
                     setPreferredApn(-1);
-                    preferredApn = null;
+                    mPreferredApn = null;
                 }
             }
         }
 
-        if (allApns != null) {
-            for (ApnSetting apn : allApns) {
-                if (apn.canHandleType(mRequestedApnType)) {
+        if (mAllApns != null) {
+            for (ApnSetting apn : mAllApns) {
+                if (apn.canHandleType(requestedApnType)) {
                     apnList.add(apn);
                 }
             }
@@ -1357,7 +1278,7 @@
      * @return the first apn found in waitingApns, null if none
      */
     private ApnSetting getNextApn() {
-        ArrayList<ApnSetting> list = waitingApns;
+        ArrayList<ApnSetting> list = mWaitingApns;
         ApnSetting apn = null;
 
         if (list != null) {
@@ -1388,7 +1309,7 @@
             return;
         }
 
-        ContentResolver resolver = phone.getContext().getContentResolver();
+        ContentResolver resolver = mPhone.getContext().getContentResolver();
         resolver.delete(PREFERAPN_URI, null, null);
 
         if (pos >= 0) {
@@ -1399,11 +1320,11 @@
     }
 
     private ApnSetting getPreferredApn() {
-        if (allApns.isEmpty()) {
+        if (mAllApns.isEmpty()) {
             return null;
         }
 
-        Cursor cursor = phone.getContext().getContentResolver().query(
+        Cursor cursor = mPhone.getContext().getContentResolver().query(
                 PREFERAPN_URI, new String[] { "_id", "name", "apn" },
                 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
 
@@ -1417,7 +1338,7 @@
             int pos;
             cursor.moveToFirst();
             pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
-            for(ApnSetting p:allApns) {
+            for(ApnSetting p:mAllApns) {
                 if (p.id == pos && p.canHandleType(mRequestedApnType)) {
                     cursor.close();
                     return p;
@@ -1432,11 +1353,12 @@
         return null;
     }
 
+    @Override
     public void handleMessage (Message msg) {
-        if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg);
+        if (DBG) log("GSMDataConnTrack handleMessage "+msg);
 
         if (!mGsmPhone.mIsTheCurrentActivePhone) {
-            Log.d(LOG_TAG, "Ignore GSM msgs since GSM phone is inactive");
+            log("Ignore GSM msgs since GSM phone is inactive");
             return;
         }
 
@@ -1454,11 +1376,11 @@
                 break;
 
             case EVENT_DATA_STATE_CHANGED:
-                onPdpStateChanged((AsyncResult) msg.obj, false);
+                onDataStateChanged((AsyncResult) msg.obj, false);
                 break;
 
             case EVENT_GET_PDP_LIST_COMPLETE:
-                onPdpStateChanged((AsyncResult) msg.obj, true);
+                onDataStateChanged((AsyncResult) msg.obj, true);
                 break;
 
             case EVENT_POLL_PDP:
@@ -1486,7 +1408,7 @@
                  * PDP context and notify us with PDP_CONTEXT_CHANGED.
                  * But we should stop the network polling and prevent reset PDP.
                  */
-                Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
+                log("[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
                 stopNetStatPoll();
                 mIsPsRestricted = true;
                 break;
@@ -1496,12 +1418,12 @@
                  * When PS restrict is removed, we need setup PDP connection if
                  * PDP connection is down.
                  */
-                Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
+                log("[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
                 mIsPsRestricted  = false;
-                if (state == State.CONNECTED) {
+                if (mState == State.CONNECTED) {
                     startNetStatPoll();
                 } else {
-                    if (state == State.FAILED) {
+                    if (mState == State.FAILED) {
                         cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
                         mRetryMgr.resetRetryCount();
                         mReregisterOnReconnectFailure = false;
@@ -1517,7 +1439,13 @@
         }
     }
 
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s);
     }
+
+    @Override
+    protected void loge(String s) {
+        Log.e(LOG_TAG, "[GsmDataConnectionTracker] " + s);
+    }
 }