Merge "In DRT2, correctly handle the case of zero tests"
diff --git a/Android.mk b/Android.mk
index b8a48a4..4a994ed 100644
--- a/Android.mk
+++ b/Android.mk
@@ -71,6 +71,7 @@
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
 	core/java/android/app/INotificationManager.aidl \
+	core/java/android/app/IProcessObserver.aidl \
 	core/java/android/app/ISearchManager.aidl \
 	core/java/android/app/ISearchManagerCallback.aidl \
 	core/java/android/app/IServiceConnection.aidl \
diff --git a/api/current.txt b/api/current.txt
index dd619cf..cf6e955 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -866,6 +866,7 @@
     field public static final int subtitleTextStyle = 16843513; // 0x10102f9
     field public static final int suggestActionMsg = 16843228; // 0x10101dc
     field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
+    field public static final int suggestionsEnabled = 16843630; // 0x101036e
     field public static final int summary = 16843241; // 0x10101e9
     field public static final int summaryColumn = 16843426; // 0x10102a2
     field public static final int summaryOff = 16843248; // 0x10101f0
@@ -13924,12 +13925,14 @@
 
   public class ParcelFileDescriptor implements android.os.Parcelable {
     ctor public ParcelFileDescriptor(android.os.ParcelFileDescriptor);
+    method public static android.os.ParcelFileDescriptor adoptFd(int);
     method public void close() throws java.io.IOException;
     method public static android.os.ParcelFileDescriptor[] createPipe() throws java.io.IOException;
     method public int describeContents();
     method public int detachFd();
     method public static android.os.ParcelFileDescriptor dup(java.io.FileDescriptor) throws java.io.IOException;
     method public static android.os.ParcelFileDescriptor fromDatagramSocket(java.net.DatagramSocket);
+    method public static android.os.ParcelFileDescriptor fromFd(int) throws java.io.IOException;
     method public static android.os.ParcelFileDescriptor fromSocket(java.net.Socket);
     method public int getFd();
     method public java.io.FileDescriptor getFileDescriptor();
@@ -25205,6 +25208,7 @@
     method public final android.content.res.ColorStateList getLinkTextColors();
     method public final boolean getLinksClickable();
     method public final android.text.method.MovementMethod getMovementMethod();
+    method public int getOffsetForPosition(float, float);
     method public android.text.TextPaint getPaint();
     method public int getPaintFlags();
     method public java.lang.String getPrivateImeOptions();
@@ -25225,6 +25229,7 @@
     method public android.text.style.URLSpan[] getUrls();
     method public boolean hasSelection();
     method public boolean isInputMethodTarget();
+    method public boolean isSuggestionsEnabled();
     method public boolean isTextSelectable();
     method public int length();
     method public boolean moveCursorToVisibleOffset();
@@ -25296,6 +25301,7 @@
     method public void setSingleLine();
     method public void setSingleLine(boolean);
     method public final void setSpannableFactory(android.text.Spannable.Factory);
+    method public void setSuggestionsEnabled(boolean);
     method public final void setText(java.lang.CharSequence);
     method public void setText(java.lang.CharSequence, android.widget.TextView.BufferType);
     method public final void setText(char[], int, int);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f2c97964..2a0d798 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1467,6 +1467,22 @@
             return true;
         }
 
+        case REGISTER_PROCESS_OBSERVER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IProcessObserver observer = IProcessObserver.Stub.asInterface(
+                    data.readStrongBinder());
+            registerProcessObserver(observer);
+            return true;
+        }
+
+        case UNREGISTER_PROCESS_OBSERVER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IProcessObserver observer = IProcessObserver.Stub.asInterface(
+                    data.readStrongBinder());
+            unregisterProcessObserver(observer);
+            return true;
+        }
+
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3300,5 +3316,27 @@
         return result;
     }
 
+    public void registerProcessObserver(IProcessObserver observer) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+        mRemote.transact(REGISTER_PROCESS_OBSERVER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+        mRemote.transact(UNREGISTER_PROCESS_OBSERVER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 54c3422..1f53c0e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -355,6 +355,9 @@
 
     public boolean removeTask(int taskId, int flags) throws RemoteException;
 
+    public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
+    public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -577,4 +580,6 @@
     int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+127;
     int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+128;
     int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+129;
+    int REGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+130;
+    int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+131;
 }
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
new file mode 100644
index 0000000..2094294
--- /dev/null
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/** {@hide} */
+oneway interface IProcessObserver {
+
+    void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
+    void onProcessDied(int pid, int uid);
+
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4c7d87f..a660bd7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1544,6 +1544,9 @@
      */
     public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
 
+    /** {@hide} */
+    public static final String NETWORK_POLICY_SERVICE = "netpolicy";
+
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.wifi.WifiManager} for handling management of
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index fa6eae5..d9351ee 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -23,9 +23,6 @@
  */
 interface INetworkPolicyManager {
 
-    void onForegroundActivitiesChanged(int uid, int pid, boolean foregroundActivities);
-    void onProcessDied(int uid, int pid);
-
     void setUidPolicy(int uid, int policy);
     int getUidPolicy(int uid);
 
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 2312bd9..1913aa7 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.content.Context;
 import android.os.RemoteException;
 
 /**
@@ -43,6 +44,10 @@
         mService = service;
     }
 
+    public static NetworkPolicyManager getSystemService(Context context) {
+        return (NetworkPolicyManager) context.getSystemService(Context.NETWORK_POLICY_SERVICE);
+    }
+
     /**
      * Set policy flags for specific UID.
      *
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 4430e00..0f207bc 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -36,6 +36,9 @@
     /** {@link #uid} value when entry is summarized over all UIDs. */
     public static final int UID_ALL = 0;
 
+    // NOTE: data should only be accounted for once in this structure; if data
+    // is broken out, the summarized version should not be included.
+
     /**
      * {@link SystemClock#elapsedRealtime()} timestamp when this data was
      * generated.
@@ -81,12 +84,13 @@
             mTx = new long[size];
         }
 
-        public void addEntry(String iface, int uid, long rx, long tx) {
+        public Builder addEntry(String iface, int uid, long rx, long tx) {
             mIface[mIndex] = iface;
             mUid[mIndex] = uid;
             mRx[mIndex] = rx;
             mTx[mIndex] = tx;
             mIndex++;
+            return this;
         }
 
         public NetworkStats build() {
@@ -97,11 +101,17 @@
         }
     }
 
+    public int length() {
+        // length is identical for all fields
+        return iface.length;
+    }
+
     /**
      * Find first stats index that matches the requested parameters.
      */
     public int findIndex(String iface, int uid) {
-        for (int i = 0; i < this.iface.length; i++) {
+        final int length = length();
+        for (int i = 0; i < length; i++) {
             if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
                 return i;
             }
@@ -109,13 +119,38 @@
         return -1;
     }
 
-    private static boolean equal(Object a, Object b) {
-        return a == b || (a != null && a.equals(b));
+    /**
+     * Subtract the given {@link NetworkStats}, effectively leaving the delta
+     * between two snapshots in time. Assumes that statistics rows collect over
+     * time, and that none of them have disappeared.
+     */
+    public NetworkStats subtract(NetworkStats value) {
+        // result will have our rows, but no meaningful timestamp
+        final int length = length();
+        final NetworkStats.Builder result = new NetworkStats.Builder(-1, length);
+
+        for (int i = 0; i < length; i++) {
+            final String iface = this.iface[i];
+            final int uid = this.uid[i];
+
+            // find remote row that matches, and subtract
+            final int j = value.findIndex(iface, uid);
+            if (j == -1) {
+                // newly appearing row, return entire value
+                result.addEntry(iface, uid, this.rx[i], this.tx[i]);
+            } else {
+                // existing row, subtract remote value
+                final long rx = this.rx[i] - value.rx[j];
+                final long tx = this.tx[i] - value.tx[j];
+                result.addEntry(iface, uid, rx, tx);
+            }
+        }
+
+        return result.build();
     }
 
-    /** {@inheritDoc} */
-    public int describeContents() {
-        return 0;
+    private static boolean equal(Object a, Object b) {
+        return a == b || (a != null && a.equals(b));
     }
 
     public void dump(String prefix, PrintWriter pw) {
@@ -138,6 +173,11 @@
     }
 
     /** {@inheritDoc} */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(elapsedRealtime);
         dest.writeStringArray(iface);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 7ee7a81..c0ff734 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,6 +16,12 @@
 
 package android.net;
 
+import android.content.Context;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
 import dalvik.system.BlockGuard;
 
 import java.net.Socket;
@@ -36,6 +42,17 @@
     public final static int UNSUPPORTED = -1;
 
     /**
+     * Snapshot of {@link NetworkStats} when the currently active profiling
+     * session started, or {@code null} if no session active.
+     *
+     * @see #startDataProfiling(Context)
+     * @see #stopDataProfiling(Context)
+     */
+    private static NetworkStats sActiveProfilingStart;
+
+    private static Object sProfilingLock = new Object();
+
+    /**
      * Set active tag to use when accounting {@link Socket} traffic originating
      * from the current thread. Only one active tag per thread is supported.
      * <p>
@@ -93,6 +110,44 @@
     }
 
     /**
+     * Start profiling data usage for current UID. Only one profiling session
+     * can be active at a time.
+     *
+     * @hide
+     */
+    public static void startDataProfiling(Context context) {
+        synchronized (sProfilingLock) {
+            if (sActiveProfilingStart != null) {
+                throw new IllegalStateException("already profiling data");
+            }
+
+            // take snapshot in time; we calculate delta later
+            sActiveProfilingStart = getNetworkStatsForUid(context);
+        }
+    }
+
+    /**
+     * Stop profiling data usage for current UID.
+     *
+     * @return Detailed {@link NetworkStats} of data that occurred since last
+     *         {@link #startDataProfiling(Context)} call.
+     * @hide
+     */
+    public static NetworkStats stopDataProfiling(Context context) {
+        synchronized (sProfilingLock) {
+            if (sActiveProfilingStart == null) {
+                throw new IllegalStateException("not profiling data");
+            }
+
+            // subtract starting values and return delta
+            final NetworkStats profilingStop = getNetworkStatsForUid(context);
+            final NetworkStats profilingDelta = profilingStop.subtract(sActiveProfilingStart);
+            sActiveProfilingStart = null;
+            return profilingDelta;
+        }
+    }
+
+    /**
      * Get the total number of packets transmitted through the mobile interface.
      *
      * @return number of packets.  If the statistics are not supported by this device,
@@ -350,4 +405,21 @@
      * {@link #UNSUPPORTED} will be returned.
      */
     public static native long getUidUdpRxPackets(int uid);
+
+    /**
+     * Return detailed {@link NetworkStats} for the current UID. Requires no
+     * special permission.
+     */
+    private static NetworkStats getNetworkStatsForUid(Context context) {
+        final IBinder binder = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        final INetworkManagementService service = INetworkManagementService.Stub.asInterface(
+                binder);
+
+        final int uid = android.os.Process.myUid();
+        try {
+            return service.getNetworkStatsUidDetail(uid);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index ecc111b..f17a6f2 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -214,6 +214,12 @@
     NetworkStats getNetworkStatsDetail();
 
     /**
+     * Return detailed network statistics for the requested UID,
+     * including interface and tag details.
+     */
+    NetworkStats getNetworkStatsUidDetail(int uid);
+
+    /**
      * Configures bandwidth throttling on an interface.
      */
     void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 727fcca..3ea3f56 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -129,7 +129,46 @@
     }
 
     /**
-     * Create a new ParcelFileDescriptor from the specified Socket.
+     * Create a new ParcelFileDescriptor from a raw native fd.  The new
+     * ParcelFileDescriptor holds a dup of the original fd passed in here,
+     * so you must still close that fd as well as the new ParcelFileDescriptor.
+     *
+     * @param fd The native fd that the ParcelFileDescriptor should dup.
+     *
+     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
+     * for a dup of the given fd.
+     */
+    public static ParcelFileDescriptor fromFd(int fd) throws IOException {
+        FileDescriptor fdesc = getFileDescriptorFromFd(fd);
+        return new ParcelFileDescriptor(fdesc);
+    }
+
+    // Extracts the file descriptor from the specified socket and returns it untouched
+    private static native FileDescriptor getFileDescriptorFromFd(int fd) throws IOException;
+
+    /**
+     * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
+     * The returned ParcelFileDescriptor now owns the given fd, and will be
+     * responsible for closing it.  You must not close the fd yourself.
+     *
+     * @param fd The native fd that the ParcelFileDescriptor should adopt.
+     *
+     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
+     * for the given fd.
+     */
+    public static ParcelFileDescriptor adoptFd(int fd) {
+        FileDescriptor fdesc = getFileDescriptorFromFdNoDup(fd);
+        return new ParcelFileDescriptor(fdesc);
+    }
+
+    // Extracts the file descriptor from the specified socket and returns it untouched
+    private static native FileDescriptor getFileDescriptorFromFdNoDup(int fd);
+
+    /**
+     * Create a new ParcelFileDescriptor from the specified Socket.  The new
+     * ParcelFileDescriptor holds a dup of the original FileDescriptor in
+     * the Socket, so you must still close the Socket as well as the new
+     * ParcelFileDescriptor.
      *
      * @param socket The Socket whose FileDescriptor is used to create
      *               a new ParcelFileDescriptor.
@@ -163,17 +202,14 @@
      */
     public static ParcelFileDescriptor[] createPipe() throws IOException {
         FileDescriptor[] fds = new FileDescriptor[2];
-        int res = createPipeNative(fds);
-        if (res == 0) {
-            ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
-            pfds[0] = new ParcelFileDescriptor(fds[0]);
-            pfds[1] = new ParcelFileDescriptor(fds[1]);
-            return pfds;
-        }
-        throw new IOException("Unable to create pipe: errno=" + -res);
+        createPipeNative(fds);
+        ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
+        pfds[0] = new ParcelFileDescriptor(fds[0]);
+        pfds[1] = new ParcelFileDescriptor(fds[1]);
+        return pfds;
     }
 
-    private static native int createPipeNative(FileDescriptor[] outFds);
+    private static native void createPipeNative(FileDescriptor[] outFds) throws IOException;
 
     /**
      * @hide Please use createPipe() or ContentProvider.openPipeHelper().
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 1375a29..01c640a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1481,6 +1481,13 @@
         onVmPolicyViolation(message, originStack);
     }
 
+    /**
+     * @hide
+     */
+    public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
+        onVmPolicyViolation(null, originStack);
+    }
+
     // Map from VM violation fingerprint to uptime millis.
     private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
 
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index d432dee..fe96565 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -234,7 +234,7 @@
             if (action == MotionEvent.ACTION_DOWN) {
               boolean cap = isSelecting(buffer);
               if (cap) {
-                  int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+                  int offset = widget.getOffsetForPosition(event.getX(), event.getY());
 
                   buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
 
@@ -259,7 +259,7 @@
                     // Update selection as we're moving the selection area.
 
                     // Get the current touch position
-                    int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+                    int offset = widget.getOffsetForPosition(event.getX(), event.getY());
 
                     Selection.extendSelection(buffer, offset);
                     return true;
@@ -275,7 +275,7 @@
                     return true;
                 }
 
-                int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+                int offset = widget.getOffsetForPosition(event.getX(), event.getY());
                 if (isSelecting(buffer)) {
                     buffer.removeSpan(LAST_TAP_DOWN);
                     Selection.extendSelection(buffer, offset);
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 976e786..12391df 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -39,9 +39,6 @@
     // immediately.
     private boolean mHasInstantTimer;
 
-    // Reference count the pause/resume of timers
-    private int mPauseTimerRefCount;
-
     private boolean mTimerPaused;
     private boolean mHasDeferredTimers;
 
@@ -136,7 +133,7 @@
      * Pause all timers.
      */
     public void pause() {
-        if (--mPauseTimerRefCount == 0) {
+        if (!mTimerPaused) {
             mTimerPaused = true;
             mHasDeferredTimers = false;
         }
@@ -146,7 +143,7 @@
      * Resume all timers.
      */
     public void resume() {
-        if (++mPauseTimerRefCount == 1) {
+        if (mTimerPaused) {
            mTimerPaused = false;
            if (mHasDeferredTimers) {
                mHasDeferredTimers = false;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f774803..61a69ca 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -54,7 +54,9 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
+import android.os.StrictMode;
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
 import android.text.Selection;
@@ -8933,15 +8935,14 @@
     }
 
     private static void checkThread() {
-        if (!"main".equals(Thread.currentThread().getName())) {
-            try {
-                throw new RuntimeException("A WebView method was called on thread '" +
-                        Thread.currentThread().getName() + "'. " +
-                        "All WebView methods must be called on the UI thread. " +
-                        "Future versions of WebView may not support use on other threads.");
-            } catch (RuntimeException e) {
-                Log.e(LOGTAG, Log.getStackTraceString(e));
-            }
+        if (Looper.myLooper() != Looper.getMainLooper()) {
+            RuntimeException exception = new RuntimeException(
+                    "A WebView method was called on thread '" +
+                    Thread.currentThread().getName() + "'. " +
+                    "All WebView methods must be called on the UI thread. " +
+                    "Future versions of WebView may not support use on other threads.");
+            Log.e(LOGTAG, Log.getStackTraceString(exception));
+            StrictMode.onWebViewMethodCalledOnWrongThread(exception);
         }
     }
 
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 1e1a043..563fc26 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1171,8 +1171,7 @@
         int bottomEdge = displayFrame.bottom;
         if (ignoreBottomDecorations) {
             Resources res = anchor.getContext().getResources();
-            bottomEdge = res.getDisplayMetrics().heightPixels -
-                    (int) res.getDimension(com.android.internal.R.dimen.screen_margin_bottom);
+            bottomEdge = res.getDisplayMetrics().heightPixels;
         }
         final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
         final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d58c72b..3875765 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,11 +16,6 @@
 
 package android.widget;
 
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.R;
 import android.content.ClipData;
 import android.content.ClipData.Item;
@@ -129,6 +124,11 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.text.BreakIterator;
@@ -320,6 +320,7 @@
     private int mTextEditSuggestionItemLayout;
     private SuggestionsPopupWindow mSuggestionsPopupWindow;
     private SuggestionRangeSpan mSuggestionRangeSpan;
+    private boolean mSuggestionsEnabled = true;
 
     private int mCursorDrawableRes;
     private final Drawable[] mCursorDrawable = new Drawable[2];
@@ -329,7 +330,7 @@
     private Drawable mSelectHandleRight;
     private Drawable mSelectHandleCenter;
 
-    private int mLastDownPositionX, mLastDownPositionY;
+    private float mLastDownPositionX, mLastDownPositionY;
     private Callback mCustomSelectionActionModeCallback;
 
     private final int mSquaredTouchSlopDistance;
@@ -806,6 +807,10 @@
             case com.android.internal.R.styleable.TextView_textIsSelectable:
                 mTextIsSelectable = a.getBoolean(attr, false);
                 break;
+
+            case com.android.internal.R.styleable.TextView_suggestionsEnabled:
+                mSuggestionsEnabled = a.getBoolean(attr, true);
+                break;
             }
         }
         a.recycle();
@@ -2898,8 +2903,7 @@
         setText(mCharWrapper, mBufferType, false, oldlen);
     }
 
-    private static class CharWrapper
-            implements CharSequence, GetChars, GraphicsOperations {
+    private static class CharWrapper implements CharSequence, GetChars, GraphicsOperations {
         private char[] mChars;
         private int mStart, mLength;
 
@@ -7323,8 +7327,8 @@
         }
 
         if (action == MotionEvent.ACTION_DOWN) {
-            mLastDownPositionX = (int) event.getX();
-            mLastDownPositionY = (int) event.getY();
+            mLastDownPositionX = event.getX();
+            mLastDownPositionY = event.getY();
 
             // Reset this state; it will be re-set if super.onTouchEvent
             // causes focus to move to the view.
@@ -7758,16 +7762,6 @@
                 hasPrimaryClip());
     }
 
-    private boolean isWordCharacter(int c, int type) {
-        return (c == '\'' || c == '"' ||
-                type == Character.UPPERCASE_LETTER ||
-                type == Character.LOWERCASE_LETTER ||
-                type == Character.TITLECASE_LETTER ||
-                type == Character.MODIFIER_LETTER ||
-                type == Character.OTHER_LETTER || // Should handle asian characters
-                type == Character.DECIMAL_DIGIT_NUMBER);
-    }
-
     private static long packRangeInLong(int start, int end) {
         return (((long) start) << 32) | end;
     }
@@ -8140,7 +8134,7 @@
         // Long press in empty space moves cursor and shows the Paste affordance if available.
         if (!isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
                 mInsertionControllerEnabled) {
-            final int offset = getOffset(mLastDownPositionX, mLastDownPositionY);
+            final int offset = getOffsetForPosition(mLastDownPositionX, mLastDownPositionY);
             stopSelectionActionMode();
             Selection.setSelection((Spannable) mText, offset);
             getInsertionController().showWithPaste();
@@ -8208,7 +8202,7 @@
         private final ViewGroup[] mSuggestionViews = new ViewGroup[2];
         private final int[] mSuggestionViewLayouts = new int[] {
                 mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout};
-        private WordIterator mWordIterator;
+        private WordIterator mSuggestionWordIterator;
         private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan[0];
 
         public SuggestionsPopupWindow() {
@@ -8344,26 +8338,27 @@
         }
 
         private long[] getWordLimits(CharSequence text) {
-            if (mWordIterator == null) mWordIterator = new WordIterator(); // TODO locale
-            mWordIterator.setCharSequence(text);
+            // TODO locale for mSuggestionWordIterator
+            if (mSuggestionWordIterator == null) mSuggestionWordIterator = new WordIterator();
+            mSuggestionWordIterator.setCharSequence(text);
 
             // First pass will simply count the number of words to be able to create an array
             // Not too expensive since previous break positions are cached by the BreakIterator
             int nbWords = 0;
-            int position = mWordIterator.following(0);
+            int position = mSuggestionWordIterator.following(0);
             while (position != BreakIterator.DONE) {
                 nbWords++;
-                position = mWordIterator.following(position);
+                position = mSuggestionWordIterator.following(position);
             }
 
             int index = 0;
             long[] result = new long[nbWords];
 
-            position = mWordIterator.following(0);
+            position = mSuggestionWordIterator.following(0);
             while (position != BreakIterator.DONE) {
-                int wordStart = mWordIterator.getBeginning(position);
+                int wordStart = mSuggestionWordIterator.getBeginning(position);
                 result[index++] = packRangeInLong(wordStart, position);
-                position = mWordIterator.following(position);
+                position = mSuggestionWordIterator.following(position);
             }
 
             return result;
@@ -8601,6 +8596,8 @@
     }
 
     void showSuggestions() {
+        if (!mSuggestionsEnabled || !isTextEditable()) return;
+
         if (mSuggestionsPopupWindow == null) {
             mSuggestionsPopupWindow = new SuggestionsPopupWindow();
         }
@@ -8615,6 +8612,31 @@
     }
 
     /**
+     * Some parts of the text can have alternate suggestion text attached. This is typically done by
+     * the IME by adding {@link SuggestionSpan}s to the text.
+     *
+     * When suggestions are enabled (default), this list of suggestions will be displayed when the
+     * user double taps on these parts of the text. No suggestions are displayed when this value is
+     * false. Use {@link #setSuggestionsEnabled(boolean)} to change this value.
+     *
+     * @return true if the suggestions popup window is enabled.
+     *
+     * @attr ref android.R.styleable#TextView_suggestionsEnabled
+     */
+    public boolean isSuggestionsEnabled() {
+        return mSuggestionsEnabled;
+    }
+
+    /**
+     * Enables or disables the suggestion popup. See {@link #isSuggestionsEnabled()}.
+     *
+     * @param enabled Whether or not suggestions are enabled.
+     */
+    public void setSuggestionsEnabled(boolean enabled) {
+        mSuggestionsEnabled = enabled;
+    }
+
+    /**
      * If provided, this ActionMode.Callback will be used to create the ActionMode when text
      * selection is initiated in this View.
      *
@@ -9115,7 +9137,7 @@
 
         public abstract void updateOffset(int offset);
 
-        public abstract void updatePosition(int x, int y);
+        public abstract void updatePosition(float x, float y);
 
         protected void positionAtCursorOffset(int offset) {
             addPositionToTouchUpFilter(offset);
@@ -9215,7 +9237,7 @@
                     final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
                     final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
 
-                    updatePosition(Math.round(newPosX), Math.round(newPosY));
+                    updatePosition(newPosX, newPosY);
                     break;
                 }
 
@@ -9366,8 +9388,8 @@
         }
 
         @Override
-        public void updatePosition(int x, int y) {
-            updateOffset(getOffset(x, y));
+        public void updatePosition(float x, float y) {
+            updateOffset(getOffsetForPosition(x, y));
         }
 
         void showPastePopupWindow() {
@@ -9421,11 +9443,11 @@
         }
 
         @Override
-        public void updatePosition(int x, int y) {
+        public void updatePosition(float x, float y) {
             final int selectionStart = getSelectionStart();
             final int selectionEnd = getSelectionEnd();
 
-            int offset = getOffset(x, y);
+            int offset = getOffsetForPosition(x, y);
 
             // No need to redraw when the offset is unchanged
             if (offset == selectionStart) return;
@@ -9458,11 +9480,11 @@
         }
 
         @Override
-        public void updatePosition(int x, int y) {
+        public void updatePosition(float x, float y) {
             final int selectionStart = getSelectionStart();
             final int selectionEnd = getSelectionEnd();
 
-            int offset = getOffset(x, y);
+            int offset = getOffsetForPosition(x, y);
 
             // No need to redraw when the offset is unchanged
             if (offset == selectionEnd) return;
@@ -9560,7 +9582,7 @@
 
         // Double tap detection
         private long mPreviousTapUpTime = 0;
-        private int mPreviousTapPositionX, mPreviousTapPositionY;
+        private float mPreviousTapPositionX, mPreviousTapPositionY;
 
         SelectionModifierCursorController() {
             resetTouchOffsets();
@@ -9593,19 +9615,19 @@
             if (isTextEditable() || mTextIsSelectable) {
                 switch (event.getActionMasked()) {
                     case MotionEvent.ACTION_DOWN:
-                        final int x = (int) event.getX();
-                        final int y = (int) event.getY();
+                        final float x = event.getX();
+                        final float y = event.getY();
 
                         // Remember finger down position, to be able to start selection from there
-                        mMinTouchOffset = mMaxTouchOffset = getOffset(x, y);
+                        mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y);
 
                         // Double tap detection
                         long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
                         if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
                                 isPositionOnText(x, y)) {
-                            final int deltaX = x - mPreviousTapPositionX;
-                            final int deltaY = y - mPreviousTapPositionY;
-                            final int distanceSquared = deltaX * deltaX + deltaY * deltaY;
+                            final float deltaX = x - mPreviousTapPositionX;
+                            final float deltaY = y - mPreviousTapPositionY;
+                            final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
                             if (distanceSquared < mSquaredTouchSlopDistance) {
                                 showSuggestions();
                                 mDiscardNextActionUp = true;
@@ -9641,9 +9663,7 @@
         private void updateMinAndMaxOffsets(MotionEvent event) {
             int pointerCount = event.getPointerCount();
             for (int index = 0; index < pointerCount; index++) {
-                final int x = (int) event.getX(index);
-                final int y = (int) event.getY(index);
-                int offset = getOffset(x, y);
+                int offset = getOffsetForPosition(event.getX(index), event.getY(index));
                 if (offset < mMinTouchOffset) mMinTouchOffset = offset;
                 if (offset > mMaxTouchOffset) mMaxTouchOffset = offset;
             }
@@ -9701,41 +9721,40 @@
     }
 
     /**
-     * Get the offset character closest to the specified absolute position.
+     * Get the character offset closest to the specified absolute position. A typical use case is to
+     * pass the result of {@link MotionEvent#getX()} and {@link MotionEvent#getY()} to this method.
      *
      * @param x The horizontal absolute position of a point on screen
      * @param y The vertical absolute position of a point on screen
      * @return the character offset for the character whose position is closest to the specified
      *  position. Returns -1 if there is no layout.
-     *
-     * @hide
      */
-    public int getOffset(int x, int y) {
+    public int getOffsetForPosition(float x, float y) {
         if (getLayout() == null) return -1;
         final int line = getLineAtCoordinate(y);
         final int offset = getOffsetAtCoordinate(line, x);
         return offset;
     }
 
-    private int convertToLocalHorizontalCoordinate(int x) {
+    private float convertToLocalHorizontalCoordinate(float x) {
         x -= getTotalPaddingLeft();
         // Clamp the position to inside of the view.
-        x = Math.max(0, x);
+        x = Math.max(0.0f, x);
         x = Math.min(getWidth() - getTotalPaddingRight() - 1, x);
         x += getScrollX();
         return x;
     }
 
-    private int getLineAtCoordinate(int y) {
+    private int getLineAtCoordinate(float y) {
         y -= getTotalPaddingTop();
         // Clamp the position to inside of the view.
-        y = Math.max(0, y);
+        y = Math.max(0.0f, y);
         y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y);
         y += getScrollY();
-        return getLayout().getLineForVertical(y);
+        return getLayout().getLineForVertical((int) y);
     }
 
-    private int getOffsetAtCoordinate(int line, int x) {
+    private int getOffsetAtCoordinate(int line, float x) {
         x = convertToLocalHorizontalCoordinate(x);
         return getLayout().getOffsetForHorizontal(line, x);
     }
@@ -9743,7 +9762,7 @@
     /** Returns true if the screen coordinates position (x,y) corresponds to a character displayed
      * in the view. Returns false when the position is in the empty space of left/right of text.
      */
-    private boolean isPositionOnText(int x, int y) {
+    private boolean isPositionOnText(float x, float y) {
         if (getLayout() == null) return false;
 
         final int line = getLineAtCoordinate(y);
@@ -9765,7 +9784,7 @@
                 return true;
 
             case DragEvent.ACTION_DRAG_LOCATION:
-                final int offset = getOffset((int) event.getX(), (int) event.getY());
+                final int offset = getOffsetForPosition(event.getX(), event.getY());
                 Selection.setSelection((Spannable)mText, offset);
                 return true;
 
@@ -9789,7 +9808,7 @@
             content.append(item.coerceToText(TextView.this.mContext));
         }
 
-        final int offset = getOffset((int) event.getX(), (int) event.getY());
+        final int offset = getOffsetForPosition(event.getX(), event.getY());
 
         Object localState = event.getLocalState();
         DragLocalState dragLocalState = null;
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 290bf08..7b4f216 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -89,7 +89,6 @@
         final int childCount = getChildCount();
         final int midVertical = (top + bottom) / 2;
         final int dividerWidth = getDividerWidth();
-        boolean hasOverflow = false;
         int overflowWidth = 0;
         int nonOverflowWidth = 0;
         int nonOverflowCount = 0;
@@ -102,7 +101,6 @@
 
             LayoutParams p = (LayoutParams) v.getLayoutParams();
             if (p.isOverflowButton) {
-                hasOverflow = true;
                 overflowWidth = v.getMeasuredWidth();
                 if (hasDividerBeforeChildAt(i)) {
                     overflowWidth += dividerWidth;
@@ -125,15 +123,12 @@
             }
         }
 
-        // Try to center non-overflow items with uniformly spaced padding, including on the edges.
-        // Overflow will always pin to the right edge. If there isn't enough room for that,
-        // center in the remaining space.
+        // Fill action items from the left. Overflow will always pin to the right edge.
         if (nonOverflowWidth <= widthRemaining - overflowWidth) {
             widthRemaining -= overflowWidth;
         }
 
-        final int spacing = (widthRemaining - nonOverflowWidth) / (nonOverflowCount + 1);
-        int startLeft = getPaddingLeft() + overflowWidth + spacing;
+        int startLeft = getPaddingLeft();
         for (int i = 0; i < childCount; i++) {
             final View v = getChildAt(i);
             final LayoutParams lp = (LayoutParams) v.getLayoutParams();
@@ -146,7 +141,7 @@
             int height = v.getMeasuredHeight();
             int t = midVertical - (height / 2);
             v.layout(startLeft, t, startLeft + width, t + height);
-            startLeft += width + lp.rightMargin + spacing;
+            startLeft += width + lp.rightMargin;
         }
     }
 
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index 4ec131c..99a2d04 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -34,20 +34,37 @@
     jfieldID mFileDescriptor;
 } gParcelFileDescriptorOffsets;
 
-static int android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
+static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFd(JNIEnv* env,
+    jobject clazz, jint origfd)
+{
+    int fd = dup(origfd);
+    if (fd < 0) {
+        jniThrowException(env, "java/io/IOException", strerror(errno));
+        return NULL;
+    }
+    return jniCreateFileDescriptor(env, fd);
+}
+
+static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup(JNIEnv* env,
+    jobject clazz, jint fd)
+{
+    return jniCreateFileDescriptor(env, fd);
+}
+
+static void android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
     jobject clazz, jobjectArray outFds)
 {
     int fds[2];
     if (pipe(fds) < 0) {
-        return -errno;
+        int therr = errno;
+        jniThrowException(env, "java/io/IOException", strerror(therr));
+        return;
     }
 
     for (int i=0; i<2; i++) {
         jobject fdObj = jniCreateFileDescriptor(env, fds[i]);
         env->SetObjectArrayElement(outFds, i, fdObj);
     }
-
-    return 0;
 }
 
 static jint getFd(JNIEnv* env, jobject clazz)
@@ -102,7 +119,11 @@
 }
 
 static const JNINativeMethod gParcelFileDescriptorMethods[] = {
-    {"createPipeNative", "([Ljava/io/FileDescriptor;)I",
+    {"getFileDescriptorFromFd", "(I)Ljava/io/FileDescriptor;",
+        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFd},
+    {"getFileDescriptorFromFdNoDup", "(I)Ljava/io/FileDescriptor;",
+        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup},
+    {"createPipeNative", "([Ljava/io/FileDescriptor;)V",
         (void*)android_os_ParcelFileDescriptor_createPipeNative},
     {"getStatSize", "()J",
         (void*)android_os_ParcelFileDescriptor_getStatSize},
diff --git a/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png b/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png
deleted file mode 100644
index 61db22c..0000000
--- a/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/keyboard_textfield_selected.9.png b/core/res/res/drawable-ldpi/keyboard_textfield_selected.9.png
deleted file mode 100644
index d6478fb..0000000
--- a/core/res/res/drawable-ldpi/keyboard_textfield_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png b/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png
deleted file mode 100644
index 6e703af..0000000
--- a/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/extract_edit_text.xml b/core/res/res/drawable/extract_edit_text.xml
deleted file mode 100644
index c7f66f6..0000000
--- a/core/res/res/drawable/extract_edit_text.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:drawable="@drawable/keyboard_textfield_selected" />
-    <item android:drawable="@drawable/textfield_disabled" />
-</selector>
-
diff --git a/core/res/res/layout-large/keyguard.xml b/core/res/res/layout-sw600dp/keyguard.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard.xml
rename to core/res/res/layout-sw600dp/keyguard.xml
diff --git a/core/res/res/layout-large/keyguard_screen_glogin_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_glogin_unlock.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_glogin_unlock.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_glogin_unlock.xml
diff --git a/core/res/res/layout-large/keyguard_screen_lock.xml b/core/res/res/layout-sw600dp/keyguard_screen_lock.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_lock.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_lock.xml
diff --git a/core/res/res/layout-large/keyguard_screen_password_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_password_landscape.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
diff --git a/core/res/res/layout-large/keyguard_screen_password_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_password_portrait.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
diff --git a/core/res/res/layout-large/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_sim_pin_landscape.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
diff --git a/core/res/res/layout-large/keyguard_screen_sim_pin_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_portrait.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_sim_pin_portrait.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_sim_pin_portrait.xml
diff --git a/core/res/res/layout-large/keyguard_screen_status_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_status_land.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
diff --git a/core/res/res/layout-large/keyguard_screen_status_port.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_status_port.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
diff --git a/core/res/res/layout-large/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_tab_unlock.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
diff --git a/core/res/res/layout-large/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_tab_unlock_land.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
diff --git a/core/res/res/layout-large/keyguard_screen_unlock_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_unlock_landscape.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
diff --git a/core/res/res/layout-large/keyguard_screen_unlock_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_unlock_portrait.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
diff --git a/core/res/res/layout/input_method_extract_view.xml b/core/res/res/layout/input_method_extract_view.xml
index 689ba7b..7d59d02 100644
--- a/core/res/res/layout/input_method_extract_view.xml
+++ b/core/res/res/layout/input_method_extract_view.xml
@@ -31,7 +31,6 @@
             android:gravity="top"
             android:minLines="1"
             android:inputType="text"
-            android:background="@android:drawable/extract_edit_text"
         >
     </android.inputmethodservice.ExtractEditText>
 
diff --git a/core/res/res/values-xlarge/config.xml b/core/res/res/values-sw600dp/config.xml
similarity index 99%
rename from core/res/res/values-xlarge/config.xml
rename to core/res/res/values-sw600dp/config.xml
index 4c8bbe6..49ace34 100644
--- a/core/res/res/values-xlarge/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -27,6 +27,7 @@
 
     <!-- Show sliding tab before lockscreen -->
     <bool name="config_enableSlidingTabFirst">false</bool>
+
     <!-- Enable lockscreen rotation -->
     <bool name="config_enableLockScreenRotation">true</bool>
 
diff --git a/core/res/res/values-xlarge/dimens.xml b/core/res/res/values-xlarge/dimens.xml
index e058442..b906e1a 100644
--- a/core/res/res/values-xlarge/dimens.xml
+++ b/core/res/res/values-xlarge/dimens.xml
@@ -25,10 +25,6 @@
     <!-- Size of the giant number (unread count) in the notifications -->
     <dimen name="status_bar_content_number_size">48sp</dimen>
 
-    <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
-    <!-- Margin for permanent screen decorations at the bottom. -->
-    <dimen name="screen_margin_bottom">48dip</dimen>
-
     <!-- Default height of a key in the password keyboard for alpha -->
     <dimen name="password_keyboard_key_height_alpha">75dip</dimen>
     <!-- Default height of a key in the password keyboard for numeric -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6c18089..ebb70e3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -823,6 +823,10 @@
      Default value is false. EditText content is always selectable. -->
     <attr name="textIsSelectable" format="boolean" />
 
+    <!-- When true, IME suggestions will be displayed when the user double taps on editable text.
+     The default value is true. -->
+    <attr name="suggestionsEnabled" format="boolean" />
+
     <!-- Where to ellipsize text. -->
     <attr name="ellipsize">
         <enum name="none" value="0" />
@@ -2877,6 +2881,8 @@
 
         <!-- Indicates that the content of a non-editable text can be selected. -->
         <attr name="textIsSelectable" />
+        <!-- Suggestions will be displayed when the user double taps on editable text. -->
+        <attr name="suggestionsEnabled" />
     </declare-styleable>
     <!-- An <code>input-extras</code> is a container for extra data to supply to
          an input method.  Contains
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 39d2329..6529fe1 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -77,6 +77,7 @@
     <drawable name="dialog_holo_light_frame">@drawable/dialog_full_holo_light</drawable>
     
     <drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
+    <drawable name="input_method_fullscreen_background_holo">@drawable/screen_background_holo_dark</drawable>
 
     <!-- For date picker widget -->
     <drawable name="selected_day_background">#ff0092f4</drawable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8ad8f67..1957b2a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1670,5 +1670,6 @@
   <public type="attr" name="horizontalDirection" />
 
   <public type="attr" name="fullBackupAgent" />
+  <public type="attr" name="suggestionsEnabled" />
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 158d524..ccb3518 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2449,6 +2449,20 @@
     <!-- See SMS_DIALOG.  This is a button choice to disallow sending the SMSes.. -->
     <string name="sms_control_no">Cancel</string>
 
+    <!-- SIM swap and device reboot Dialog --> <skip />
+    <!-- See SIM_REMOVED_DIALOG.  This is the title of that dialog. -->
+    <string name="sim_removed_title">SIM card removed</string>
+    <!-- See SIM_REMOVED_DIALOG.  This is the message of that dialog. -->
+    <string name="sim_removed_message">The mobile network will be unavailable until you replace the SIM card.</string>
+    <!-- See SIM_REMOVED_DIALOG.  This is the button of that dialog. -->
+    <string name="sim_done_button">Done</string>
+    <!-- See SIM_ADDED_DIALOG.  This is the title of that dialog. -->
+    <string name="sim_added_title">SIM card added</string>
+    <!-- See SIM_ADDED_DIALOG.  This is the message of that dialog. -->
+    <string name="sim_added_message">You must restart your device to access the mobile network.</string>
+    <!-- See SIM_ADDED_DIALOG.  This is the button of that dialog. -->
+    <string name="sim_restart_button">Restart</string>
+
     <!-- Date/Time picker dialogs strings -->
 
     <!-- The title of the time picker dialog. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index aa9ddff..0a614b2 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -681,7 +681,7 @@
          and a few custom attributes. -->
     <style name="Theme.Holo.InputMethod" parent="Theme.Holo.Panel">
         <item name="android:windowAnimationStyle">@android:style/Animation.InputMethod</item>
-        <item name="android:imeFullscreenBackground">@android:drawable/input_method_fullscreen_background</item>
+        <item name="android:imeFullscreenBackground">@android:drawable/input_method_fullscreen_background_holo</item>
         <item name="android:imeExtractEnterAnimation">@android:anim/input_method_extract_enter</item>
         <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
     </style>
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
new file mode 100644
index 0000000..45719c2
--- /dev/null
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+@SmallTest
+public class NetworkStatsTest extends TestCase {
+
+    private static final String TEST_IFACE = "test0";
+
+    public void testFindIndex() throws Exception {
+        final NetworkStats stats = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3)
+                .addEntry(TEST_IFACE, 100, 1024, 0)
+                .addEntry(TEST_IFACE, 101, 0, 1024)
+                .addEntry(TEST_IFACE, 102, 1024, 1024).build();
+
+        assertEquals(2, stats.findIndex(TEST_IFACE, 102));
+        assertEquals(2, stats.findIndex(TEST_IFACE, 102));
+        assertEquals(0, stats.findIndex(TEST_IFACE, 100));
+        assertEquals(-1, stats.findIndex(TEST_IFACE, 6));
+    }
+
+    public void testSubtractIdenticalData() throws Exception {
+        final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+                .addEntry(TEST_IFACE, 100, 1024, 0)
+                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+        final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+                .addEntry(TEST_IFACE, 100, 1024, 0)
+                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+        final NetworkStats result = after.subtract(before);
+
+        assertEquals(0, result.rx[0]);
+        assertEquals(0, result.tx[0]);
+        assertEquals(0, result.rx[1]);
+        assertEquals(0, result.tx[1]);
+    }
+
+    public void testSubtractIdenticalRows() throws Exception {
+        final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+                .addEntry(TEST_IFACE, 100, 1024, 0)
+                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+        final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+                .addEntry(TEST_IFACE, 100, 1025, 2)
+                .addEntry(TEST_IFACE, 101, 3, 1028).build();
+
+        final NetworkStats result = after.subtract(before);
+
+        // expect delta between measurements
+        assertEquals(1, result.rx[0]);
+        assertEquals(2, result.tx[0]);
+        assertEquals(3, result.rx[1]);
+        assertEquals(4, result.tx[1]);
+    }
+
+    public void testSubtractNewRows() throws Exception {
+        final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+                .addEntry(TEST_IFACE, 100, 1024, 0)
+                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+        final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3)
+                .addEntry(TEST_IFACE, 100, 1024, 0)
+                .addEntry(TEST_IFACE, 101, 0, 1024)
+                .addEntry(TEST_IFACE, 102, 1024, 1024).build();
+
+        final NetworkStats result = after.subtract(before);
+
+        // its okay to have new rows
+        assertEquals(0, result.rx[0]);
+        assertEquals(0, result.tx[0]);
+        assertEquals(0, result.rx[1]);
+        assertEquals(0, result.tx[1]);
+        assertEquals(1024, result.rx[2]);
+        assertEquals(1024, result.tx[2]);
+    }
+
+}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index fb7a871..70053ea 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -400,6 +400,7 @@
 }
 
 void AwesomePlayer::reset() {
+    LOGI("reset");
     Mutex::Autolock autoLock(mLock);
     reset_l();
 }
@@ -413,8 +414,10 @@
                     Playback::STOP, 0);
             mDecryptHandle = NULL;
             mDrmManagerClient = NULL;
+            LOGI("DRM manager client stopped");
     }
 
+
     if (mFlags & PLAYING) {
         uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
         if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
@@ -447,6 +450,7 @@
         mPreparedCondition.wait(mLock);
     }
 
+    LOGI("cancel player events");
     cancelPlayerEvents();
 
     mWVMExtractor.clear();
@@ -1081,6 +1085,7 @@
         usleep(1000);
     }
     IPCThreadState::self()->flushCommands();
+    LOGI("video decoder shutdown completed");
 }
 
 void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 0f0ffd4..ba495cc 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3443,7 +3443,7 @@
 }
 
 status_t OMXCodec::stop() {
-    CODEC_LOGV("stop mState=%d", mState);
+    CODEC_LOGI("stop mState=%d", mState);
 
     Mutex::Autolock autoLock(mLock);
 
@@ -3505,6 +3505,7 @@
         mLeftOverBuffer = NULL;
     }
 
+    CODEC_LOGI("stopping video source");
     mSource->stop();
 
     CODEC_LOGI("stopped in state %d", mState);
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index afefee6..ff45edc 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -14,7 +14,6 @@
 	EGL/eglApi.cpp 	       \
 	EGL/trace.cpp              \
 	EGL/getProcAddress.cpp.arm \
-	EGL/hooks.cpp 	       \
 	EGL/Loader.cpp 	       \
 #
 
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index da26229..e94e50e 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -26,11 +26,10 @@
 
 #include <EGL/egl.h>
 
-#include "hooks.h"
-#include "egl_impl.h"
-
-#include "Loader.h"
+#include "egldefs.h"
 #include "glesv2dbg.h"
+#include "hooks.h"
+#include "Loader.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 31fe306..b11db32 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -33,6 +33,7 @@
 
 #include <utils/String8.h>
 
+#include "egldefs.h"
 #include "egl_impl.h"
 #include "egl_tls.h"
 #include "glesv2dbg.h"
@@ -278,6 +279,71 @@
     return res;
 }
 
+void gl_unimplemented() {
+    LOGE("called unimplemented OpenGL ES API");
+}
+
+// ----------------------------------------------------------------------------
+
+#if USE_FAST_TLS_KEY
+
+// We have a dedicated TLS slot in bionic
+static inline gl_hooks_t const * volatile * get_tls_hooks() {
+    volatile void *tls_base = __get_tls();
+    gl_hooks_t const * volatile * tls_hooks =
+            reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
+    return tls_hooks;
+}
+
+void setGlThreadSpecific(gl_hooks_t const *value) {
+    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+    tls_hooks[TLS_SLOT_OPENGL_API] = value;
+}
+
+gl_hooks_t const* getGlThreadSpecific() {
+    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+    gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
+    if (hooks) return hooks;
+    return &gHooksNoContext;
+}
+
+#else
+
+void setGlThreadSpecific(gl_hooks_t const *value) {
+    pthread_setspecific(gGLWrapperKey, value);
+}
+
+gl_hooks_t const* getGlThreadSpecific() {
+    gl_hooks_t const* hooks =  static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
+    if (hooks) return hooks;
+    return &gHooksNoContext;
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+// GL / EGL hooks
+// ----------------------------------------------------------------------------
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
+
+char const * const gl_names[] = {
+    #include "entries.in"
+    NULL
+};
+
+char const * const egl_names[] = {
+    #include "egl_entries.in"
+    NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 8c482c3..113595f 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -30,6 +30,7 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
+#include "egldefs.h"
 #include "hooks.h"
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index 8b31468..a7989ef 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -21,7 +21,12 @@
 
 #include <EGL/egl.h>
 
+#include "egldefs.h"
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
 namespace android {
+// ----------------------------------------------------------------------------
 
 class DbgContext;
 
@@ -58,6 +63,16 @@
 
 #define setError(_e, _r) egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
 
+// ----------------------------------------------------------------------------
+
+#if EGL_TRACE
+
+extern gl_hooks_t const* getGLTraceThreadSpecific();
+
+#endif
+
+// ----------------------------------------------------------------------------
 }; // namespace android
+// ----------------------------------------------------------------------------
 
 #endif // ANDROID_EGL_TLS_H
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
new file mode 100644
index 0000000..107acd9
--- /dev/null
+++ b/opengl/libs/EGL/egldefs.h
@@ -0,0 +1,71 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_EGLDEFS_H
+#define ANDROID_EGLDEFS_H
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+
+//  EGLDisplay are global, not attached to a given thread
+const unsigned int NUM_DISPLAYS = 1;
+
+enum {
+    IMPL_HARDWARE = 0,
+    IMPL_SOFTWARE,
+    IMPL_NUM_IMPLEMENTATIONS
+};
+
+enum {
+    GLESv1_INDEX = 0,
+    GLESv2_INDEX = 1,
+};
+
+// ----------------------------------------------------------------------------
+
+struct egl_connection_t
+{
+    inline egl_connection_t() : dso(0) { }
+    void *              dso;
+    gl_hooks_t *        hooks[2];
+    EGLint              major;
+    EGLint              minor;
+    egl_t               egl;
+};
+
+// ----------------------------------------------------------------------------
+
+extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+extern gl_hooks_t gHooksNoContext;
+extern pthread_key_t gGLWrapperKey;
+extern "C" void gl_unimplemented();
+
+extern char const * const gl_names[];
+extern char const * const egl_names[];
+
+extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGLDEFS_H */
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index dcf8735c..f89c865 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -20,6 +20,7 @@
 
 #include <cutils/log.h>
 
+#include "egldefs.h"
 #include "hooks.h"
 
 // ----------------------------------------------------------------------------
@@ -34,7 +35,7 @@
 #undef GL_EXTENSION_LIST
 #undef GET_TLS
 
-#if defined(__arm__)
+#if USE_FAST_TLS_KEY
 
     #ifdef HAVE_ARM_TLS_REGISTER
         #define GET_TLS(reg) \
@@ -77,7 +78,7 @@
 
     #define GL_EXTENSION(_n)
 
-    #warning "eglGetProcAddress() partially supported on this architecture"
+    #warning "eglGetProcAddress() partially supported"
 
 #endif
 
diff --git a/opengl/libs/EGL/hooks.cpp b/opengl/libs/EGL/hooks.cpp
deleted file mode 100644
index 72ad6b3..0000000
--- a/opengl/libs/EGL/hooks.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/* 
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License"); 
- ** you may not use this file except in compliance with the License. 
- ** You may obtain a copy of the License at 
- **
- **     http://www.apache.org/licenses/LICENSE-2.0 
- **
- ** Unless required by applicable law or agreed to in writing, software 
- ** distributed under the License is distributed on an "AS IS" BASIS, 
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- ** See the License for the specific language governing permissions and 
- ** limitations under the License.
- */
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <cutils/log.h>
-
-#include "hooks.h"
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-void gl_unimplemented() {
-    LOGE("called unimplemented OpenGL ES API");
-}
-
-
-// ----------------------------------------------------------------------------
-// GL / EGL hooks
-// ----------------------------------------------------------------------------
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-#define GL_ENTRY(_r, _api, ...) #_api,
-#define EGL_ENTRY(_r, _api, ...) #_api,
-
-char const * const gl_names[] = {
-    #include "entries.in"
-    NULL
-};
-
-char const * const egl_names[] = {
-    #include "egl_entries.in"
-    NULL
-};
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp
index f3e101b..0e934e2 100644
--- a/opengl/libs/EGL/trace.cpp
+++ b/opengl/libs/EGL/trace.cpp
@@ -26,6 +26,7 @@
 
 #include <cutils/log.h>
 
+#include "egl_tls.h"
 #include "hooks.h"
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index d24b047..a809316 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -25,27 +25,12 @@
 
 #include "hooks.h"
 
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 4
-
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
 
-struct egl_connection_t
-{
-    inline egl_connection_t() : dso(0) { }
-    void *              dso;
-    gl_hooks_t *        hooks[2];
-    EGLint              major;
-    EGLint              minor;
-    egl_t               egl;
-};
-
 EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
 
-extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
-
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 812e26d..7ac88cd 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -54,22 +54,6 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-//  EGLDisplay are global, not attached to a given thread
-const unsigned int NUM_DISPLAYS = 1;
-
-enum {
-    IMPL_HARDWARE = 0,
-    IMPL_SOFTWARE,
-    IMPL_NUM_IMPLEMENTATIONS
-};
-
-enum {
-    GLESv1_INDEX = 0,
-    GLESv2_INDEX = 1,
-};
-
-// ----------------------------------------------------------------------------
-
 // GL / EGL hooks
 
 #undef GL_ENTRY
@@ -92,60 +76,8 @@
 #undef GL_ENTRY
 #undef EGL_ENTRY
 
-
-// ----------------------------------------------------------------------------
-
-extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
-extern gl_hooks_t gHooksNoContext;
-extern pthread_key_t gGLWrapperKey;
-extern "C" void gl_unimplemented();
-
-extern char const * const gl_names[];
-extern char const * const egl_names[];
-
-// ----------------------------------------------------------------------------
-
-#if USE_FAST_TLS_KEY
-
-// We have a dedicated TLS slot in bionic
-static inline gl_hooks_t const * volatile * get_tls_hooks() {
-    volatile void *tls_base = __get_tls();
-    gl_hooks_t const * volatile * tls_hooks = 
-            reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
-    return tls_hooks;
-}
-
-static inline void setGlThreadSpecific(gl_hooks_t const *value) {
-    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
-    tls_hooks[TLS_SLOT_OPENGL_API] = value;
-}
-
-static gl_hooks_t const* getGlThreadSpecific() {
-    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
-    gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
-    if (hooks) return hooks;
-    return &gHooksNoContext;
-}
-
-#else
-
-static inline void setGlThreadSpecific(gl_hooks_t const *value) {
-    pthread_setspecific(gGLWrapperKey, value);
-}
-
-static gl_hooks_t const* getGlThreadSpecific() {
-    gl_hooks_t const* hooks =  static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
-    if (hooks) return hooks;
-    return &gHooksNoContext;
-}
-
-#endif
-
-#if EGL_TRACE
-
-extern gl_hooks_t const* getGLTraceThreadSpecific();
-
-#endif
+EGLAPI void setGlThreadSpecific(gl_hooks_t const *value);
+EGLAPI gl_hooks_t const* getGlThreadSpecific();
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/packages/SystemUI/res/layout-large/status_bar.xml b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_input_methods_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_input_methods_item.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_input_methods_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_input_methods_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_area.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_area.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_panel_title.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_peek.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_peek.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_peek.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_peek.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_row.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_row.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_pocket_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_pocket_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_pocket_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_pocket_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_recent_item.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_panel_footer.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel_footer.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_recent_panel_footer.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel_footer.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_settings_view.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_settings_view.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_settings_view.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_settings_view.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_ticker_compat.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_compat.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_ticker_compat.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_ticker_compat.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_ticker_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_ticker_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
diff --git a/packages/SystemUI/res/values-large/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
similarity index 100%
rename from packages/SystemUI/res/values-large/styles.xml
rename to packages/SystemUI/res/values-sw600dp/styles.xml
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 7c613c1..8f179f5 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -16,51 +16,34 @@
 
 package com.android.server;
 
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
 import android.content.pm.PackageManager;
-import android.net.NetworkStats;
-import android.net.Uri;
-import android.net.InterfaceConfiguration;
 import android.net.INetworkManagementEventObserver;
+import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
+import android.net.NetworkStats;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.Binder;
 import android.os.INetworkManagementService;
-import android.os.Handler;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
-import java.util.ArrayList;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-import android.provider.Settings;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.RandomAccessFile;
-import java.io.Reader;
-import java.lang.IllegalStateException;
-import java.net.InetAddress;
 import java.net.Inet4Address;
-import java.net.UnknownHostException;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
 import java.util.concurrent.CountDownLatch;
 
 import libcore.io.IoUtils;
@@ -69,14 +52,16 @@
  * @hide
  */
 class NetworkManagementService extends INetworkManagementService.Stub {
-
-    private static final String TAG = "NetworkManagmentService";
+    private static final String TAG = "NetworkManagementService";
     private static final boolean DBG = false;
     private static final String NETD_TAG = "NetdConnector";
 
     private static final int ADD = 1;
     private static final int REMOVE = 2;
 
+    /** Base path to UID-granularity network statistics. */
+    private static final File PATH_PROC_UID_STAT = new File("/proc/uid_stat");
+
     class NetdResponseCode {
         public static final int InterfaceListResult       = 110;
         public static final int TetherInterfaceListResult = 111;
@@ -891,7 +876,7 @@
         return -1;
     }
 
-    /** {@inheritDoc} */
+    @Override
     public NetworkStats getNetworkStatsSummary() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
@@ -909,31 +894,46 @@
         return stats.build();
     }
 
-    /** {@inheritDoc} */
+    @Override
     public NetworkStats getNetworkStatsDetail() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
-        final File procPath = new File("/proc/uid_stat");
-        final String[] knownUids = procPath.list();
+        final String[] knownUids = PATH_PROC_UID_STAT.list();
         final NetworkStats.Builder stats = new NetworkStats.Builder(
                 SystemClock.elapsedRealtime(), knownUids.length);
 
-        // TODO: kernel module will provide interface-level stats in future
-        // TODO: migrate these stats to come across netd in bulk, instead of all
-        // these individual file reads.
         for (String uid : knownUids) {
-            final File uidPath = new File(procPath, uid);
-            final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
-            final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));
-
             final int uidInt = Integer.parseInt(uid);
-            stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
+            collectNetworkStatsDetail(stats, uidInt);
         }
 
         return stats.build();
     }
 
+    @Override
+    public NetworkStats getNetworkStatsUidDetail(int uid) {
+        if (Binder.getCallingUid() != uid) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+        }
+
+        final NetworkStats.Builder stats = new NetworkStats.Builder(
+                SystemClock.elapsedRealtime(), 1);
+        collectNetworkStatsDetail(stats, uid);
+        return stats.build();
+    }
+
+    private void collectNetworkStatsDetail(NetworkStats.Builder stats, int uid) {
+        // TODO: kernel module will provide interface-level stats in future
+        // TODO: migrate these stats to come across netd in bulk, instead of all
+        // these individual file reads.
+        final File uidPath = new File(PATH_PROC_UID_STAT, Integer.toString(uid));
+        final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
+        final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
+        stats.addEntry(NetworkStats.IFACE_ALL, uid, rx, tx);
+    }
+
     public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
@@ -994,22 +994,17 @@
     }
 
     /**
-     * Utility method to read a single plain-text {@link Integer} from the given
+     * Utility method to read a single plain-text {@link Long} from the given
      * {@link File}, usually from a {@code /proc/} filesystem.
      */
-    private static int readSingleIntFromFile(File file) {
-        RandomAccessFile f = null;
+    private static long readSingleLongFromFile(File file) {
         try {
-            f = new RandomAccessFile(file, "r");
-            byte[] buffer = new byte[(int) f.length()];
-            f.readFully(buffer);
-            return Integer.parseInt(new String(buffer).trim());
+            final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
+            return Long.parseLong(new String(buffer).trim());
         } catch (NumberFormatException e) {
             return -1;
         } catch (IOException e) {
             return -1;
-        } finally {
-            IoUtils.closeQuietly(f);
         }
     }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd8915d..5355d44 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -18,6 +18,7 @@
 
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
+import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.usb.UsbService;
 import com.android.server.wm.WindowManagerService;
@@ -119,6 +120,7 @@
         LightsService lights = null;
         PowerManagerService power = null;
         BatteryService battery = null;
+        NetworkPolicyManagerService networkPolicy = null;
         ConnectivityService connectivity = null;
         IPackageManager pm = null;
         Context context = null;
@@ -282,6 +284,15 @@
             }
 
             try {
+                Slog.i(TAG, "NetworkPolicy Service");
+                networkPolicy = new NetworkPolicyManagerService(
+                        context, ActivityManagerService.self(), power);
+                ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
+            } catch (Throwable e) {
+                Slog.e(TAG, "Failure starting Connectivity Service", e);
+            }
+
+            try {
                 Slog.i(TAG, "NetworkManagement Service");
                 ServiceManager.addService(
                         Context.NETWORKMANAGEMENT_SERVICE,
@@ -528,6 +539,7 @@
         // These are needed to propagate to the runnable below.
         final Context contextF = context;
         final BatteryService batteryF = battery;
+        final NetworkPolicyManagerService networkPolicyF = networkPolicy;
         final ConnectivityService connectivityF = connectivity;
         final DockObserver dockF = dock;
         final UsbService usbF = usb;
@@ -553,6 +565,7 @@
 
                 startSystemUi(contextF);
                 if (batteryF != null) batteryF.systemReady();
+                if (networkPolicyF != null) networkPolicyF.systemReady();
                 if (connectivityF != null) connectivityF.systemReady();
                 if (dockF != null) dockF.systemReady();
                 if (usbF != null) usbF.systemReady();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5aae539..568183b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -43,6 +43,7 @@
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
 import android.app.INotificationManager;
+import android.app.IProcessObserver;
 import android.app.IServiceConnection;
 import android.app.IThumbnailReceiver;
 import android.app.IThumbnailRetriever;
@@ -752,8 +753,6 @@
      */
     final UsageStatsService mUsageStatsService;
 
-    final NetworkPolicyManagerService mNetworkPolicyService;
-
     /**
      * Current configuration information.  HistoryRecord objects are given
      * a reference to this object to indicate which configuration they are
@@ -885,7 +884,10 @@
 
     final RemoteCallbackList<IActivityWatcher> mWatchers
             = new RemoteCallbackList<IActivityWatcher>();
-    
+
+    final RemoteCallbackList<IProcessObserver> mProcessObservers
+            = new RemoteCallbackList<IProcessObserver>();
+
     /**
      * Callback of last caller to {@link #requestPss}.
      */
@@ -1277,16 +1279,15 @@
                 }
             } break;
             case DISPATCH_FOREGROUND_ACTIVITIES_CHANGED: {
-                // Flag might have changed during dispatch, but it's always
-                // consistent since we dispatch for every change.
                 final ProcessRecord app = (ProcessRecord) msg.obj;
-                mNetworkPolicyService.onForegroundActivitiesChanged(
-                        app.info.uid, app.pid, app.foregroundActivities);
+                final boolean foregroundActivities = msg.arg1 != 0;
+                dispatchForegroundActivitiesChanged(
+                        app.pid, app.info.uid, foregroundActivities);
                 break;
             }
             case DISPATCH_PROCESS_DIED: {
                 final ProcessRecord app = (ProcessRecord) msg.obj;
-                mNetworkPolicyService.onProcessDied(app.info.uid, app.pid);
+                dispatchProcessDied(app.pid, app.info.uid);
                 break;
             }
             }
@@ -1358,7 +1359,6 @@
         
         m.mBatteryStatsService.publish(context);
         m.mUsageStatsService.publish(context);
-        m.mNetworkPolicyService.publish(context);
         
         synchronized (thr) {
             thr.mReady = true;
@@ -1480,8 +1480,6 @@
         mUsageStatsService = new UsageStatsService(new File(
                 systemDir, "usagestats").toString());
 
-        mNetworkPolicyService = new NetworkPolicyManagerService();
-
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
             ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
 
@@ -2152,6 +2150,36 @@
         mWatchers.finishBroadcast();
     }
 
+    private void dispatchForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
+        int i = mProcessObservers.beginBroadcast();
+        while (i > 0) {
+            i--;
+            final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
+            if (observer != null) {
+                try {
+                    observer.onForegroundActivitiesChanged(pid, uid, foregroundActivities);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        mProcessObservers.finishBroadcast();
+    }
+
+    private void dispatchProcessDied(int pid, int uid) {
+        int i = mProcessObservers.beginBroadcast();
+        while (i > 0) {
+            i--;
+            final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
+            if (observer != null) {
+                try {
+                    observer.onProcessDied(pid, uid);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        mProcessObservers.finishBroadcast();
+    }
+
     final void doPendingActivityLaunchesLocked(boolean doResume) {
         final int N = mPendingActivityLaunches.size();
         if (N <= 0) {
@@ -6084,7 +6112,6 @@
         
         mUsageStatsService.shutdown();
         mBatteryStatsService.shutdown();
-        mNetworkPolicyService.shutdown();
         
         return timedout;
     }
@@ -6241,6 +6268,14 @@
         }
     }
 
+    public void registerProcessObserver(IProcessObserver observer) {
+        mProcessObservers.register(observer);
+    }
+
+    public void unregisterProcessObserver(IProcessObserver observer) {
+        mProcessObservers.unregister(observer);
+    }
+
     public void setImmersive(IBinder token, boolean immersive) {
         synchronized(this) {
             int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
@@ -12755,7 +12790,8 @@
         app.curSchedGroup = schedGroup;
 
         if (hadForegroundActivities != app.foregroundActivities) {
-            mHandler.obtainMessage(DISPATCH_FOREGROUND_ACTIVITIES_CHANGED, app).sendToTarget();
+            mHandler.obtainMessage(DISPATCH_FOREGROUND_ACTIVITIES_CHANGED,
+                    app.foregroundActivities ? 1 : 0, 0, app).sendToTarget();
         }
 
         return adj;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index a7a4f07..d083d01 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -19,13 +19,20 @@
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
 import static android.Manifest.permission.UPDATE_DEVICE_STATS;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
-import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_BACKGROUND;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID;
 
+import android.app.IActivityManager;
+import android.app.IProcessObserver;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.INetworkPolicyManager;
-import android.os.ServiceManager;
+import android.os.IPowerManager;
+import android.os.RemoteException;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
@@ -38,92 +45,139 @@
     private static final String TAG = "NetworkPolicy";
     private static final boolean LOGD = true;
 
-    private static final String SERVICE_NAME = "netpolicy";
-
     private Context mContext;
+    private IActivityManager mActivityManager;
+    private IPowerManager mPowerManager;
+
+    private Object mRulesLock = new Object();
+
+    private boolean mScreenOn = false;
 
     /** Current network policy for each UID. */
-    private SparseIntArray mUidPolicy;
+    private SparseIntArray mUidPolicy = new SparseIntArray();
 
     /** Foreground at both UID and PID granularity. */
-    private SparseBooleanArray mUidForeground;
-    private SparseArray<SparseBooleanArray> mUidPidForeground;
+    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
+    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
+            SparseBooleanArray>();
 
     // TODO: periodically poll network stats and write to disk
     // TODO: save/restore policy information from disk
 
-    // TODO: watch screen on/off broadcasts to track foreground
+    public NetworkPolicyManagerService(
+            Context context, IActivityManager activityManager, IPowerManager powerManager) {
+        mContext = checkNotNull(context, "missing context");
+        mActivityManager = checkNotNull(activityManager, "missing activityManager");
+        mPowerManager = checkNotNull(powerManager, "missing powerManager");
+    }
 
-    public void publish(Context context) {
-        mContext = context;
-        ServiceManager.addService(SERVICE_NAME, asBinder());
-
-        mUidPolicy = new SparseIntArray();
-        mUidForeground = new SparseBooleanArray();
-        mUidPidForeground = new SparseArray<SparseBooleanArray>();
-
-        // TODO: register for NetworkManagementService callbacks
+    public void systemReady() {
         // TODO: read current policy+stats from disk and generate NMS rules
-    }
 
-    public void shutdown() {
-        // TODO: persist any pending stats during clean shutdown
+        updateScreenOn();
 
-        mUidPolicy = null;
-        mUidForeground = null;
-        mUidPidForeground = null;
-    }
-
-    @Override
-    public void onForegroundActivitiesChanged(int uid, int pid, boolean foreground) {
-        // only someone like AMS should only be calling us
-        mContext.enforceCallingOrSelfPermission(
-                MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
-
-        // because a uid can have multiple pids running inside, we need to
-        // remember all pid states and summarize foreground at uid level.
-
-        // record foreground for this specific pid
-        SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
-        if (pidForeground == null) {
-            pidForeground = new SparseBooleanArray(2);
-            mUidPidForeground.put(uid, pidForeground);
+        try {
+            mActivityManager.registerProcessObserver(mProcessObserver);
+        } catch (RemoteException e) {
+            // ouch, no foregroundActivities updates means some processes may
+            // never get network access.
+            Slog.e(TAG, "unable to register IProcessObserver", e);
         }
-        pidForeground.put(pid, foreground);
-        computeUidForeground(uid);
+
+        // TODO: traverse existing processes to know foreground state, or have
+        // activitymanager dispatch current state when new observer attached.
+
+        final IntentFilter screenFilter = new IntentFilter();
+        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
+        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
+        mContext.registerReceiver(mScreenReceiver, screenFilter);
+
+        final IntentFilter shutdownFilter = new IntentFilter();
+        shutdownFilter.addAction(Intent.ACTION_SHUTDOWN);
+        mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
+
     }
 
-    @Override
-    public void onProcessDied(int uid, int pid) {
-        // only someone like AMS should only be calling us
-        mContext.enforceCallingOrSelfPermission(
-                MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
+    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
+        @Override
+        public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
+            // only someone like AMS should only be calling us
+            mContext.enforceCallingOrSelfPermission(
+                    MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
 
-        // clear records and recompute, when they exist
-        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
-        if (pidForeground != null) {
-            pidForeground.delete(pid);
-            computeUidForeground(uid);
+            synchronized (mRulesLock) {
+                // because a uid can have multiple pids running inside, we need to
+                // remember all pid states and summarize foreground at uid level.
+
+                // record foreground for this specific pid
+                SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+                if (pidForeground == null) {
+                    pidForeground = new SparseBooleanArray(2);
+                    mUidPidForeground.put(uid, pidForeground);
+                }
+                pidForeground.put(pid, foregroundActivities);
+                computeUidForegroundL(uid);
+            }
         }
-    }
+
+        @Override
+        public void onProcessDied(int pid, int uid) {
+            // only someone like AMS should only be calling us
+            mContext.enforceCallingOrSelfPermission(
+                    MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
+
+            synchronized (mRulesLock) {
+                // clear records and recompute, when they exist
+                final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+                if (pidForeground != null) {
+                    pidForeground.delete(pid);
+                    computeUidForegroundL(uid);
+                }
+            }
+        }
+    };
+
+    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mRulesLock) {
+                // screen-related broadcasts are protected by system, no need
+                // for permissions check.
+                updateScreenOn();
+            }
+        }
+    };
+
+    private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // TODO: persist any pending stats during clean shutdown
+            Log.d(TAG, "persisting stats");
+        }
+    };
 
     @Override
     public void setUidPolicy(int uid, int policy) {
         mContext.enforceCallingOrSelfPermission(
                 UPDATE_DEVICE_STATS, "requires UPDATE_DEVICE_STATS permission");
-        mUidPolicy.put(uid, policy);
+
+        synchronized (mRulesLock) {
+            mUidPolicy.put(uid, policy);
+        }
     }
 
     @Override
     public int getUidPolicy(int uid) {
-        return mUidPolicy.get(uid, POLICY_NONE);
+        synchronized (mRulesLock) {
+            return mUidPolicy.get(uid, POLICY_NONE);
+        }
     }
 
     /**
      * Foreground for PID changed; recompute foreground at UID level. If
-     * changed, will trigger {@link #updateRulesForUid(int)}.
+     * changed, will trigger {@link #updateRulesForUidL(int)}.
      */
-    private void computeUidForeground(int uid) {
+    private void computeUidForegroundL(int uid) {
         final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
 
         // current pid is dropping foreground; examine other pids
@@ -140,12 +194,37 @@
         if (oldUidForeground != uidForeground) {
             // foreground changed, push updated rules
             mUidForeground.put(uid, uidForeground);
-            updateRulesForUid(uid);
+            updateRulesForUidL(uid);
         }
     }
 
-    private void updateRulesForUid(int uid) {
-        final boolean uidForeground = mUidForeground.get(uid, false);
+    private void updateScreenOn() {
+        synchronized (mRulesLock) {
+            try {
+                mScreenOn = mPowerManager.isScreenOn();
+            } catch (RemoteException e) {
+            }
+            updateRulesForScreenL();
+        }
+    }
+
+    /**
+     * Update rules that might be changed by {@link #mScreenOn} value.
+     */
+    private void updateRulesForScreenL() {
+        // only update rules for anyone with foreground activities
+        final int size = mUidForeground.size();
+        for (int i = 0; i < size; i++) {
+            if (mUidForeground.valueAt(i)) {
+                final int uid = mUidForeground.keyAt(i);
+                updateRulesForUidL(uid);
+            }
+        }
+    }
+
+    private void updateRulesForUidL(int uid) {
+        // only really in foreground when screen on
+        final boolean uidForeground = mUidForeground.get(uid, false) && mScreenOn;
         final int uidPolicy = getUidPolicy(uid);
 
         if (LOGD) {
@@ -162,4 +241,10 @@
         }
     }
 
+    private static <T> T checkNotNull(T value, String message) {
+        if (value == null) {
+            throw new NullPointerException(message);
+        }
+        return value;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index f20d5e5..ca33d32 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -42,6 +42,7 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.Suppress;
 import android.text.format.DateUtils;
 import android.util.Log;
@@ -54,6 +55,7 @@
 /**
  * Tests for {@link ThrottleService}.
  */
+@LargeTest
 public class ThrottleServiceTest extends AndroidTestCase {
     private static final String TAG = "ThrottleServiceTest";
 
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 9fc4667..0c4581b 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -25,6 +25,11 @@
 import android.os.SystemProperties;
 import android.util.Log;
 
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * {@hide}
  */
@@ -794,6 +799,34 @@
     }
 
     /**
+     * The contents of the /proc/cmdline file
+     */
+    private static String getProcCmdLine()
+    {
+        String cmdline = "";
+        FileInputStream is = null;
+        try {
+            is = new FileInputStream("/proc/cmdline");
+            byte [] buffer = new byte[2048];
+            int count = is.read(buffer);
+            if (count > 0) {
+                cmdline = new String(buffer, 0, count);
+            }
+        } catch (IOException e) {
+            Log.d(LOG_TAG, "No /proc/cmdline exception=" + e);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        Log.d(LOG_TAG, "/proc/cmdline=" + cmdline);
+        return cmdline;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -801,6 +834,17 @@
         return getLteOnCdmaModeStatic();
     }
 
+    /** Kernel command line */
+    private static final String sKernelCmdLine = getProcCmdLine();
+
+    /** Pattern for selecting the product type from the kernel command line */
+    private static final Pattern sProductTypePattern =
+        Pattern.compile("\\sproduct_type\\s*=\\s*(\\w+)");
+
+    /** The ProductType used for LTE on CDMA devices */
+    private static final String sLteOnCdmaProductType =
+        SystemProperties.get(TelephonyProperties.PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE, "");
+
     /**
      * Return if the current radio is LTE on CDMA. This
      * is a tri-state return value as for a period of time
@@ -810,9 +854,24 @@
      * or {@link Phone#LTE_ON_CDMA_TRUE}
      */
     public static int getLteOnCdmaModeStatic() {
-        int retVal = SystemProperties.getInt(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA,
-                Phone.LTE_ON_CDMA_FALSE);
-        Log.d(LOG_TAG, "getLteOnCdmaMode=" + retVal);
+        int retVal;
+        String productType;
+
+        Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine);
+        if (matcher.find()) {
+            productType = matcher.group(1);
+            if (sLteOnCdmaProductType.equals(productType)) {
+                retVal = Phone.LTE_ON_CDMA_TRUE;
+            } else {
+                retVal = Phone.LTE_ON_CDMA_FALSE;
+            }
+        } else {
+            retVal = Phone.LTE_ON_CDMA_FALSE;
+            productType = "";
+        }
+
+        Log.d(LOG_TAG, "getLteOnCdmaMode=" + retVal + " product_type='" + productType +
+                "' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'");
         return retVal;
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 2e781b2..3636baa 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -22,8 +22,10 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
+import android.net.LinkAddress;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
+import android.net.NetworkUtils;
 import android.net.ProxyProperties;
 import android.os.AsyncResult;
 import android.os.Bundle;
@@ -33,6 +35,7 @@
 import android.os.SystemProperties;
 import android.text.TextUtils;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -202,6 +205,7 @@
     protected long lastFailTime;
     protected FailCause lastFailCause;
     protected static final String NULL_IP = "0.0.0.0";
+    private int mRefCount;
     Object userData;
 
     //***** Abstract methods
@@ -249,6 +253,8 @@
             Message m = dp.onCompletedMsg;
             if (TextUtils.equals(dp.reason, Phone.REASON_RADIO_TURNED_OFF)) {
                 discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
+            } else if (TextUtils.equals(dp.reason, Phone.REASON_PDP_RESET)) {
+                discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
             }
         }
         if (phone.mCM.getRadioState().isOn()) {
@@ -408,49 +414,6 @@
         return mRetryMgr.configure(configStr);
     }
 
-    private AtomicInteger mRefCount = new AtomicInteger(0);
-
-    /**
-     * Set refCount.
-     *
-     * @param val is new refCount
-     */
-    public void setRefCount(int val) {
-        mRefCount.set(val);
-    }
-
-    /**
-     * Get refCount
-     *
-     * @return refCount
-     */
-    public int getRefCount() {
-        return mRefCount.get();
-    }
-
-    /**
-     * @return decrement and return refCount
-     *
-     * TODO: Consider using the refCount for defining the
-     * life time of a connection. When this goes zero the
-     * DataConnection could tear itself down.
-     */
-    public int decAndGetRefCount() {
-        int v = mRefCount.decrementAndGet();
-        if (v < 0) {
-            log("BUG: decAndGetRefCount caused refCount to be < 0");
-            mRefCount.set(0);
-        }
-        return v;
-     }
-
-    /**
-     * @return increment and return refCount
-     */
-    public int incAndGetRefCount() {
-        return mRefCount.incrementAndGet();
-    }
-
     /*
      * **************************************************************************
      * End members owned by DataConnectionTracker
@@ -466,6 +429,7 @@
         createTime = -1;
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
+        mRefCount = 0;
 
         mLinkProperties = new LinkProperties();
         mApn = null;
@@ -531,8 +495,10 @@
         return response.setLinkProperties(lp, okToUseSystemPropertyDns);
     }
 
-    private boolean updateLinkProperty(DataCallState newState) {
-        boolean changed = false;
+    private DataConnectionAc.LinkPropertyChangeAction updateLinkProperty(
+                                                      DataCallState newState) {
+        DataConnectionAc.LinkPropertyChangeAction changed =
+                        DataConnectionAc.LinkPropertyChangeAction.NONE;
 
         if (newState == null) return changed;
 
@@ -551,9 +517,23 @@
         if (DBG) log("old LP=" + mLinkProperties);
         if (DBG) log("new LP=" + newLp);
 
+        // Check consistency of link address. Currently we expect
+        // only one "global" address is assigned per each IP type.
+        Collection<LinkAddress> oLinks = mLinkProperties.getLinkAddresses();
+        Collection<LinkAddress> nLinks = newLp.getLinkAddresses();
+        for (LinkAddress oldLink : oLinks) {
+            for (LinkAddress newLink : nLinks) {
+                if ((NetworkUtils.addressTypeMatches(oldLink.getAddress(),
+                                        newLink.getAddress())) &&
+                    (oldLink.equals(newLink) == false)) {
+                    return DataConnectionAc.LinkPropertyChangeAction.RESET;
+                }
+            }
+        }
+
         if (mLinkProperties == null || !mLinkProperties.equals(newLp)) {
             mLinkProperties = newLp;
-            changed = true;
+            changed = DataConnectionAc.LinkPropertyChangeAction.CHANGED;
         }
 
         return changed;
@@ -631,15 +611,14 @@
                 }
                 case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
                     DataCallState newState = (DataCallState) msg.obj;
-                    int updated = updateLinkProperty(newState) ? 1 : 0;
+                    DataConnectionAc.LinkPropertyChangeAction action = updateLinkProperty(newState);
                     if (DBG) {
-                        log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE updated="
-                                + (updated == 1)
-                                + " newState=" + newState);
+                        log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE action="
+                            + action + " newState=" + newState);
                     }
                     mAc.replyToMessage(msg,
                                    DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
-                                   updated);
+                                   action.ordinal());
                     break;
                 }
                 case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
@@ -654,6 +633,11 @@
                     mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
                     transitionTo(mInactiveState);
                     break;
+                case DataConnectionAc.REQ_GET_REFCOUNT: {
+                    log("REQ_GET_REFCOUNT  refCount=" + mRefCount);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount);
+                    break;
+                }
 
                 case EVENT_CONNECT:
                     if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
@@ -754,9 +738,13 @@
                     break;
 
                 case EVENT_CONNECT:
-                    if (DBG) log("DcInactiveState msg.what=EVENT_CONNECT");
                     ConnectionParams cp = (ConnectionParams) msg.obj;
                     cp.tag = mTag;
+                    if (DBG) {
+                        log("DcInactiveState msg.what=EVENT_CONNECT." + "RefCount = "
+                                + mRefCount);
+                    }
+                    mRefCount = 1;
                     onConnect(cp);
                     transitionTo(mActivatingState);
                     retVal = HANDLED;
@@ -784,7 +772,15 @@
 
             switch (msg.what) {
                 case EVENT_DISCONNECT:
-                    if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
+                    if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT"
+                            + mRefCount);
+                    deferMessage(msg);
+                    retVal = HANDLED;
+                    break;
+
+                case EVENT_CONNECT:
+                    if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = "
+                            + mRefCount);
                     deferMessage(msg);
                     retVal = HANDLED;
                     break;
@@ -908,12 +904,28 @@
             boolean retVal;
 
             switch (msg.what) {
+                case EVENT_CONNECT:
+                    mRefCount++;
+                    if (DBG) log("DcActiveState msg.what=EVENT_CONNECT RefCount=" + mRefCount);
+                    if (msg.obj != null) {
+                        notifyConnectCompleted((ConnectionParams) msg.obj, FailCause.NONE);
+                    }
+                    retVal = HANDLED;
+                    break;
                 case EVENT_DISCONNECT:
-                    if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT");
-                    DisconnectParams dp = (DisconnectParams) msg.obj;
-                    dp.tag = mTag;
-                    tearDownData(dp);
-                    transitionTo(mDisconnectingState);
+                    mRefCount--;
+                    if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" + mRefCount);
+                    if (mRefCount == 0)
+                    {
+                        DisconnectParams dp = (DisconnectParams) msg.obj;
+                        dp.tag = mTag;
+                        tearDownData(dp);
+                        transitionTo(mDisconnectingState);
+                    } else {
+                        if (msg.obj != null) {
+                            notifyDisconnectCompleted((DisconnectParams) msg.obj);
+                        }
+                    }
                     retVal = HANDLED;
                     break;
 
@@ -936,6 +948,13 @@
             boolean retVal;
 
             switch (msg.what) {
+                case EVENT_CONNECT:
+                    if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
+                            + mRefCount);
+                    deferMessage(msg);
+                    retVal = HANDLED;
+                    break;
+
                 case EVENT_DEACTIVATE_DONE:
                     if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE");
                     AsyncResult ar = (AsyncResult) msg.obj;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index 2ab6184..a0d9b0f 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -59,6 +59,29 @@
     public static final int REQ_RESET = BASE + 14;
     public static final int RSP_RESET = BASE + 15;
 
+    public static final int REQ_GET_REFCOUNT = BASE + 16;
+    public static final int RSP_GET_REFCOUNT = BASE + 17;
+
+    /**
+     * enum used to notify action taken or necessary to be
+     * taken after the link property is changed.
+     */
+    public enum LinkPropertyChangeAction {
+        NONE, CHANGED, RESET;
+
+        public static LinkPropertyChangeAction fromInt(int value) {
+            if (value == NONE.ordinal()) {
+                return NONE;
+            } else if (value == CHANGED.ordinal()) {
+                return CHANGED;
+            } else if (value == RESET.ordinal()) {
+                return RESET;
+            } else {
+                throw new RuntimeException("LinkPropertyChangeAction.fromInt: bad value=" + value);
+            }
+        }
+    }
+
     public DataConnectionAc(DataConnection dc, String logTag) {
         dataConnection = dc;
         mLogTag = logTag;
@@ -132,6 +155,40 @@
     }
 
     /**
+     * Request the Reference Count.
+     * Response {@link #rspRefCount}
+     */
+    public void reqRefCount() {
+        sendMessage(REQ_GET_REFCOUNT);
+        if (DBG) log("reqRefCount");
+    }
+
+    /**
+     * Evaluate a RSP_GET_REFCOUNT message and return the refCount.
+     *
+     * @param response Message
+     * @return ref count or -1 if an error
+     */
+    public int rspRefCount(Message response) {
+        int retVal = response.arg1;
+        if (DBG) log("rspRefCount=" + retVal);
+        return retVal;
+    }
+
+    /**
+     * @return connection id or -1 if an error
+     */
+    public int getRefCountSync() {
+        Message response = sendMessageSynchronously(REQ_GET_REFCOUNT);
+        if ((response != null) && (response.what == RSP_GET_REFCOUNT)) {
+            return rspRefCount(response);
+        } else {
+            log("rspRefCount error response=" + response);
+            return -1;
+        }
+    }
+
+    /**
      * Request the connections ApnSetting.
      * Response {@link #rspApnSetting}
      */
@@ -234,8 +291,8 @@
         if (DBG) log("reqUpdateLinkPropertiesDataCallState");
     }
 
-    public boolean rspUpdateLinkPropertiesDataCallState(Message response) {
-        boolean retVal = response.arg1 == 1;
+    public LinkPropertyChangeAction rspUpdateLinkPropertiesDataCallState(Message response) {
+        LinkPropertyChangeAction retVal = LinkPropertyChangeAction.fromInt(response.arg1);
         if (DBG) log("rspUpdateLinkPropertiesState=" + retVal);
         return retVal;
     }
@@ -245,7 +302,7 @@
      *
      * @return true if link property has been updated. false otherwise.
      */
-    public boolean updateLinkPropertiesDataCallStateSync(DataCallState newState) {
+    public LinkPropertyChangeAction updateLinkPropertiesDataCallStateSync(DataCallState newState) {
         Message response =
             sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
         if ((response != null) &&
@@ -253,7 +310,7 @@
             return rspUpdateLinkPropertiesDataCallState(response);
         } else {
             log("getLinkProperties error response=" + response);
-            return false;
+            return LinkPropertyChangeAction.NONE;
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index b7ac879..5ddfcd1 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -987,7 +987,7 @@
                     resetAllRetryCounts();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
-                    onCleanUpConnection(true, APN_DEFAULT_ID, Phone.REASON_DATA_DISABLED);
+                    onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
                 }
             }
         }
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 1b49d2d..a516b49 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -18,13 +18,20 @@
 
 import static android.Manifest.permission.READ_PHONE_STATE;
 import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.Power;
+import android.os.PowerManager;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.util.Log;
+import android.view.WindowManager;
 
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.CommandsInterface.RadioState;
@@ -32,6 +39,8 @@
 
 import android.os.SystemProperties;
 
+import com.android.internal.R;
+
 /**
  * {@hide}
  */
@@ -88,6 +97,8 @@
     private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
     private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
     private static final int EVENT_ICC_STATUS_CHANGED = 12;
+    private static final int EVENT_CARD_REMOVED = 13;
+    private static final int EVENT_CARD_ADDED = 14;
 
     /*
       UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
@@ -106,6 +117,11 @@
         public boolean isPinLocked() {
             return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
         }
+
+        public boolean iccCardExist() {
+            return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)
+                    || (this == NETWORK_LOCKED) || (this == READY));
+        }
     }
 
     public State getState() {
@@ -400,6 +416,8 @@
         boolean transitionedIntoPinLocked;
         boolean transitionedIntoAbsent;
         boolean transitionedIntoNetworkLocked;
+        boolean isIccCardRemoved;
+        boolean isIccCardAdded;
 
         State oldState, newState;
 
@@ -416,24 +434,36 @@
         transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
         transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
                 && newState == State.NETWORK_LOCKED);
+        isIccCardRemoved = (oldState != null &&
+                        oldState.iccCardExist() && newState == State.ABSENT);
+        isIccCardAdded = (oldState == State.ABSENT &&
+                        newState != null && newState.iccCardExist());
 
         if (transitionedIntoPinLocked) {
-            if(mDbg) log("Notify SIM pin or puk locked.");
+            if (mDbg) log("Notify SIM pin or puk locked.");
             mPinLockedRegistrants.notifyRegistrants();
             broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
                     (newState == State.PIN_REQUIRED) ?
                        INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
         } else if (transitionedIntoAbsent) {
-            if(mDbg) log("Notify SIM missing.");
+            if (mDbg) log("Notify SIM missing.");
             mAbsentRegistrants.notifyRegistrants();
             broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null);
         } else if (transitionedIntoNetworkLocked) {
-            if(mDbg) log("Notify SIM network locked.");
+            if (mDbg) log("Notify SIM network locked.");
             mNetworkLockedRegistrants.notifyRegistrants();
             broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
                   INTENT_VALUE_LOCKED_NETWORK);
         }
 
+        if (isIccCardRemoved) {
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));
+        } else if (isIccCardAdded) {
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
+        }
+
+
+
         /*
          * TODO: We need to try to remove this, maybe if the RIL sends up a RIL_UNSOL_SIM_REFRESH?
          */
@@ -443,6 +473,48 @@
                 ((SIMRecords)mPhone.mIccRecords).onSimReady();
             }
         }
+
+    }
+
+    private void onIccSwap(boolean isAdded) {
+        // TODO: Here we assume the device can't handle SIM hot-swap
+        //      and has to reboot. We may want to add a property,
+        //      e.g. REBOOT_ON_SIM_SWAP, to indicate if modem support
+        //      hot-swap.
+        DialogInterface.OnClickListener listener = null;
+
+
+        // TODO: SimRecords is not reset while SIM ABSENT (only reset while
+        //       Radio_off_or_not_available). Have to reset in both both
+        //       added or removed situation.
+        listener = new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if (which == DialogInterface.BUTTON_POSITIVE) {
+                    if (mDbg) log("Reboot due to SIM swap");
+                    PowerManager pm = (PowerManager) mPhone.getContext()
+                    .getSystemService(Context.POWER_SERVICE);
+                    pm.reboot("SIM is added.");
+                }
+            }
+
+        };
+
+        Resources r = Resources.getSystem();
+
+        String title = (isAdded) ? r.getString(R.string.sim_added_title) :
+            r.getString(R.string.sim_removed_title);
+        String message = (isAdded) ? r.getString(R.string.sim_added_message) :
+            r.getString(R.string.sim_removed_message);
+        String buttonTxt = r.getString(R.string.sim_restart_button);
+
+        AlertDialog dialog = new AlertDialog.Builder(mPhone.getContext())
+            .setTitle(title)
+            .setMessage(message)
+            .setPositiveButton(buttonTxt, listener)
+            .create();
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        dialog.show();
     }
 
     /**
@@ -609,6 +681,12 @@
                     Log.d(mLogTag, "Received Event EVENT_ICC_STATUS_CHANGED");
                     mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
                     break;
+                case EVENT_CARD_REMOVED:
+                    onIccSwap(false);
+                    break;
+                case EVENT_CARD_ADDED:
+                    onIccSwap(true);
+                    break;
                 default:
                     Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what);
             }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index f5d6c51..93fc9ce 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -113,6 +113,7 @@
     /* Deactivate data call reasons */
     int DEACTIVATE_REASON_NONE = 0;
     int DEACTIVATE_REASON_RADIO_OFF = 1;
+    int DEACTIVATE_REASON_PDP_RESET = 2;
 
 /*
 cat include/telephony/ril.h | \
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 4927006..4309309 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -72,10 +72,12 @@
      */
     static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country";
 
-    /** 'true' if device supports both LTE and CDMA mode of operation.
-     *  Availability: Set only on devices supporting LTE and CDMA.
+    /**
+     * The contents of this property is the value of the kernel command line
+     * product_type variable that corresponds to a product that supports LTE on CDMA.
+     * {@see BaseCommands#getLteOnCdmaMode()}
      */
-    static final String PROPERTY_NETWORK_LTE_ON_CDMA = "telephony.lte_on_cdma";
+    static final String PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE = "telephony.lteOnCdmaProductType";
 
     static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 375d0d1..e3e3d78 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -521,19 +521,7 @@
              * TODO: Make this configurable?
              */
             int nextReconnectDelay = mDataConnections.get(0).getRetryTimer();
-            log("Data Connection activate failed. Scheduling next attempt for "
-                    + (nextReconnectDelay / 1000) + "s");
-
-            AlarmManager am =
-                (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-            Intent intent = new Intent(INTENT_RECONNECT_ALARM);
-            intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason);
-            mReconnectIntent = PendingIntent.getBroadcast(
-                    mPhone.getContext(), 0, intent, 0);
-            am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    SystemClock.elapsedRealtime() + nextReconnectDelay,
-                    mReconnectIntent);
-
+            startAlarmForReconnect(nextReconnectDelay, reason);
             mDataConnections.get(0).increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
@@ -545,6 +533,22 @@
         }
     }
 
+    private void startAlarmForReconnect(int delay, String reason) {
+
+        log("Data Connection activate failed. Scheduling next attempt for "
+                + (delay / 1000) + "s");
+
+        AlarmManager am =
+            (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+        Intent intent = new Intent(INTENT_RECONNECT_ALARM);
+        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason);
+        mReconnectIntent = PendingIntent.getBroadcast(
+                mPhone.getContext(), 0, intent, 0);
+        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + delay, mReconnectIntent);
+
+    }
+
     private void notifyNoData(FailCause lastFailCauseCode) {
         setState(State.FAILED);
         notifyDataAvailability(null);
@@ -702,7 +706,7 @@
         mActiveApn = null;
         if (retryAfterDisconnected(reason)) {
           // Wait a bit before trying, so we're not tying up RIL command channel.
-          sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
+          startAlarmForReconnect(APN_DELAY_MILLIS, reason);
       }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 6b4054a..e1a6fef 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -127,10 +127,7 @@
         if (apnContext != null) {
             apnContext.setReason(reason);
             if (apnContext.getState() == State.FAILED) {
-                Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
-                msg.arg1 = 0; // tearDown is false
-                msg.obj = (ApnContext)apnContext;
-                sendMessage(msg);
+                apnContext.setState(State.IDLE);
             }
             sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
         }
@@ -615,28 +612,26 @@
      *
      * @param apnContext
      * @param tearDown
-     * @return refCount
+     * @return none
      */
-    private int releaseApnContext(ApnContext apnContext, boolean tearDown) {
+    private void releaseApnContext(ApnContext apnContext, boolean tearDown) {
         if (apnContext == null) {
             if (DBG) loge("releaseApnContext: apnContext null should not happen, ignore");
-            return -1;
+            return;
         }
         DataConnection dc = apnContext.getDataConnection();
         if (dc == null) {
             if (DBG) loge("releaseApnContext: apnContext dc == null should not happen, ignore");
-            return -1;
+            return;
         }
-        int refCount = dc.decAndGetRefCount();
-        if (DBG) log("releaseApnContext: dec refCount=" + refCount + " tearDown=" + tearDown);
-        if (tearDown && (refCount == 0)) {
+        if (tearDown) {
             if (DBG) log("releaseApnContext: tearing down");
             Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
             apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
         }
         apnContext.setDataConnection(null);
         apnContext.setDataConnectionAc(null);
-        return refCount;
+        return;
     }
 
     private void setupDataOnReadyApns(String reason) {
@@ -644,7 +639,7 @@
         for (ApnContext apnContext : mApnContexts.values()) {
             if (apnContext.isReady()) {
                 if (apnContext.getState() == State.FAILED) {
-                    cleanUpConnection(false, apnContext);
+                    cleanApnContextBeforeRestart(apnContext);
                     if (apnContext.getDataConnection() != null) {
                         apnContext.getDataConnection().resetRetryCount();
                     }
@@ -800,6 +795,34 @@
         if (DBG) {
             log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
         }
+        if (tearDown && cleanApnContextBeforeRestart(apnContext)) {
+            // if the request is tearDown and ApnContext does not hold an active connection,
+            // we're ok to return here.
+            return;
+        }
+
+        DataConnectionAc dcac = apnContext.getDataConnectionAc();
+        if (dcac != null) {
+            if (tearDown) {
+                apnContext.setState(State.DISCONNECTING);
+                releaseApnContext(apnContext, tearDown);
+            } else {
+                dcac.resetSync();
+                apnContext.setState(State.IDLE);
+                mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+                apnContext.setDataConnection(null);
+                apnContext.setDataConnectionAc(null);
+            }
+        }
+    }
+
+    /**
+     * @param APNContext to clean
+     * @return true if ApnContext is not connected anymore.
+     *         false if ApnContext still holds a connection.
+     */
+    private boolean cleanApnContextBeforeRestart(ApnContext apnContext) {
+        if (apnContext == null) return true;
 
         // Clear the reconnect alarm, if set.
         if (apnContext.getReconnectIntent() != null) {
@@ -811,32 +834,16 @@
 
         if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
             if (DBG) log("cleanUpConnection: state= " + apnContext.getState());
-            return;
+            return true;
         }
 
         if (apnContext.getState() == State.FAILED) {
-            if (DBG) log("cleanUpConnection: state is in FAILED");
             apnContext.setState(State.IDLE);
-            return;
+            return true;
         }
-
-        DataConnection conn = apnContext.getDataConnection();
-        if (conn != null) {
-            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
-            apnContext.setState(State.DISCONNECTING);
-            if (tearDown) {
-                releaseApnContext(apnContext, tearDown);
-            } else {
-                if (dcac != null) {
-                    dcac.resetSync();
-                }
-                apnContext.setState(State.IDLE);
-                mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-            }
-        }
+        return false;
     }
 
-
     /**
      * @param types comma delimited list of APN types
      * @return array of APN types
@@ -927,37 +934,48 @@
             return false;
         }
 
-        dc = findReadyDataConnection(apn);
+        // First, check to see if ApnContext already has DC.
+        // This could happen if the retries are currently  engaged.
+        dc = (GsmDataConnection)apnContext.getDataConnection();
 
         if (dc == null) {
-            if (DBG) log("setupData: No ready GsmDataConnection found!");
-            // TODO: When allocating you are mapping type to id. If more than 1 free,
-            // then could findFreeDataConnection get the wrong one??
-            dc = findFreeDataConnection();
-        }
 
-        if (dc == null) {
-            dc = createDataConnection();
-        }
+            dc = (GsmDataConnection) checkForConnectionForApnContext(apnContext);
 
-        if (dc == null) {
-            if (DBG) log("setupData: No free GsmDataConnection found!");
-            return false;
-        }
+            if (dc == null) {
+                dc = findReadyDataConnection(apn);
+            }
 
-        dc.setProfileId( profileId );
-        dc.setActiveApnType(apnContext.getApnType());
-        int refCount = dc.incAndGetRefCount();
-        if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
+            if (dc == null) {
+                if (DBG) log("setupData: No ready GsmDataConnection found!");
+                // TODO: When allocating you are mapping type to id. If more than 1 free,
+                // then could findFreeDataConnection get the wrong one??
+                dc = findFreeDataConnection();
+            }
 
-        // configure retry count if no other Apn is using the same connection.
-        if (refCount == 1) {
-            configureRetry(dc, apnContext.getApnType());
+            if (dc == null) {
+                dc = createDataConnection();
+            }
+
+            if (dc == null) {
+                if (DBG) log("setupData: No free GsmDataConnection found!");
+                return false;
+            }
+
+            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
+            dc.setProfileId( profileId );
+            dc.setActiveApnType(apnContext.getApnType());
+            int refCount = dcac.getRefCountSync();
+            if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
+
+            // configure retry count if no other Apn is using the same connection.
+            if (refCount == 0) {
+                configureRetry(dc, apnContext.getApnType());
+            }
+            apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId()));
+            apnContext.setApnSetting(apn);
+            apnContext.setDataConnection(dc);
         }
-        DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
-        apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId()));
-        apnContext.setApnSetting(apn);
-        apnContext.setDataConnection(dc);
 
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
@@ -1053,25 +1071,37 @@
                     if (DBG) log("onDataStateChanged(ar): Found ConnId=" + connectionId
                             + " newState=" + newState.toString());
                     if (newState.active != 0) {
-                        boolean changed
-                            = dcac.updateLinkPropertiesDataCallStateSync(newState);
-                        if (changed) {
+                        boolean resetConnection;
+                        switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) {
+                        case NONE:
+                            if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
+                            resetConnection = false;
+                            break;
+                        case CHANGED:
                             if (DBG) log("onDataStateChanged(ar): Found and changed, notify");
                             mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
-                                    apnContext.getApnType());
-                            // Temporary hack, if false we'll reset connections and at this
-                            // time a transition from CDMA -> Global fails. The DEACTIVATE
-                            // fails with a GENERIC_FAILURE and the VZWINTERNET connection is
-                            // never setup. @see bug/
+                                                        apnContext.getApnType());
+                            // Temporary hack, at this time a transition from CDMA -> Global
+                            // fails so we'll hope for the best and not reset the connection.
+                            // @see bug/4455071
                             if (SystemProperties.getBoolean("telephony.ignore-state-changes",
-                                    true)) {
+                                                            true)) {
                                 log("onDataStateChanged(ar): STOPSHIP don't reset, continue");
-                                continue;
+                                resetConnection = false;
+                            } else {
+                                // Things changed so reset connection, when hack is removed
+                                // this is the normal path.
+                                log("onDataStateChanged(ar): changed so resetting connection");
+                                resetConnection = true;
                             }
-                        } else {
-                            if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
-                            continue;
+                            break;
+                        case RESET:
+                        default:
+                            if (DBG) log("onDataStateChanged(ar): an error, reset connection");
+                            resetConnection = true;
+                            break;
                         }
+                        if (resetConnection == false) continue;
                     }
                 }
 
@@ -1214,10 +1244,30 @@
             preTxPkts = mTxPkts;
             preRxPkts = mRxPkts;
 
-            mTxPkts = TrafficStats.getMobileTxPackets();
-            mRxPkts = TrafficStats.getMobileRxPackets();
+            long txSum = 0, rxSum = 0;
+            for (ApnContext apnContext : mApnContexts.values()) {
+                if (apnContext.getState() == State.CONNECTED) {
+                    DataConnectionAc dcac = apnContext.getDataConnectionAc();
+                    if (dcac == null) continue;
 
-            //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts));
+                    LinkProperties linkProp = dcac.getLinkPropertiesSync();
+                    if (linkProp == null) continue;
+
+                    String iface = linkProp.getInterfaceName();
+
+                    if (iface != null) {
+                        long stats = TrafficStats.getTxPackets(iface);
+                        if (stats > 0) txSum += stats;
+                        stats = TrafficStats.getRxPackets(iface);
+                        if (stats > 0) rxSum += stats;
+                    }
+                }
+            }
+
+            mTxPkts = txSum;
+            mRxPkts = rxSum;
+
+            // log("tx " + mTxPkts + " rx " + mRxPkts);
 
             if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
                 sent = mTxPkts - preTxPkts;
@@ -1333,7 +1383,8 @@
             loge("reconnectAfterFail: apnContext == null, impossible");
             return;
         }
-        if (apnContext.getState() == State.FAILED) {
+        if ((apnContext.getState() == State.FAILED) &&
+            (apnContext.getDataConnection() != null)) {
             if (!apnContext.getDataConnection().isRetryNeeded()) {
                 if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
                     mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
@@ -1353,23 +1404,7 @@
             }
 
             int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
-            if (DBG) {
-                log("reconnectAfterFail: activate failed. Scheduling next attempt for "
-                    + (nextReconnectDelay / 1000) + "s");
-            }
-
-            AlarmManager am =
-                (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-            Intent intent = new Intent(INTENT_RECONNECT_ALARM);
-            intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
-            // Should put an extra of apn type?
-            intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType());
-            apnContext.setReconnectIntent(PendingIntent.getBroadcast (
-                    mPhone.getContext(), 0, intent, 0));
-            am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    SystemClock.elapsedRealtime() + nextReconnectDelay,
-                    apnContext.getReconnectIntent());
-
+            startAlarmForReconnect(nextReconnectDelay, apnContext);
             apnContext.getDataConnection().increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
@@ -1383,6 +1418,25 @@
         }
     }
 
+    private void startAlarmForReconnect(int delay, ApnContext apnContext) {
+
+        if (DBG) {
+            log("Schedule alarm for reconnect: activate failed. Scheduling next attempt for "
+                + (delay / 1000) + "s");
+        }
+
+        AlarmManager am =
+            (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+        Intent intent = new Intent(INTENT_RECONNECT_ALARM);
+        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
+        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType());
+        apnContext.setReconnectIntent(PendingIntent.getBroadcast (
+                mPhone.getContext(), 0, intent, 0));
+        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + delay, apnContext.getReconnectIntent());
+
+    }
+
     private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode,
                               ApnContext apnContext) {
         if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
@@ -1437,23 +1491,10 @@
                 } else {
                     apnContext.setReason(Phone.REASON_DATA_ENABLED);
                 }
-                DataConnection conn = checkForConnectionForApnContext(apnContext);
-                if (conn == null) {
-                    if (apnContext.getState() == State.FAILED) {
-                        apnContext.setState(State.IDLE);
-                    }
-                    trySetup = true;
-                } else {
-                    int refCount = conn.incAndGetRefCount();
-                    apnContext.setDataConnection(conn);
-                    apnContext.setDataConnectionAc(
-                            mDataConnectionAsyncChannels.get(conn.getDataConnectionId()));
-                    if (DBG) {
-                        log("applyNewState: Found existing connection for " +
-                                apnContext.getApnType() + " inc refCount=" + refCount +
-                                " conn=" + conn);
-                    }
+                if (apnContext.getState() == State.FAILED) {
+                    apnContext.setState(State.IDLE);
                 }
+                trySetup = true;
             }
         }
         apnContext.setEnabled(enabled);
@@ -1588,7 +1629,7 @@
 
             if (DBG) {
                 log(String.format("onDataSetupComplete: success apn=%s",
-                    apnContext.getWaitingApns().get(0).apn) + " refCount=" + dc.getRefCount());
+                    apnContext.getWaitingApns().get(0).apn));
             }
             ApnSetting apn = apnContext.getApnSetting();
             if (apn.proxy != null && apn.proxy.length() != 0) {
@@ -1655,6 +1696,11 @@
                     }
                     apnContext.setState(State.FAILED);
                     mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
+
+                    releaseApnContext(apnContext, false);
+                    if (DBG) {
+                        log("onDataSetupComplete: permanent error apn=%s" + apnString );
+                    }
                 } else {
                     if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
                     startDelayedRetry(cause, apnContext);
@@ -1664,13 +1710,7 @@
                 apnContext.setState(State.SCANNING);
                 // Wait a bit before trying the next APN, so that
                 // we're not tying up the RIL command channel
-                sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),
-                        APN_DELAY_MILLIS);
-            }
-
-            int refCount = releaseApnContext(apnContext, false);
-            if (DBG) {
-                log("onDataSetupComplete: error apn=%s" + apnString + " refCount=" + refCount);
+                startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
             }
         }
     }
@@ -1710,7 +1750,7 @@
             // Wait a bit before trying the next APN, so that
             // we're not tying up the RIL command channel.
             // This also helps in any external dependency to turn off the context.
-            sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),APN_DELAY_MILLIS);
+            startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
         }
     }
 
@@ -1753,7 +1793,10 @@
     protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
         if (DBG) log("onCleanUpConnection");
         ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
-        cleanUpConnection(tearDown, apnContext);
+        if (apnContext != null) {
+            apnContext.setReason(reason);
+            cleanUpConnection(tearDown, apnContext);
+        }
     }
 
     protected boolean isConnected() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index b7b0af3..643f709 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -50,6 +50,7 @@
 
         if(mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) {
             mPhone.mCM.registerForNVReady(mHandler, EVENT_ICC_READY, null);
+            mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
         }
     }
 
@@ -60,6 +61,11 @@
         mPhone.mCM.unregisterForSIMLockedOrAbsent(mHandler);
         mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
         mPhone.mCM.unregisterForSIMReady(mHandler);
+
+        if(mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) {
+            mPhone.mCM.unregisterForNVReady(mHandler);
+            mPhone.mCM.unregisterForIccStatusChanged(mHandler);
+        }
     }
 
     @Override